mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-11-28 13:45:36 +01:00
Various
will document in next commit
This commit is contained in:
parent
06f61208f3
commit
4cab0b223d
2
.gitignore
vendored
2
.gitignore
vendored
@ -13,6 +13,8 @@
|
||||
*.log
|
||||
gradle.log
|
||||
/lib
|
||||
/core/lib
|
||||
/bukkit/lib
|
||||
/core/build
|
||||
/forge189/build
|
||||
/forge1710/build
|
||||
|
@ -1,3 +1,6 @@
|
||||
repositories {
|
||||
flatDir {dirs 'lib'}
|
||||
}
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
compile 'org.bukkit.craftbukkitv1_10:craftbukkitv1_10:1.10'
|
||||
@ -37,8 +40,8 @@ apply plugin: 'com.github.johnrengelman.shadow'
|
||||
shadowJar {
|
||||
dependencies {
|
||||
include(dependency('com.github.luben:zstd-jni:1.1.1'))
|
||||
include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('co.aikar:fastutil-lite:1.0'))
|
||||
// include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('it.unimi.dsi:fastutil:6.5.1'))
|
||||
include(dependency(':core'))
|
||||
}
|
||||
archiveName = "${parent.name}-${project.name}-${parent.version}.jar"
|
||||
|
@ -5,7 +5,6 @@ import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
|
||||
import com.boydti.fawe.bukkit.v0.BukkitQueue_All;
|
||||
import com.boydti.fawe.bukkit.v1_10.BukkitQueue_1_10;
|
||||
import com.boydti.fawe.bukkit.v1_11.BukkitQueue_1_11;
|
||||
import com.boydti.fawe.bukkit.v1_11.compression.CompressionOptimizer;
|
||||
import com.boydti.fawe.bukkit.v1_7.BukkitQueue17;
|
||||
import com.boydti.fawe.bukkit.v1_8.BukkitQueue18R3;
|
||||
import com.boydti.fawe.bukkit.v1_9.BukkitQueue_1_9_R1;
|
||||
@ -69,15 +68,6 @@ public class BukkitMain extends JavaPlugin {
|
||||
break;
|
||||
} catch (IllegalStateException e) {}
|
||||
}
|
||||
switch (version) {
|
||||
case v1_11_R1:
|
||||
try {
|
||||
CompressionOptimizer optimizer = new CompressionOptimizer();
|
||||
// optimizer.optimize();
|
||||
} catch (Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum Version {
|
||||
|
@ -195,7 +195,8 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
|
||||
|
||||
@Override
|
||||
public boolean hasSky() {
|
||||
return getWorld().getEnvironment() == World.Environment.NORMAL;
|
||||
World world = getWorld();
|
||||
return world == null || world.getEnvironment() == World.Environment.NORMAL;
|
||||
}
|
||||
|
||||
private volatile boolean timingsEnabled;
|
||||
|
@ -1,118 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.v1_11.compression;
|
||||
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtMethod;
|
||||
import javassist.LoaderClassPath;
|
||||
import net.minecraft.server.v1_11_R1.RegionFile;
|
||||
|
||||
public class CompressionOptimizer {
|
||||
|
||||
private final ClassPool pool;
|
||||
|
||||
public CompressionOptimizer() {
|
||||
this.pool = ClassPool.getDefault();
|
||||
}
|
||||
|
||||
public void loadSafe(String name) throws Throwable {
|
||||
try {
|
||||
pool.get(name).toClass();
|
||||
} catch (Throwable e) {
|
||||
while (e.getCause() != null) {
|
||||
e = e.getCause();
|
||||
}
|
||||
if (e instanceof ClassNotFoundException) {
|
||||
loadSafe(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadPackage(String... packages) throws IOException {
|
||||
JarInputStream jarFile = new JarInputStream(new FileInputStream(MainUtil.getJarFile()));
|
||||
JarEntry jarEntry;
|
||||
while(true) {
|
||||
jarEntry = jarFile.getNextJarEntry();
|
||||
if(jarEntry == null){
|
||||
break;
|
||||
}
|
||||
if (jarEntry.getName ().endsWith (".class")) {
|
||||
for (String p : packages) {
|
||||
if (jarEntry.getName ().startsWith(p)) {
|
||||
String name = jarEntry.getName().substring(0, jarEntry.getName().length() - 6).replaceAll("/", "\\.");
|
||||
try {
|
||||
loadSafe(name);
|
||||
} catch (Throwable ignore) {}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void optimize() throws Throwable {
|
||||
// pool.insertClassPath(new ClassClassPath(PGZIPOutputStream.class));
|
||||
// pool.insertClassPath(new ClassClassPath(PGZIPBlock.class));
|
||||
// pool.insertClassPath(new ClassClassPath(PGZIPState.class));
|
||||
// pool.insertClassPath(new ClassClassPath(PGZIPThreadLocal.class));
|
||||
// pool.insertClassPath(new ClassClassPath(ClassPath.class));
|
||||
// pool.insertClassPath(new ClassClassPath(CompressionOptimizer.class));
|
||||
pool.insertClassPath(new LoaderClassPath(this.getClass().getClassLoader()));
|
||||
pool.get("com.boydti.fawe.object.io.PGZIPOutputStream").toClass();
|
||||
pool.get("com.boydti.fawe.object.io.PGZIPBlock").toClass();
|
||||
pool.get("com.boydti.fawe.object.io.PGZIPState").toClass();
|
||||
pool.get("com.boydti.fawe.object.io.PGZIPThreadLocal").toClass();
|
||||
pool.get("com.boydti.fawe.bukkit.v1_11.compression.CompressionOptimizer").toClass();
|
||||
pool.get("javassist.ClassPath").toClass();
|
||||
pool.importPackage("net.minecraft.server.v1_11_R1");
|
||||
pool.importPackage("java.lang");
|
||||
pool.importPackage("java.lang.reflect");
|
||||
pool.importPackage("java.io");
|
||||
pool.importPackage("com.boydti.fawe.bukkit.v1_11.compression");
|
||||
// RegionFile.class.getDeclaredClasses()[0];
|
||||
|
||||
|
||||
{ // Optimize NBTCompressedStreamTools
|
||||
CtClass clazz = pool.get("net.minecraft.server.v1_11_R1.NBTCompressedStreamTools");
|
||||
CtMethod methodA_getStream = clazz.getDeclaredMethod("a", new CtClass[]{pool.get("net.minecraft.server.v1_11_R1.NBTTagCompound"), pool.get("java.io.OutputStream")});
|
||||
methodA_getStream.setBody("{" +
|
||||
"java.io.DataOutputStream dataoutputstream = new java.io.DataOutputStream(new java.io.BufferedOutputStream(new com.boydti.fawe.object.io.PGZIPOutputStream($2)));" +
|
||||
"try {" +
|
||||
" a($1, (java.io.DataOutput) dataoutputstream);" +
|
||||
"} finally {" +
|
||||
" dataoutputstream.close();" +
|
||||
"}" +
|
||||
"}");
|
||||
clazz.toClass();
|
||||
}
|
||||
|
||||
{ // Optimize RegionFile
|
||||
CtClass clazz = pool.get("net.minecraft.server.v1_11_R1.RegionFile");
|
||||
CtMethod methodB_getStream = clazz.getDeclaredMethod("b", new CtClass[]{CtClass.intType, CtClass.intType});
|
||||
methodB_getStream.setBody("{" +
|
||||
"Constructor constructor = $0.getClass().getDeclaredClasses()[0].getConstructors()[0];" +
|
||||
" constructor.setAccessible(true);" +
|
||||
" return $0.d($1, $2) ? null : new java.io.DataOutputStream(new java.io.BufferedOutputStream(new com.boydti.fawe.object.io.PGZIPOutputStream((OutputStream) CompressionOptimizer.newInstance(constructor, $0, $1, $2))));" +
|
||||
"}");
|
||||
clazz.toClass();
|
||||
|
||||
// RegionFile $0 = null;
|
||||
// int $1 = 0;
|
||||
// int $2 = 0;
|
||||
//
|
||||
// Constructor<?> constructor = $0.getClass().getDeclaredClasses()[0].getConstructors()[0];
|
||||
// constructor.setAccessible(true);
|
||||
// return $0.d($1, $2) ? null : new java.io.DataOutputStream(new java.io.BufferedOutputStream(new com.boydti.fawe.object.io.PGZIPOutputStream((OutputStream) constructor.newInstance($1, $2))));
|
||||
}
|
||||
}
|
||||
|
||||
public static Object newInstance(Constructor constructor, RegionFile file, int a, int b) throws IllegalAccessException, InvocationTargetException, InstantiationException {
|
||||
return constructor.newInstance(file, a, b);
|
||||
}
|
||||
}
|
@ -1,3 +1,6 @@
|
||||
repositories {
|
||||
flatDir {dirs 'lib'}
|
||||
}
|
||||
dependencies {
|
||||
testCompile 'junit:junit:4.12'
|
||||
compile 'org.yaml:snakeyaml:1.16'
|
||||
@ -7,8 +10,8 @@ dependencies {
|
||||
compile group: "com.plotsquared", name: "plotsquared-api", version: "latest", changing: true
|
||||
compile 'org.primesoft:BlocksHub:2.0'
|
||||
compile 'com.github.luben:zstd-jni:1.1.1'
|
||||
compile 'org.javassist:javassist:3.22.0-CR1'
|
||||
compile 'co.aikar:fastutil-lite:1.0'
|
||||
// compile 'org.javassist:javassist:3.22.0-CR1'
|
||||
compile 'it.unimi.dsi:fastutil:6.5.1'
|
||||
compile(group: 'com.sk89q.worldedit', name: 'worldedit-core', version:'6.1.3-SNAPSHOT') {
|
||||
exclude(module: 'bukkit-classloader-check')
|
||||
}
|
||||
|
@ -533,11 +533,7 @@ public class FaweAPI {
|
||||
final int i = i2 + x;
|
||||
final int xx = x_offset + x;
|
||||
final short id = (short) (ids[i] & 0xFF);
|
||||
if (FaweCache.hasData(id)) {
|
||||
queue.setBlock(xx, yy, zz, id, datas[i]);
|
||||
} else {
|
||||
queue.setBlock(xx, yy, zz, id, (byte) 0);
|
||||
}
|
||||
queue.setBlock(xx, yy, zz, id, datas[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,11 @@ 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.FaweQueue;
|
||||
import com.boydti.fawe.object.mask.FaweBlockMatcher;
|
||||
import com.boydti.fawe.object.number.LongAdder;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
@ -16,9 +19,12 @@ import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.function.pattern.RandomPattern;
|
||||
import com.sk89q.worldedit.util.command.binding.Switch;
|
||||
import com.sk89q.worldedit.util.command.parametric.Optional;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
@ -60,61 +66,107 @@ public class AnvilCommands {
|
||||
final FaweBlockMatcher matchTo = FaweBlockMatcher.setBlocks(worldEdit.getBlocks(player, to, true));
|
||||
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);
|
||||
}
|
||||
if (matchFrom.apply(block)) matchTo.apply(block);
|
||||
}
|
||||
});
|
||||
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(count.longValue()));
|
||||
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(-1));
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = {"/replaceallpattern", "/reap", "/repallpat"},
|
||||
usage = "<folder> [from-block] <to-pattern>",
|
||||
desc = "Replace all blocks in the selection with another",
|
||||
flags = "d",
|
||||
flags = "dm",
|
||||
min = 2,
|
||||
max = 4
|
||||
)
|
||||
@CommandPermissions("worldedit.anvil.replaceall")
|
||||
public void replaceAllPattern(Player player, EditSession editSession, String folder, @Optional String from, final Pattern 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);
|
||||
}
|
||||
File root = new File(folder + File.separator + "region");
|
||||
MCAQueue queue = new MCAQueue(folder, root, true);
|
||||
final LongAdder count = new LongAdder();
|
||||
queue.filterWorld(new MCAFilter() {
|
||||
private final MutableBlockVector mutable = new MutableBlockVector(0, 0, 0);
|
||||
|
||||
@Override
|
||||
public void applyBlock(int x, int y, int z, BaseBlock block) {
|
||||
if (matchFrom.apply(block)) {
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
mutable.mutZ(z);
|
||||
BaseBlock newBlock = to.apply(mutable);
|
||||
int currentId = block.getId();
|
||||
if (FaweCache.hasNBT(currentId)) {
|
||||
block.setNbtData(null);
|
||||
public void replaceAllPattern(Player player, String folder, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap) throws WorldEditException {
|
||||
FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(folder, true, false);
|
||||
MCAQueue queue = new MCAQueue(folder, defaultQueue.getSaveFolder(), defaultQueue.hasSky());
|
||||
if (useMap) {
|
||||
List<String> split = StringMan.split(from, ',');
|
||||
if (to instanceof RandomPattern) {
|
||||
Pattern[] patterns = ((RandomPattern) to).getPatterns().toArray(new Pattern[0]);
|
||||
if (patterns.length == split.size()) {
|
||||
Pattern[] map = new Pattern[Character.MAX_VALUE + 1];
|
||||
for (int i = 0; i < split.size(); i++) {
|
||||
Pattern pattern = patterns[i];
|
||||
String arg = split.get(i);
|
||||
ArrayList<BaseBlock> blocks = new ArrayList<BaseBlock>();
|
||||
for (String arg2 : arg.split(",")) {
|
||||
BaseBlock block = worldEdit.getBlock(player, arg, true);
|
||||
if (!useData && !arg2.contains(":")) {
|
||||
block = new BaseBlock(block.getId(), -1);
|
||||
}
|
||||
blocks.add(block);
|
||||
}
|
||||
for (BaseBlock block : blocks) {
|
||||
if (block.getData() != -1) {
|
||||
int combined = FaweCache.getCombined(block);
|
||||
map[combined] = pattern;
|
||||
} else {
|
||||
for (int data = 0; data < 16; data++) {
|
||||
int combined = FaweCache.getCombined(block.getId(), data);
|
||||
map[combined] = pattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
block.setId(newBlock.getId());
|
||||
block.setData(newBlock.getData());
|
||||
count.add(1);
|
||||
queue.filterWorld(new MCAFilter() {
|
||||
private final MutableBlockVector mutable = new MutableBlockVector(0, 0, 0);
|
||||
@Override
|
||||
public void applyBlock(int x, int y, int z, BaseBlock block) {
|
||||
int id = block.getId();
|
||||
int data = FaweCache.hasData(id) ? block.getData() : 0;
|
||||
int combined = FaweCache.getCombined(id, data);
|
||||
Pattern p = map[combined];
|
||||
if (p != null) {
|
||||
BaseBlock newBlock = p.apply(x, y, z);
|
||||
int currentId = block.getId();
|
||||
if (FaweCache.hasNBT(currentId)) {
|
||||
block.setNbtData(null);
|
||||
}
|
||||
block.setId(newBlock.getId());
|
||||
block.setData(newBlock.getData());
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
player.print(BBC.getPrefix() + "Mask:Pattern must be a 1:1 match");
|
||||
}
|
||||
} else {
|
||||
player.print(BBC.getPrefix() + "Must be a pattern list!");
|
||||
}
|
||||
});
|
||||
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(count.longValue()));
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
queue.filterWorld(new MCAFilter() {
|
||||
@Override
|
||||
public void applyBlock(int x, int y, int z, BaseBlock block) {
|
||||
if (matchFrom.apply(block)) {
|
||||
BaseBlock newBlock = to.apply(x, y, z);
|
||||
int currentId = block.getId();
|
||||
if (FaweCache.hasNBT(currentId)) {
|
||||
block.setNbtData(null);
|
||||
}
|
||||
block.setId(newBlock.getId());
|
||||
block.setData(newBlock.getData());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(-1));
|
||||
}
|
||||
|
||||
@Command(
|
||||
|
@ -123,6 +123,8 @@ public enum BBC {
|
||||
BRUSH_SPHERE("Sphere brush shape equipped (%s0).", "WorldEdit.Brush"),
|
||||
BRUSH_SCATTER("Scatter brush shape equipped (%s0, %s1).", "WorldEdit.Brush"),
|
||||
BRUSH_SHATTER("Shatter brush shape equipped (%s0, %s1).", "WorldEdit.Brush"),
|
||||
BRUSH_POPULATE("Populate brush shape equipped (%s0, %s1).", "WorldEdit.Brush"),
|
||||
BRUSH_LAYER("Layer brush shape equipped (%s0, %s1).", "WorldEdit.Brush"),
|
||||
BRUSH_STENCIL("Stencil brush equipped (%s0).", "WorldEdit.Brush"),
|
||||
BRUSH_LINE("Line brush shape equipped (%s0).", "WorldEdit.Brush"),
|
||||
BRUSH_SPLINE("Spline brush shape equipped (%s0). Right click an end to add a shape", "WorldEdit.Brush"),
|
||||
|
@ -9,6 +9,7 @@ import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Commands {
|
||||
@ -36,6 +37,15 @@ public class Commands {
|
||||
return new TranslatedCommand(command);
|
||||
}
|
||||
|
||||
public static String getAlias(String command) {
|
||||
if (cmdConfig == null) {
|
||||
return command;
|
||||
}
|
||||
ConfigurationSection commands = cmdConfig.getConfigurationSection(command);
|
||||
List<String> aliases = commands.getStringList("aliases");
|
||||
return (aliases == null || aliases.isEmpty()) ? command : aliases.get(0);
|
||||
}
|
||||
|
||||
public static class TranslatedCommand implements Command {
|
||||
private final String[] aliases;
|
||||
private final String usage;
|
||||
|
@ -206,7 +206,7 @@ public class NMSRelighter implements Relighter{
|
||||
currentMap.put((int) MathMan.tripleBlockCoord(x, y, z), present);
|
||||
}
|
||||
|
||||
public synchronized void fixLightingSafe(boolean sky) {
|
||||
public void fixLightingSafe(boolean sky) {
|
||||
try {
|
||||
if (sky) {
|
||||
fixSkyLighting();
|
||||
|
@ -14,7 +14,7 @@ import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import java.io.BufferedInputStream;
|
||||
import it.unimi.dsi.fastutil.io.FastBufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -49,7 +49,7 @@ public class CorruptSchematicStreamer {
|
||||
try {
|
||||
stream.reset();
|
||||
stream.mark(Integer.MAX_VALUE);
|
||||
DataInputStream dataInput = new DataInputStream(new BufferedInputStream(new GZIPInputStream(stream)));
|
||||
DataInputStream dataInput = new DataInputStream(new FastBufferedInputStream(new GZIPInputStream(stream)));
|
||||
byte[] match = matchTag.getBytes();
|
||||
int[] matchValue = new int[match.length];
|
||||
int matchIndex = 0;
|
||||
|
@ -27,7 +27,6 @@ public class SchematicStreamer extends NBTStreamer {
|
||||
}
|
||||
|
||||
public void addBlockReaders() {
|
||||
final long start = System.currentTimeMillis();
|
||||
NBTStreamReader initializer = new NBTStreamReader<Integer, Integer>() {
|
||||
@Override
|
||||
public void run(Integer length, Integer type) {
|
||||
|
@ -0,0 +1,940 @@
|
||||
package com.boydti.fawe.jnbt.anvil;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.PseudoRandom;
|
||||
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MutableBlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.pattern.BlockPattern;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
import it.unimi.dsi.fastutil.chars.Char2CharMap;
|
||||
import it.unimi.dsi.fastutil.chars.Char2CharOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
public class HeightMapMCAGenerator implements Extent {
|
||||
private final MutableBlockVector mutable = new MutableBlockVector();
|
||||
private final ForkJoinPool pool = new ForkJoinPool();
|
||||
|
||||
final Int2ObjectOpenHashMap<Char2CharOpenHashMap> blocks = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
private final byte[] heights;
|
||||
private final byte[] biomes;
|
||||
private final char[] floor;
|
||||
private final char[] main;
|
||||
private char[] overlay;
|
||||
|
||||
private final File folder;
|
||||
private final int length;
|
||||
private final int width;
|
||||
private final int area;
|
||||
|
||||
private boolean modifiedMain = false;
|
||||
|
||||
public HeightMapMCAGenerator(BufferedImage img, File regionFolder) {
|
||||
if (!regionFolder.exists()) {
|
||||
regionFolder.mkdirs();
|
||||
}
|
||||
this.folder = regionFolder;
|
||||
this.width = img.getWidth();
|
||||
this.length = img.getHeight();
|
||||
this.area = width * length;
|
||||
heights = new byte[area];
|
||||
biomes = new byte[area];
|
||||
floor = new char[area];
|
||||
main = new char[area];
|
||||
char stone = (char) FaweCache.getCombined(1, 0);
|
||||
char grass = (char) FaweCache.getCombined(2, 0);
|
||||
Arrays.fill(main, stone);
|
||||
Arrays.fill(floor, grass);
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
heights[index] = (byte) img.getRGB(x, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addCaves() throws WorldEditException {
|
||||
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(width, 255, length));
|
||||
addCaves(region);
|
||||
}
|
||||
|
||||
public void addSchems(Mask mask, WorldData worldData, ClipboardHolder[] clipboards, int rarity, boolean rotate) throws WorldEditException{
|
||||
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(width, 255, length));
|
||||
addSchems(region, mask, worldData, clipboards, rarity, rotate);
|
||||
}
|
||||
|
||||
public void addOre(Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException {
|
||||
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(width, 255, length));
|
||||
addOre(region, mask, material, size, frequency, rarity, minY, maxY);
|
||||
}
|
||||
|
||||
public void addDefaultOres(Mask mask) throws WorldEditException {
|
||||
addOres(new CuboidRegion(new Vector(0, 0, 0), new Vector(width, 255, length)), mask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector getMinimumPoint() {
|
||||
return new Vector(0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector getMaximumPoint() {
|
||||
return new Vector(width - 1, 255, length - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(Vector position, BaseBlock block) throws WorldEditException {
|
||||
return setBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ(), block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(Vector2D position, BaseBiome biome) {
|
||||
int index = position.getBlockZ() * width + position.getBlockX();
|
||||
if (index < 0 || index >= heights.length) return false;
|
||||
biomes[index] = (byte) biome.getId();
|
||||
return true;
|
||||
}
|
||||
|
||||
public int count;
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
|
||||
count++;
|
||||
int index = z * width + x;
|
||||
if (index < 0 || index >= heights.length) return false;
|
||||
int height = heights[index] & 0xFF;
|
||||
char combined = (char) FaweCache.getCombined(block);
|
||||
if (y > height) {
|
||||
if (y == height + 1) {
|
||||
if (overlay == null) {
|
||||
overlay = new char[area];
|
||||
}
|
||||
overlay[index] = combined;
|
||||
return true;
|
||||
}
|
||||
} else if (y == height) {
|
||||
floor[index] = combined;
|
||||
return true;
|
||||
}
|
||||
short chunkX = (short) (x >> 4);
|
||||
short chunkZ = (short) (z >> 4);
|
||||
int pair = MathMan.pair(chunkX, chunkZ);
|
||||
Char2CharOpenHashMap map = blocks.get(pair);
|
||||
if (map == null) {
|
||||
map = new Char2CharOpenHashMap();
|
||||
blocks.put(pair, map);
|
||||
}
|
||||
char blockPair = (char) (((y >> 4) << 12) + (x & 15) + ((z & 15) << 4) + ((y & 15) << 8));
|
||||
map.put(blockPair, combined != 0 ? combined : 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBiome getBiome(Vector2D position) {
|
||||
int index = position.getBlockZ() * width + position.getBlockX();
|
||||
if (index < 0 || index >= heights.length) return EditSession.nullBiome;
|
||||
return FaweCache.CACHE_BIOME[biomes[index] & 0xFF];
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlock(Vector position) {
|
||||
return getLazyBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(Vector position) {
|
||||
return getLazyBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(int x, int y, int z) {
|
||||
int index = z * width + x;
|
||||
if (index < 0 || index >= heights.length) return EditSession.nullBlock;
|
||||
int height = heights[index] & 0xFF;
|
||||
if (y > height) {
|
||||
if (y == height + 1) {
|
||||
return FaweCache.CACHE_BLOCK[overlay != null ? overlay[index] : 0];
|
||||
}
|
||||
if (!blocks.isEmpty()) {
|
||||
short chunkX = (short) (x >> 4);
|
||||
short chunkZ = (short) (z >> 4);
|
||||
int pair = MathMan.pair(chunkX, chunkZ);
|
||||
Char2CharOpenHashMap map = blocks.get(pair);
|
||||
if (map != null) {
|
||||
char blockPair = (char)(((y >> 4) << 12) + (x & 15) + ((z & 15) << 4) + ((y & 15) << 8));
|
||||
char combined = map.get(blockPair);
|
||||
if (combined != 0) {
|
||||
return FaweCache.CACHE_BLOCK[combined];
|
||||
}
|
||||
}
|
||||
}
|
||||
return FaweCache.CACHE_BLOCK[0];
|
||||
} else if (y == height) {
|
||||
return FaweCache.CACHE_BLOCK[floor[index]];
|
||||
} else {
|
||||
if (!blocks.isEmpty()) {
|
||||
short chunkX = (short) (x >> 4);
|
||||
short chunkZ = (short) (z >> 4);
|
||||
int pair = MathMan.pair(chunkX, chunkZ);
|
||||
Char2CharOpenHashMap map = blocks.get(pair);
|
||||
if (map != null) {
|
||||
char blockPair = (char)(((y >> 4) << 12) + (x & 15) + ((z & 15) << 4) + ((y & 15) << 8));
|
||||
char combined = map.get(blockPair);
|
||||
if (combined != 0) {
|
||||
return FaweCache.CACHE_BLOCK[combined];
|
||||
}
|
||||
}
|
||||
}
|
||||
return FaweCache.CACHE_BLOCK[main[index]];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
|
||||
int index = z * width + x;
|
||||
if (index < 0 || index >= heights.length) return y;
|
||||
return ((heights[index] & 0xFF) << 3) + (floor[index] & 0xFF) + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
|
||||
int index = z * width + x;
|
||||
if (index < 0 || index >= heights.length) return y;
|
||||
return heights[index] & 0xFF;
|
||||
}
|
||||
|
||||
public void setBiome(BufferedImage img, byte biome, boolean white) {
|
||||
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int height = img.getRGB(x, z) & 0xFF;
|
||||
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
|
||||
biomes[index] = biome;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setOverlay(BufferedImage img, char combined, boolean white) {
|
||||
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
||||
if (overlay == null) overlay = new char[area];
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int height = img.getRGB(x, z) & 0xFF;
|
||||
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
|
||||
overlay[index] = combined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setMain(BufferedImage img, char combined, boolean white) {
|
||||
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
||||
modifiedMain = true;
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int height = img.getRGB(x, z) & 0xFF;
|
||||
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
|
||||
main[index] = combined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setFloor(BufferedImage img, char combined, boolean white) {
|
||||
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int height = img.getRGB(x, z) & 0xFF;
|
||||
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
|
||||
floor[index] = combined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setColumn(BufferedImage img, char combined, boolean white) {
|
||||
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
||||
modifiedMain = true;
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int height = img.getRGB(x, z) & 0xFF;
|
||||
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
|
||||
main[index] = combined;
|
||||
floor[index] = combined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setBiome(Mask mask, byte biome) {
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int y = heights[index] & 0xFF;
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
if (mask.test(mutable)) {
|
||||
biomes[index] = biome;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setOverlay(Mask mask, char combined) {
|
||||
int index = 0;
|
||||
if (overlay == null) overlay = new char[area];
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int y = heights[index] & 0xFF;
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
if (mask.test(mutable)) {
|
||||
overlay[index] = combined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setFloor(Mask mask, char combined) {
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int y = heights[index] & 0xFF;
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
if (mask.test(mutable)) {
|
||||
floor[index] = combined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setMain(Mask mask, char combined) {
|
||||
modifiedMain = true;
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int y = heights[index] & 0xFF;
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
if (mask.test(mutable)) {
|
||||
main[index] = combined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setColumn(Mask mask, char combined) {
|
||||
modifiedMain = true;
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int y = heights[index] & 0xFF;
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
if (mask.test(mutable)) {
|
||||
floor[index] = combined;
|
||||
main[index] = combined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setOverlay(BufferedImage img, Pattern pattern, boolean white) {
|
||||
if (pattern instanceof BlockPattern) {
|
||||
setOverlay(img, (char) ((BlockPattern) pattern).getBlock().getCombined(), white);
|
||||
return;
|
||||
}
|
||||
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
||||
if (overlay == null) overlay = new char[area];
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int height = img.getRGB(x, z) & 0xFF;
|
||||
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(height);
|
||||
overlay[index] = (char) pattern.apply(mutable).getCombined();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setMain(BufferedImage img, Pattern pattern, boolean white) {
|
||||
if (pattern instanceof BlockPattern) {
|
||||
setMain(img, (char) ((BlockPattern) pattern).getBlock().getCombined(), white);
|
||||
return;
|
||||
}
|
||||
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
||||
modifiedMain = true;
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int height = img.getRGB(x, z) & 0xFF;
|
||||
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(height);
|
||||
main[index] = (char) pattern.apply(mutable).getCombined();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setFloor(BufferedImage img, Pattern pattern, boolean white) {
|
||||
if (pattern instanceof BlockPattern) {
|
||||
setFloor(img, (char) ((BlockPattern) pattern).getBlock().getCombined(), white);
|
||||
return;
|
||||
}
|
||||
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int height = img.getRGB(x, z) & 0xFF;
|
||||
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(height);
|
||||
floor[index] = (char) pattern.apply(mutable).getCombined();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setColumn(BufferedImage img, Pattern pattern, boolean white) {
|
||||
if (pattern instanceof BlockPattern) {
|
||||
setColumn(img, (char) ((BlockPattern) pattern).getBlock().getCombined(), white);
|
||||
return;
|
||||
}
|
||||
if (img.getWidth() != width || img.getHeight() != length) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
|
||||
modifiedMain = true;
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int height = img.getRGB(x, z) & 0xFF;
|
||||
if (height == 255 || height > 0 && white && PseudoRandom.random.nextInt(256) <= height) {
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(height);
|
||||
char combined = (char) pattern.apply(mutable).getCombined();
|
||||
main[index] = combined;
|
||||
floor[index] = combined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setOverlay(Mask mask, Pattern pattern) {
|
||||
if (pattern instanceof BlockPattern) {
|
||||
setOverlay(mask, (char) ((BlockPattern) pattern).getBlock().getCombined());
|
||||
return;
|
||||
}
|
||||
int index = 0;
|
||||
if (overlay == null) overlay = new char[area];
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int y = heights[index] & 0xFF;
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
if (mask.test(mutable)) {
|
||||
overlay[index] = (char) pattern.apply(mutable).getCombined();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setFloor(Mask mask, Pattern pattern) {
|
||||
if (pattern instanceof BlockPattern) {
|
||||
setFloor(mask, (char) ((BlockPattern) pattern).getBlock().getCombined());
|
||||
return;
|
||||
}
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int y = heights[index] & 0xFF;
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
if (mask.test(mutable)) {
|
||||
floor[index] = (char) pattern.apply(mutable).getCombined();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setMain(Mask mask, Pattern pattern) {
|
||||
if (pattern instanceof BlockPattern) {
|
||||
setMain(mask, (char) ((BlockPattern) pattern).getBlock().getCombined());
|
||||
return;
|
||||
}
|
||||
modifiedMain = true;
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int y = heights[index] & 0xFF;
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
if (mask.test(mutable)) {
|
||||
main[index] = (char) pattern.apply(mutable).getCombined();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setColumn(Mask mask, Pattern pattern) {
|
||||
if (pattern instanceof BlockPattern) {
|
||||
setColumn(mask, (char) ((BlockPattern) pattern).getBlock().getCombined());
|
||||
return;
|
||||
}
|
||||
modifiedMain = true;
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++){
|
||||
int y = heights[index] & 0xFF;
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
if (mask.test(mutable)) {
|
||||
char combined = (char) pattern.apply(mutable).getCombined();
|
||||
floor[index] = combined;
|
||||
main[index] = combined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setBiome(int biome) {
|
||||
Arrays.fill(biomes, (byte) biome);
|
||||
}
|
||||
|
||||
private void setFloor(int value) {
|
||||
Arrays.fill(floor, (char) value);
|
||||
}
|
||||
|
||||
private void setColumn(int value) {
|
||||
setFloor(value);
|
||||
setMain(value);
|
||||
}
|
||||
|
||||
private void setMain(int value) {
|
||||
modifiedMain = true;
|
||||
Arrays.fill(main, (char) value);
|
||||
}
|
||||
|
||||
private void setOverlay(int value) {
|
||||
if (overlay == null) overlay = new char[area];
|
||||
Arrays.fill(overlay, (char) value);
|
||||
}
|
||||
|
||||
public void setFloor(Pattern value) {
|
||||
if (value instanceof BlockPattern) {
|
||||
setFloor(((BlockPattern) value).getBlock().getCombined());
|
||||
return;
|
||||
}
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++) {
|
||||
int y = heights[index] & 0xFF;
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
floor[index] = (char) value.apply(mutable).getCombined();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setColumn(Pattern value) {
|
||||
if (value instanceof BlockPattern) {
|
||||
setColumn(((BlockPattern) value).getBlock().getCombined());
|
||||
return;
|
||||
}
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++) {
|
||||
int y = heights[index] & 0xFF;
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
char combined = (char) value.apply(mutable).getCombined();
|
||||
main[index] = combined;
|
||||
floor[index] = combined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setMain(Pattern value) {
|
||||
if (value instanceof BlockPattern) {
|
||||
setMain(((BlockPattern) value).getBlock().getCombined());
|
||||
return;
|
||||
}
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++) {
|
||||
int y = heights[index] & 0xFF;
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
main[index] = (char) value.apply(mutable).getCombined();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setOverlay(Pattern value) {
|
||||
if (overlay == null) overlay = new char[area];
|
||||
if (value instanceof BlockPattern) {
|
||||
setOverlay(((BlockPattern) value).getBlock().getCombined());
|
||||
return;
|
||||
}
|
||||
int index = 0;
|
||||
for (int z = 0; z < length; z++) {
|
||||
mutable.mutZ(z);
|
||||
for (int x = 0; x < width; x++, index++) {
|
||||
int y = heights[index] & 0xFF;
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
overlay[index] = (char) value.apply(mutable).getCombined();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setHeights(int value) {
|
||||
Arrays.fill(heights, (byte) value);
|
||||
}
|
||||
|
||||
public void generate() throws IOException {
|
||||
int bcx = 0;
|
||||
int bcz = 0;
|
||||
int tcx = (width - 1) >> 4;
|
||||
int tcz = (length - 1) >> 4;
|
||||
final ThreadLocal<MCAChunk> chunkStore = new ThreadLocal<MCAChunk>() {
|
||||
@Override
|
||||
protected MCAChunk initialValue() {
|
||||
MCAChunk chunk = new MCAChunk(null, 0, 0);
|
||||
chunk.biomes = new byte[256];
|
||||
return chunk;
|
||||
}
|
||||
};
|
||||
final ThreadLocal<byte[]> byteStore1 = new ThreadLocal<byte[]>() {
|
||||
@Override
|
||||
protected byte[] initialValue() {
|
||||
return new byte[500000];
|
||||
}
|
||||
};
|
||||
final ThreadLocal<byte[]> byteStore2 = new ThreadLocal<byte[]>() {
|
||||
@Override
|
||||
protected byte[] initialValue() {
|
||||
return new byte[500000];
|
||||
}
|
||||
};
|
||||
final ThreadLocal<Deflater> deflateStore = new ThreadLocal<Deflater>() {
|
||||
@Override
|
||||
protected Deflater initialValue() {
|
||||
Deflater deflater = new Deflater(1, false);
|
||||
return deflater;
|
||||
}
|
||||
};
|
||||
final ThreadLocal<int[]> indexStore = new ThreadLocal<int[]>() {
|
||||
@Override
|
||||
protected int[] initialValue() {
|
||||
return new int[256];
|
||||
}
|
||||
};
|
||||
boolean hasOverlay = this.overlay != null;
|
||||
byte[] fileBuf = new byte[1 << 16];
|
||||
for (int mcaZ = 0; mcaZ <= (length >> 9); mcaZ++) {
|
||||
for (int mcaX = 0; mcaX <= (width >> 9); mcaX++) {
|
||||
final int fmcaX = mcaX;
|
||||
final int fmcaZ = mcaZ;
|
||||
File file = new File(folder, "r." + mcaX + "." + mcaZ + ".mca");
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
final BufferedRandomAccessFile raf = new BufferedRandomAccessFile(file, "rw", fileBuf);
|
||||
final byte[] header = new byte[4096];
|
||||
final byte[][] compressed = new byte[1024][];
|
||||
int bx = mcaX << 9;
|
||||
int bz = mcaZ << 9;
|
||||
int scx = bx >> 4;
|
||||
int ecx = Math.min(scx + 31, tcx);
|
||||
int scz = bz >> 4;
|
||||
int ecz = Math.min(scz + 31, tcz);
|
||||
short pair = MathMan.pairByte(mcaX, mcaZ);
|
||||
for (int cz = scz; cz <= ecz; cz++) {
|
||||
final int csz = cz << 4;
|
||||
final int cez = Math.min(csz + 15, length - 1);
|
||||
for (int cx = scx; cx <= ecx; cx++) {
|
||||
final int csx = cx << 4;
|
||||
final int cex = Math.min(csx + 15, width - 1);
|
||||
final int fcx = cx;
|
||||
final int fcz = cz;
|
||||
int chunkPair = MathMan.pair((short) cx, (short) cz);
|
||||
final Char2CharOpenHashMap localBlocks = blocks.get(chunkPair);
|
||||
pool.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
MCAChunk chunk = chunkStore.get();
|
||||
int[] indexes = indexStore.get();
|
||||
for (byte[] array : chunk.ids) {
|
||||
if (array != null) {
|
||||
Arrays.fill(array, (byte) 0);
|
||||
}
|
||||
}
|
||||
int index = 0;
|
||||
int maxY = 0;
|
||||
int minY = Integer.MAX_VALUE;
|
||||
int[] heightMap = chunk.getHeightMapArray();
|
||||
int globalIndex;
|
||||
for (int z = csz; z <= cez; z++) {
|
||||
globalIndex = z * width + csx;
|
||||
for (int x = csx; x <= cex; x++, index++, globalIndex++) {
|
||||
indexes[index] = globalIndex;
|
||||
int height = heights[globalIndex] & 0xFF;
|
||||
heightMap[index] = height;
|
||||
maxY = Math.max(maxY, height);
|
||||
minY = Math.min(minY, height);
|
||||
}
|
||||
}
|
||||
if (hasOverlay) {
|
||||
maxY++;
|
||||
}
|
||||
int maxLayer = maxY >> 4;
|
||||
int fillLayers = Math.max(0, (minY - 1)) >> 4;
|
||||
for (int layer = 0; layer <= maxLayer; layer++) {
|
||||
if (chunk.ids[layer] == null) {
|
||||
chunk.ids[layer] = new byte[4096];
|
||||
chunk.data[layer] = new byte[2048];
|
||||
chunk.skyLight[layer] = new byte[2048];
|
||||
chunk.blockLight[layer] = new byte[2048];
|
||||
}
|
||||
}
|
||||
if (modifiedMain) { // If the main block is modified, we can't short circuit this
|
||||
for (int layer = 0; layer < fillLayers; layer++) {
|
||||
index = 0;
|
||||
byte[] layerIds = chunk.ids[layer];
|
||||
byte[] layerDatas = chunk.data[layer];
|
||||
for (int z = csz; z <= cez; z++) {
|
||||
for (int x = csx; x <= cex; x++, index++) {
|
||||
globalIndex = indexes[index];
|
||||
char mainCombined = main[globalIndex];
|
||||
byte id = (byte) FaweCache.getId(mainCombined);
|
||||
int data = FaweCache.getData(mainCombined);
|
||||
if (data != 0) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
int mainIndex = index + (y << 8);
|
||||
chunk.setNibble(mainIndex, layerDatas, data);
|
||||
}
|
||||
}
|
||||
for (int y = 0; y < 16; y++) {
|
||||
layerIds[index + (y << 8)] = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int layer = 0; layer < fillLayers; layer++) {
|
||||
Arrays.fill(chunk.ids[layer], (byte) 1);
|
||||
}
|
||||
}
|
||||
for (int layer = fillLayers; layer <= maxLayer; layer++) {
|
||||
Arrays.fill(chunk.skyLight[layer], (byte) 255);
|
||||
byte[] layerIds = chunk.ids[layer];
|
||||
byte[] layerDatas = chunk.data[layer];
|
||||
index = 0;
|
||||
int startY = layer << 4;
|
||||
int endY = startY + 15;
|
||||
for (int z = csz; z <= cez; z++) {
|
||||
for (int x = csx; x <= cex; x++, index++) {
|
||||
globalIndex = indexes[index];
|
||||
int height = heightMap[index];
|
||||
int diff;
|
||||
if (height > endY) {
|
||||
diff = 16;
|
||||
} else if (height >= startY) {
|
||||
diff = height - startY;
|
||||
char floorCombined = floor[globalIndex];
|
||||
int id = FaweCache.getId(floorCombined);
|
||||
int floorIndex = index + ((height & 15) << 8);
|
||||
layerIds[floorIndex] = (byte) id;
|
||||
int data = FaweCache.getData(floorCombined);
|
||||
if (data != 0) {
|
||||
chunk.setNibble(floorIndex, layerDatas, data);
|
||||
}
|
||||
if (hasOverlay && height >= startY - 1 && height < endY) {
|
||||
char overlayCombined = overlay[globalIndex];
|
||||
id = FaweCache.getId(overlayCombined);
|
||||
int overlayIndex = index + (((height + 1) & 15) << 8);
|
||||
layerIds[overlayIndex] = (byte) id;
|
||||
data = FaweCache.getData(overlayCombined);
|
||||
if (data != 0) {
|
||||
chunk.setNibble(overlayIndex, layerDatas, data);
|
||||
}
|
||||
}
|
||||
} else if (hasOverlay && height == startY - 1) {
|
||||
char overlayCombined = overlay[globalIndex];
|
||||
int id = FaweCache.getId(overlayCombined);
|
||||
int overlayIndex = index + (((height + 1) & 15) << 8);
|
||||
layerIds[overlayIndex] = (byte) id;
|
||||
int data = FaweCache.getData(overlayCombined);
|
||||
if (data != 0) {
|
||||
chunk.setNibble(overlayIndex, layerDatas, data);
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
char mainCombined = main[globalIndex];
|
||||
byte id = (byte) FaweCache.getId(mainCombined);
|
||||
int data = FaweCache.getData(mainCombined);
|
||||
if (data != 0) {
|
||||
for (int y = 0; y < diff; y++) {
|
||||
int mainIndex = index + (y << 8);
|
||||
chunk.setNibble(mainIndex, layerDatas, data);
|
||||
}
|
||||
}
|
||||
for (int y = 0; y < diff; y++) {
|
||||
layerIds[index + (y << 8)] = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int maxYMod = 15 + (maxLayer << 4);
|
||||
for (int layer = (maxY >> 4) + 1; layer < 16; layer++) {
|
||||
chunk.ids[layer] = null;
|
||||
}
|
||||
index = 0;
|
||||
{ // Bedrock
|
||||
byte[] layerIds = chunk.ids[0];
|
||||
for (int z = csz; z <= cez; z++) {
|
||||
for (int x = csx; x <= cex; x++) {
|
||||
layerIds[index++] = (byte) 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (localBlocks != null && !localBlocks.isEmpty()) {
|
||||
for (Char2CharMap.Entry entry : localBlocks.char2CharEntrySet()) {
|
||||
char key = entry.getCharKey();
|
||||
char combined = entry.getCharValue();
|
||||
byte id = (byte) FaweCache.getId(combined);
|
||||
|
||||
int and = key & 4095;
|
||||
int y = ((key >> 12) << 4) + (and >> 8);
|
||||
int x = and & 0xF;
|
||||
int z = (and >> 4) & 0xF;
|
||||
int layer = key >> 12;
|
||||
int localIndex = key & 4095;
|
||||
if (!FaweCache.hasData(id)) {
|
||||
if (chunk.ids[layer] == null) {
|
||||
chunk.ids[layer] = new byte[4096];
|
||||
chunk.data[layer] = new byte[2048];
|
||||
chunk.skyLight[layer] = new byte[2048];
|
||||
chunk.blockLight[layer] = new byte[2048];
|
||||
}
|
||||
chunk.setIdUnsafe(layer, localIndex, id);
|
||||
} else {
|
||||
int data = FaweCache.getData(combined);
|
||||
chunk.setBlockUnsafe(layer, localIndex, id, data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
chunk.setLoc(null, fcx, fcz);
|
||||
byte[] bytes = chunk.toBytes(byteStore1.get());
|
||||
byte[] compressedBytes = MainUtil.compress(bytes, byteStore2.get(), deflateStore.get());
|
||||
int blocks = (compressed.length + 4095) >> 12;
|
||||
compressed[((fcx & 31)) + ((fcz & 31) << 5)] = compressedBytes.clone();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
pool.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
int totalLength = 8192;
|
||||
for (int i = 0; i < compressed.length; i++) {
|
||||
byte[] compressedBytes = compressed[i];
|
||||
if (compressedBytes != null) {
|
||||
int blocks = ((4095 + compressedBytes.length + 5) / 4096) * 4096;
|
||||
totalLength += blocks;
|
||||
}
|
||||
}
|
||||
raf.setLength(totalLength);
|
||||
int offset = 8192;
|
||||
for (int i = 0; i < compressed.length; i++) {
|
||||
byte[] compressedBytes = compressed[i];
|
||||
if (compressedBytes != null) {
|
||||
// Set header
|
||||
int index = i << 2;
|
||||
int offsetMedium = offset >> 12;
|
||||
int blocks = ((4095 + compressedBytes.length + 5) / 4096);
|
||||
header[index] = (byte) (offsetMedium >> 16);
|
||||
header[index + 1] = (byte) ((offsetMedium >> 8));
|
||||
header[index + 2] = (byte) ((offsetMedium >> 0));
|
||||
header[index + 3] = (byte) (blocks);
|
||||
// Write bytes
|
||||
int cx = (fmcaX << 5) + (i & 31);
|
||||
int cz = (fmcaZ << 5) + (i >> 5);
|
||||
raf.seek(offset);
|
||||
raf.writeInt(compressedBytes.length);
|
||||
raf.write(2);
|
||||
raf.write(compressedBytes);
|
||||
offset += blocks * 4096;
|
||||
}
|
||||
}
|
||||
raf.seek(0);
|
||||
raf.write(header);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
raf.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
@ -5,11 +5,15 @@ import com.boydti.fawe.jnbt.NBTStreamer;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.NBTConstants;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -19,6 +23,9 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class MCAChunk extends FaweChunk<Void> {
|
||||
|
||||
// ids: byte[16][4096]
|
||||
@ -47,6 +54,65 @@ public class MCAChunk extends FaweChunk<Void> {
|
||||
private boolean modified;
|
||||
private boolean deleted;
|
||||
|
||||
public byte[] toBytes(byte[] buffer) throws IOException {
|
||||
checkNotNull(buffer);
|
||||
if (buffer == null) {
|
||||
buffer = new byte[8192];
|
||||
}
|
||||
FastByteArrayOutputStream buffered = new FastByteArrayOutputStream(buffer);
|
||||
DataOutputStream dataOut = new DataOutputStream(buffered);
|
||||
NBTOutputStream nbtOut = new NBTOutputStream(dataOut);
|
||||
nbtOut.writeNamedTagName("", NBTConstants.TYPE_COMPOUND);
|
||||
nbtOut.writeLazyCompoundTag("Level", new NBTOutputStream.LazyWrite() {
|
||||
@Override
|
||||
public void write(NBTOutputStream out) throws IOException {
|
||||
out.writeNamedTag("V", (byte) 1);
|
||||
out.writeNamedTag("xPos", getX());
|
||||
out.writeNamedTag("zPos", getZ());
|
||||
out.writeNamedTag("LightPopulated", (byte) 0);
|
||||
out.writeNamedTag("TerrainPopulated", (byte) 1);
|
||||
if (entities.isEmpty()) {
|
||||
out.writeNamedEmptyList("Entities");
|
||||
} else {
|
||||
out.writeNamedTag("Entities", new ListTag(CompoundTag.class, new ArrayList<CompoundTag>(entities.values())));
|
||||
}
|
||||
if (tiles.isEmpty()) {
|
||||
out.writeNamedEmptyList("TileEntities");
|
||||
} else {
|
||||
out.writeNamedTag("TileEntities", new ListTag(CompoundTag.class, new ArrayList<CompoundTag>(tiles.values())));
|
||||
}
|
||||
out.writeNamedTag("InhabitedTime", inhabitedTime);
|
||||
out.writeNamedTag("LastUpdate", lastUpdate);
|
||||
if (biomes != null) {
|
||||
out.writeNamedTag("Biomes", biomes);
|
||||
}
|
||||
out.writeNamedTag("HeightMap", heightMap);
|
||||
out.writeNamedTagName("Sections", NBTConstants.TYPE_LIST);
|
||||
dataOut.writeByte(NBTConstants.TYPE_COMPOUND);
|
||||
int len = 0;
|
||||
for (int layer = 0; layer < ids.length; layer++) {
|
||||
if (ids[layer] != null) len++;
|
||||
}
|
||||
dataOut.writeInt(len);
|
||||
for (int layer = 0; layer < ids.length; layer++) {
|
||||
byte[] idLayer = ids[layer];
|
||||
if (idLayer == null) {
|
||||
continue;
|
||||
}
|
||||
out.writeNamedTag("Y", (byte) layer);
|
||||
out.writeNamedTag("BlockLight", blockLight[layer]);
|
||||
out.writeNamedTag("SkyLight", skyLight[layer]);
|
||||
out.writeNamedTag("Blocks", idLayer);
|
||||
out.writeNamedTag("Data", data[layer]);
|
||||
out.writeEndTag();
|
||||
}
|
||||
}
|
||||
});
|
||||
nbtOut.writeEndTag();
|
||||
nbtOut.close();
|
||||
return buffered.toByteArray();
|
||||
}
|
||||
|
||||
public CompoundTag toTag() {
|
||||
if (deleted) {
|
||||
return null;
|
||||
@ -87,6 +153,20 @@ public class MCAChunk extends FaweChunk<Void> {
|
||||
return FaweCache.asTag(root);
|
||||
}
|
||||
|
||||
public MCAChunk(FaweQueue queue, int x, int z) {
|
||||
super(queue, x, z);
|
||||
this.ids = new byte[16][];
|
||||
this.data = new byte[16][];
|
||||
this.skyLight = new byte[16][];
|
||||
this.blockLight = new byte[16][];
|
||||
this.biomes = new byte[256];
|
||||
this.tiles = new HashMap<>();
|
||||
this.entities = new HashMap<>();
|
||||
this.lastUpdate = System.currentTimeMillis();
|
||||
this.heightMap = new int[256];
|
||||
this.modified = true;
|
||||
}
|
||||
|
||||
public MCAChunk(MCAChunk parent, boolean shallow) {
|
||||
super(parent.getParent(), parent.getX(), parent.getZ());
|
||||
if (shallow) {
|
||||
@ -127,7 +207,6 @@ public class MCAChunk extends FaweChunk<Void> {
|
||||
skyLight = new byte[16][];
|
||||
blockLight = new byte[16][];
|
||||
this.compressedSize = compressedSize;
|
||||
// NamedTag tag = nis.readNamedTag();
|
||||
NBTStreamer streamer = new NBTStreamer(nis);
|
||||
streamer.addReader(".Level.InhabitedTime", new RunnableVal2<Integer, Long>() {
|
||||
@Override
|
||||
@ -151,7 +230,7 @@ public class MCAChunk extends FaweChunk<Void> {
|
||||
blockLight[layer] = tag.getByteArray("BlockLight");
|
||||
}
|
||||
});
|
||||
streamer.addReader(".Level.Entities.#", new RunnableVal2<Integer, CompoundTag>() {
|
||||
streamer.addReader(".Level.TileEntities.#", new RunnableVal2<Integer, CompoundTag>() {
|
||||
@Override
|
||||
public void run(Integer index, CompoundTag tile) {
|
||||
int x = tile.getInt("x") & 15;
|
||||
@ -161,12 +240,13 @@ public class MCAChunk extends FaweChunk<Void> {
|
||||
tiles.put(pair, tile);
|
||||
}
|
||||
});
|
||||
streamer.addReader(".Level.TileEntities.#", new RunnableVal2<Integer, CompoundTag>() {
|
||||
streamer.addReader(".Level.Entities.#", new RunnableVal2<Integer, CompoundTag>() {
|
||||
@Override
|
||||
public void run(Integer index, CompoundTag entityTag) {
|
||||
if (entities == null) {
|
||||
entities = new HashMap<UUID, CompoundTag>();
|
||||
}
|
||||
|
||||
long least = entityTag.getLong("UUIDLeast");
|
||||
long most = entityTag.getLong("UUIDMost");
|
||||
entities.put(new UUID(most, least), entityTag);
|
||||
@ -205,7 +285,7 @@ public class MCAChunk extends FaweChunk<Void> {
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setModified() {
|
||||
public final void setModified() {
|
||||
this.modified = true;
|
||||
}
|
||||
|
||||
@ -375,11 +455,34 @@ public class MCAChunk extends FaweChunk<Void> {
|
||||
|
||||
public void setNibble(int index, byte[] array, int value) {
|
||||
int indexShift = index >> 1;
|
||||
if((index & 1) == 0) {
|
||||
array[indexShift] = (byte)(array[indexShift] & 240 | value & 15);
|
||||
} else {
|
||||
array[indexShift] = (byte)(array[indexShift] & 15 | (value & 15) << 4);
|
||||
byte existing = array[indexShift];
|
||||
int valueShift = value << 4;
|
||||
if (existing == value + valueShift) {
|
||||
return;
|
||||
}
|
||||
if((index & 1) == 0) {
|
||||
array[indexShift] = (byte)(existing & 240 | value);
|
||||
} else {
|
||||
array[indexShift] = (byte)(existing & 15 | valueShift);
|
||||
}
|
||||
}
|
||||
|
||||
public void setIdUnsafe(int layer, int index, byte id) {
|
||||
byte[] idsLayer = ids[layer];
|
||||
idsLayer[index] = id;
|
||||
}
|
||||
|
||||
public void setBlockUnsafe(int layer, int index, byte id, int data) {
|
||||
byte[] idsLayer = ids[layer];
|
||||
if (idsLayer == null) {
|
||||
idsLayer = this.ids[layer] = new byte[4096];
|
||||
this.data[layer] = new byte[2048];
|
||||
this.skyLight[layer] = new byte[2048];
|
||||
this.blockLight[layer] = new byte[2048];
|
||||
}
|
||||
idsLayer[index] = id;
|
||||
byte[] dataLayer = this.data[layer];
|
||||
setNibble(index, dataLayer, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -399,6 +502,11 @@ public class MCAChunk extends FaweChunk<Void> {
|
||||
setNibble(j, dataLayer, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(byte biome) {
|
||||
Arrays.fill(biomes, biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEntity(UUID uuid) {
|
||||
modified = true;
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.jnbt.anvil;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.jnbt.NBTStreamer;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
@ -8,21 +9,22 @@ import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
|
||||
import com.boydti.fawe.object.io.FastByteArrayInputStream;
|
||||
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import java.io.BufferedInputStream;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.io.FastBufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
@ -33,24 +35,55 @@ import java.util.zip.InflaterInputStream;
|
||||
*/
|
||||
public class MCAFile {
|
||||
|
||||
private static Field fieldBuf2;
|
||||
private static Field fieldBuf3;
|
||||
private static Field fieldBuf4;
|
||||
private static Field fieldBuf5;
|
||||
private static Field fieldBuf6;
|
||||
static {
|
||||
try {
|
||||
fieldBuf2 = InflaterInputStream.class.getDeclaredField("buf");
|
||||
fieldBuf2.setAccessible(true);
|
||||
fieldBuf3 = NBTInputStream.class.getDeclaredField("buf");
|
||||
fieldBuf3.setAccessible(true);
|
||||
fieldBuf4 = FastByteArrayOutputStream.class.getDeclaredField("buffer");
|
||||
fieldBuf4.setAccessible(true);
|
||||
fieldBuf5 = DeflaterOutputStream.class.getDeclaredField("buf");
|
||||
fieldBuf5.setAccessible(true);
|
||||
fieldBuf6 = BufferedOutputStream.class.getDeclaredField("buf");
|
||||
fieldBuf6.setAccessible(true);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private FaweQueue queue;
|
||||
private File file;
|
||||
private RandomAccessFile raf;
|
||||
private byte[] locations;
|
||||
private FaweQueue queue;
|
||||
private Field fieldBuf1;
|
||||
private Field fieldBuf2;
|
||||
private Field fieldBuf3;
|
||||
private Field fieldBuf4;
|
||||
private Field fieldBuf5;
|
||||
private Field fieldBuf6;
|
||||
|
||||
private byte[] buffer1 = new byte[4096];
|
||||
private byte[] buffer2 = new byte[4096];
|
||||
private byte[] buffer3 = new byte[720];
|
||||
final ThreadLocal<byte[]> byteStore1 = new ThreadLocal<byte[]>() {
|
||||
@Override
|
||||
protected byte[] initialValue() {
|
||||
return new byte[4096];
|
||||
}
|
||||
};
|
||||
final ThreadLocal<byte[]> byteStore2 = new ThreadLocal<byte[]>() {
|
||||
@Override
|
||||
protected byte[] initialValue() {
|
||||
return new byte[4096];
|
||||
}
|
||||
};
|
||||
final ThreadLocal<byte[]> byteStore3 = new ThreadLocal<byte[]>() {
|
||||
@Override
|
||||
protected byte[] initialValue() {
|
||||
return new byte[1024];
|
||||
}
|
||||
};
|
||||
|
||||
private final int X, Z;
|
||||
|
||||
private Map<Integer, MCAChunk> chunks = new HashMap<>();
|
||||
private Int2ObjectOpenHashMap<MCAChunk> chunks = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
public MCAFile(FaweQueue parent, File file) {
|
||||
this.queue = parent;
|
||||
@ -71,20 +104,10 @@ public class MCAFile {
|
||||
try {
|
||||
if (raf == null) {
|
||||
this.locations = new byte[4096];
|
||||
this.raf = new BufferedRandomAccessFile(file, "rw", (int) file.length());
|
||||
this.raf = new RandomAccessFile(file, "rw");
|
||||
raf.seek(0);
|
||||
raf.readFully(locations);
|
||||
fieldBuf1 = BufferedInputStream.class.getDeclaredField("buf");
|
||||
fieldBuf1.setAccessible(true);
|
||||
fieldBuf2 = InflaterInputStream.class.getDeclaredField("buf");
|
||||
fieldBuf2.setAccessible(true);
|
||||
fieldBuf3 = NBTInputStream.class.getDeclaredField("buf");
|
||||
fieldBuf3.setAccessible(true);
|
||||
fieldBuf4 = FastByteArrayOutputStream.class.getDeclaredField("buffer");
|
||||
fieldBuf4.setAccessible(true);
|
||||
fieldBuf5 = DeflaterOutputStream.class.getDeclaredField("buf");
|
||||
fieldBuf5.setAccessible(true);
|
||||
fieldBuf6 = BufferedOutputStream.class.getDeclaredField("buf");
|
||||
fieldBuf6.setAccessible(true);
|
||||
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
@ -109,7 +132,9 @@ public class MCAFile {
|
||||
|
||||
public MCAChunk getCachedChunk(int cx, int cz) {
|
||||
int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31));
|
||||
return chunks.get(pair);
|
||||
synchronized (chunks) {
|
||||
return chunks.get(pair);
|
||||
}
|
||||
}
|
||||
|
||||
public MCAChunk getChunk(int cx, int cz) throws IOException {
|
||||
@ -132,10 +157,42 @@ public class MCAFile {
|
||||
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);
|
||||
synchronized (chunks) {
|
||||
chunks.put(pair, chunk);
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
public void forEachSortedChunk(RunnableVal4<Integer, Integer, Integer, Integer> onEach) throws IOException {
|
||||
char[] offsets = new char[(int) (raf.length() / 4096) - 2];
|
||||
Arrays.fill(offsets, Character.MAX_VALUE);
|
||||
char i = 0;
|
||||
for (int z = 0; z < 32; z++) {
|
||||
for (int x = 0; x < 32; x++, i += 4) {
|
||||
int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i+ 2] & 0xFF))) - 2;
|
||||
int size = locations[i + 3] & 0xFF;
|
||||
if (size != 0) {
|
||||
if (offset < offsets.length) {
|
||||
offsets[offset] = i;
|
||||
} else {
|
||||
Fawe.debug("Ignoring invalid offset " + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < offsets.length; i++) {
|
||||
int index = offsets[i];
|
||||
if (index != Character.MAX_VALUE) {
|
||||
int offset = i + 2;
|
||||
int size = locations[index + 3] & 0xFF;
|
||||
int index2 = index >> 2;
|
||||
int x = (index2) & 31;
|
||||
int z = (index2) >> 5;
|
||||
onEach.run(x, z, offset << 12, size << 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param onEach cx, cz, offset, size
|
||||
*/
|
||||
@ -188,23 +245,17 @@ public class MCAFile {
|
||||
}
|
||||
|
||||
private byte[] getChunkCompressedBytes(int offset) throws IOException{
|
||||
raf.seek(offset);
|
||||
int size = raf.readInt();
|
||||
int compression = raf.read();
|
||||
byte[] data = new byte[size];
|
||||
raf.readFully(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
private void writeSafe(int offset, byte[] data) throws IOException {
|
||||
int len = data.length + 5;
|
||||
raf.seek(offset);
|
||||
if (raf.length() - offset < len) {
|
||||
raf.setLength(offset + len);
|
||||
if (offset == 0) {
|
||||
return null;
|
||||
}
|
||||
synchronized (raf) {
|
||||
raf.seek(offset);
|
||||
int size = raf.readInt();
|
||||
int compression = raf.read();
|
||||
byte[] data = new byte[size];
|
||||
raf.readFully(data);
|
||||
return data;
|
||||
}
|
||||
raf.writeInt(data.length);
|
||||
raf.write(2);
|
||||
raf.write(data);
|
||||
}
|
||||
|
||||
private NBTInputStream getChunkIS(int offset) throws IOException {
|
||||
@ -212,11 +263,10 @@ public class MCAFile {
|
||||
byte[] data = getChunkCompressedBytes(offset);
|
||||
FastByteArrayInputStream bais = new FastByteArrayInputStream(data);
|
||||
InflaterInputStream iis = new InflaterInputStream(bais, new Inflater(), 1);
|
||||
fieldBuf2.set(iis, buffer2);
|
||||
BufferedInputStream bis = new BufferedInputStream(iis, 1);
|
||||
fieldBuf1.set(bis, buffer1);
|
||||
fieldBuf2.set(iis, byteStore2.get());
|
||||
FastBufferedInputStream bis = new FastBufferedInputStream(iis, byteStore1.get());
|
||||
NBTInputStream nis = new NBTInputStream(bis);
|
||||
fieldBuf3.set(nis, buffer3);
|
||||
fieldBuf3.set(nis, byteStore3.get());
|
||||
return nis;
|
||||
} catch (IllegalAccessException unlikely) {
|
||||
unlikely.printStackTrace();
|
||||
@ -243,45 +293,33 @@ public class MCAFile {
|
||||
* @param onEach chunk
|
||||
*/
|
||||
public void forEachCachedChunk(RunnableVal<MCAChunk> onEach) {
|
||||
for (Map.Entry<Integer, MCAChunk> entry : chunks.entrySet()) {
|
||||
onEach.run(entry.getValue());
|
||||
synchronized (chunks) {
|
||||
for (Map.Entry<Integer, MCAChunk> entry : chunks.entrySet()) {
|
||||
onEach.run(entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<MCAChunk> getCachedChunks() {
|
||||
return new ArrayList<>(chunks.values());
|
||||
synchronized (chunks) {
|
||||
return new ArrayList<>(chunks.values());
|
||||
}
|
||||
}
|
||||
|
||||
public void uncache(int cx, int cz) {
|
||||
int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31));
|
||||
chunks.remove(pair);
|
||||
synchronized (chunks) {
|
||||
chunks.remove(pair);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] toBytes(MCAChunk chunk) throws Exception {
|
||||
CompoundTag tag = chunk.toTag();
|
||||
if (tag == null || chunk.isDeleted()) {
|
||||
if (chunk.isDeleted()) {
|
||||
return null;
|
||||
}
|
||||
FastByteArrayOutputStream baos = new FastByteArrayOutputStream(buffer3);
|
||||
|
||||
// PGZIPOutputStream deflater = new PGZIPOutputStream(baos);
|
||||
// deflater.setStrategy(Deflater.FILTERED);
|
||||
Deflater deflate = new Deflater(1);
|
||||
deflate.setStrategy(Deflater.FILTERED);
|
||||
DeflaterOutputStream deflater = new DeflaterOutputStream(baos, deflate, 1, true);
|
||||
fieldBuf5.set(deflater, buffer2);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(deflater, 1);
|
||||
fieldBuf6.set(bos, buffer1);
|
||||
NBTOutputStream nos = new NBTOutputStream(bos);
|
||||
nos.writeNamedTag("", tag);
|
||||
bos.flush();
|
||||
bos.close();
|
||||
byte[] result = baos.toByteArray();
|
||||
baos.close();
|
||||
deflater.close();
|
||||
bos.close();
|
||||
nos.close();
|
||||
return result;
|
||||
byte[] uncompressed = chunk.toBytes(byteStore3.get());
|
||||
byte[] compressed = MainUtil.compress(uncompressed, byteStore2.get(), null);
|
||||
return compressed;
|
||||
}
|
||||
|
||||
private byte[] getChunkBytes(int cx, int cz) throws Exception{
|
||||
@ -296,7 +334,19 @@ public class MCAFile {
|
||||
return toBytes(mca);
|
||||
}
|
||||
|
||||
private void writeHeader(int cx, int cz, int offsetMedium, int sizeByte) throws IOException {
|
||||
|
||||
private void writeSafe(RandomAccessFile raf, int offset, byte[] data) throws IOException {
|
||||
int len = data.length + 5;
|
||||
raf.seek(offset);
|
||||
if (raf.length() - offset < len) {
|
||||
raf.setLength(((offset + len + 4095) / 4096) * 4096);
|
||||
}
|
||||
raf.writeInt(data.length);
|
||||
raf.write(2);
|
||||
raf.write(data);
|
||||
}
|
||||
|
||||
private void writeHeader(RandomAccessFile raf, int cx, int cz, int offsetMedium, int sizeByte, boolean writeTime) throws IOException {
|
||||
int i = ((cx & 31) << 2) + ((cz & 31) << 7);
|
||||
raf.seek(i);
|
||||
raf.write((offsetMedium >> 16));
|
||||
@ -309,134 +359,150 @@ public class MCAFile {
|
||||
} else {
|
||||
raf.writeInt((int) (System.currentTimeMillis() / 1000L));
|
||||
}
|
||||
int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i+ 2] & 0xFF))) << 12;
|
||||
int size = (locations[i + 3] & 0xFF) << 12;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
flush();
|
||||
if (raf != null) {
|
||||
try {
|
||||
raf.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
file = null;
|
||||
raf = null;
|
||||
locations = null;
|
||||
queue = null;
|
||||
fieldBuf1 = null;
|
||||
fieldBuf2 = null;
|
||||
fieldBuf3 = null;
|
||||
fieldBuf4 = null;
|
||||
fieldBuf5 = null;
|
||||
fieldBuf6 = null;
|
||||
buffer1 = null;
|
||||
buffer2 = null;
|
||||
buffer3 = null;
|
||||
chunks = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
boolean modified = false;
|
||||
for (MCAChunk chunk : getCachedChunks()) {
|
||||
if (chunk.isModified()) {
|
||||
modified = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!modified) {
|
||||
return;
|
||||
}
|
||||
final HashMap<Integer, Integer> offsetMap = new HashMap<>(); // Offset -> <byte cx, byte cz, short size>
|
||||
forEachChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
|
||||
@Override
|
||||
public void run(Integer cx, Integer cz, Integer offset, Integer size) {
|
||||
short pair1 = MathMan.pairByte((byte) (cx & 31), (byte) (cz & 31));
|
||||
short pair2 = (short) (size >> 12);
|
||||
offsetMap.put(offset, MathMan.pair(pair1, pair2));
|
||||
}
|
||||
});
|
||||
|
||||
HashMap<Integer, byte[]> relocate = new HashMap<Integer, byte[]>();
|
||||
int start = 8192;
|
||||
int written = start;
|
||||
int end = 8192;
|
||||
int nextOffset = 8192;
|
||||
try {
|
||||
for (int count = 0; count < offsetMap.size(); count++) {
|
||||
Integer loc = offsetMap.get(nextOffset);
|
||||
while (loc == null) {
|
||||
nextOffset += 4096;
|
||||
loc = offsetMap.get(nextOffset);
|
||||
public void close(ForkJoinPool pool) {
|
||||
synchronized (raf) {
|
||||
if (raf != null) {
|
||||
flush(pool);
|
||||
try {
|
||||
raf.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
int offset = nextOffset;
|
||||
short cxz = MathMan.unpairX(loc);
|
||||
int cx = MathMan.unpairShortX(cxz);
|
||||
int cz = MathMan.unpairShortY(cxz);
|
||||
int size = MathMan.unpairY(loc) << 12;
|
||||
nextOffset += size;
|
||||
end += size;
|
||||
int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31));
|
||||
byte[] newBytes = relocate.get(pair);
|
||||
if (newBytes == null) {
|
||||
if (offset == start) {
|
||||
MCAChunk cached = getCachedChunk(cx, cz);
|
||||
if (cached == null || !cached.isModified()) {
|
||||
start += size;
|
||||
written = start + size;
|
||||
file = null;
|
||||
raf = null;
|
||||
locations = null;
|
||||
queue = null;
|
||||
chunks = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void flush(ForkJoinPool pool) {
|
||||
synchronized (raf) {
|
||||
boolean wait;
|
||||
if (pool == null) {
|
||||
wait = true;
|
||||
pool = new ForkJoinPool();
|
||||
} else wait = false;
|
||||
Int2ObjectOpenHashMap<byte[]> relocate = new Int2ObjectOpenHashMap<>();
|
||||
final Int2ObjectOpenHashMap<Integer> offsetMap = new Int2ObjectOpenHashMap<>(); // Offset -> <byte cx, byte cz, short size>
|
||||
final Int2ObjectOpenHashMap<byte[]> compressedMap = new Int2ObjectOpenHashMap<>();
|
||||
boolean modified = false;
|
||||
for (MCAChunk chunk : getCachedChunks()) {
|
||||
if (chunk.isModified()) {
|
||||
modified = true;
|
||||
if (!chunk.isDeleted()) {
|
||||
pool.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
byte[] compressed = toBytes(chunk);
|
||||
int pair = MathMan.pair((short) (chunk.getX() & 31), (short) (chunk.getZ() & 31));
|
||||
synchronized (compressedMap) {
|
||||
compressedMap.put(pair, compressed);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (modified) {
|
||||
forEachChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
|
||||
@Override
|
||||
public void run(Integer cx, Integer cz, Integer offset, Integer size) {
|
||||
short pair1 = MathMan.pairByte((byte) (cx & 31), (byte) (cz & 31));
|
||||
short pair2 = (short) (size >> 12);
|
||||
offsetMap.put((int) offset, (Integer) MathMan.pair(pair1, pair2));
|
||||
}
|
||||
});
|
||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
int start = 8192;
|
||||
int written = start;
|
||||
int end = 8192;
|
||||
int nextOffset = 8192;
|
||||
try {
|
||||
for (int count = 0; count < offsetMap.size(); count++) {
|
||||
Integer loc = offsetMap.get(nextOffset);
|
||||
while (loc == null) {
|
||||
nextOffset += 4096;
|
||||
loc = offsetMap.get(nextOffset);
|
||||
}
|
||||
int offset = nextOffset;
|
||||
short cxz = MathMan.unpairX(loc);
|
||||
int cx = MathMan.unpairShortX(cxz);
|
||||
int cz = MathMan.unpairShortY(cxz);
|
||||
int size = MathMan.unpairY(loc) << 12;
|
||||
nextOffset += size;
|
||||
end = Math.min(start + size, end);
|
||||
int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31));
|
||||
byte[] newBytes = relocate.get(pair);
|
||||
if (newBytes == null) {
|
||||
if (offset == start) {
|
||||
MCAChunk cached = getCachedChunk(cx, cz);
|
||||
if (cached == null || !cached.isModified()) {
|
||||
writeHeader(raf, cx, cz, start >> 12, size >> 12, true);
|
||||
start += size;
|
||||
written = start + size;
|
||||
continue;
|
||||
} else {
|
||||
newBytes = compressedMap.get(pair);
|
||||
}
|
||||
} else {
|
||||
newBytes = compressedMap.get(pair);
|
||||
if (newBytes == null) {
|
||||
newBytes = getChunkCompressedBytes(getOffset(cx, cz));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newBytes == null) {
|
||||
writeHeader(raf, cx, cz, 0, 0, false);
|
||||
continue;
|
||||
} else {
|
||||
newBytes = toBytes(cached);
|
||||
}
|
||||
} else {
|
||||
newBytes = getChunkBytes(cx, cz);
|
||||
}
|
||||
}
|
||||
if (newBytes == null) {
|
||||
writeHeader(cx, cz, 0, 0);
|
||||
continue;
|
||||
}
|
||||
int len = newBytes.length + 5;
|
||||
int oldSize = (size + 4095) >> 12;
|
||||
int newSize = (len + 4095) >> 12;
|
||||
int nextOffset2 = nextOffset;
|
||||
while (start + len > end) {
|
||||
Integer nextLoc = offsetMap.get(nextOffset2);
|
||||
if (nextLoc != null) {
|
||||
short nextCXZ = MathMan.unpairX(nextLoc);
|
||||
int nextCX = MathMan.unpairShortX(nextCXZ);
|
||||
int nextCZ = MathMan.unpairShortY(nextCXZ);
|
||||
if (getCachedChunk(nextCX, nextCZ) == null) {
|
||||
byte[] nextBytes = getChunkCompressedBytes(nextOffset2);
|
||||
relocate.put(pair, nextBytes);
|
||||
int len = newBytes.length + 5;
|
||||
int oldSize = (size + 4095) >> 12;
|
||||
int newSize = (len + 4095) >> 12;
|
||||
int nextOffset2 = end;
|
||||
while (start + len > end) {
|
||||
Integer nextLoc = offsetMap.get(nextOffset2);
|
||||
if (nextLoc != null) {
|
||||
short nextCXZ = MathMan.unpairX(nextLoc);
|
||||
int nextCX = MathMan.unpairShortX(nextCXZ);
|
||||
int nextCZ = MathMan.unpairShortY(nextCXZ);
|
||||
if (getCachedChunk(nextCX, nextCZ) == null) {
|
||||
byte[] nextBytes = getChunkCompressedBytes(nextOffset2);
|
||||
relocate.put(MathMan.pair((short) (nextCX & 31), (short) (nextCZ & 31)), nextBytes);
|
||||
}
|
||||
int nextSize = MathMan.unpairY(nextLoc) << 12;
|
||||
end += nextSize;
|
||||
nextOffset2 += nextSize;
|
||||
} else {
|
||||
end += 4096;
|
||||
nextOffset2 += 4096;
|
||||
}
|
||||
}
|
||||
// System.out.println("Relocating " + nextCX + "," + nextCZ);
|
||||
int nextSize = MathMan.unpairY(nextLoc) << 12;
|
||||
end += nextSize;
|
||||
nextOffset2 += nextSize;
|
||||
} else {
|
||||
end = start + len;
|
||||
break;
|
||||
writeSafe(raf, start, newBytes);
|
||||
writeHeader(raf, cx, cz, start >> 12, newSize, true);
|
||||
written = start + newBytes.length + 5;
|
||||
start += newSize << 12;
|
||||
}
|
||||
raf.setLength(4096 * ((written + 4095) / 4096));
|
||||
if (raf instanceof BufferedRandomAccessFile) {
|
||||
((BufferedRandomAccessFile) raf).flush();
|
||||
}
|
||||
raf.close();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// System.out.println("Writing: " + cx + "," + cz);
|
||||
writeSafe(start, newBytes);
|
||||
if (offset != start || end != start + size || oldSize != newSize || true) {
|
||||
// System.out.println("Header: " + cx + "," + cz + " | " + offset + "," + start + " | " + end + "," + (start + size) + " | " + size + " | " + start);
|
||||
writeHeader(cx, cz, start >> 12, newSize);
|
||||
if (wait) {
|
||||
pool.shutdown();
|
||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
written = start + newBytes.length + 5;
|
||||
start += newSize << 12;
|
||||
}
|
||||
raf.setLength(written);
|
||||
if (raf instanceof BufferedRandomAccessFile) {
|
||||
((BufferedRandomAccessFile) raf).flush();
|
||||
}
|
||||
raf.close();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,12 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
||||
public void filterWorld(final MCAFilter filter) {
|
||||
File folder = getSaveFolder();
|
||||
final ForkJoinPool pool = new ForkJoinPool();
|
||||
final ThreadLocal<MutableMCABackedBaseBlock> blockStore = new ThreadLocal<MutableMCABackedBaseBlock>() {
|
||||
@Override
|
||||
protected MutableMCABackedBaseBlock initialValue() {
|
||||
return new MutableMCABackedBaseBlock();
|
||||
}
|
||||
};
|
||||
for (final File file : folder.listFiles()) {
|
||||
try {
|
||||
String name = file.getName();
|
||||
@ -82,18 +88,16 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
||||
final MCAFile finalFile = filter.applyFile(mcaFile);
|
||||
if (finalFile != null) {
|
||||
finalFile.init();
|
||||
Runnable run = new Runnable() {
|
||||
// May not do anything, but seems to lead to smaller lag spikes
|
||||
final int cbx = mcaX << 5;
|
||||
final int cbz = mcaZ << 5;
|
||||
|
||||
finalFile.forEachSortedChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
|
||||
@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;
|
||||
finalFile.forEachChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
|
||||
public void run(final Integer rcx, final Integer rcz, Integer offset, Integer size) {
|
||||
pool.submit(new Runnable() {
|
||||
@Override
|
||||
public void run(final Integer rcx, final Integer rcz, Integer offset, Integer size) {
|
||||
public void run() {
|
||||
int cx = cbx + rcx;
|
||||
int cz = cbz + rcz;
|
||||
if (filter.appliesChunk(cx, cz)) {
|
||||
@ -102,6 +106,7 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
||||
try {
|
||||
chunk = filter.applyChunk(chunk);
|
||||
if (chunk != null) {
|
||||
final MutableMCABackedBaseBlock mutableBlock = blockStore.get();
|
||||
mutableBlock.setChunk(chunk);
|
||||
int bx = cx << 4;
|
||||
int bz = cz << 4;
|
||||
@ -111,9 +116,12 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
||||
int yStart = layer << 4;
|
||||
int index = 0;
|
||||
for (int y = yStart; y < yStart + 16; y++) {
|
||||
mutableBlock.setY(y);
|
||||
for (int z = bz; z < bz + 16; z++) {
|
||||
mutableBlock.setZ(z);
|
||||
for (int x = bx; x < bx + 16; x++,index++) {
|
||||
mutableBlock.setIndex(x & 15, y, z & 15, index);
|
||||
mutableBlock.setX(x);
|
||||
mutableBlock.setIndex(index);
|
||||
filter.applyBlock(x, y, z, mutableBlock);
|
||||
}
|
||||
}
|
||||
@ -131,26 +139,26 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
||||
}
|
||||
}
|
||||
});
|
||||
original.close();
|
||||
finalFile.close();
|
||||
System.gc();
|
||||
System.gc();
|
||||
}
|
||||
};
|
||||
pool.submit(run);
|
||||
});
|
||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
original.close(pool);
|
||||
if (original != finalFile) finalFile.close(pool);
|
||||
} else {
|
||||
try {
|
||||
original.close();
|
||||
original.close(pool);
|
||||
file.delete();
|
||||
} catch (Throwable ignore) {}
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignore) {}
|
||||
} catch (Throwable ignore) {
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
}
|
||||
pool.shutdown();
|
||||
try {
|
||||
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -162,8 +162,7 @@ public class MCAQueueMap implements IFaweQueueMap {
|
||||
if (result = iter.hasNext()) {
|
||||
MCAFile file = iter.next().getValue();
|
||||
iter.remove();
|
||||
file.flush();
|
||||
file.close();
|
||||
file.close(null);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -31,28 +31,37 @@ public class MutableMCABackedBaseBlock extends BaseBlock {
|
||||
data = chunk.data[layer];
|
||||
}
|
||||
|
||||
public void setIndex(int x, int y, int z, int index) {
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public void setZ(int z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ids[index] & 0xFF;
|
||||
return Byte.toUnsignedInt(ids[index]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getData() {
|
||||
if (!FaweCache.hasData(ids[index])) {
|
||||
if (!FaweCache.hasData(ids[index] & 0xFF)) {
|
||||
return 0;
|
||||
} else {
|
||||
int indexShift = index >> 1;
|
||||
if ((index & 1) == 0) {
|
||||
return data[index] & 15;
|
||||
return data[indexShift] & 15;
|
||||
} else {
|
||||
return data[index] >> 4 & 15;
|
||||
return (data[indexShift] >> 4) & 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,256 @@
|
||||
package com.boydti.fawe.jnbt.anvil.generator;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.PseudoRandom;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.blocks.BlockID;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
public class CavesGen extends GenBase {
|
||||
|
||||
private boolean evenCaveDistribution = false;
|
||||
private int caveFrequency = 40;
|
||||
private int caveRarity = 7;
|
||||
private int caveMinAltitude = 8;
|
||||
private int caveMaxAltitude = 127;
|
||||
private int caveSystemFrequency = 1;
|
||||
private int individualCaveRarity = 25;
|
||||
private int caveSystemPocketChance = 0;
|
||||
private int caveSystemPocketMinSize = 0;
|
||||
private int caveSystemPocketMaxSize = 3;
|
||||
|
||||
public CavesGen(int caveSize) {
|
||||
super(caveSize);
|
||||
}
|
||||
|
||||
public CavesGen(int caveSize, int caveFrequency, int caveRarity, int caveMinAltitude, int caveMaxAltitude, int caveSystemFrequency, int individualCaveRarity, int caveSystemPocketChance, int caveSystemPocketMinSize, int caveSystemPocketMaxSize) {
|
||||
super(caveSize);
|
||||
this.caveFrequency = caveFrequency;
|
||||
this.caveRarity = caveRarity;
|
||||
this.caveMinAltitude = caveMinAltitude;
|
||||
this.caveMaxAltitude = caveMaxAltitude;
|
||||
this.caveSystemFrequency = caveSystemFrequency;
|
||||
this.individualCaveRarity = individualCaveRarity;
|
||||
this.caveSystemPocketChance = caveSystemPocketChance;
|
||||
this.caveSystemPocketMinSize = caveSystemPocketMinSize;
|
||||
this.caveSystemPocketMaxSize = caveSystemPocketMaxSize;
|
||||
}
|
||||
|
||||
protected void generateLargeCaveNode(long seed, Vector2D pos, Extent chunk, double x, double y, double z) throws WorldEditException {
|
||||
generateCaveNode(seed, pos, chunk, x, y, z, 1.0F + PseudoRandom.random.nextDouble() * 6.0F, 0.0F, 0.0F, -1, -1, 0.5D);
|
||||
}
|
||||
|
||||
protected void generateCaveNode(long seed, Vector2D chunkPos, Extent chunk, double x, double y, double z, double paramdouble1, double paramdouble2, double paramdouble3, int angle, int maxAngle, double paramDouble4) throws WorldEditException {
|
||||
int bx = (chunkPos.getBlockX() << 4);
|
||||
int bz = (chunkPos.getBlockZ() << 4);
|
||||
double real_x = bx + 7;
|
||||
double real_z = bz + 7;
|
||||
|
||||
double f1 = 0.0F;
|
||||
double f2 = 0.0F;
|
||||
|
||||
PseudoRandom localRandom = new PseudoRandom(seed);
|
||||
|
||||
if (maxAngle <= 0) {
|
||||
int checkAreaSize = this.getCheckAreaSize() * 16 - 16;
|
||||
maxAngle = checkAreaSize - localRandom.nextInt(checkAreaSize / 4);
|
||||
}
|
||||
boolean isLargeCave = false;
|
||||
|
||||
if (angle == -1) {
|
||||
angle = maxAngle / 2;
|
||||
isLargeCave = true;
|
||||
}
|
||||
|
||||
int j = localRandom.nextInt(maxAngle / 2) + maxAngle / 4;
|
||||
int k = localRandom.nextInt(6) == 0 ? 1 : 0;
|
||||
|
||||
for (; angle < maxAngle; angle++) {
|
||||
double d3 = 1.5D + MathMan.sinInexact(angle * 3.141593F / maxAngle) * paramdouble1 * 1.0F;
|
||||
double d4 = d3 * paramDouble4;
|
||||
|
||||
double f3 = MathMan.cosInexact(paramdouble3);
|
||||
double f4 = MathMan.sinInexact(paramdouble3);
|
||||
x += MathMan.cosInexact(paramdouble2) * f3;
|
||||
y += f4;
|
||||
z += MathMan.sinInexact(paramdouble2) * f3;
|
||||
|
||||
if (k != 0)
|
||||
paramdouble3 *= 0.92F;
|
||||
else {
|
||||
paramdouble3 *= 0.7F;
|
||||
}
|
||||
paramdouble3 += f2 * 0.1F;
|
||||
paramdouble2 += f1 * 0.1F;
|
||||
|
||||
f2 *= 0.9F;
|
||||
f1 *= 0.75F;
|
||||
f2 += (localRandom.nextDouble() - localRandom.nextDouble()) * localRandom.nextDouble() * 2.0F;
|
||||
f1 += (localRandom.nextDouble() - localRandom.nextDouble()) * localRandom.nextDouble() * 4.0F;
|
||||
|
||||
if ((!isLargeCave) && (angle == j) && (paramdouble1 > 1.0F) && (maxAngle > 0)) {
|
||||
generateCaveNode(localRandom.nextLong(), chunkPos, chunk, x, y, z, localRandom.nextDouble() * 0.5F + 0.5F, paramdouble2 - 1.570796F, paramdouble3 / 3.0F, angle, maxAngle, 1.0D);
|
||||
generateCaveNode(localRandom.nextLong(), chunkPos, chunk, x, y, z, localRandom.nextDouble() * 0.5F + 0.5F, paramdouble2 + 1.570796F, paramdouble3 / 3.0F, angle, maxAngle, 1.0D);
|
||||
return;
|
||||
}
|
||||
if ((!isLargeCave) && (localRandom.nextInt(4) == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if distance to working point (x and z) too larger than working radius (maybe ??)
|
||||
double d5 = x - real_x;
|
||||
double d6 = z - real_z;
|
||||
double d7 = maxAngle - angle;
|
||||
double d8 = paramdouble1 + 2.0F + 16.0F;
|
||||
if (d5 * d5 + d6 * d6 - d7 * d7 > d8 * d8) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Boundaries check.
|
||||
if ((x < real_x - 16.0D - d3 * 2.0D) || (z < real_z - 16.0D - d3 * 2.0D) || (x > real_x + 16.0D + d3 * 2.0D) || (z > real_z + 16.0D + d3 * 2.0D))
|
||||
continue;
|
||||
|
||||
|
||||
int m = (int) (x - d3) - bx - 1;
|
||||
int n = (int) (x + d3) - bx + 1;
|
||||
|
||||
int i1 = (int) (y - d4) - 1;
|
||||
int i2 = (int) (y + d4) + 1;
|
||||
|
||||
int i3 = (int) (z - d3) - bz - 1;
|
||||
int i4 = (int) (z + d3) - bz + 1;
|
||||
|
||||
if (m < 0)
|
||||
m = 0;
|
||||
if (n > 16)
|
||||
n = 16;
|
||||
|
||||
if (i1 < 1)
|
||||
i1 = 1;
|
||||
if (i2 > 256 - 8) {
|
||||
i2 = 256 - 8;
|
||||
}
|
||||
if (i3 < 0)
|
||||
i3 = 0;
|
||||
if (i4 > 16)
|
||||
i4 = 16;
|
||||
|
||||
// Search for water
|
||||
boolean waterFound = false;
|
||||
for (int local_x = m; (!waterFound) && (local_x < n); local_x++) {
|
||||
for (int local_z = i3; (!waterFound) && (local_z < i4); local_z++) {
|
||||
for (int local_y = i2 + 1; (!waterFound) && (local_y >= i1 - 1); local_y--) {
|
||||
if (local_y >= 0 && local_y < 255) {
|
||||
BaseBlock material = chunk.getLazyBlock(bx + local_x, local_y, bz + local_z);
|
||||
if (material.getId() == 8 || material.getId() == 9) {
|
||||
waterFound = true;
|
||||
}
|
||||
if ((local_y != i1 - 1) && (local_x != m) && (local_x != n - 1) && (local_z != i3) && (local_z != i4 - 1))
|
||||
local_y = i1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (waterFound) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Generate cave
|
||||
for (int local_x = m; local_x < n; local_x++) {
|
||||
double d9 = (local_x + bx + 0.5D - x) / d3;
|
||||
for (int local_z = i3; local_z < i4; local_z++) {
|
||||
double d10 = (local_z + bz + 0.5D - z) / d3;
|
||||
boolean grassFound = false;
|
||||
if (d9 * d9 + d10 * d10 < 1.0D) {
|
||||
for (int local_y = i2; local_y > i1; local_y--) {
|
||||
double d11 = ((local_y - 1) + 0.5D - y) / d4;
|
||||
if ((d11 > -0.7D) && (d9 * d9 + d11 * d11 + d10 * d10 < 1.0D)) {
|
||||
BaseBlock material = chunk.getLazyBlock(bx + local_x, local_y, bz + local_z);
|
||||
BaseBlock materialAbove = chunk.getLazyBlock(bx + local_x, local_y + 1, bz + local_z);
|
||||
if (material.getId() == BlockID.GRASS || material.getId() == BlockID.MYCELIUM) {
|
||||
grassFound = true;
|
||||
}
|
||||
if (this.isSuitableBlock(material, materialAbove)) {
|
||||
if (local_y - 1 < 10) {
|
||||
chunk.setBlock(bx + local_x, local_y, bz + local_z, FaweCache.getBlock(BlockID.LAVA, 0));
|
||||
} else {
|
||||
chunk.setBlock(bx + local_x, local_y, bz + local_z, FaweCache.getBlock(0, 0));
|
||||
|
||||
// If grass was just deleted, try to
|
||||
// move it down
|
||||
if (grassFound) {
|
||||
BaseBlock block = chunk.getLazyBlock(bx + local_x, local_y - 1, bz + local_z);
|
||||
if (block.getId() == BlockID.DIRT) {
|
||||
chunk.setBlock(bx + local_x, local_y - 1, bz + local_z, FaweCache.getBlock(BlockID.STONE, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isLargeCave)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isSuitableBlock(BaseBlock material, BaseBlock materialAbove) {
|
||||
switch (material.getId()) {
|
||||
case 0:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 7:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateChunk(Vector2D adjacentChunk, Vector2D originChunk, Extent chunk) throws WorldEditException {
|
||||
PseudoRandom random = getRandom();
|
||||
int i = random.nextInt(random.nextInt(random.nextInt(this.caveFrequency) + 1) + 1);
|
||||
if (this.evenCaveDistribution)
|
||||
i = this.caveFrequency;
|
||||
if (random.nextInt(100) >= this.caveRarity)
|
||||
i = 0;
|
||||
|
||||
for (int j = 0; j < i; j++) {
|
||||
double x = (adjacentChunk.getBlockX() << 4) + random.nextInt(16);
|
||||
|
||||
double y;
|
||||
|
||||
if (this.evenCaveDistribution)
|
||||
y = random.nextInt(this.caveMinAltitude, this.caveMaxAltitude);
|
||||
else
|
||||
y = random.nextInt(random.nextInt(this.caveMaxAltitude - this.caveMinAltitude + 1) + 1) + this.caveMinAltitude;
|
||||
|
||||
double z = (adjacentChunk.getBlockZ() << 4) + random.nextInt(16);
|
||||
|
||||
int count = this.caveSystemFrequency;
|
||||
boolean largeCaveSpawned = false;
|
||||
if (random.nextInt(100) <= this.individualCaveRarity) {
|
||||
generateLargeCaveNode(random.nextLong(), originChunk, chunk, x, y, z);
|
||||
largeCaveSpawned = true;
|
||||
}
|
||||
|
||||
if ((largeCaveSpawned) || (random.nextInt(100) <= this.caveSystemPocketChance - 1)) {
|
||||
count += random.nextInt(this.caveSystemPocketMinSize, this.caveSystemPocketMaxSize);
|
||||
}
|
||||
while (count > 0) {
|
||||
count--;
|
||||
double f1 = random.nextDouble() * 3.141593F * 2.0F;
|
||||
double f2 = (random.nextDouble() - 0.5F) * 2.0F / 8.0F;
|
||||
double f3 = random.nextDouble() * 2.0F + random.nextDouble();
|
||||
generateCaveNode(random.nextLong(), originChunk, chunk, x, y, z, f3, f1, f2, 0, 0, 1.0D);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.boydti.fawe.jnbt.anvil.generator;
|
||||
|
||||
import com.boydti.fawe.object.PseudoRandom;
|
||||
import com.sk89q.worldedit.MutableBlockVector2D;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
public abstract class GenBase {
|
||||
|
||||
private final int checkAreaSize;
|
||||
private final PseudoRandom random;
|
||||
private final long seed;
|
||||
private final long worldSeed1, worldSeed2;
|
||||
private MutableBlockVector2D mutable = new MutableBlockVector2D();
|
||||
|
||||
public GenBase(int area) {
|
||||
this.random = new PseudoRandom();
|
||||
this.checkAreaSize = area;
|
||||
this.seed = PseudoRandom.random.nextLong();
|
||||
this.worldSeed1 = PseudoRandom.random.nextLong();
|
||||
this.worldSeed2 = PseudoRandom.random.nextLong();
|
||||
}
|
||||
|
||||
public int getCheckAreaSize() {
|
||||
return checkAreaSize;
|
||||
}
|
||||
|
||||
public PseudoRandom getRandom() {
|
||||
return random;
|
||||
}
|
||||
|
||||
public void generate(Vector2D chunkPos, Extent chunk) throws WorldEditException {
|
||||
int i = this.checkAreaSize;
|
||||
int chunkX = chunkPos.getBlockX();
|
||||
int chunkZ = chunkPos.getBlockZ();
|
||||
|
||||
for (int x = chunkX - i; x <= chunkX + i; x++) {
|
||||
mutable.mutX(x);
|
||||
for (int z = chunkZ - i; z <= chunkZ + i; z++) {
|
||||
mutable.mutZ(z);
|
||||
this.random.setSeed(worldSeed1 * x ^ worldSeed2 * z ^ seed);
|
||||
generateChunk(mutable, chunkPos, chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void generateChunk(Vector2D adjacentChunk, Vector2D originChunk, Extent chunk) throws WorldEditException;
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
package com.boydti.fawe.jnbt.anvil.generator;
|
||||
|
||||
import com.boydti.fawe.object.PseudoRandom;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.worldedit.MutableBlockVector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
|
||||
public class OreGen extends Resource {
|
||||
private final int maxSize;
|
||||
private final double maxSizeO8;
|
||||
private final double maxSizeO16;
|
||||
private final double sizeInverse;
|
||||
private final int minY;
|
||||
private final int maxY;
|
||||
private final Pattern pattern;
|
||||
private final Extent extent;
|
||||
private final Mask mask;
|
||||
private MutableBlockVector mutable = new MutableBlockVector();
|
||||
|
||||
private double ONE_2 = 1 / 2F;
|
||||
private double ONE_8 = 1 / 8F;
|
||||
private double ONE_16 = 1 / 16F;
|
||||
|
||||
public int laced =0;
|
||||
|
||||
public OreGen(Extent extent, Mask mask, Pattern pattern, int size, int minY, int maxY) {
|
||||
this.maxSize = size;
|
||||
this.maxSizeO8 = size * ONE_8;
|
||||
this.maxSizeO16 = size * ONE_16;
|
||||
this.sizeInverse = 1.0 / size;
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
this.mask = mask;
|
||||
this.pattern = pattern;
|
||||
this.extent = extent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean spawn(PseudoRandom rand, int x, int z) throws WorldEditException {
|
||||
int y = rand.nextInt(minY, maxY);
|
||||
if (!mask.test(mutable.setComponents(x, y, z))) {
|
||||
return false;
|
||||
}
|
||||
double f = rand.nextDouble() * Math.PI;
|
||||
|
||||
int x8 = x + 8;
|
||||
int z8 = z + 8;
|
||||
double so8 = maxSizeO8;
|
||||
double so16 = maxSizeO16;
|
||||
double sf = MathMan.sinInexact(f) * so8;
|
||||
double cf = MathMan.cosInexact(f) * so8;
|
||||
double d1 = x8 + sf;
|
||||
double d2 = x8 - sf;
|
||||
double d3 = z8 + cf;
|
||||
double d4 = z8 - cf;
|
||||
|
||||
double d5 = y + rand.nextInt(3) - 2;
|
||||
double d6 = y + rand.nextInt(3) - 2;
|
||||
|
||||
double xd = (d2 - d1);
|
||||
double yd = (d6 - d5);
|
||||
double zd = (d4 - d3);
|
||||
|
||||
double iFactor = 0;
|
||||
for (int i = 0; i < maxSize; i++, iFactor += sizeInverse) {
|
||||
double d7 = d1 + xd * iFactor;
|
||||
double d8 = d5 + yd * iFactor;
|
||||
double d9 = d3 + zd * iFactor;
|
||||
|
||||
double d10 = rand.nextDouble() * so16;
|
||||
double sif = MathMan.sinInexact(Math.PI * iFactor);
|
||||
double d11 = (sif + 1.0) * d10 + 1.0;
|
||||
double d12 = (sif + 1.0) * d10 + 1.0;
|
||||
|
||||
double d11o2 = d11 * ONE_2;
|
||||
double d12o2 = d12 * ONE_2;
|
||||
|
||||
int minX = MathMan.floorZero(d7 - d11o2);
|
||||
int minY = Math.max(1, MathMan.floorZero(d8 - d12o2));
|
||||
int minZ = MathMan.floorZero(d9 - d11o2);
|
||||
|
||||
int maxX = MathMan.floorZero(d7 + d11o2);
|
||||
int maxY = Math.min(255, MathMan.floorZero(d8 + d12o2));
|
||||
int maxZ = MathMan.floorZero(d9 + d11o2);
|
||||
|
||||
double id11o2 = 1.0 / (d11o2);
|
||||
double id12o2 = 1.0 / (d12o2);
|
||||
|
||||
for (int xx = minX; xx <= maxX; xx++) {
|
||||
double dx = (xx + 0.5D - d7) * id11o2;
|
||||
double dx2 = dx * dx;
|
||||
if (dx2 < 1) {
|
||||
mutable.mutX(xx);
|
||||
for (int yy = minY; yy <= maxY; yy++) {
|
||||
double dy = (yy + 0.5D - d8) * id12o2;
|
||||
double dxy2 = dx2 + dy * dy;
|
||||
if (dxy2 < 1) {
|
||||
mutable.mutY(yy);
|
||||
for (int zz = minZ; zz <= maxZ; zz++) {
|
||||
mutable.mutZ(zz);
|
||||
double dz = (zz + 0.5D - d9) * id11o2;
|
||||
double dxyz2 = dxy2 + dz * dz;
|
||||
if ((dxyz2 < 1)) {
|
||||
if (mask.test(mutable))
|
||||
extent.setBlock(xx, yy, zz, pattern.apply(mutable));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.boydti.fawe.jnbt.anvil.generator;
|
||||
|
||||
import com.boydti.fawe.object.PseudoRandom;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
|
||||
public abstract class Resource {
|
||||
public Resource() {
|
||||
}
|
||||
|
||||
public abstract boolean spawn(PseudoRandom random, int x, int z) throws WorldEditException;
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.boydti.fawe.jnbt.anvil.generator;
|
||||
|
||||
import com.boydti.fawe.object.PseudoRandom;
|
||||
import com.boydti.fawe.object.schematic.Schematic;
|
||||
import com.sk89q.worldedit.MutableBlockVector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
|
||||
public class SchemGen extends Resource {
|
||||
|
||||
private final Extent extent;
|
||||
private final WorldData worldData;
|
||||
private final ClipboardHolder[] clipboards;
|
||||
private final boolean randomRotate;
|
||||
private final Mask mask;
|
||||
|
||||
private MutableBlockVector mutable = new MutableBlockVector();
|
||||
|
||||
public SchemGen(Mask mask, Extent extent, WorldData worldData, ClipboardHolder[] clipboards, boolean randomRotate) {
|
||||
this.mask = mask;
|
||||
this.extent = extent;
|
||||
this.worldData = worldData;
|
||||
this.clipboards = clipboards;
|
||||
this.randomRotate = randomRotate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean spawn(PseudoRandom random, int x, int z) throws WorldEditException {
|
||||
mutable.mutX(x);
|
||||
mutable.mutZ(z);
|
||||
int y = extent.getNearestSurfaceTerrainBlock(x, z, mutable.getBlockY(), 0, 255);
|
||||
mutable.mutY(y);
|
||||
if (!mask.test(mutable)) {
|
||||
return false;
|
||||
}
|
||||
mutable.mutY(y + 1);
|
||||
ClipboardHolder holder = clipboards[PseudoRandom.random.random(clipboards.length)];
|
||||
if (randomRotate) {
|
||||
holder.setTransform(new AffineTransform().rotateY(PseudoRandom.random.random(4) * 90));
|
||||
}
|
||||
Clipboard clipboard = holder.getClipboard();
|
||||
Schematic schematic = new Schematic(clipboard);
|
||||
if (holder.getTransform().isIdentity()) {
|
||||
schematic.paste(extent, mutable, false);
|
||||
} else {
|
||||
schematic.paste(extent, worldData, mutable, false, holder.getTransform());
|
||||
}
|
||||
mutable.mutY(y);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -295,6 +295,14 @@ public abstract class FaweChunk<T> implements Callable<FaweChunk> {
|
||||
|
||||
public abstract void setBiome(final int x, final int z, final byte biome);
|
||||
|
||||
public void setBiome(final byte biome) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
setBiome(x, z, biome);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spend time now so that the chunk can be more efficiently dispatched later<br>
|
||||
* - Modifications after this call will be ignored
|
||||
|
@ -146,7 +146,7 @@ public class HistoryExtent extends AbstractDelegateExtent {
|
||||
}
|
||||
}
|
||||
|
||||
private class TrackedEntity implements Entity {
|
||||
public class TrackedEntity implements Entity {
|
||||
private final Entity entity;
|
||||
|
||||
private TrackedEntity(final Entity entity) {
|
||||
|
@ -1,7 +1,5 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class PseudoRandom {
|
||||
|
||||
public static PseudoRandom random = new PseudoRandom();
|
||||
@ -10,13 +8,16 @@ public class PseudoRandom {
|
||||
|
||||
public PseudoRandom() {
|
||||
this.state = System.nanoTime();
|
||||
new Random().nextDouble();
|
||||
}
|
||||
|
||||
public PseudoRandom(final long state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public void setSeed(long state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public long nextLong() {
|
||||
final long a = this.state;
|
||||
this.state = this.xorShift64(a);
|
||||
@ -45,4 +46,8 @@ public class PseudoRandom {
|
||||
public int nextInt(int i) {
|
||||
return random(i);
|
||||
}
|
||||
|
||||
public int nextInt(int start, int end) {
|
||||
return nextInt(end - start + 1) + start;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import com.sk89q.worldedit.Vector;
|
||||
public class RegionWrapper {
|
||||
public int minX;
|
||||
public int maxX;
|
||||
public int minY;
|
||||
public int maxY;
|
||||
public int minZ;
|
||||
public int maxZ;
|
||||
|
||||
@ -13,10 +15,16 @@ public class RegionWrapper {
|
||||
}
|
||||
|
||||
public RegionWrapper(final int minX, final int maxX, final int minZ, final int maxZ) {
|
||||
this(minX, maxX, 0, 255, minZ, maxZ);
|
||||
}
|
||||
|
||||
public RegionWrapper(final int minX, final int maxX, final int minY, final int maxY, final int minZ, final int maxZ) {
|
||||
this.maxX = maxX;
|
||||
this.minX = minX;
|
||||
this.maxZ = maxZ;
|
||||
this.minZ = minZ;
|
||||
this.minY = minY;
|
||||
this.maxY = Math.min(255, maxY);
|
||||
}
|
||||
|
||||
public RegionWrapper(final Vector pos1, final Vector pos2) {
|
||||
@ -24,12 +32,35 @@ public class RegionWrapper {
|
||||
this.minZ = Math.min(pos1.getBlockZ(), pos2.getBlockZ());
|
||||
this.maxX = Math.max(pos1.getBlockX(), pos2.getBlockX());
|
||||
this.maxZ = Math.max(pos1.getBlockZ(), pos2.getBlockZ());
|
||||
this.minY = Math.min(pos1.getBlockY(), pos2.getBlockY());
|
||||
this.maxY = Math.max(pos1.getBlockY(), pos2.getBlockY());
|
||||
}
|
||||
|
||||
public RegionWrapper[] toArray() {
|
||||
return new RegionWrapper[]{this};
|
||||
}
|
||||
|
||||
private int ly = Integer.MIN_VALUE;
|
||||
private int lz = Integer.MIN_VALUE;
|
||||
private boolean lr, lry, lrz;
|
||||
|
||||
public boolean isIn(int x, int y, int z) {
|
||||
if (z != lz) {
|
||||
lz = z;
|
||||
lrz = z >= this.minZ && z <= this.maxZ;
|
||||
if (y != ly) {
|
||||
ly = y;
|
||||
lry = y >= this.minY && y <= this.maxY;
|
||||
}
|
||||
lr = lrz && lry;
|
||||
} else if (y != ly) {
|
||||
ly = y;
|
||||
lry = y >= this.minY && y <= this.maxY;
|
||||
lr = lrz && lry;
|
||||
}
|
||||
return lr && (x >= this.minX && x <= this.maxX);
|
||||
}
|
||||
|
||||
public boolean isIn(final int x, final int z) {
|
||||
return ((x >= this.minX) && (x <= this.maxX) && (z >= this.minZ) && (z <= this.maxZ));
|
||||
}
|
||||
@ -91,7 +122,7 @@ public class RegionWrapper {
|
||||
}
|
||||
|
||||
public boolean isGlobal() {
|
||||
return minX == Integer.MIN_VALUE && minZ == Integer.MIN_VALUE && maxX == Integer.MAX_VALUE && maxZ == Integer.MAX_VALUE;
|
||||
return minX == Integer.MIN_VALUE && minZ == Integer.MIN_VALUE && maxX == Integer.MAX_VALUE && maxZ == Integer.MAX_VALUE && minY <= 0 && maxY >= 255;
|
||||
}
|
||||
|
||||
public boolean contains(RegionWrapper current) {
|
||||
|
@ -0,0 +1,85 @@
|
||||
package com.boydti.fawe.object.brush;
|
||||
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.collection.BlockVectorSet;
|
||||
import com.boydti.fawe.object.mask.AdjacentAnyMask;
|
||||
import com.boydti.fawe.object.mask.RadiusMask;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.MutableBlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.command.tool.brush.Brush;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.SolidBlockMask;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.function.visitor.BreadthFirstSearch;
|
||||
import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class LayerBrush implements Brush {
|
||||
|
||||
private final BaseBlock[] layers;
|
||||
private RecursiveVisitor visitor;
|
||||
private MutableBlockVector mutable = new MutableBlockVector();
|
||||
|
||||
public LayerBrush(BaseBlock[] layers) {
|
||||
this.layers = layers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(EditSession editSession, Vector position, Pattern ignore, double size) throws MaxChangedBlocksException {
|
||||
final FaweQueue queue = editSession.getQueue();
|
||||
final AdjacentAnyMask adjacent = new AdjacentAnyMask(editSession, Arrays.asList(new BaseBlock(0)));
|
||||
final SolidBlockMask solid = new SolidBlockMask(editSession);
|
||||
final RadiusMask radius = new RadiusMask(0, (int) size);
|
||||
visitor = new RecursiveVisitor(vector -> solid.test(vector) && radius.test(vector) && adjacent.test(vector), function -> true);
|
||||
visitor.visit(position);
|
||||
visitor.setDirections(Arrays.asList(BreadthFirstSearch.DIAGONAL_DIRECTIONS));
|
||||
Operations.completeBlindly(visitor);
|
||||
BlockVectorSet visited = visitor.getVisited();
|
||||
BaseBlock firstPattern = layers[0];
|
||||
visitor = new RecursiveVisitor(new Mask() {
|
||||
@Override
|
||||
public boolean test(Vector pos) {
|
||||
int depth = visitor.getDepth() + 1;
|
||||
if (depth > 1) {
|
||||
boolean found = false;
|
||||
int previous = layers[depth - 1].getCombined();
|
||||
int previous2 = layers[depth - 2].getCombined();
|
||||
for (Vector dir : BreadthFirstSearch.DEFAULT_DIRECTIONS) {
|
||||
mutable.setComponents(pos.getBlockX() + dir.getBlockX(), pos.getBlockY() + dir.getBlockY(), pos.getBlockZ() + dir.getBlockZ());
|
||||
if (visitor.isVisited(mutable) && queue.getCachedCombinedId4Data(mutable.getBlockX(), mutable.getBlockY(), mutable.getBlockZ()) == previous) {
|
||||
mutable.setComponents(pos.getBlockX() + dir.getBlockX() * 2, pos.getBlockY() + dir.getBlockY() * 2, pos.getBlockZ() + dir.getBlockZ() * 2);
|
||||
if (visitor.isVisited(mutable) && queue.getCachedCombinedId4Data(mutable.getBlockX(), mutable.getBlockY(), mutable.getBlockZ()) == previous2) {
|
||||
found = true;
|
||||
break;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !adjacent.test(pos);
|
||||
}
|
||||
}, new RegionFunction() {
|
||||
@Override
|
||||
public boolean apply(Vector pos) throws WorldEditException {
|
||||
int depth = visitor.getDepth();
|
||||
BaseBlock currentPattern = layers[depth];
|
||||
return editSession.setBlock(pos, currentPattern);
|
||||
}
|
||||
}, layers.length - 1, editSession);
|
||||
for (Vector pos : visited) {
|
||||
visitor.visit(pos);
|
||||
}
|
||||
Operations.completeBlindly(visitor);
|
||||
visitor = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.boydti.fawe.object.brush;
|
||||
|
||||
import com.boydti.fawe.jnbt.anvil.generator.SchemGen;
|
||||
import com.boydti.fawe.util.MaskTraverser;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.command.tool.brush.Brush;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
|
||||
public class PopulateSchem implements Brush {
|
||||
private final Mask mask;
|
||||
private final boolean randomRotate;
|
||||
private final ClipboardHolder[] clipboards;
|
||||
private final int rarity;
|
||||
|
||||
public PopulateSchem(Mask mask, ClipboardHolder[] clipboards, int rarity, boolean randomRotate) {
|
||||
this.mask = mask;
|
||||
this.clipboards = clipboards;
|
||||
this.rarity = rarity;
|
||||
this.randomRotate = randomRotate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
|
||||
new MaskTraverser(mask).reset(editSession);
|
||||
SchemGen gen = new SchemGen(mask, editSession, editSession.getWorldData(), clipboards, randomRotate);
|
||||
CuboidRegion cuboid = new CuboidRegion(position.subtract(size, size, size), position.add(size, size, size));
|
||||
try {
|
||||
editSession.addSchems(cuboid, mask, editSession.getWorldData(), clipboards, rarity, randomRotate);
|
||||
} catch (WorldEditException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -50,7 +50,7 @@ public class SplatterBrush extends ScatterBrush {
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
double dist = vector.distanceSq(position);
|
||||
if (!placed.contains(vector) && (PseudoRandom.random.random(5) < 2) && solid.test(vector) && adjacent.test(vector)) {
|
||||
if (dist < size2 && !placed.contains(vector) && (PseudoRandom.random.random(5) < 2) && solid.test(vector) && adjacent.test(vector)) {
|
||||
placed.add(vector);
|
||||
return true;
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
@ -40,9 +39,8 @@ public class StencilBrush extends HeightBrush {
|
||||
final HeightMap map = getHeightMap();
|
||||
map.setSize(size);
|
||||
int cutoff = onlyWhite ? maxY : 0;
|
||||
|
||||
final AdjacentAnyMask adjacent = new AdjacentAnyMask(editSession, Arrays.asList(new BaseBlock(0)));
|
||||
final SolidBlockMask solid = new SolidBlockMask(editSession);
|
||||
final AdjacentAnyMask adjacent = new AdjacentAnyMask(editSession, solid.getInverseBlocks());
|
||||
RegionMask region = new RegionMask(new CuboidRegion(position.subtract(size, size, size), position.add(size, size, size)));
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(new Mask() {
|
||||
@Override
|
||||
|
@ -312,6 +312,8 @@ public class LocalBlockVectorSet implements Set<Vector> {
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
offsetZ = Integer.MAX_VALUE;
|
||||
offsetX = Integer.MAX_VALUE;
|
||||
set.clear();
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import com.sk89q.jnbt.DoubleTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
@ -105,9 +104,6 @@ public class FastWorldEditExtent extends AbstractDelegateExtent implements HasFa
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(int x, int y, int z) {
|
||||
if (y > maxY || y < 0) {
|
||||
return EditSession.nullBlock;
|
||||
}
|
||||
int combinedId4Data = queue.getCombinedId4Data(x, y, z, 0);
|
||||
int id = FaweCache.getId(combinedId4Data);
|
||||
if (!FaweCache.hasNBT(id)) {
|
||||
@ -149,9 +145,6 @@ public class FastWorldEditExtent extends AbstractDelegateExtent implements HasFa
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, final BaseBlock block) throws WorldEditException {
|
||||
if (y > maxY || y < 0) {
|
||||
return false;
|
||||
}
|
||||
final short id = (short) block.getId();
|
||||
switch (id) {
|
||||
case 63:
|
||||
|
@ -1,21 +1,200 @@
|
||||
package com.boydti.fawe.object.extent;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.util.Collection;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class FaweRegionExtent extends AbstractDelegateExtent {
|
||||
private final FaweLimit limit;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param extent the extent
|
||||
*/
|
||||
public FaweRegionExtent(Extent extent) {
|
||||
public FaweRegionExtent(Extent extent, FaweLimit limit) {
|
||||
super(extent);
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public abstract boolean contains(int x, int y, int z);
|
||||
|
||||
public abstract boolean contains(int x, int z);
|
||||
|
||||
public abstract Collection<RegionWrapper> getRegions();
|
||||
|
||||
public boolean isGlobal() {
|
||||
for (RegionWrapper region : getRegions()) {
|
||||
if (region.isGlobal()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public final boolean contains(Vector p) {
|
||||
return contains(p.getBlockX(), p.getBlockY(), p.getBlockZ());
|
||||
}
|
||||
|
||||
public final boolean contains(Vector2D p) {
|
||||
return contains(p.getBlockX(), p.getBlockZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException {
|
||||
if (!contains(location)) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return super.setBlock(location, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
|
||||
if (!contains(x, y, z)) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return super.setBlock(x, y, z, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(Vector2D position, BaseBiome biome) {
|
||||
if (!contains(position)) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return super.setBiome(position, biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBiome getBiome(Vector2D position) {
|
||||
if (!contains(position)) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return EditSession.nullBiome;
|
||||
}
|
||||
return super.getBiome(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlock(Vector position) {
|
||||
if (!contains(position)) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return EditSession.nullBlock;
|
||||
}
|
||||
return super.getBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(Vector position) {
|
||||
if (!contains(position)) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return EditSession.nullBlock;
|
||||
}
|
||||
return super.getLazyBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(int x, int y, int z) {
|
||||
if (!contains(x, y, z)) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return EditSession.nullBlock;
|
||||
}
|
||||
return super.getLazyBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockLight(int x, int y, int z) {
|
||||
if (!contains(x, y, z)) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return super.getBlockLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightness(int x, int y, int z) {
|
||||
if (!contains(x, y, z)) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return super.getBrightness(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLight(int x, int y, int z) {
|
||||
if (!contains(x, y, z)) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return super.getLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity(int x, int y, int z) {
|
||||
if (!contains(x, y, z)) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return super.getOpacity(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
if (!contains(x, y, z)) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return super.getSkyLight(x, y, z);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Entity createEntity(Location location, BaseEntity entity) {
|
||||
if (!contains(location.getBlockX(), location.getBlockY(), location.getBlockZ())) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return super.createEntity(location, entity);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
package com.boydti.fawe.object.extent;
|
||||
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
public class HeightBoundExtent extends FaweRegionExtent {
|
||||
|
||||
private final int min, max;
|
||||
private int lastY;
|
||||
private boolean lastResult;
|
||||
|
||||
public HeightBoundExtent(Extent extent, FaweLimit limit, int min, int max) {
|
||||
super(extent, limit);
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int x, int z) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int x, int y, int z) {
|
||||
if (y == lastY) {
|
||||
return lastResult;
|
||||
}
|
||||
lastY = y;
|
||||
return lastResult = (y >= min && y <= max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<RegionWrapper> getRegions() {
|
||||
return Arrays.asList(new RegionWrapper(Integer.MIN_VALUE, Integer.MAX_VALUE, min, max, Integer.MIN_VALUE, Integer.MAX_VALUE));
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package com.boydti.fawe.object.extent;
|
||||
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
public class MultiRegionExtent extends FaweRegionExtent {
|
||||
|
||||
private RegionWrapper region;
|
||||
private final RegionWrapper[] regions;
|
||||
private int index;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param extent the extent
|
||||
*/
|
||||
public MultiRegionExtent(Extent extent, FaweLimit limit, RegionWrapper[]regions) {
|
||||
super(extent, limit);
|
||||
this.index = 0;
|
||||
this.region = regions[0];
|
||||
this.regions = regions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int x, int y, int z) {
|
||||
if (region.isIn(x, y, z)) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < regions.length; i++) {
|
||||
if (i != index) {
|
||||
RegionWrapper current = regions[i];
|
||||
if (current.isIn(x, y, z)) {
|
||||
region = current;
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int x, int z) {
|
||||
if (region.isIn(x, z)) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < regions.length; i++) {
|
||||
if (i != index) {
|
||||
RegionWrapper current = regions[i];
|
||||
if (current.isIn(x, z)) {
|
||||
region = current;
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<RegionWrapper> getRegions() {
|
||||
return Arrays.asList(regions);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.boydti.fawe.object.extent;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
@ -29,7 +30,7 @@ public class NullExtent extends FaweRegionExtent {
|
||||
* @param extent the extent
|
||||
*/
|
||||
public NullExtent(Extent extent, BBC failReason) {
|
||||
super(extent);
|
||||
super(extent, FaweLimit.MAX);
|
||||
this.reason = failReason;
|
||||
}
|
||||
|
||||
@ -94,7 +95,14 @@ public class NullExtent extends FaweRegionExtent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int x, int y, int z) { return false; }
|
||||
public boolean contains(int x, int z) {
|
||||
throw new FaweException(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int x, int y, int z) {
|
||||
throw new FaweException(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<RegionWrapper> getRegions() {
|
||||
|
@ -1,10 +1,9 @@
|
||||
package com.boydti.fawe.object.extent;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
@ -17,27 +16,18 @@ import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ProcessedWEExtent extends FaweRegionExtent {
|
||||
public class ProcessedWEExtent extends AbstractDelegateExtent {
|
||||
private final FaweLimit limit;
|
||||
private final RegionWrapper[] mask;
|
||||
private final AbstractDelegateExtent extent;
|
||||
|
||||
public ProcessedWEExtent(final Extent parent, final RegionWrapper[] mask, FaweLimit limit) {
|
||||
public ProcessedWEExtent(final Extent parent, FaweLimit limit) {
|
||||
super(parent);
|
||||
this.mask = mask;
|
||||
this.limit = limit;
|
||||
this.extent = (AbstractDelegateExtent) parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<RegionWrapper> getRegions() {
|
||||
return Arrays.asList(mask);
|
||||
}
|
||||
|
||||
public void setLimit(FaweLimit other) {
|
||||
this.limit.set(other);
|
||||
}
|
||||
@ -47,16 +37,11 @@ public class ProcessedWEExtent extends FaweRegionExtent {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
if (WEManager.IMP.maskContains(this.mask, location.getBlockX(), location.getBlockZ())) {
|
||||
if (!limit.MAX_ENTITIES()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_ENTITIES);
|
||||
return null;
|
||||
}
|
||||
return super.createEntity(location, entity);
|
||||
} else if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
if (!limit.MAX_ENTITIES()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_ENTITIES);
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
return super.createEntity(location, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -74,23 +59,13 @@ public class ProcessedWEExtent extends FaweRegionExtent {
|
||||
return super.getEntities(region);
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(int x, int y, int z) {
|
||||
count++;
|
||||
if (WEManager.IMP.maskContains(this.mask, x, z)) {
|
||||
if (!limit.MAX_CHECKS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS);
|
||||
return EditSession.nullBlock;
|
||||
} else {
|
||||
return extent.getLazyBlock(x, y, z);
|
||||
}
|
||||
} else if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
if (!limit.MAX_CHECKS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS);
|
||||
return EditSession.nullBlock;
|
||||
} else {
|
||||
return EditSession.nullBlock;
|
||||
return extent.getLazyBlock(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,56 +81,33 @@ public class ProcessedWEExtent extends FaweRegionExtent {
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
|
||||
if (block.hasNbtData() && FaweCache.hasNBT(block.getType())) {
|
||||
CompoundTag nbt = block.getNbtData();
|
||||
if (nbt != null) {
|
||||
if (!limit.MAX_BLOCKSTATES()) {
|
||||
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_TILES);
|
||||
return false;
|
||||
} else if (WEManager.IMP.maskContains(this.mask, x, z)) {
|
||||
} else {
|
||||
if (!limit.MAX_CHANGES()) {
|
||||
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES);
|
||||
return false;
|
||||
}
|
||||
return extent.setBlock(x, y, z, block);
|
||||
} else if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (WEManager.IMP.maskContains(this.mask, x, z)) {
|
||||
if (!limit.MAX_CHANGES()) {
|
||||
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES);
|
||||
return false;
|
||||
} else {
|
||||
return extent.setBlock(x, y, z, block);
|
||||
}
|
||||
} else if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
if (!limit.MAX_CHANGES()) {
|
||||
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES);
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
return extent.setBlock(x, y, z, block);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(final Vector2D position, final BaseBiome biome) {
|
||||
if (WEManager.IMP.maskContains(this.mask, position.getBlockX(), position.getBlockZ())) {
|
||||
if (!limit.MAX_CHANGES()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES);
|
||||
return false;
|
||||
}
|
||||
return super.setBiome(position, biome);
|
||||
} else if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
return false;
|
||||
} else {
|
||||
if (!limit.MAX_CHANGES()) {
|
||||
WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int x, int y, int z) {
|
||||
return WEManager.IMP.maskContains(this.mask, x, z);
|
||||
return super.setBiome(position, biome);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
package com.boydti.fawe.object.extent;
|
||||
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
public class SingleRegionExtent extends FaweRegionExtent{
|
||||
|
||||
private final RegionWrapper region;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param extent the extent
|
||||
*/
|
||||
public SingleRegionExtent(Extent extent, FaweLimit limit, RegionWrapper region) {
|
||||
super(extent, limit);
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int x, int y, int z) {
|
||||
return region.isIn(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(int x, int z) {
|
||||
return region.isIn(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<RegionWrapper> getRegions() {
|
||||
return Arrays.asList(region);
|
||||
}
|
||||
}
|
@ -141,6 +141,17 @@ public class BufferedRandomAccessFile extends RandomAccessFile
|
||||
this.init(size);
|
||||
}
|
||||
|
||||
public BufferedRandomAccessFile(File file, String mode, byte[] buf) throws FileNotFoundException
|
||||
{
|
||||
super(file, mode);
|
||||
this.dirty_ = this.closed_ = false;
|
||||
this.lo_ = this.curr_ = this.hi_ = 0;
|
||||
this.buff_ = buf;
|
||||
this.maxHi_ = (long) BuffSz_;
|
||||
this.hitEOF_ = false;
|
||||
this.diskPos_ = 0L;
|
||||
}
|
||||
|
||||
private void init(int size)
|
||||
{
|
||||
this.dirty_ = this.closed_ = false;
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.boydti.fawe.object.mask;
|
||||
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MutableBlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.mask.Mask2D;
|
||||
import com.sk89q.worldedit.function.mask.SolidBlockMask;
|
||||
import javax.annotation.Nullable;
|
||||
@ -15,16 +15,16 @@ public class AngleMask extends SolidBlockMask {
|
||||
|
||||
private final double max;
|
||||
private final double min;
|
||||
private final EditSession extent;
|
||||
private final Extent extent;
|
||||
private MutableBlockVector mutable = new MutableBlockVector();
|
||||
private int maxY;
|
||||
|
||||
public AngleMask(EditSession editSession, double min, double max) {
|
||||
super(editSession);
|
||||
this.extent = editSession;
|
||||
public AngleMask(Extent extent, double min, double max) {
|
||||
super(extent);
|
||||
this.extent = extent;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.maxY = extent.getMaxY();
|
||||
this.maxY = extent.getMaximumPoint().getBlockY();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -32,11 +32,11 @@ public class AngleMask extends SolidBlockMask {
|
||||
int x = vector.getBlockX();
|
||||
int y = vector.getBlockY();
|
||||
int z = vector.getBlockZ();
|
||||
BaseBlock block = extent.getBlock(x, y, z);
|
||||
BaseBlock block = extent.getLazyBlock(x, y, z);
|
||||
if (!test(block.getId(), block.getData())) {
|
||||
return false;
|
||||
}
|
||||
block = extent.getBlock(x, y + 1, z);
|
||||
block = extent.getLazyBlock(x, y + 1, z);
|
||||
if (test(block.getId(), block.getData())) {
|
||||
return false;
|
||||
}
|
||||
|
@ -32,4 +32,4 @@ public class SkyLightMask implements Mask {
|
||||
public Mask2D toMask2D() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -43,7 +43,7 @@ public class BiomePattern extends ExistingPattern {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
public Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +0,0 @@
|
||||
package com.boydti.fawe.object.player;
|
||||
|
||||
public class DefaultFawePlayer {
|
||||
}
|
@ -0,0 +1,337 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.boydti.fawe.object.regions;
|
||||
|
||||
import com.sk89q.worldedit.LocalWorld;
|
||||
import com.sk89q.worldedit.MutableBlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.regions.AbstractRegion;
|
||||
import com.sk89q.worldedit.regions.RegionOperationException;
|
||||
import com.sk89q.worldedit.regions.polyhedron.Edge;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class PolyhedralRegion extends AbstractRegion {
|
||||
|
||||
/**
|
||||
* Vertices that are contained in the convex hull.
|
||||
*/
|
||||
private final Set<Vector> vertices = new LinkedHashSet<Vector>();
|
||||
|
||||
/**
|
||||
* Triangles that form the convex hull.
|
||||
*/
|
||||
private final List<Triangle> triangles = new ArrayList<Triangle>();
|
||||
|
||||
/**
|
||||
* Vertices that are coplanar to the first 3 vertices.
|
||||
*/
|
||||
private final Set<Vector> vertexBacklog = new LinkedHashSet<Vector>();
|
||||
|
||||
/**
|
||||
* Minimum point of the axis-aligned bounding box.
|
||||
*/
|
||||
private Vector minimumPoint;
|
||||
|
||||
/**
|
||||
* Maximum point of the axis-aligned bounding box.
|
||||
*/
|
||||
private Vector maximumPoint;
|
||||
|
||||
/**
|
||||
* Accumulator for the barycenter of the polyhedron. Divide by vertices.size() to get the actual center.
|
||||
*/
|
||||
private Vector centerAccum = Vector.ZERO;
|
||||
|
||||
/**
|
||||
* The last triangle that caused a {@link #contains(Vector)} to classify a point as "outside". Used for optimization.
|
||||
*/
|
||||
private Triangle lastTriangle;
|
||||
|
||||
/**
|
||||
* Constructs an empty mesh, containing no vertices or triangles.
|
||||
*
|
||||
* @param world the world
|
||||
*/
|
||||
public PolyhedralRegion(@Nullable World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated cast {@code world} to {@link World}
|
||||
*/
|
||||
@Deprecated
|
||||
public PolyhedralRegion(LocalWorld world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an independent copy of the given region.
|
||||
*
|
||||
* @param region the region to copy
|
||||
*/
|
||||
public PolyhedralRegion(PolyhedralRegion region) {
|
||||
this(region.world);
|
||||
vertices.addAll(region.vertices);
|
||||
triangles.addAll(region.triangles);
|
||||
vertexBacklog.addAll(region.vertexBacklog);
|
||||
|
||||
minimumPoint = region.minimumPoint;
|
||||
maximumPoint = region.maximumPoint;
|
||||
centerAccum = region.centerAccum;
|
||||
lastTriangle = region.lastTriangle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the region, removing all vertices and triangles.
|
||||
*/
|
||||
public void clear() {
|
||||
vertices.clear();
|
||||
triangles.clear();
|
||||
vertexBacklog.clear();
|
||||
|
||||
minimumPoint = null;
|
||||
maximumPoint = null;
|
||||
centerAccum = Vector.ZERO;
|
||||
lastTriangle = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add a vertex to the region.
|
||||
*
|
||||
* @param vertex the vertex
|
||||
* @return true, if something changed.
|
||||
*/
|
||||
public boolean addVertex(Vector vertex) {
|
||||
checkNotNull(vertex);
|
||||
|
||||
lastTriangle = null; // Probably not necessary
|
||||
|
||||
if (vertices.contains(vertex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vertices.size() == 3) {
|
||||
if (vertexBacklog.contains(vertex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (containsRaw(vertex)) {
|
||||
return vertexBacklog.add(vertex);
|
||||
}
|
||||
}
|
||||
|
||||
vertices.add(vertex);
|
||||
|
||||
centerAccum = centerAccum.add(vertex);
|
||||
|
||||
if (minimumPoint == null) {
|
||||
minimumPoint = maximumPoint = vertex;
|
||||
} else {
|
||||
minimumPoint = new MutableBlockVector(Vector.getMinimum(minimumPoint, vertex));
|
||||
maximumPoint = new MutableBlockVector(Vector.getMaximum(maximumPoint, vertex));
|
||||
}
|
||||
|
||||
int size = vertices.size();
|
||||
switch (size) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
// Incomplete, can't make a mesh yet
|
||||
return true;
|
||||
|
||||
case 3:
|
||||
// Generate minimal mesh to start from
|
||||
final Vector[] v = vertices.toArray(new Vector[vertices.size()]);
|
||||
|
||||
triangles.add((new Triangle(v[0], v[size - 2], v[size - 1])));
|
||||
triangles.add((new Triangle(v[0], v[size - 1], v[size - 2])));
|
||||
return true;
|
||||
}
|
||||
final Set<Edge> borderEdges = new LinkedHashSet<Edge>();
|
||||
for (Iterator<Triangle> it = triangles.iterator(); it.hasNext(); ) {
|
||||
final Triangle triangle = it.next();
|
||||
|
||||
// If the triangle can't be seen, it's not relevant
|
||||
if (!triangle.above(vertex)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove the triangle from the mesh
|
||||
it.remove();
|
||||
|
||||
// ...and remember its edges
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
final Edge edge = triangle.getEdge(i);
|
||||
if (borderEdges.remove(edge)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
borderEdges.add(edge);
|
||||
}
|
||||
}
|
||||
|
||||
// Add triangles between the remembered edges and the new vertex.
|
||||
for (Edge edge : borderEdges) {
|
||||
com.sk89q.worldedit.regions.polyhedron.Triangle triangle = edge.createTriangle(vertex);
|
||||
Triangle fTria = new Triangle(triangle.getVertex(0), triangle.getVertex(1), triangle.getVertex(2));
|
||||
triangles.add(fTria);
|
||||
}
|
||||
|
||||
if (!vertexBacklog.isEmpty()) {
|
||||
// Remove the new vertex
|
||||
vertices.remove(vertex);
|
||||
|
||||
// Clone, clear and work through the backlog
|
||||
final List<Vector> vertexBacklog2 = new ArrayList<Vector>(vertexBacklog);
|
||||
vertexBacklog.clear();
|
||||
for (Vector vertex2 : vertexBacklog2) {
|
||||
addVertex(vertex2);
|
||||
}
|
||||
|
||||
// Re-add the new vertex after the backlog.
|
||||
vertices.add(vertex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDefined() {
|
||||
return !triangles.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector getMinimumPoint() {
|
||||
return minimumPoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector getMaximumPoint() {
|
||||
return maximumPoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector getCenter() {
|
||||
return centerAccum.divide(vertices.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expand(Vector... changes) throws RegionOperationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contract(Vector... changes) throws RegionOperationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shift(Vector change) throws RegionOperationException {
|
||||
shiftCollection(vertices, change);
|
||||
shiftCollection(vertexBacklog, change);
|
||||
|
||||
for (int i = 0; i < triangles.size(); ++i) {
|
||||
final Triangle triangle = triangles.get(i);
|
||||
|
||||
final Vector v0 = change.add(triangle.getVertex(0));
|
||||
final Vector v1 = change.add(triangle.getVertex(1));
|
||||
final Vector v2 = change.add(triangle.getVertex(2));
|
||||
|
||||
triangles.set(i, new Triangle(v0, v1, v2));
|
||||
}
|
||||
|
||||
minimumPoint = change.add(minimumPoint);
|
||||
maximumPoint = change.add(maximumPoint);
|
||||
centerAccum = change.multiply(vertices.size()).add(centerAccum);
|
||||
lastTriangle = null;
|
||||
}
|
||||
|
||||
private static void shiftCollection(Collection<Vector> collection, Vector change) {
|
||||
final List<Vector> tmp = new ArrayList<Vector>(collection);
|
||||
collection.clear();
|
||||
for (Vector vertex : tmp) {
|
||||
collection.add(change.add(vertex));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Vector position) {
|
||||
if (!isDefined()) {
|
||||
return false;
|
||||
}
|
||||
final int x = position.getBlockX();
|
||||
final int y = position.getBlockY();
|
||||
final int z = position.getBlockZ();
|
||||
final Vector min = getMinimumPoint();
|
||||
final Vector max = getMaximumPoint();
|
||||
if (x < min.getBlockX()) return false;
|
||||
if (x > max.getBlockX()) return false;
|
||||
if (z < min.getBlockZ()) return false;
|
||||
if (z > max.getBlockZ()) return false;
|
||||
if (y < min.getBlockY()) return false;
|
||||
if (y > max.getBlockY()) return false;
|
||||
return containsRaw(position);
|
||||
}
|
||||
|
||||
private boolean containsRaw(Vector pt) {
|
||||
if (lastTriangle != null && lastTriangle.contains(pt)) {
|
||||
return true;
|
||||
}
|
||||
for (Triangle triangle : triangles) {
|
||||
if (lastTriangle == triangle) {
|
||||
continue;
|
||||
}
|
||||
if (triangle.contains(pt)) {
|
||||
lastTriangle = triangle;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Collection<Vector> getVertices() {
|
||||
if (vertexBacklog.isEmpty()) {
|
||||
return vertices;
|
||||
}
|
||||
|
||||
final List<Vector> ret = new ArrayList<Vector>(vertices);
|
||||
ret.addAll(vertexBacklog);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Collection<Triangle> getTriangles() {
|
||||
return triangles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractRegion clone() {
|
||||
return new PolyhedralRegion(this);
|
||||
}
|
||||
}
|
246
core/src/main/java/com/boydti/fawe/object/regions/Triangle.java
Normal file
246
core/src/main/java/com/boydti/fawe/object/regions/Triangle.java
Normal file
@ -0,0 +1,246 @@
|
||||
package com.boydti.fawe.object.regions;
|
||||
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.regions.polyhedron.Edge;
|
||||
|
||||
public class Triangle {
|
||||
|
||||
public static double RADIUS = 0.5;
|
||||
|
||||
private final double[][] verts = new double[3][3];
|
||||
private final double[] center = new double[3];
|
||||
private final double[] radius = new double[3];
|
||||
private final double[] v0 = new double[3];
|
||||
private final double[] v1 = new double[3];
|
||||
private final double[] v2 = new double[3];
|
||||
private final double[] normal = new double[3];
|
||||
private final double[] e0 = new double[3];
|
||||
private final double[] e1 = new double[3];
|
||||
private final double[] e2 = new double[3];
|
||||
private final double[] vmin = new double[3];
|
||||
private final double[] vmax = new double[3];
|
||||
|
||||
private final Vector normalVec;
|
||||
private final double b;
|
||||
|
||||
public Triangle(Vector pos1, Vector pos2, Vector pos3) {
|
||||
verts[0] = new double[]{pos1.getBlockX(), pos1.getBlockY(), pos1.getBlockZ()};
|
||||
verts[1] = new double[]{pos2.getBlockX(), pos2.getBlockY(), pos2.getBlockZ()};
|
||||
verts[2] = new double[]{pos3.getBlockX(), pos3.getBlockY(), pos3.getBlockZ()};
|
||||
radius[0] = RADIUS;
|
||||
radius[1] = RADIUS;
|
||||
radius[2] = RADIUS;
|
||||
this.normalVec = pos2.subtract(pos1).cross(pos3.subtract(pos1)).normalize();
|
||||
this.b = Math.max(Math.max(this.normalVec.dot(pos1), this.normalVec.dot(pos2)), this.normalVec.dot(pos3));
|
||||
}
|
||||
|
||||
public boolean above(Vector pt) {
|
||||
Preconditions.checkNotNull(pt);
|
||||
return this.normalVec.dot(pt) > this.b;
|
||||
}
|
||||
|
||||
public Edge getEdge(int index) {
|
||||
if (index == this.verts.length - 1) {
|
||||
return new Edge(new Vector(this.verts[index]), new Vector(this.verts[0]));
|
||||
} else {
|
||||
return new Edge(new Vector(this.verts[index]), new Vector(this.verts[index + 1]));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return StringMan.getString(verts);
|
||||
}
|
||||
|
||||
public Vector getVertex(int index) {
|
||||
return new Vector(verts[index]);
|
||||
}
|
||||
|
||||
public boolean contains(Vector pos) {
|
||||
center[0] = pos.getBlockX() + RADIUS;
|
||||
center[1] = pos.getBlockY() + RADIUS;
|
||||
center[2] = pos.getBlockZ() + RADIUS;
|
||||
return overlaps(center, radius, verts);
|
||||
}
|
||||
|
||||
private void sub(double[] dest, double[] v1, double[] v2) {
|
||||
dest[0] = v1[0] - v2[0];
|
||||
dest[1] = v1[1] - v2[1];
|
||||
dest[2] = v1[2] - v2[2];
|
||||
}
|
||||
|
||||
private void cross(double[] dest, double[] v1, double[] v2) {
|
||||
dest[0] = v1[1] * v2[2] - v1[2] * v2[1];
|
||||
dest[1] = v1[2] * v2[0] - v1[0] * v2[2];
|
||||
dest[2] = v1[0] * v2[1] - v1[1] * v2[0];
|
||||
}
|
||||
|
||||
private double dot(double[] v1, double[] v2) {
|
||||
return (v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]);
|
||||
}
|
||||
|
||||
|
||||
private boolean axisTestX01(double a, double b, double fa, double fb) {
|
||||
double p0 = a * v0[1] - b * v0[2];
|
||||
double p2 = a * v2[1] - b * v2[2];
|
||||
double min, max;
|
||||
if (p0 < p2) {
|
||||
min = p0;
|
||||
max = p2;
|
||||
} else {
|
||||
min = p2;
|
||||
max = p0;
|
||||
}
|
||||
double rad = fa * radius[1] + fb * radius[2];
|
||||
return !(min > rad || max < -rad);
|
||||
}
|
||||
|
||||
private boolean axisTestX2(double a, double b, double fa, double fb) {
|
||||
double p0 = a * v0[1] - b * v0[2];
|
||||
double p1 = a * v1[1] - b * v1[2];
|
||||
double min, max;
|
||||
if (p0 < p1) {
|
||||
min = p0;
|
||||
max = p1;
|
||||
} else {
|
||||
min = p1;
|
||||
max = p0;
|
||||
}
|
||||
double rad = fa * radius[1] + fb * radius[2];
|
||||
return !(min > rad || max < -rad);
|
||||
}
|
||||
|
||||
private boolean axisTestY02(double a, double b, double fa, double fb) {
|
||||
double p0 = -a * v0[0] + b * v0[2];
|
||||
double p2 = -a * v2[0] + b * v2[2];
|
||||
double min, max;
|
||||
if (p0 < p2) {
|
||||
min = p0;
|
||||
max = p2;
|
||||
} else {
|
||||
min = p2;
|
||||
max = p0;
|
||||
}
|
||||
double rad = fa * radius[0] + fb * radius[2];
|
||||
return !(min > rad || max < -rad);
|
||||
}
|
||||
|
||||
private boolean axisTestY1(double a, double b, double fa, double fb) {
|
||||
double p0 = -a * v0[0] + b * v0[2];
|
||||
double p1 = -a * v1[0] + b * v1[2];
|
||||
double min, max;
|
||||
if (p0 < p1) {
|
||||
min = p0;
|
||||
max = p1;
|
||||
} else {
|
||||
min = p1;
|
||||
max = p0;
|
||||
}
|
||||
double rad = fa * radius[0] + fb * radius[2];
|
||||
return !(min > rad || max < -rad);
|
||||
}
|
||||
|
||||
private boolean axisTestZ12(double a, double b, double fa, double fb) {
|
||||
double p1 = a * v1[0] - b * v1[1];
|
||||
double p2 = a * v2[0] - b * v2[1];
|
||||
double min, max;
|
||||
if (p2 < p1) {
|
||||
min = p2;
|
||||
max = p1;
|
||||
} else {
|
||||
min = p1;
|
||||
max = p2;
|
||||
}
|
||||
double rad = fa * radius[0] + fb * radius[1];
|
||||
return !(min > rad || max < -rad);
|
||||
}
|
||||
|
||||
private boolean axisTestZ0(double a, double b, double fa, double fb) {
|
||||
double p0 = a * v0[0] - b * v0[1];
|
||||
double p1 = a * v1[0] - b * v1[1];
|
||||
double min, max;
|
||||
if (p0 < p1) {
|
||||
min = p0;
|
||||
max = p1;
|
||||
} else {
|
||||
min = p1;
|
||||
max = p0;
|
||||
}
|
||||
double rad = fa * radius[0] + fb * radius[1];
|
||||
return !(min > rad || max < -rad);
|
||||
}
|
||||
|
||||
|
||||
private boolean overlaps(double boxcenter[], double boxhalfsize[], double triverts[][]) {
|
||||
double min, max, p0, p1, p2, rad, fex, fey, fez;
|
||||
sub(v0, triverts[0], boxcenter);
|
||||
sub(v1, triverts[1], boxcenter);
|
||||
sub(v2, triverts[2], boxcenter);
|
||||
sub(e0, v1, v0); /* tri edge 0 */
|
||||
sub(e1, v2, v1); /* tri edge 1 */
|
||||
sub(e2, v0, v2); /* tri edge 2 */
|
||||
|
||||
fex = Math.abs(e0[0]);
|
||||
fey = Math.abs(e0[1]);
|
||||
fez = Math.abs(e0[2]);
|
||||
|
||||
if (!axisTestX01(e0[2], e0[1], fez, fey)) return false;
|
||||
if (!axisTestY02(e0[2], e0[0], fez, fex)) return false;
|
||||
if (!axisTestZ12(e0[1], e0[0], fey, fex)) return false;
|
||||
|
||||
fex = Math.abs(e1[0]);
|
||||
fey = Math.abs(e1[1]);
|
||||
fez = Math.abs(e1[2]);
|
||||
|
||||
if (!axisTestX01(e1[2], e1[1], fez, fey)) return false;
|
||||
if (!axisTestY02(e1[2], e1[0], fez, fex)) return false;
|
||||
if (!axisTestZ0(e1[1], e1[0], fey, fex)) return false;
|
||||
|
||||
|
||||
fex = Math.abs(e2[0]);
|
||||
fey = Math.abs(e2[1]);
|
||||
fez = Math.abs(e2[2]);
|
||||
|
||||
if (!axisTestX2(e2[2], e2[1], fez, fey)) return false;
|
||||
if (!axisTestY1(e2[2], e2[0], fez, fex)) return false;
|
||||
if (!axisTestZ12(e2[1], e2[0], fey, fex)) return false;
|
||||
|
||||
max = MathMan.max(v0[0], v1[0], v2[0]);
|
||||
min = MathMan.min(v0[0], v1[0], v2[0]);
|
||||
|
||||
if (min > boxhalfsize[0] || max < -boxhalfsize[0]) return false;
|
||||
|
||||
max = MathMan.max(v0[1], v1[1], v2[1]);
|
||||
min = MathMan.min(v0[1], v1[1], v2[1]);
|
||||
|
||||
if (min > boxhalfsize[1] || max < -boxhalfsize[1]) return false;
|
||||
|
||||
max = MathMan.max(v0[2], v1[2], v2[2]);
|
||||
min = MathMan.min(v0[2], v1[2], v2[2]);
|
||||
|
||||
if (min > boxhalfsize[2] || max < -boxhalfsize[2]) return false;
|
||||
|
||||
cross(normal, e0, e1);
|
||||
|
||||
return (planeBoxOverlap(normal, v0, boxhalfsize));
|
||||
}
|
||||
|
||||
private boolean planeBoxOverlap(double normal[], double vert[], double maxbox[]) {
|
||||
for (int q = 0; q <= 2; q++) {
|
||||
double v = vert[q];
|
||||
if (normal[q] > 0.0f) {
|
||||
vmin[q] = -maxbox[q] - v;
|
||||
vmax[q] = maxbox[q] - v;
|
||||
} else {
|
||||
vmin[q] = maxbox[q] - v;
|
||||
vmax[q] = -maxbox[q] - v;
|
||||
}
|
||||
}
|
||||
if (dot(normal, vmin) > 0.0f) return false;
|
||||
if (dot(normal, vmax) >= 0.0f) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.boydti.fawe.object.regions.selector;
|
||||
|
||||
import com.boydti.fawe.object.regions.PolyhedralRegion;
|
||||
import com.boydti.fawe.object.regions.Triangle;
|
||||
import com.google.common.base.Optional;
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.internal.cui.CUIRegion;
|
||||
import com.sk89q.worldedit.internal.cui.SelectionPointEvent;
|
||||
import com.sk89q.worldedit.internal.cui.SelectionPolygonEvent;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.regions.RegionSelector;
|
||||
import com.sk89q.worldedit.regions.selector.limit.SelectorLimits;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Creates a {@code PolyhedralRegion} from a user's selections.
|
||||
*/
|
||||
public class PolyhedralRegionSelector implements RegionSelector, CUIRegion {
|
||||
|
||||
private final transient PolyhedralRegion region;
|
||||
private transient BlockVector pos1;
|
||||
|
||||
/**
|
||||
* Create a new selector with a {@code null} world.
|
||||
*/
|
||||
public PolyhedralRegionSelector() {
|
||||
this((World) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new selector.
|
||||
*
|
||||
* @param world the world, which may be {@code null}
|
||||
*/
|
||||
public PolyhedralRegionSelector(@Nullable World world) {
|
||||
region = new PolyhedralRegion(world);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public World getWorld() {
|
||||
return region.getWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWorld(@Nullable World world) {
|
||||
region.setWorld(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean selectPrimary(Vector position, SelectorLimits limits) {
|
||||
checkNotNull(position);
|
||||
clear();
|
||||
pos1 = position.toBlockVector();
|
||||
return region.addVertex(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean selectSecondary(Vector position, SelectorLimits limits) {
|
||||
checkNotNull(position);
|
||||
|
||||
Optional<Integer> vertexLimit = limits.getPolyhedronVertexLimit();
|
||||
|
||||
if (vertexLimit.isPresent() && region.getVertices().size() > vertexLimit.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return region.addVertex(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector getPrimaryPosition() throws IncompleteRegionException {
|
||||
return pos1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region getRegion() throws IncompleteRegionException {
|
||||
if (!region.isDefined()) {
|
||||
throw new IncompleteRegionException();
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region getIncompleteRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefined() {
|
||||
return region.isDefined();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getArea() {
|
||||
return region.getArea();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void learnChanges() {
|
||||
pos1 = region.getVertices().iterator().next().toBlockVector();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
region.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "Polyhedron";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getInformationLines() {
|
||||
List<String> ret = new ArrayList<String>();
|
||||
|
||||
ret.add("Vertices: "+region.getVertices().size());
|
||||
ret.add("Triangles: "+region.getTriangles().size());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void explainPrimarySelection(Actor player, LocalSession session, Vector pos) {
|
||||
checkNotNull(player);
|
||||
checkNotNull(session);
|
||||
checkNotNull(pos);
|
||||
|
||||
session.describeCUI(player);
|
||||
|
||||
player.print("Started new selection with vertex "+pos+".");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void explainSecondarySelection(Actor player, LocalSession session, Vector pos) {
|
||||
checkNotNull(player);
|
||||
checkNotNull(session);
|
||||
checkNotNull(pos);
|
||||
|
||||
session.describeCUI(player);
|
||||
|
||||
player.print("Added vertex " + pos + " to the selection.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void explainRegionAdjust(Actor player, LocalSession session) {
|
||||
checkNotNull(player);
|
||||
checkNotNull(session);
|
||||
session.describeCUI(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtocolVersion() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeID() {
|
||||
return "polyhedron";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeCUI(LocalSession session, Actor player) {
|
||||
checkNotNull(player);
|
||||
checkNotNull(session);
|
||||
|
||||
Collection<Vector> vertices = region.getVertices();
|
||||
Collection<Triangle> triangles = region.getTriangles();
|
||||
|
||||
Map<Vector, Integer> vertexIds = new HashMap<Vector, Integer>(vertices.size());
|
||||
int lastVertexId = -1;
|
||||
for (Vector vertex : vertices) {
|
||||
vertexIds.put(vertex, ++lastVertexId);
|
||||
session.dispatchCUIEvent(player, new SelectionPointEvent(lastVertexId, vertex, getArea()));
|
||||
}
|
||||
|
||||
for (Triangle triangle : triangles) {
|
||||
final int[] v = new int[3];
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
v[i] = vertexIds.get(triangle.getVertex(i));
|
||||
}
|
||||
session.dispatchCUIEvent(player, new SelectionPolygonEvent(v));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLegacyTypeID() {
|
||||
return "cuboid";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeLegacyCUI(LocalSession session, Actor player) {
|
||||
checkNotNull(player);
|
||||
checkNotNull(session);
|
||||
|
||||
if (isDefined()) {
|
||||
session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getArea()));
|
||||
session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getArea()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -30,7 +30,7 @@ public class FaweMask {
|
||||
public HashSet<RegionWrapper> getRegions() {
|
||||
final BlockVector lower = this.getLowerBound();
|
||||
final BlockVector upper = this.getUpperBound();
|
||||
return new HashSet<>(Arrays.asList(new RegionWrapper(lower.getBlockX(), upper.getBlockX(), lower.getBlockZ(), upper.getBlockZ())));
|
||||
return new HashSet<>(Arrays.asList(new RegionWrapper(lower.getBlockX(), upper.getBlockX(), lower.getBlockY(), upper.getBlockY(), lower.getBlockZ(), upper.getBlockZ())));
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
@ -0,0 +1,362 @@
|
||||
package com.boydti.fawe.regions.general.plot;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.jnbt.anvil.HeightMapMCAGenerator;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.commands.Auto;
|
||||
import com.intellectualcrafters.plot.commands.CommandCategory;
|
||||
import com.intellectualcrafters.plot.commands.MainCommand;
|
||||
import com.intellectualcrafters.plot.commands.RequiredType;
|
||||
import com.intellectualcrafters.plot.config.C;
|
||||
import com.intellectualcrafters.plot.config.Settings;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.object.PlotId;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
import com.intellectualcrafters.plot.object.RunnableVal2;
|
||||
import com.intellectualcrafters.plot.object.RunnableVal3;
|
||||
import com.intellectualcrafters.plot.object.worlds.PlotAreaManager;
|
||||
import com.intellectualcrafters.plot.object.worlds.SinglePlotArea;
|
||||
import com.intellectualcrafters.plot.object.worlds.SinglePlotAreaManager;
|
||||
import com.intellectualcrafters.plot.util.MainUtil;
|
||||
import com.plotsquared.general.commands.Command;
|
||||
import com.plotsquared.general.commands.CommandDeclaration;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.session.request.Request;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import com.sk89q.worldedit.world.biome.Biomes;
|
||||
import com.sk89q.worldedit.world.registry.BiomeRegistry;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
@CommandDeclaration(
|
||||
command = "cfi",
|
||||
permission = "plots.createfromimage",
|
||||
aliases = {"createfromheightmap", "createfromimage", "cfhm"},
|
||||
category = CommandCategory.APPEARANCE,
|
||||
requiredType = RequiredType.NONE,
|
||||
description = "Generate a world from an image",
|
||||
usage = "/plots cfi [url]"
|
||||
)
|
||||
public class CreateFromImage extends Command {
|
||||
private final WorldEdit we;
|
||||
|
||||
public CreateFromImage() {
|
||||
super(MainCommand.getInstance(), true);
|
||||
this.we = WorldEdit.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(final PlotPlayer player, String[] args, RunnableVal3<Command, Runnable, Runnable> confirm, RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
|
||||
List<String> argList = StringMan.split(StringMan.join(args, " "), ' ');
|
||||
checkTrue(argList.size() >= 1, C.COMMAND_SYNTAX, getUsage());
|
||||
PlotAreaManager manager = PS.get().getPlotAreaManager();
|
||||
if (manager instanceof SinglePlotAreaManager) {
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
FawePlayer<Object> fp = FawePlayer.wrap(player.getName());
|
||||
if (argList.get(0).toLowerCase().startsWith("http")) {
|
||||
final BufferedImage image;
|
||||
try {
|
||||
URL url = new URL(argList.get(0));
|
||||
if (!url.getHost().equals("i.imgur.com")) {
|
||||
player.sendMessage("Images can only be loaded from i.imgur.com");
|
||||
return;
|
||||
}
|
||||
player.sendMessage(BBC.getPrefix() + "Loading image... (1)");
|
||||
image = ImageIO.read(url);
|
||||
} catch (IOException e) {
|
||||
player.sendMessage(e.getMessage());
|
||||
return;
|
||||
}
|
||||
fp.runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SinglePlotAreaManager sManager = (SinglePlotAreaManager) manager;
|
||||
SinglePlotArea area = sManager.getArea();
|
||||
Plot plot = TaskManager.IMP.sync(new com.boydti.fawe.object.RunnableVal<Plot>() {
|
||||
@Override
|
||||
public void run(Plot o) {
|
||||
int currentPlots = Settings.Limit.GLOBAL ? player.getPlotCount() : player.getPlotCount(area.worldname);
|
||||
int diff = player.getAllowedPlots() - currentPlots;
|
||||
if (diff < 1) {
|
||||
MainUtil.sendMessage(player, C.CANT_CLAIM_MORE_PLOTS_NUM, -diff + "");
|
||||
return;
|
||||
}
|
||||
if (area.getMeta("lastPlot") == null) {
|
||||
area.setMeta("lastPlot", new PlotId(0, 0));
|
||||
}
|
||||
PlotId lastId = (PlotId) area.getMeta("lastPlot");
|
||||
while (true) {
|
||||
lastId = Auto.getNextPlotId(lastId, 1);
|
||||
if (area.canClaim(player, lastId, lastId)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
area.setMeta("lastPlot", lastId);
|
||||
this.value = area.getPlot(lastId);
|
||||
this.value.setOwner(player.getUUID());
|
||||
}
|
||||
});
|
||||
fp.sendMessage(BBC.getPrefix() + "Initializing components... (2)");
|
||||
fp.sendMessage(BBC.getPrefix() + "/2 cfi setbiome");
|
||||
fp.sendMessage(BBC.getPrefix() + "/2 cfi setoverlay");
|
||||
fp.sendMessage(BBC.getPrefix() + "/2 cfi setmain");
|
||||
fp.sendMessage(BBC.getPrefix() + "/2 cfi setfloor");
|
||||
fp.sendMessage(BBC.getPrefix() + "/2 cfi setcolumn");
|
||||
fp.sendMessage(BBC.getPrefix() + "/2 cfi addcaves");
|
||||
fp.sendMessage(BBC.getPrefix() + "/2 cfi addore[s]");
|
||||
fp.sendMessage(BBC.getPrefix() + "/2 cfi addschems");
|
||||
fp.sendMessage(BBC.getPrefix() + "/2 cfi done");
|
||||
fp.sendMessage(BBC.getPrefix() + "/2 cfi cancel");
|
||||
File folder = new File(PS.imp().getWorldContainer(), plot.getWorldName() + File.separator + "region");
|
||||
HeightMapMCAGenerator generator = new HeightMapMCAGenerator(image, folder);
|
||||
player.setMeta("HMGenerator", generator);
|
||||
player.setMeta("HMGeneratorPlot", plot);
|
||||
}
|
||||
}, true, false);
|
||||
return;
|
||||
}
|
||||
fp.runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
HeightMapMCAGenerator generator = player.getMeta("HMGenerator");
|
||||
Plot plot = player.getMeta("HMGeneratorPlot");
|
||||
if (generator == null) {
|
||||
C.COMMAND_SYNTAX.send(player, getUsage());
|
||||
return;
|
||||
}
|
||||
if (argList.size() == 1) {
|
||||
if (StringMan.isEqualIgnoreCaseToAny(argList.get(0), "setbiome", "setoverlay", "setmain", "setfloor", "setcolumn")) {
|
||||
C.COMMAND_SYNTAX.send(player, "/2 cfi " + argList.get(0) + " <image or mask> <value> [white-only]");
|
||||
C.COMMAND_SYNTAX.send(player, "/2 cfi " + argList.get(0) + " <value>");
|
||||
return;
|
||||
} else if (!StringMan.isEqualIgnoreCaseToAny(argList.get(0), "done", "cancel", "addcaves", "addore", "addores", "addschems")) {
|
||||
C.COMMAND_SYNTAX.send(player, "/2 cfi <setbiome|setoverlay|setmain|setfloor|setcolumn|done|cancel|addcaves|addore[s]|addschems>");
|
||||
return;
|
||||
}
|
||||
}
|
||||
ParserContext context = new ParserContext();
|
||||
context.setActor(fp.getPlayer());
|
||||
context.setWorld(fp.getWorld());
|
||||
context.setSession(fp.getSession());
|
||||
context.setExtent(generator);
|
||||
Request.request().setExtent(generator);
|
||||
try {
|
||||
switch (argList.get(0).toLowerCase()) {
|
||||
case "addschems": {
|
||||
if (argList.size() != 5) {
|
||||
C.COMMAND_SYNTAX.send(player, "/2 cfi " + argList.get(0) + " <mask> <file|folder|url> <rarity> <rotate>");
|
||||
return;
|
||||
}
|
||||
World world = fp.getWorld();
|
||||
WorldData wd = world.getWorldData();
|
||||
Mask mask = we.getMaskFactory().parseFromInput(argList.get(1), context);
|
||||
ClipboardHolder[] clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(fp.getPlayer(), wd, argList.get(2), true);
|
||||
if (clipboards == null) {
|
||||
return;
|
||||
}
|
||||
int rarity = Integer.parseInt(argList.get(3));
|
||||
boolean rotate = Boolean.parseBoolean(argList.get(4));
|
||||
generator.addSchems(mask, wd, clipboards, rarity, rotate);
|
||||
player.sendMessage(BBC.getPrefix() + "Added schems, what's next?");
|
||||
return;
|
||||
}
|
||||
case "addores":
|
||||
if (argList.size() != 2) {
|
||||
C.COMMAND_SYNTAX.send(player, "/2 cfi " + argList.get(0) + " <mask>");
|
||||
return;
|
||||
}
|
||||
generator.addDefaultOres(we.getMaskFactory().parseFromInput(argList.get(1), context));
|
||||
player.sendMessage(BBC.getPrefix() + "Added ores, what's next?");
|
||||
return;
|
||||
case "addore": {
|
||||
if (argList.size() != 8) {
|
||||
C.COMMAND_SYNTAX.send(player, "/2 cfi " + argList.get(0) + " <mask> <pattern> <size> <frequency> <rarity> <min-Y> <max-Y>");
|
||||
return;
|
||||
}
|
||||
// mask pattern size freq rarity miny maxy
|
||||
Mask mask = we.getMaskFactory().parseFromInput(argList.get(1), context);
|
||||
Pattern pattern = we.getPatternFactory().parseFromInput(argList.get(2), context);
|
||||
int size = Integer.parseInt(argList.get(3));
|
||||
int frequency = Integer.parseInt(argList.get(4));
|
||||
int rarity = Integer.parseInt(argList.get(5));
|
||||
int min = Integer.parseInt(argList.get(6));
|
||||
int max = Integer.parseInt(argList.get(7));
|
||||
generator.addOre(mask, pattern, size, frequency, rarity, min, max);
|
||||
player.sendMessage(BBC.getPrefix() + "Added ore, what's next?");
|
||||
return;
|
||||
}
|
||||
case "addcaves": {
|
||||
generator.addCaves();
|
||||
player.sendMessage(BBC.getPrefix() + "Added caves, what's next?");
|
||||
return;
|
||||
}
|
||||
case "setbiome": {
|
||||
int id;
|
||||
if (argList.size() == 2) {
|
||||
id = getBiome(argList.get(1), fp).getId();
|
||||
generator.setBiome(id);
|
||||
} else {
|
||||
id = getBiome(argList.get(2), fp).getId();
|
||||
BufferedImage img = getImgurImage(argList.get(1), fp);
|
||||
if (img != null) {
|
||||
boolean whiteOnly = argList.size() == 4 && Boolean.parseBoolean(argList.get(3));
|
||||
generator.setBiome(img, (byte) id, whiteOnly);
|
||||
} else {
|
||||
generator.setBiome(we.getMaskFactory().parseFromInput(argList.get(1), context), (byte) id);
|
||||
}
|
||||
}
|
||||
player.sendMessage(BBC.getPrefix() + "Set biome, what's next?");
|
||||
return;
|
||||
}
|
||||
case "setoverlay": {
|
||||
Pattern id;
|
||||
if (argList.size() == 2) {
|
||||
id = we.getPatternFactory().parseFromInput(argList.get(1), context);
|
||||
generator.setOverlay(id);
|
||||
} else {
|
||||
id = we.getPatternFactory().parseFromInput(argList.get(2), context);
|
||||
BufferedImage img = getImgurImage(argList.get(1), fp);
|
||||
if (img != null) {
|
||||
boolean whiteOnly = argList.size() == 4 && Boolean.parseBoolean(argList.get(3));
|
||||
generator.setOverlay(img, id, whiteOnly);
|
||||
} else {
|
||||
generator.setOverlay(we.getMaskFactory().parseFromInput(argList.get(1), context), id);
|
||||
}
|
||||
}
|
||||
player.sendMessage(BBC.getPrefix() + "Set overlay, what's next?");
|
||||
return;
|
||||
}
|
||||
case "setmain": {
|
||||
Pattern id;
|
||||
if (argList.size() == 2) {
|
||||
id = we.getPatternFactory().parseFromInput(argList.get(1), context);
|
||||
generator.setMain(id);
|
||||
} else {
|
||||
id = we.getPatternFactory().parseFromInput(argList.get(2), context);
|
||||
BufferedImage img = getImgurImage(argList.get(1), fp);
|
||||
if (img != null) {
|
||||
boolean whiteOnly = argList.size() == 4 && Boolean.parseBoolean(argList.get(3));
|
||||
generator.setMain(img, id, whiteOnly);
|
||||
} else {
|
||||
generator.setMain(we.getMaskFactory().parseFromInput(argList.get(1), context), id);
|
||||
}
|
||||
}
|
||||
player.sendMessage(BBC.getPrefix() + "Set main, what's next?");
|
||||
return;
|
||||
}
|
||||
case "setfloor": {
|
||||
Pattern id;
|
||||
if (argList.size() == 2) {
|
||||
id = we.getPatternFactory().parseFromInput(argList.get(1), context);
|
||||
generator.setFloor(id);
|
||||
} else {
|
||||
id = we.getPatternFactory().parseFromInput(argList.get(2), context);
|
||||
BufferedImage img = getImgurImage(argList.get(1), fp);
|
||||
if (img != null) {
|
||||
boolean whiteOnly = argList.size() == 4 && Boolean.parseBoolean(argList.get(3));
|
||||
generator.setFloor(img, id, whiteOnly);
|
||||
} else {
|
||||
generator.setFloor(we.getMaskFactory().parseFromInput(argList.get(1), context), id);
|
||||
}
|
||||
}
|
||||
player.sendMessage(BBC.getPrefix() + "Set floor, what's next?");
|
||||
return;
|
||||
}
|
||||
case "setcolumn": {
|
||||
Pattern id;
|
||||
if (argList.size() == 2) {
|
||||
id = we.getPatternFactory().parseFromInput(argList.get(1), context);
|
||||
generator.setColumn(id);
|
||||
} else {
|
||||
id = we.getPatternFactory().parseFromInput(argList.get(2), context);
|
||||
BufferedImage img = getImgurImage(argList.get(1), fp);
|
||||
if (img != null) {
|
||||
boolean whiteOnly = argList.size() == 4 && Boolean.parseBoolean(argList.get(3));
|
||||
generator.setColumn(img, id, whiteOnly);
|
||||
} else {
|
||||
generator.setColumn(we.getMaskFactory().parseFromInput(argList.get(1), context), id);
|
||||
}
|
||||
}
|
||||
player.sendMessage(BBC.getPrefix() + "Set columns, what's next?");
|
||||
return;
|
||||
}
|
||||
case "done":
|
||||
player.deleteMeta("HMGenerator");
|
||||
player.deleteMeta("HMGeneratorPlot");
|
||||
player.sendMessage("Generating... (4)");
|
||||
try {
|
||||
generator.generate();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
player.sendMessage(e.getMessage() + " (see console)");
|
||||
return;
|
||||
}
|
||||
player.sendMessage("Done!");
|
||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
plot.teleportPlayer(player);
|
||||
}
|
||||
});
|
||||
return;
|
||||
case "cancel":
|
||||
player.deleteMeta("HMGenerator");
|
||||
player.deleteMeta("HMGeneratorPlot");
|
||||
player.sendMessage(BBC.getPrefix() + "Cancelled!");
|
||||
return;
|
||||
default:
|
||||
C.COMMAND_SYNTAX.send(player, getUsage());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
player.sendMessage("Invalid url: " + e.getMessage());
|
||||
} catch (InputParseException e) {
|
||||
player.sendMessage("Invalid mask " + e.getMessage());
|
||||
} catch (Throwable e) {
|
||||
player.sendMessage("Error " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}, true, false);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
player.sendMessage("Must have the `worlds` component enabled in the PlotSquared config.yml");
|
||||
}
|
||||
}
|
||||
|
||||
private BaseBiome getBiome(String arg, FawePlayer fp) {
|
||||
World world = fp.getWorld();
|
||||
BiomeRegistry biomeRegistry = world.getWorldData().getBiomeRegistry();
|
||||
List<BaseBiome> knownBiomes = biomeRegistry.getBiomes();
|
||||
return Biomes.findBiomeByName(knownBiomes, arg, biomeRegistry);
|
||||
}
|
||||
|
||||
private BufferedImage getImgurImage(String arg, FawePlayer fp) throws IOException {
|
||||
if (arg.startsWith("http")) {
|
||||
URL url = new URL(arg);
|
||||
if (!url.getHost().equalsIgnoreCase("i.imgur.com")) {
|
||||
throw new IOException("Only i.imgur.com links are allowed!");
|
||||
}
|
||||
fp.sendMessage(BBC.getPrefix() + "Downloading image... (3)");
|
||||
return ImageIO.read(url);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -33,6 +33,10 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
}
|
||||
if (MainCommand.getInstance().getCommand("generatebiome") == null) {
|
||||
new PlotSetBiome();
|
||||
new CreateFromImage();
|
||||
}
|
||||
if (Settings.Enabled_Components.WORLDS) {
|
||||
new ReplaceAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,81 @@
|
||||
package com.boydti.fawe.regions.general.plot;
|
||||
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.wrappers.FakePlayer;
|
||||
import com.intellectualcrafters.plot.commands.CommandCategory;
|
||||
import com.intellectualcrafters.plot.commands.MainCommand;
|
||||
import com.intellectualcrafters.plot.commands.RequiredType;
|
||||
import com.intellectualcrafters.plot.config.C;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.object.PlotArea;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
import com.intellectualcrafters.plot.object.RunnableVal2;
|
||||
import com.intellectualcrafters.plot.object.RunnableVal3;
|
||||
import com.intellectualcrafters.plot.object.worlds.SinglePlotArea;
|
||||
import com.plotsquared.bukkit.util.BukkitSetupUtils;
|
||||
import com.plotsquared.general.commands.Command;
|
||||
import com.plotsquared.general.commands.CommandDeclaration;
|
||||
import com.sk89q.worldedit.event.platform.CommandEvent;
|
||||
import com.sk89q.worldedit.extension.platform.CommandManager;
|
||||
|
||||
@CommandDeclaration(
|
||||
command = "replaceall",
|
||||
permission = "plots.replaceall",
|
||||
category = CommandCategory.APPEARANCE,
|
||||
requiredType = RequiredType.NONE,
|
||||
description = "Replace all block in the plot",
|
||||
usage = "/plots replaceall <from> <to>"
|
||||
)
|
||||
public class ReplaceAll extends Command {
|
||||
public ReplaceAll() {
|
||||
super(MainCommand.getInstance(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(final PlotPlayer player, String[] args, RunnableVal3<Command, Runnable, Runnable> confirm, RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
|
||||
checkTrue(args.length >= 1, C.COMMAND_SYNTAX, getUsage());
|
||||
final Plot plot = check(player.getCurrentPlot(), C.NOT_IN_PLOT);
|
||||
checkTrue(plot.isOwner(player.getUUID()), C.NOW_OWNER);
|
||||
checkTrue(plot.getRunning() == 0, C.WAIT_FOR_TIMER);
|
||||
final PlotArea area = plot.getArea();
|
||||
if (area instanceof SinglePlotArea) {
|
||||
plot.addRunning();
|
||||
FawePlayer<Object> fp = FawePlayer.wrap(player.getName());
|
||||
C.TASK_START.send(player);
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fp.runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String worldName = plot.getWorldName();
|
||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
BukkitSetupUtils.manager.unload(worldName, true);
|
||||
}
|
||||
});
|
||||
FakePlayer actor = FakePlayer.getConsole();
|
||||
String cmd = "/replaceallpattern " + worldName + " " + StringMan.join(args, " ");
|
||||
CommandEvent event = new CommandEvent(actor, cmd);
|
||||
CommandManager.getInstance().handleCommandOnCurrentThread(event);
|
||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
plot.teleportPlayer(player);
|
||||
}
|
||||
});
|
||||
plot.removeRunning();
|
||||
}
|
||||
}, true, false);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
player.sendMessage("Must have the `worlds` component enabled in the PlotSquared config.yml");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ package com.boydti.fawe.util;
|
||||
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.io.BufferedInputStream;
|
||||
import it.unimi.dsi.fastutil.io.FastBufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@ -24,7 +24,7 @@ public class ImgurUtility {
|
||||
}
|
||||
|
||||
public static URL uploadImage(InputStream is) throws IOException {
|
||||
is = new BufferedInputStream(is);
|
||||
is = new FastBufferedInputStream(is);
|
||||
FastByteArrayOutputStream baos = new FastByteArrayOutputStream(Short.MAX_VALUE);
|
||||
int d;
|
||||
while ((d = is.read()) != -1) {
|
||||
|
@ -24,8 +24,9 @@ import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import java.io.BufferedInputStream;
|
||||
import it.unimi.dsi.fastutil.io.FastBufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@ -58,7 +59,10 @@ import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import net.jpountz.lz4.LZ4Compressor;
|
||||
@ -244,6 +248,43 @@ public class MainUtil {
|
||||
return LZ4Utils.maxCompressedLength(size);
|
||||
}
|
||||
|
||||
public static byte[] compress(byte[] bytes, byte[] buffer, Deflater deflate) throws IOException {
|
||||
if (buffer == null) {
|
||||
buffer = new byte[8192];
|
||||
}
|
||||
if (deflate == null) {
|
||||
deflate = new Deflater(1, false);
|
||||
} else {
|
||||
deflate.reset();
|
||||
}
|
||||
deflate.setInput(bytes);
|
||||
deflate.finish();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
while (!deflate.finished()) {
|
||||
int n = deflate.deflate(buffer);
|
||||
if (n != 0) baos.write(buffer, 0, n);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public static byte[] decompress(byte[] bytes, byte[] buffer, Inflater inflater) throws IOException, DataFormatException {
|
||||
if (buffer == null) {
|
||||
buffer = new byte[8192];
|
||||
}
|
||||
if (inflater == null) {
|
||||
inflater = new Inflater(false);
|
||||
} else {
|
||||
inflater.reset();
|
||||
}
|
||||
inflater.setInput(bytes);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
while (!inflater.finished()) {
|
||||
int n = inflater.inflate(buffer);
|
||||
if (n != 0) baos.write(buffer, 0, n);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public static byte[] compress(byte[] bytes, byte[] buffer, int level) {
|
||||
if (level == 0) {
|
||||
return bytes;
|
||||
@ -302,14 +343,14 @@ public class MainUtil {
|
||||
|
||||
public static FaweInputStream getCompressedIS(InputStream is, int buffer) throws IOException {
|
||||
int amount = (byte) is.read();
|
||||
is = new BufferedInputStream(is, buffer);
|
||||
is = new FastBufferedInputStream(is, buffer);
|
||||
if (amount == 0) {
|
||||
return new FaweInputStream(is);
|
||||
}
|
||||
int amountAbs = Math.abs(amount);
|
||||
if (amountAbs > 6) {
|
||||
if (amount > 0) {
|
||||
is = new BufferedInputStream(new GZIPInputStream(is, buffer));
|
||||
is = new FastBufferedInputStream(new GZIPInputStream(is, buffer));
|
||||
} else {
|
||||
is = new ZstdInputStream(is);
|
||||
}
|
||||
@ -836,8 +877,7 @@ public class MainUtil {
|
||||
if (file.isDirectory()) {
|
||||
deleteDirectory(files[i]);
|
||||
} else {
|
||||
Fawe.debug("Deleting file: " + file);
|
||||
file.delete();
|
||||
Fawe.debug("Deleting file: " + file + " | " + file.delete());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,76 @@ public class MathMan {
|
||||
}
|
||||
}
|
||||
|
||||
private static float[] ANGLES = new float[65536];
|
||||
|
||||
public static float sinInexact(double paramFloat) {
|
||||
return ANGLES[(int)(paramFloat * 10430.378F) & 0xFFFF];
|
||||
}
|
||||
|
||||
public static float cosInexact(double paramFloat) {
|
||||
return ANGLES[(int)(paramFloat * 10430.378F + 16384.0F) & 0xFFFF];
|
||||
}
|
||||
|
||||
public static int floorZero(double d0) {
|
||||
int i = (int)d0;
|
||||
return d0 < (double) i ? i - 1 : i;
|
||||
}
|
||||
|
||||
public static double max(double... values) {
|
||||
double max = Double.MIN_VALUE;
|
||||
for (double d : values) {
|
||||
if (d > max) {
|
||||
max = d;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
public static int max(int... values) {
|
||||
int max = Integer.MIN_VALUE;
|
||||
for (int d : values) {
|
||||
if (d > max) {
|
||||
max = d;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
public static int min(int... values) {
|
||||
int min = Integer.MAX_VALUE;
|
||||
for (int d : values) {
|
||||
if (d < min) {
|
||||
min = d;
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
public static double min(double... values) {
|
||||
double min = Double.MAX_VALUE;
|
||||
for (double d : values) {
|
||||
if (d < min) {
|
||||
min = d;
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
public static int ceilZero(float floatNumber) {
|
||||
int floor = (int)floatNumber;
|
||||
return floatNumber > (float) floor ? floor + 1 : floor;
|
||||
}
|
||||
|
||||
public static int clamp(int check, int min, int max) {
|
||||
return check > max?max:(check < min?min:check);
|
||||
}
|
||||
|
||||
static {
|
||||
for(int i = 0; i < 65536; ++i) {
|
||||
ANGLES[i] = (float)Math.sin((double)i * 3.141592653589793D * 2.0D / 65536.0D);
|
||||
}
|
||||
}
|
||||
|
||||
private final static int[] table = {
|
||||
0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57,
|
||||
59, 61, 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83,
|
||||
|
@ -76,7 +76,7 @@ public class WEManager {
|
||||
*/
|
||||
public RegionWrapper[] getMask(final FawePlayer<?> player, FaweMaskManager.MaskType type) {
|
||||
if (player.hasPermission("fawe.bypass") || !Settings.IMP.REGION_RESTRICTIONS) {
|
||||
return new RegionWrapper[] {new RegionWrapper(Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE)};
|
||||
return new RegionWrapper[] {RegionWrapper.GLOBAL()};
|
||||
}
|
||||
HashSet<RegionWrapper> mask = new HashSet<>();
|
||||
String world = player.getLocation().world;
|
||||
|
@ -346,7 +346,7 @@ public class TaskBuilder extends Metadatable {
|
||||
|
||||
public static final class TaskAbortException extends RuntimeException {
|
||||
@Override
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
public Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -157,12 +157,12 @@ public final class NBTInputStream implements Closeable {
|
||||
int i = 0;
|
||||
if (is instanceof InputStream) {
|
||||
DataInputStream dis = (DataInputStream) is;
|
||||
if (length > 720) {
|
||||
if (length > 1024) {
|
||||
if (buf == null) {
|
||||
buf = new byte[720];
|
||||
buf = new byte[1024];
|
||||
}
|
||||
int left = length;
|
||||
for (; left > 720; left -= 720) {
|
||||
for (; left > 1024; left -= 1024) {
|
||||
dis.readFully(buf);
|
||||
for (byte b : buf) {
|
||||
byteReader.run(i++, b & 0xFF);
|
||||
@ -173,12 +173,12 @@ public final class NBTInputStream implements Closeable {
|
||||
byteReader.run(i, dis.read());
|
||||
}
|
||||
} else {
|
||||
if (length > 720) {
|
||||
if (length > 1024) {
|
||||
if (buf == null) {
|
||||
buf = new byte[720];
|
||||
buf = new byte[1024];
|
||||
}
|
||||
int left = length;
|
||||
for (; left > 720; left -= 720) {
|
||||
for (; left > 1024; left -= 1024) {
|
||||
is.readFully(buf);
|
||||
for (byte b : buf) {
|
||||
byteReader.run(i++, b & 0xFF);
|
||||
@ -338,8 +338,17 @@ public final class NBTInputStream implements Closeable {
|
||||
case NBTConstants.TYPE_INT_ARRAY:
|
||||
length = is.readInt();
|
||||
int[] data = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
data[i] = is.readInt();
|
||||
if (buf == null) {
|
||||
buf = new byte[1024];
|
||||
}
|
||||
int index = 0;
|
||||
while (length > 0) {
|
||||
int toRead = Math.min(length << 2, buf.length);
|
||||
is.readFully(buf, 0, toRead);
|
||||
for (int i = 0; i < toRead; i += 4, index++) {
|
||||
data[index] = ((buf[i] << 24) + (buf[i + 1]<< 16) + (buf[i + 2] << 8) + (buf[i + 3] << 0));
|
||||
}
|
||||
length -= toRead;
|
||||
}
|
||||
return (data);
|
||||
default:
|
||||
|
@ -80,6 +80,72 @@ public final class NBTOutputStream implements Closeable {
|
||||
writeTagPayload(tag);
|
||||
}
|
||||
|
||||
public void writeNamedTag(String name, String value) throws IOException {
|
||||
checkNotNull(name);
|
||||
checkNotNull(value);
|
||||
int type = NBTConstants.TYPE_STRING;
|
||||
writeNamedTagName(name, type);
|
||||
byte[] bytes = value.getBytes(NBTConstants.CHARSET);
|
||||
os.writeShort(bytes.length);
|
||||
os.write(bytes);
|
||||
}
|
||||
|
||||
public void writeNamedTag(String name, int value) throws IOException {
|
||||
checkNotNull(name);
|
||||
int type = NBTConstants.TYPE_INT;
|
||||
writeNamedTagName(name, type);
|
||||
os.writeInt(value);
|
||||
}
|
||||
|
||||
public void writeNamedTag(String name, byte value) throws IOException {
|
||||
checkNotNull(name);
|
||||
int type = NBTConstants.TYPE_BYTE;
|
||||
writeNamedTagName(name, type);
|
||||
os.writeByte(value);
|
||||
}
|
||||
|
||||
public void writeNamedTag(String name, short value) throws IOException {
|
||||
checkNotNull(name);
|
||||
int type = NBTConstants.TYPE_SHORT;
|
||||
writeNamedTagName(name, type);
|
||||
os.writeShort(value);
|
||||
}
|
||||
|
||||
public void writeNamedTag(String name, long value) throws IOException {
|
||||
checkNotNull(name);
|
||||
int type = NBTConstants.TYPE_LONG;
|
||||
writeNamedTagName(name, type);
|
||||
os.writeLong(value);
|
||||
}
|
||||
|
||||
public void writeNamedTag(String name, byte[] bytes) throws IOException {
|
||||
checkNotNull(name);
|
||||
int type = NBTConstants.TYPE_BYTE_ARRAY;
|
||||
writeNamedTagName(name, type);
|
||||
os.writeInt(bytes.length);
|
||||
os.write(bytes);
|
||||
}
|
||||
|
||||
public void writeNamedTag(String name, int[] data) throws IOException {
|
||||
checkNotNull(name);
|
||||
int type = NBTConstants.TYPE_INT_ARRAY;
|
||||
writeNamedTagName(name, type);
|
||||
os.writeInt(data.length);
|
||||
for (int aData : data) {
|
||||
os.writeInt(aData);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeNamedEmptyList(String name) throws IOException {
|
||||
writeNamedEmptyList(name, NBTConstants.TYPE_COMPOUND);
|
||||
}
|
||||
|
||||
public void writeNamedEmptyList(String name, int type) throws IOException {
|
||||
writeNamedTagName(name, NBTConstants.TYPE_LIST);
|
||||
os.writeByte(type);
|
||||
os.writeInt(0);
|
||||
}
|
||||
|
||||
public void writeNamedTagName(String name, int type) throws IOException {
|
||||
byte[] nameBytes = name.getBytes(NBTConstants.CHARSET);
|
||||
os.writeByte(type);
|
||||
@ -213,6 +279,9 @@ public final class NBTOutputStream implements Closeable {
|
||||
*/
|
||||
private void writeListTagPayload(ListTag tag) throws IOException {
|
||||
Class<? extends Tag> clazz = tag.getType();
|
||||
if (clazz == null) {
|
||||
clazz = CompoundTag.class;
|
||||
}
|
||||
List<Tag> tags = tag.getValue();
|
||||
int size = tags.size();
|
||||
if (!tags.isEmpty()) {
|
||||
|
@ -46,10 +46,13 @@ import com.boydti.fawe.object.collection.LocalBlockVectorSet;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.boydti.fawe.object.extent.FastWorldEditExtent;
|
||||
import com.boydti.fawe.object.extent.FaweRegionExtent;
|
||||
import com.boydti.fawe.object.extent.HeightBoundExtent;
|
||||
import com.boydti.fawe.object.extent.LightingExtent;
|
||||
import com.boydti.fawe.object.extent.MultiRegionExtent;
|
||||
import com.boydti.fawe.object.extent.NullExtent;
|
||||
import com.boydti.fawe.object.extent.ProcessedWEExtent;
|
||||
import com.boydti.fawe.object.extent.ResettableExtent;
|
||||
import com.boydti.fawe.object.extent.SingleRegionExtent;
|
||||
import com.boydti.fawe.object.extent.SlowExtent;
|
||||
import com.boydti.fawe.object.extent.SourceMaskExtent;
|
||||
import com.boydti.fawe.object.mask.ResettableMask;
|
||||
@ -319,15 +322,22 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
}
|
||||
}
|
||||
}
|
||||
this.maxY = getWorld() == null ? 255 : world.getMaxY();
|
||||
if (allowedRegions != null) {
|
||||
if (allowedRegions.length == 0) {
|
||||
this.extent = new NullExtent(this.extent, BBC.WORLDEDIT_CANCEL_REASON_NO_REGION);
|
||||
} else {
|
||||
this.extent = new ProcessedWEExtent(this.extent, allowedRegions, this.limit);
|
||||
this.extent = new ProcessedWEExtent(this.extent, this.limit);
|
||||
if (allowedRegions.length == 1) {
|
||||
this.extent = new SingleRegionExtent(this.extent, limit, allowedRegions[0]);
|
||||
} else {
|
||||
this.extent = new MultiRegionExtent(this.extent, limit, allowedRegions);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.extent = new HeightBoundExtent(this.extent, limit, 0, maxY);
|
||||
}
|
||||
this.extent = wrapExtent(this.extent, bus, event, Stage.BEFORE_HISTORY);
|
||||
this.maxY = getWorld() == null ? 255 : world.getMaxY();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -981,84 +991,6 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
return this.getHighestTerrainBlock(x, z, minY, maxY, false);
|
||||
}
|
||||
|
||||
public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
|
||||
int clearanceAbove = maxY - y;
|
||||
int clearanceBelow = y - minY;
|
||||
int clearance = Math.min(clearanceAbove, clearanceBelow);
|
||||
|
||||
BaseBlock block = getBlock(x, y, z);
|
||||
boolean state = FaweCache.isLiquidOrGas(block.getId());
|
||||
int data1 = block.getData();
|
||||
int data2 = block.getData();
|
||||
int offset = state ? 0 : 1;
|
||||
for (int d = 0; d <= clearance; d++) {
|
||||
int y1 = y + d;
|
||||
block = getLazyBlock(x, y1, z);
|
||||
if (FaweCache.isLiquidOrGas(block.getId()) != state) {
|
||||
return ((y1 - offset) << 3) - (7 - (state ? block.getData() : data1));
|
||||
}
|
||||
data1 = block.getData();
|
||||
int y2 = y - d;
|
||||
block = getLazyBlock(x, y2, z);
|
||||
if (FaweCache.isLiquidOrGas(block.getId()) != state) {
|
||||
return ((y2 + offset) << 3) - (7 - (state ? block.getData() : data2));
|
||||
}
|
||||
data2 = block.getData();
|
||||
}
|
||||
if (clearanceAbove != clearanceBelow) {
|
||||
if (clearanceAbove < clearanceBelow) {
|
||||
for (int layer = y - clearance - 1; layer >= minY; layer--) {
|
||||
block = getLazyBlock(x, layer, z);
|
||||
if (FaweCache.isLiquidOrGas(block.getId()) != state) {
|
||||
return ((layer + offset) << 3) - (7 - (state ? block.getData() : data1));
|
||||
}
|
||||
data1 = block.getData();
|
||||
}
|
||||
} else {
|
||||
for (int layer = y + clearance + 1; layer <= maxY; layer++) {
|
||||
block = getLazyBlock(x, layer, z);
|
||||
if (FaweCache.isLiquidOrGas(block.getId()) != state) {
|
||||
return ((layer - offset) << 3) - (7 - (state ? block.getData() : data2));
|
||||
}
|
||||
data2 = block.getData();
|
||||
}
|
||||
}
|
||||
}
|
||||
return maxY << 4;
|
||||
}
|
||||
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
|
||||
int clearanceAbove = maxY - y;
|
||||
int clearanceBelow = y - minY;
|
||||
int clearance = Math.min(clearanceAbove, clearanceBelow);
|
||||
|
||||
BaseBlock block = getBlock(x, y, z);
|
||||
boolean state = FaweCache.canPassThrough(block.getId(), block.getData());
|
||||
int offset = state ? 0 : 1;
|
||||
for (int d = 0; d <= clearance; d++) {
|
||||
int y1 = y + d;
|
||||
block = getLazyBlock(x, y1, z);
|
||||
if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return y1 - offset;
|
||||
int y2 = y - d;
|
||||
block = getLazyBlock(x, y2, z);
|
||||
if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return y2 + offset;
|
||||
}
|
||||
if (clearanceAbove != clearanceBelow) {
|
||||
if (clearanceAbove < clearanceBelow) {
|
||||
for (int layer = y - clearance - 1; layer >= minY; layer--) {
|
||||
block = getLazyBlock(x, layer, z);
|
||||
if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return layer + offset;
|
||||
}
|
||||
} else {
|
||||
for (int layer = y + clearance + 1; layer <= maxY; layer++) {
|
||||
block = getLazyBlock(x, layer, z);
|
||||
if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return layer - offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return maxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the highest solid 'terrain' block which can occur naturally.
|
||||
*
|
||||
|
@ -88,6 +88,12 @@ public class Vector implements Comparable<Vector> {
|
||||
this.mutZ(other.getZ());
|
||||
}
|
||||
|
||||
public Vector(double[] arr) {
|
||||
this.mutX(arr[0]);
|
||||
this.mutY(arr[1]);
|
||||
this.mutZ(arr[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance with X, Y, and Z coordinates set to 0.
|
||||
*
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
package com.sk89q.worldedit.blocks;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
@ -125,6 +126,10 @@ public class BaseBlock extends Block implements TileEntityBlock {
|
||||
this(other.getId(), other.getData(), other.getNbtData());
|
||||
}
|
||||
|
||||
public final int getCombined() {
|
||||
return FaweCache.getCombined(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID of the block.
|
||||
*
|
||||
|
@ -31,7 +31,9 @@ import com.boydti.fawe.object.brush.CopyPastaBrush;
|
||||
import com.boydti.fawe.object.brush.ErodeBrush;
|
||||
import com.boydti.fawe.object.brush.FlattenBrush;
|
||||
import com.boydti.fawe.object.brush.HeightBrush;
|
||||
import com.boydti.fawe.object.brush.LayerBrush;
|
||||
import com.boydti.fawe.object.brush.LineBrush;
|
||||
import com.boydti.fawe.object.brush.PopulateSchem;
|
||||
import com.boydti.fawe.object.brush.RaiseBrush;
|
||||
import com.boydti.fawe.object.brush.RecurseBrush;
|
||||
import com.boydti.fawe.object.brush.ScatterBrush;
|
||||
@ -98,6 +100,8 @@ import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
@ -525,6 +529,7 @@ public class BrushCommands {
|
||||
help =
|
||||
"Chooses the scatter brush.\n" +
|
||||
" The -o flag will overlay the block",
|
||||
flags = "o",
|
||||
min = 1,
|
||||
max = 4
|
||||
)
|
||||
@ -544,6 +549,62 @@ public class BrushCommands {
|
||||
player.print(BBC.getPrefix() + BBC.BRUSH_SCATTER.f(radius, points));
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "populateschematic", "populateschem", "popschem", "pschem", "ps" },
|
||||
usage = "<mask> <file|folder|url> [radius=30] [points=5]",
|
||||
desc = "Scatter a schematic on a surface",
|
||||
help =
|
||||
"Chooses the scatter schematic brush.\n" +
|
||||
"The -r flag will apply random rotation",
|
||||
flags = "r",
|
||||
min = 2,
|
||||
max = 4
|
||||
)
|
||||
@CommandPermissions("worldedit.brush.populateschematic")
|
||||
public void scatterSchemBrush(Player player, EditSession editSession, LocalSession session, Mask mask, String clipboard, @Optional("30") double radius, @Optional("50") double density, @Switch('r') boolean rotate) throws WorldEditException {
|
||||
worldEdit.checkMaxBrushRadius(radius);
|
||||
BrushTool tool = session.getBrushTool(player);
|
||||
tool.setSize(radius);
|
||||
try {
|
||||
ClipboardHolder[] clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(player, player.getWorld().getWorldData(), clipboard, true);
|
||||
if (clipboards == null) {
|
||||
return;
|
||||
}
|
||||
Brush brush = new PopulateSchem(mask, clipboards, (int) density, rotate);
|
||||
tool.setBrush(brush, "worldedit.brush.populateschematic", player);
|
||||
player.print(BBC.getPrefix() + BBC.BRUSH_POPULATE.f(radius, density));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "layer" },
|
||||
usage = "<radius> <pattern1> <patern2> <pattern3>...",
|
||||
desc = "Scatter a schematic on a surface",
|
||||
help = "Chooses the layer brush.",
|
||||
min = 3,
|
||||
max = 999
|
||||
)
|
||||
@CommandPermissions("worldedit.brush.layer")
|
||||
public void surfaceLayer(Player player, EditSession editSession, LocalSession session, double radius, CommandContext args) throws WorldEditException {
|
||||
worldEdit.checkMaxBrushRadius(radius);
|
||||
BrushTool tool = session.getBrushTool(player);
|
||||
tool.setSize(radius);
|
||||
ParserContext parserContext = new ParserContext();
|
||||
parserContext.setActor(player);
|
||||
parserContext.setWorld(player.getWorld());
|
||||
parserContext.setSession(session);
|
||||
parserContext.setExtent(editSession);
|
||||
List<BaseBlock> blocks = new ArrayList<>();
|
||||
for (int i = 1; i < args.argsLength(); i++) {
|
||||
String arg = args.getString(i);
|
||||
blocks.add(worldEdit.getBlockFactory().parseFromInput(arg, parserContext));
|
||||
}
|
||||
tool.setBrush(new LayerBrush(blocks.toArray(new BaseBlock[blocks.size()])), "worldedit.brush.layer", player);
|
||||
player.print(BBC.getPrefix() + BBC.BRUSH_LAYER.f(radius, args.getJoinedStrings(1)));
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "splatter", "splat" },
|
||||
usage = "<pattern> [radius=5] [seeds=1] [recursion=5] [solid=true]",
|
||||
@ -852,6 +913,7 @@ public class BrushCommands {
|
||||
BrushTool tool = session.getBrushTool(player);
|
||||
String cmd = args.getJoinedStrings(1);
|
||||
tool.setBrush(new CommandBrush(cmd, radius), "worldedit.brush.copy", player);
|
||||
tool.setSize(radius);
|
||||
player.print(BBC.getPrefix() + BBC.BRUSH_COMMAND.f(cmd));
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,6 @@ public class GeneralCommands {
|
||||
aliases = { "/tips", "tips" },
|
||||
desc = "Toggle WorldEdit tips"
|
||||
)
|
||||
@CommandPermissions("fawe.use")
|
||||
public void tips(Player player, LocalSession session) throws WorldEditException {
|
||||
FawePlayer<Object> fp = FawePlayer.wrap(player);
|
||||
if (fp.toggle("fawe.tips")) {
|
||||
|
@ -21,6 +21,7 @@ package com.sk89q.worldedit.command;
|
||||
|
||||
import com.boydti.fawe.command.FawePrimitiveBinding;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.jnbt.anvil.generator.CavesGen;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||
import com.sk89q.minecraft.util.commands.Logging;
|
||||
@ -30,6 +31,7 @@ import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.internal.annotation.Selection;
|
||||
import com.sk89q.worldedit.internal.expression.ExpressionException;
|
||||
@ -66,6 +68,49 @@ public class GenerationCommands {
|
||||
this.worldEdit = worldEdit;
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "/caves [size=8] [freq=40] [rarity=7] [minY=8] [maxY=127] [sysFreq=1] [sysRarity=25] [pocketRarity=0] [pocketMin=0] [pocketMax=3]" },
|
||||
desc = "Generates caves",
|
||||
help = "Generates a cave network"
|
||||
)
|
||||
@CommandPermissions("worldedit.generation.cylinder")
|
||||
@Logging(PLACEMENT)
|
||||
public void caves(Player player, LocalSession session, EditSession editSession, @Selection Region region, @Optional("8") int size, @Optional("40") int frequency, @Optional("7") int rarity, @Optional("8") int minY, @Optional("127") int maxY, @Optional("1") int systemFrequency, @Optional("25") int individualRarity, @Optional("0") int pocketChance, @Optional("0") int pocketMin, @Optional("3") int pocketMax) throws WorldEditException, ParameterException {
|
||||
CavesGen gen = new CavesGen(size, frequency, rarity, minY, maxY, systemFrequency, individualRarity, pocketChance, pocketMin, pocketMax);
|
||||
editSession.generate(region, gen);
|
||||
BBC.VISITOR_BLOCK.send(player, editSession.getBlockChangeCount());
|
||||
}
|
||||
|
||||
// public void addOre(Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException {
|
||||
|
||||
@Command(
|
||||
aliases = { "/ores" },
|
||||
desc = "Generates ores",
|
||||
help = "Generates ores",
|
||||
min = 1,
|
||||
max = 1
|
||||
)
|
||||
@CommandPermissions("worldedit.generation.cylinder")
|
||||
@Logging(PLACEMENT)
|
||||
public void ores(Player player, LocalSession session, EditSession editSession, @Selection Region region, Mask mask) throws WorldEditException, ParameterException {
|
||||
editSession.addOres(region, mask);
|
||||
BBC.VISITOR_BLOCK.send(player, editSession.getBlockChangeCount());
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "/ore <mask> <pattern> <size> <freq> <rarity> <minY> <maxY>" },
|
||||
desc = "Generates ores",
|
||||
help = "Generates ores",
|
||||
min = 7,
|
||||
max = 7
|
||||
)
|
||||
@CommandPermissions("worldedit.generation.cylinder")
|
||||
@Logging(PLACEMENT)
|
||||
public void ore(Player player, LocalSession session, EditSession editSession, @Selection Region region, Mask mask, Pattern material, int size, int freq, int rarity, int minY, int maxY) throws WorldEditException, ParameterException {
|
||||
editSession.addOre(region, mask, material, size, freq, rarity, minY, maxY);
|
||||
BBC.VISITOR_BLOCK.send(player, editSession.getBlockChangeCount());
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "/hcyl" },
|
||||
usage = "<pattern> <radius>[,<radius>] [height]",
|
||||
|
@ -313,24 +313,6 @@ public class RegionCommands {
|
||||
if (!FawePlayer.wrap(player).hasPermission("fawe.tips")) BBC.TIP_REPLACE_ID.or(BBC.TIP_REPLACE_LIGHT, BBC.TIP_REPLACE_MARKER, BBC.TIP_TAB_COMPLETE).send(player);
|
||||
}
|
||||
|
||||
// @Command(
|
||||
// aliases = { "/mapreplace", "/mr", "/maprep" },
|
||||
// usage = "<from-block-1,from-block-2> <to-block-1,to-block-2>",
|
||||
// desc = "Replace all blocks in a selection 1:1 with the ",
|
||||
// flags = "f",
|
||||
// min = 1,
|
||||
// max = 2
|
||||
// )
|
||||
// @CommandPermissions("worldedit.region.mapreplace")
|
||||
// @Logging(REGION)
|
||||
// public void mapreplace(Player player, EditSession editSession, @Selection Region region, @Optional Mask from, Pattern to) throws WorldEditException {
|
||||
// if (from == null) {
|
||||
// from = new ExistingBlockMask(editSession);
|
||||
// }
|
||||
// int affected = editSession.replaceBlocks(region, from, to);
|
||||
// BBC.VISITOR_BLOCK.send(player, affected);
|
||||
// }
|
||||
|
||||
@Command(
|
||||
aliases = { "/set" },
|
||||
usage = "[pattern]",
|
||||
|
@ -293,11 +293,13 @@ public class SchematicCommands {
|
||||
}
|
||||
}
|
||||
|
||||
// schem list all|mine|global page
|
||||
|
||||
@Command(
|
||||
aliases = {"list", "all", "ls"},
|
||||
desc = "List saved schematics",
|
||||
min = 0,
|
||||
max = 1,
|
||||
max = 2,
|
||||
flags = "dnp",
|
||||
help = "List all schematics in the schematics directory\n" +
|
||||
" -d sorts by date, oldest first\n" +
|
||||
@ -306,8 +308,12 @@ public class SchematicCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.schematic.list")
|
||||
public void list(Actor actor, CommandContext args, @Switch('p') @Optional("1") int page) throws WorldEditException {
|
||||
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS) {
|
||||
|
||||
}
|
||||
|
||||
File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().saveDir);
|
||||
List<File> fileList = allFiles(dir);
|
||||
List<File> fileList = allFiles(dir, true);
|
||||
|
||||
if (fileList == null || fileList.isEmpty()) {
|
||||
BBC.SCHEMATIC_NONE.send(actor);
|
||||
@ -367,13 +373,13 @@ public class SchematicCommands {
|
||||
}
|
||||
|
||||
|
||||
private List<File> allFiles(File root) {
|
||||
private List<File> allFiles(File root, boolean recursive) {
|
||||
File[] files = root.listFiles();
|
||||
if (files == null) return null;
|
||||
List<File> fileList = new ArrayList<File>();
|
||||
for (File f : files) {
|
||||
if (f.isDirectory()) {
|
||||
List<File> subFiles = allFiles(f);
|
||||
if (recursive && f.isDirectory()) {
|
||||
List<File> subFiles = allFiles(f, recursive);
|
||||
if (subFiles == null) continue; // empty subdir
|
||||
fileList.addAll(subFiles);
|
||||
} else {
|
||||
|
@ -23,6 +23,7 @@ import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.mask.IdMask;
|
||||
import com.boydti.fawe.object.regions.selector.FuzzyRegionSelector;
|
||||
import com.boydti.fawe.object.regions.selector.PolyhedralRegionSelector;
|
||||
import com.google.common.base.Optional;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
@ -736,7 +737,7 @@ public class SelectionCommands {
|
||||
} else if (typeName.equalsIgnoreCase("cyl")) {
|
||||
selector = new CylinderRegionSelector(oldSelector);
|
||||
player.print(BBC.getPrefix() + BBC.SEL_CYLINDRICAL.s());
|
||||
} else if (typeName.equalsIgnoreCase("convex") || typeName.equalsIgnoreCase("hull") || typeName.equalsIgnoreCase("polyhedron")) {
|
||||
} else if (typeName.equalsIgnoreCase("convex") || typeName.equalsIgnoreCase("hull")) {
|
||||
selector = new ConvexPolyhedralRegionSelector(oldSelector);
|
||||
player.print(BBC.getPrefix() + BBC.SEL_CONVEX_POLYHEDRAL.s());
|
||||
Optional<Integer> limit = ActorSelectorLimits.forActor(player).getPolyhedronVertexLimit();
|
||||
@ -744,6 +745,14 @@ public class SelectionCommands {
|
||||
player.print(BBC.getPrefix() + BBC.SEL_MAX.f(limit.get()));
|
||||
}
|
||||
player.print(BBC.getPrefix() + BBC.SEL_LIST.s());
|
||||
} else if (typeName.equalsIgnoreCase("polyhedral") || typeName.equalsIgnoreCase("polyhedron")) {
|
||||
selector = new PolyhedralRegionSelector(player.getWorld());
|
||||
player.print(BBC.getPrefix() + BBC.SEL_CONVEX_POLYHEDRAL.s());
|
||||
Optional<Integer> limit = ActorSelectorLimits.forActor(player).getPolyhedronVertexLimit();
|
||||
if (limit.isPresent()) {
|
||||
player.print(BBC.getPrefix() + BBC.SEL_MAX.f(limit.get()));
|
||||
}
|
||||
player.print(BBC.getPrefix() + BBC.SEL_LIST.s());
|
||||
} else if (typeName.startsWith("fuzzy") || typeName.startsWith("magic")) {
|
||||
Mask mask;
|
||||
if (typeName.length() > 6) {
|
||||
@ -772,6 +781,7 @@ public class SelectionCommands {
|
||||
box.appendCommand("//sel sphere", "Select a sphere");
|
||||
box.appendCommand("//sel cyl", "Select a cylinder");
|
||||
box.appendCommand("//sel convex", "Select a convex polyhedral");
|
||||
box.appendCommand("//sel polyhedral", "Select a hollow polyhedral");
|
||||
box.appendCommand("//sel fuzzy[=<mask>]", "Select all connected blocks");
|
||||
|
||||
player.printRaw(ColorCodeBuilder.asColorCodes(box));
|
||||
|
@ -100,7 +100,7 @@ public class SelectionCommand extends SimpleCommand<Operation> {
|
||||
FawePlayer fp = FawePlayer.wrap(player);
|
||||
FaweRegionExtent regionExtent = editSession.getRegionExtent();
|
||||
|
||||
if (function instanceof BlockReplace && regionExtent == null) {
|
||||
if (function instanceof BlockReplace && regionExtent == null || regionExtent.isGlobal()) {
|
||||
try {
|
||||
BlockReplace replace = ((BlockReplace) function);
|
||||
Field field = replace.getClass().getDeclaredField("pattern");
|
||||
@ -148,7 +148,6 @@ public class SelectionCommand extends SimpleCommand<Operation> {
|
||||
}
|
||||
});
|
||||
queue.enqueue();
|
||||
long start = System.currentTimeMillis();
|
||||
BBC.OPERATION.send(actor, BBC.VISITOR_BLOCK.format(cuboid.getArea()));
|
||||
queue.flush();
|
||||
return null;
|
||||
|
@ -164,6 +164,7 @@ public class DefaultMaskParser extends FaweParser<Mask> {
|
||||
|
||||
private Mask getBlockMaskComponent(List<Mask> masks, String input, ParserContext context) throws InputParseException {
|
||||
Extent extent = Request.request().getExtent();
|
||||
if (extent == null) extent = context.getExtent();
|
||||
final char firstChar = input.charAt(0);
|
||||
switch (firstChar) {
|
||||
case '#':
|
||||
@ -303,7 +304,7 @@ public class DefaultMaskParser extends FaweParser<Mask> {
|
||||
y1 = (Expression.compile(split[0]).evaluate());
|
||||
y2 = (Expression.compile(split[1]).evaluate());
|
||||
}
|
||||
return new AngleMask(Request.request().getEditSession(), y1, y2);
|
||||
return new AngleMask(extent, y1, y2);
|
||||
} catch (NumberFormatException | ExpressionException e) {
|
||||
throw new SuggestInputParseException(input, "/<min-angle>:<max-angle>");
|
||||
}
|
||||
@ -385,7 +386,7 @@ public class DefaultMaskParser extends FaweParser<Mask> {
|
||||
try {
|
||||
Expression exp = Expression.compile(input.substring(1), "x", "y", "z");
|
||||
WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment(
|
||||
Request.request().getEditSession(), Vector.ONE, Vector.ZERO);
|
||||
Request.request().getEditSession (), Vector.ONE, Vector.ZERO);
|
||||
exp.setEnvironment(env);
|
||||
return new ExpressionMask(exp);
|
||||
} catch (ExpressionException e) {
|
||||
|
@ -22,6 +22,7 @@ import com.boydti.fawe.object.pattern.RelativePattern;
|
||||
import com.boydti.fawe.object.pattern.SolidRandomOffsetPattern;
|
||||
import com.boydti.fawe.object.pattern.SurfaceRandomOffsetPattern;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.EmptyClipboardException;
|
||||
@ -122,7 +123,7 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
|
||||
switch (split2[0].toLowerCase()) {
|
||||
case "#*":
|
||||
case "#existing": {
|
||||
return new ExistingPattern(Request.request().getEditSession());
|
||||
return new ExistingPattern(Request.request().getExtent());
|
||||
}
|
||||
case "#clipboard":
|
||||
case "#copy": {
|
||||
@ -151,7 +152,7 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
|
||||
throw new InputParseException("#fullcopy:<source>");
|
||||
}
|
||||
boolean random = split2.length == 3 && split2[2].equalsIgnoreCase("true");
|
||||
return new RandomFullClipboardPattern(Request.request().getEditSession(), context.requireWorld().getWorldData(), clipboards, random);
|
||||
return new RandomFullClipboardPattern(Request.request().getExtent(), context.requireWorld().getWorldData(), clipboards, random);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
@ -159,7 +160,7 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
|
||||
}
|
||||
ClipboardHolder holder = session.getClipboard();
|
||||
Clipboard clipboard = holder.getClipboard();
|
||||
return new FullClipboardPattern(Request.request().getEditSession(), clipboard);
|
||||
return new FullClipboardPattern(Request.request().getExtent(), clipboard);
|
||||
} catch (EmptyClipboardException e) {
|
||||
throw new InputParseException("To use #fullcopy, please first copy something to your clipboard");
|
||||
}
|
||||
@ -168,17 +169,20 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
|
||||
}
|
||||
}
|
||||
case "#id": {
|
||||
return new IdPattern(Request.request().getEditSession(), catchSuggestion(input, rest, context));
|
||||
return new IdPattern(Request.request().getExtent(), catchSuggestion(input, rest, context));
|
||||
}
|
||||
case "#data": {
|
||||
return new DataPattern(Request.request().getEditSession(), catchSuggestion(input, rest, context));
|
||||
return new DataPattern(Request.request().getExtent(), catchSuggestion(input, rest, context));
|
||||
}
|
||||
case "#biome": {
|
||||
if (MathMan.isInteger(rest)) {
|
||||
return new BiomePattern(Request.request().getExtent(), new BaseBiome(Integer.parseInt(rest)));
|
||||
}
|
||||
World world = context.requireWorld();
|
||||
BiomeRegistry biomeRegistry = world.getWorldData().getBiomeRegistry();
|
||||
List<BaseBiome> knownBiomes = biomeRegistry.getBiomes();
|
||||
BaseBiome biome = Biomes.findBiomeByName(knownBiomes, rest, biomeRegistry);
|
||||
return new BiomePattern(Request.request().getEditSession(), biome);
|
||||
return new BiomePattern(Request.request().getExtent(), biome);
|
||||
}
|
||||
case "#~":
|
||||
case "#r":
|
||||
@ -272,6 +276,9 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
|
||||
}
|
||||
case "#l":
|
||||
case "#linear": {
|
||||
if (rest.startsWith("\"") && rest.endsWith("\"")) {
|
||||
rest = rest.substring(1, rest.length() - 1);
|
||||
}
|
||||
ArrayList<Pattern> patterns = new ArrayList<>();
|
||||
for (String token : StringMan.split(rest, ',')) {
|
||||
patterns.add(catchSuggestion(input, token, context));
|
||||
@ -283,6 +290,9 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
|
||||
}
|
||||
case "#l3d":
|
||||
case "#linear3d": {
|
||||
if (rest.startsWith("\"") && rest.endsWith("\"")) {
|
||||
rest = rest.substring(1, rest.length() - 1);
|
||||
}
|
||||
ArrayList<Pattern> patterns = new ArrayList<>();
|
||||
for (String token : StringMan.split(rest, ',')) {
|
||||
patterns.add(catchSuggestion(input, token, context));
|
||||
|
@ -117,6 +117,7 @@ public abstract class AbstractDelegateExtent implements LightingExtent {
|
||||
|
||||
private MutableBlockVector mutable = new MutableBlockVector(0,0,0);
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(int x, int y, int z) {
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
@ -129,6 +130,7 @@ public abstract class AbstractDelegateExtent implements LightingExtent {
|
||||
return extent.getLazyBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
|
191
core/src/main/java/com/sk89q/worldedit/extent/Extent.java
Normal file
191
core/src/main/java/com/sk89q/worldedit/extent/Extent.java
Normal file
@ -0,0 +1,191 @@
|
||||
package com.sk89q.worldedit.extent;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.jnbt.anvil.generator.CavesGen;
|
||||
import com.boydti.fawe.jnbt.anvil.generator.GenBase;
|
||||
import com.boydti.fawe.jnbt.anvil.generator.OreGen;
|
||||
import com.boydti.fawe.jnbt.anvil.generator.Resource;
|
||||
import com.boydti.fawe.jnbt.anvil.generator.SchemGen;
|
||||
import com.boydti.fawe.object.PseudoRandom;
|
||||
import com.sk89q.worldedit.MutableBlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.blocks.BlockID;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.pattern.BlockPattern;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface Extent extends InputExtent, OutputExtent {
|
||||
|
||||
Vector getMinimumPoint();
|
||||
|
||||
Vector getMaximumPoint();
|
||||
|
||||
default List<? extends Entity> getEntities(Region region) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
default List<? extends Entity> getEntities() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
default @Nullable Entity createEntity(Location location, BaseEntity entity) {
|
||||
throw new UnsupportedOperationException(getClass() + " does not support entity creation!");
|
||||
}
|
||||
|
||||
@Override
|
||||
default BaseBlock getLazyBlock(Vector position) {
|
||||
return getBlock(position);
|
||||
}
|
||||
|
||||
default public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
|
||||
return setBlock(MutableBlockVector.get(x, y, z), block);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
default Operation commit() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default BaseBlock getLazyBlock(int x, int y, int z) {
|
||||
return getLazyBlock(MutableBlockVector.get(x, y, z));
|
||||
}
|
||||
|
||||
default public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
|
||||
int clearanceAbove = maxY - y;
|
||||
int clearanceBelow = y - minY;
|
||||
int clearance = Math.min(clearanceAbove, clearanceBelow);
|
||||
|
||||
BaseBlock block = getLazyBlock(x, y, z);
|
||||
boolean state = FaweCache.isLiquidOrGas(block.getId());
|
||||
int data1 = block.getData();
|
||||
int data2 = block.getData();
|
||||
int offset = state ? 0 : 1;
|
||||
for (int d = 0; d <= clearance; d++) {
|
||||
int y1 = y + d;
|
||||
block = getLazyBlock(x, y1, z);
|
||||
if (FaweCache.isLiquidOrGas(block.getId()) != state) {
|
||||
return ((y1 - offset) << 3) - (7 - (state ? block.getData() : data1));
|
||||
}
|
||||
data1 = block.getData();
|
||||
int y2 = y - d;
|
||||
block = getLazyBlock(x, y2, z);
|
||||
if (FaweCache.isLiquidOrGas(block.getId()) != state) {
|
||||
return ((y2 + offset) << 3) - (7 - (state ? block.getData() : data2));
|
||||
}
|
||||
data2 = block.getData();
|
||||
}
|
||||
if (clearanceAbove != clearanceBelow) {
|
||||
if (clearanceAbove < clearanceBelow) {
|
||||
for (int layer = y - clearance - 1; layer >= minY; layer--) {
|
||||
block = getLazyBlock(x, layer, z);
|
||||
if (FaweCache.isLiquidOrGas(block.getId()) != state) {
|
||||
return ((layer + offset) << 3) - (7 - (state ? block.getData() : data1));
|
||||
}
|
||||
data1 = block.getData();
|
||||
}
|
||||
} else {
|
||||
for (int layer = y + clearance + 1; layer <= maxY; layer++) {
|
||||
block = getLazyBlock(x, layer, z);
|
||||
if (FaweCache.isLiquidOrGas(block.getId()) != state) {
|
||||
return ((layer - offset) << 3) - (7 - (state ? block.getData() : data2));
|
||||
}
|
||||
data2 = block.getData();
|
||||
}
|
||||
}
|
||||
}
|
||||
return maxY << 4;
|
||||
}
|
||||
|
||||
public default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
|
||||
int clearanceAbove = maxY - y;
|
||||
int clearanceBelow = y - minY;
|
||||
int clearance = Math.min(clearanceAbove, clearanceBelow);
|
||||
BaseBlock block = getLazyBlock(x, y, z);
|
||||
boolean state = FaweCache.canPassThrough(block.getId(), block.getData());
|
||||
int offset = state ? 0 : 1;
|
||||
for (int d = 0; d <= clearance; d++) {
|
||||
int y1 = y + d;
|
||||
block = getLazyBlock(x, y1, z);
|
||||
if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return y1 - offset;
|
||||
int y2 = y - d;
|
||||
block = getLazyBlock(x, y2, z);
|
||||
if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return y2 + offset;
|
||||
}
|
||||
if (clearanceAbove != clearanceBelow) {
|
||||
if (clearanceAbove < clearanceBelow) {
|
||||
for (int layer = y - clearance - 1; layer >= minY; layer--) {
|
||||
block = getLazyBlock(x, layer, z);
|
||||
if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return layer + offset;
|
||||
}
|
||||
} else {
|
||||
for (int layer = y + clearance + 1; layer <= maxY; layer++) {
|
||||
block = getLazyBlock(x, layer, z);
|
||||
if (FaweCache.canPassThrough(block.getId(), block.getData()) != state) return layer - offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return maxY;
|
||||
}
|
||||
|
||||
|
||||
default public void addCaves(Region region) throws WorldEditException {
|
||||
generate(region, new CavesGen(8));
|
||||
}
|
||||
|
||||
public default void generate(Region region, GenBase gen) throws WorldEditException {
|
||||
for (Vector2D chunkPos : region.getChunks()) {
|
||||
gen.generate(chunkPos, this);
|
||||
}
|
||||
}
|
||||
|
||||
default public void addSchems(Region region, Mask mask, WorldData worldData, ClipboardHolder[] clipboards, int rarity, boolean rotate) throws WorldEditException{
|
||||
spawnResource(region, new SchemGen(mask, this, worldData, clipboards, rotate), rarity, 1);
|
||||
}
|
||||
|
||||
default public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException {
|
||||
PseudoRandom random = new PseudoRandom();
|
||||
for (Vector2D chunkPos : region.getChunks()) {
|
||||
for (int i = 0; i < frequency; i++) {
|
||||
if (random.nextInt(101) > rarity) {
|
||||
continue;
|
||||
}
|
||||
int x = (chunkPos.getBlockX() << 4) + PseudoRandom.random.nextInt(16);
|
||||
int z = (chunkPos.getBlockZ() << 4) + PseudoRandom.random.nextInt(16);
|
||||
gen.spawn(random, x, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException {
|
||||
spawnResource(region, new OreGen(this, mask, material, size, minY, maxY), rarity, frequency);
|
||||
}
|
||||
|
||||
default public void addOres(Region region, Mask mask) throws WorldEditException {
|
||||
addOre(region, mask, new BlockPattern(BlockID.DIRT), 20, 2, 100, 0, 255);
|
||||
addOre(region, mask, new BlockPattern(BlockID.GRAVEL), 20, 1, 100, 0, 255);
|
||||
addOre(region, mask, new BlockPattern(BlockID.STONE, 1), 20, 2, 100, 0, 79);
|
||||
addOre(region, mask, new BlockPattern(BlockID.STONE, 3), 20, 2, 100, 0, 79);
|
||||
addOre(region, mask, new BlockPattern(BlockID.STONE, 5), 20, 2, 100, 0, 79);
|
||||
addOre(region, mask, new BlockPattern(BlockID.COAL_ORE), 17, 20, 100, 0, 127);
|
||||
addOre(region, mask, new BlockPattern(BlockID.IRON_ORE), 9, 20, 100, 0, 63);
|
||||
addOre(region, mask, new BlockPattern(BlockID.GOLD_ORE), 9, 2, 100, 0, 31);
|
||||
addOre(region, mask, new BlockPattern(BlockID.REDSTONE_ORE), 8, 8, 100, 0, 15);
|
||||
addOre(region, mask, new BlockPattern(BlockID.DIAMOND_ORE), 8, 1, 100, 0, 15);
|
||||
addOre(region, mask, new BlockPattern(BlockID.LAPIS_LAZULI_ORE), 7, 1, 100, 0, 15);
|
||||
addOre(region, mask, new BlockPattern(BlockID.EMERALD_ORE), 5, 1, 100, 4, 31);
|
||||
}
|
||||
}
|
@ -52,7 +52,7 @@ import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
import java.io.BufferedInputStream;
|
||||
import it.unimi.dsi.fastutil.io.FastBufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
@ -94,8 +94,8 @@ public enum ClipboardFormat {
|
||||
if (inputStream instanceof FileInputStream) {
|
||||
inputStream = new ResettableFileInputStream((FileInputStream) inputStream);
|
||||
}
|
||||
BufferedInputStream buffered = new BufferedInputStream(inputStream);
|
||||
NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered)));
|
||||
FastBufferedInputStream buffered = new FastBufferedInputStream(inputStream);
|
||||
NBTInputStream nbtStream = new NBTInputStream(new FastBufferedInputStream(new GZIPInputStream(buffered)));
|
||||
SchematicReader input = new SchematicReader(nbtStream);
|
||||
input.setUnderlyingStream(inputStream);
|
||||
return input;
|
||||
@ -151,8 +151,8 @@ public enum ClipboardFormat {
|
||||
STRUCTURE(new AbstractClipboardFormat("STRUCTURE", "structure", "nbt") {
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
inputStream = new BufferedInputStream(inputStream);
|
||||
NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(inputStream)));
|
||||
inputStream = new FastBufferedInputStream(inputStream);
|
||||
NBTInputStream nbtStream = new NBTInputStream(new FastBufferedInputStream(new GZIPInputStream(inputStream)));
|
||||
return new StructureFormat(nbtStream);
|
||||
}
|
||||
|
||||
@ -340,10 +340,14 @@ public enum ClipboardFormat {
|
||||
dir = new File(worldEdit.getWorkingDirectoryFile(config.saveDir), input);
|
||||
}
|
||||
}
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
if (!dir.exists()) {
|
||||
if (message) BBC.SCHEMATIC_NOT_FOUND.send(player, input);
|
||||
return null;
|
||||
}
|
||||
if (!dir.isDirectory()) {
|
||||
ByteSource source = Files.asByteSource(dir);
|
||||
return new ClipboardHolder[] {new LazyClipboardHolder(source, this, worldData, null)};
|
||||
}
|
||||
ClipboardHolder[] clipboards = loadAllFromDirectory(dir, worldData);
|
||||
if (clipboards.length < 1) {
|
||||
if (message) BBC.SCHEMATIC_NOT_FOUND.send(player, input);
|
||||
|
@ -146,16 +146,16 @@ public class SchematicWriter implements ClipboardWriter {
|
||||
public void write(NBTOutputStream out) throws IOException {
|
||||
int volume = width * height * length;
|
||||
|
||||
out.writeNamedTag("Width", new ShortTag((short) width));
|
||||
out.writeNamedTag("Length", new ShortTag((short) length));
|
||||
out.writeNamedTag("Height", new ShortTag((short) height));
|
||||
out.writeNamedTag("Materials", new StringTag("Alpha"));
|
||||
out.writeNamedTag("WEOriginX", new IntTag(min.getBlockX()));
|
||||
out.writeNamedTag("WEOriginY", new IntTag(min.getBlockY()));
|
||||
out.writeNamedTag("WEOriginZ", new IntTag(min.getBlockZ()));
|
||||
out.writeNamedTag("WEOffsetX", new IntTag(offset.getBlockX()));
|
||||
out.writeNamedTag("WEOffsetY", new IntTag(offset.getBlockY()));
|
||||
out.writeNamedTag("WEOffsetZ", new IntTag(offset.getBlockZ()));
|
||||
out.writeNamedTag("Width", ((short) width));
|
||||
out.writeNamedTag("Length", ((short) length));
|
||||
out.writeNamedTag("Height", ((short) height));
|
||||
out.writeNamedTag("Materials", ("Alpha"));
|
||||
out.writeNamedTag("WEOriginX", (min.getBlockX()));
|
||||
out.writeNamedTag("WEOriginY", (min.getBlockY()));
|
||||
out.writeNamedTag("WEOriginZ", (min.getBlockZ()));
|
||||
out.writeNamedTag("WEOffsetX", (offset.getBlockX()));
|
||||
out.writeNamedTag("WEOffsetY", (offset.getBlockY()));
|
||||
out.writeNamedTag("WEOffsetZ", (offset.getBlockZ()));
|
||||
|
||||
out.writeNamedTagName("Blocks", NBTConstants.TYPE_BYTE_ARRAY);
|
||||
out.getOutputStream().writeInt(volume);
|
||||
@ -217,7 +217,7 @@ public class SchematicWriter implements ClipboardWriter {
|
||||
final List<CompoundTag> tileEntities = clipboard.IMP.getTileEntities();
|
||||
out.writeNamedTag("TileEntities", new ListTag(CompoundTag.class, tileEntities));
|
||||
} else {
|
||||
out.writeNamedTag("TileEntities", new ListTag(CompoundTag.class, new ArrayList<Tag>()));
|
||||
out.writeNamedEmptyList("TileEntities");
|
||||
}
|
||||
|
||||
List<Tag> entities = new ArrayList<Tag>();
|
||||
@ -242,7 +242,11 @@ public class SchematicWriter implements ClipboardWriter {
|
||||
entities.add(entityTag);
|
||||
}
|
||||
}
|
||||
out.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
|
||||
if (entities.isEmpty()) {
|
||||
out.writeNamedEmptyList("Entities");
|
||||
} else {
|
||||
out.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
|
||||
}
|
||||
}
|
||||
});
|
||||
outputStream.flush();
|
||||
|
@ -115,6 +115,28 @@ public class BlockMask extends AbstractExtentMask {
|
||||
return computedLegacyList;
|
||||
}
|
||||
|
||||
public Collection<BaseBlock> getInverseBlocks() {
|
||||
if (computedLegacyList != null) {
|
||||
return computedLegacyList;
|
||||
}
|
||||
computedLegacyList = new LinkedHashSet<>();
|
||||
for (int id = 0; id < FaweCache.getId(blocks.length); id++) {
|
||||
boolean all = true;
|
||||
ArrayList<BaseBlock> tmp = new ArrayList<BaseBlock>(16);
|
||||
for (int data = 0; data < 16; data++) {
|
||||
if (!blocks[FaweCache.getCombined(id, data)]) {
|
||||
tmp.add(FaweCache.getBlock(id, data));
|
||||
}
|
||||
}
|
||||
if (tmp.size() == 16) {
|
||||
computedLegacyList.add(new BaseBlock(id, -1));
|
||||
} else {
|
||||
computedLegacyList.addAll(tmp);
|
||||
}
|
||||
}
|
||||
return computedLegacyList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return StringMan.getString(getBlocks());
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.sk89q.worldedit.function.pattern;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
|
||||
@ -14,6 +15,14 @@ public class BlockPattern implements Pattern {
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
public BlockPattern(int id) {
|
||||
this.block = FaweCache.getBlock(id, 0);
|
||||
}
|
||||
|
||||
public BlockPattern(int id, int data) {
|
||||
this.block = FaweCache.getBlock(id, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock apply(Vector position) {
|
||||
return block;
|
||||
|
@ -6,6 +6,7 @@ import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@ -19,7 +20,7 @@ public class RandomPattern extends AbstractPattern {
|
||||
|
||||
private Map<Pattern, Double> weights = new HashMap<>();
|
||||
private RandomCollection<Pattern> collection;
|
||||
private Set<Pattern> patterns;
|
||||
private LinkedHashSet<Pattern> patterns = new LinkedHashSet<>();
|
||||
|
||||
/**
|
||||
* Add a pattern to the weight list of patterns.
|
||||
@ -34,7 +35,11 @@ public class RandomPattern extends AbstractPattern {
|
||||
checkNotNull(pattern);
|
||||
weights.put(pattern, chance);
|
||||
collection = RandomCollection.of(weights);
|
||||
this.patterns = weights.keySet();
|
||||
this.patterns.add(pattern);
|
||||
}
|
||||
|
||||
public Set<Pattern> getPatterns() {
|
||||
return patterns;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,6 +58,7 @@ public abstract class BreadthFirstSearch implements Operation {
|
||||
private BlockVectorSet visited;
|
||||
private final MappedFaweQueue mFaweQueue;
|
||||
private BlockVectorSet queue;
|
||||
private int currentDepth = 0;
|
||||
private final int maxDepth;
|
||||
private int affected = 0;
|
||||
private int maxBranch = Integer.MAX_VALUE;
|
||||
@ -107,6 +108,12 @@ public abstract class BreadthFirstSearch implements Operation {
|
||||
}
|
||||
}
|
||||
|
||||
public void resetVisited() {
|
||||
queue.clear();
|
||||
visited.clear();
|
||||
affected = 0;
|
||||
}
|
||||
|
||||
public void setVisited(BlockVectorSet set) {
|
||||
this.visited = set;
|
||||
}
|
||||
@ -131,7 +138,7 @@ public abstract class BreadthFirstSearch implements Operation {
|
||||
IntegerTrio[] dirs = getIntDirections();
|
||||
BlockVectorSet tempQueue = new BlockVectorSet();
|
||||
BlockVectorSet chunkLoadSet = new BlockVectorSet();
|
||||
for (int layer = 0; !queue.isEmpty() && layer <= maxDepth; layer++) {
|
||||
for (currentDepth = 0; !queue.isEmpty() && currentDepth <= maxDepth; currentDepth++) {
|
||||
if (mFaweQueue != null && Settings.IMP.QUEUE.PRELOAD_CHUNKS > 1) {
|
||||
int cx = Integer.MIN_VALUE;
|
||||
int cz = Integer.MIN_VALUE;
|
||||
@ -176,7 +183,7 @@ public abstract class BreadthFirstSearch implements Operation {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (layer == maxDepth) {
|
||||
if (currentDepth == maxDepth) {
|
||||
break;
|
||||
}
|
||||
int size = queue.size();
|
||||
@ -190,6 +197,10 @@ public abstract class BreadthFirstSearch implements Operation {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getDepth() {
|
||||
return currentDepth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStatusMessages(List<String> messages) {
|
||||
messages.add(BBC.VISITOR_BLOCK.format(getAffected()));
|
||||
|
@ -474,7 +474,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
|
||||
if (!hasNext) {
|
||||
throw new NoSuchElementException("End of iterator") {
|
||||
@Override
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
public Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
@ -539,7 +539,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
|
||||
if (!hasNext) {
|
||||
throw new NoSuchElementException("End of iterator") {
|
||||
@Override
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
public Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
@ -561,7 +561,6 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterable<Vector2D> asFlatRegion() {
|
||||
return new Iterable<Vector2D>() {
|
||||
@ -576,7 +575,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return (nextZ != Integer.MIN_VALUE);
|
||||
return (nextZ != Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -586,7 +585,16 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
|
||||
if (++nextX > max.getBlockX()) {
|
||||
nextX = min.getBlockX();
|
||||
if (++nextZ > max.getBlockZ()) {
|
||||
nextZ = Integer.MIN_VALUE;
|
||||
if (nextZ == Integer.MIN_VALUE) {
|
||||
throw new NoSuchElementException("End of iterator") {
|
||||
@Override
|
||||
public Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
nextZ = Integer.MAX_VALUE;
|
||||
nextX = Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
@ -623,6 +631,12 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
|
||||
return new CuboidRegion(region.getMinimumPoint(), region.getMaximumPoint());
|
||||
}
|
||||
|
||||
public static boolean contains(CuboidRegion region) {
|
||||
Vector min = region.getMinimumPoint();
|
||||
Vector max = region.getMaximumPoint();
|
||||
return region.contains(min.getBlockX(), min.getBlockY(), min.getBlockZ()) && region.contains(max.getBlockX(), max.getBlockY(), max.getBlockZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a cuboid from the center.
|
||||
*
|
||||
|
@ -143,9 +143,8 @@ public class BundledBlockData {
|
||||
}
|
||||
idMap.put(entry.id, entry);
|
||||
String id = (entry.id.contains(":") ? entry.id.split(":")[1] : entry.id).toLowerCase().replace(" ", "_");
|
||||
if (!idMap.containsKey(id)) {
|
||||
idMap.put(id, entry);
|
||||
}
|
||||
localIdMap.putIfAbsent(id, entry);
|
||||
idMap.putIfAbsent(id, entry);
|
||||
legacyMap[entry.legacyId] = entry;
|
||||
if (entry.states == null) {
|
||||
return true;
|
||||
|
@ -58,8 +58,8 @@ shadowJar {
|
||||
relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml'
|
||||
dependencies {
|
||||
include(dependency('com.github.luben:zstd-jni:1.1.1'))
|
||||
include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('co.aikar:fastutil-lite:1.0'))
|
||||
// include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('it.unimi.dsi:fastutil:6.5.1'))
|
||||
include(dependency(':core'))
|
||||
include(dependency('org.yaml:snakeyaml:1.16'))
|
||||
}
|
||||
|
@ -58,8 +58,8 @@ shadowJar {
|
||||
relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml'
|
||||
dependencies {
|
||||
include(dependency('com.github.luben:zstd-jni:1.1.1'))
|
||||
include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('co.aikar:fastutil-lite:1.0'))
|
||||
// include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('it.unimi.dsi:fastutil:6.5.1'))
|
||||
include(dependency(':core'))
|
||||
include(dependency('org.yaml:snakeyaml:1.16'))
|
||||
}
|
||||
|
@ -49,8 +49,8 @@ shadowJar {
|
||||
relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml'
|
||||
dependencies {
|
||||
include(dependency('com.github.luben:zstd-jni:1.1.1'))
|
||||
include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('co.aikar:fastutil-lite:1.0'))
|
||||
// include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('it.unimi.dsi:fastutil:6.5.1'))
|
||||
include(dependency(':core'))
|
||||
include(dependency('org.yaml:snakeyaml:1.16'))
|
||||
}
|
||||
|
@ -58,8 +58,8 @@ shadowJar {
|
||||
relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml'
|
||||
dependencies {
|
||||
include(dependency('com.github.luben:zstd-jni:1.1.1'))
|
||||
include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('co.aikar:fastutil-lite:1.0'))
|
||||
// include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('it.unimi.dsi:fastutil:6.5.1'))
|
||||
include(dependency(':core'))
|
||||
include(dependency('org.yaml:snakeyaml:1.16'))
|
||||
}
|
||||
|
@ -57,8 +57,8 @@ shadowJar {
|
||||
relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml'
|
||||
dependencies {
|
||||
include(dependency('com.github.luben:zstd-jni:1.1.1'))
|
||||
include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('co.aikar:fastutil-lite:1.0'))
|
||||
// include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('it.unimi.dsi:fastutil:6.5.1'))
|
||||
include(dependency(':core'))
|
||||
include(dependency('org.yaml:snakeyaml:1.16'))
|
||||
}
|
||||
|
BIN
heightmap.png
Normal file
BIN
heightmap.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 MiB |
@ -23,8 +23,8 @@ jar.enabled = false
|
||||
shadowJar {
|
||||
dependencies {
|
||||
include(dependency('com.github.luben:zstd-jni:1.1.1'))
|
||||
include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('co.aikar:fastutil-lite:1.0'))
|
||||
// include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('it.unimi.dsi:fastutil:6.5.1'))
|
||||
include(dependency(name: 'worldedit-core-6.1.4-SNAPSHOT-dist'))
|
||||
include(dependency('com.google.code.gson:gson:2.2.4'))
|
||||
include(dependency('org.yaml:snakeyaml:1.16'))
|
||||
|
BIN
region/r.0.-1.mca
Normal file
BIN
region/r.0.-1.mca
Normal file
Binary file not shown.
@ -1,3 +1,3 @@
|
||||
rootProject.name = 'FastAsyncWorldEdit'
|
||||
|
||||
include 'core', 'bukkit', 'favs', 'nukkit', 'sponge', 'forge1710', 'forge189', 'forge194', 'forge110', 'forge111'
|
||||
include 'core', 'bukkit'//, 'favs', 'nukkit', 'sponge', 'forge1710', 'forge189', 'forge194', 'forge110', 'forge111'
|
@ -76,8 +76,8 @@ shadowJar {
|
||||
dependencies {
|
||||
include(dependency(':core'))
|
||||
include(dependency('com.github.luben:zstd-jni:1.1.1'))
|
||||
include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('co.aikar:fastutil-lite:1.0'))
|
||||
// include(dependency('org.javassist:javassist:3.22.0-CR1'))
|
||||
include(dependency('it.unimi.dsi:fastutil:6.5.1'))
|
||||
include(dependency(name: 'worldedit-core-6.1.7-SNAPSHOT-dist'))
|
||||
include(dependency('com.sk89q.worldedit:worldedit-sponge:6.1.7-SNAPSHOT'))
|
||||
include(dependency('org.yaml:snakeyaml:1.16'))
|
||||
|
Loading…
Reference in New Issue
Block a user