Various
Add #clipboard transform Add #fullcopy pattern - similar to transform, it pastes the full clipboard at any changed block - e.g. //replace <marker> #fullcopy Async block get optimizations for bukkit by running tasks multiple times during a single tick Tweak the OOM message to be more informative Tweak the max memory config comment to be more informative Restructured transforms to use resettable extent + reduce code duplication Clipboards can now be streamed to a schematic file without significant memory overhead - This means you can now load/paste/copy/save arbitrarily large sizes with fixed memory usage Optimizations to the various clipboard implementations Add optimized extent block translation (no additional object creation for set block) Optimized forward extent block copy - use optimized extent transform/translate - pre calculate required functions/extents outside iterations - short circuit certain functions depending on input parameters Use edit session for patterns rather than world (faster/safer)
This commit is contained in:
parent
98b79e7ccc
commit
1c948cf0ed
@ -21,6 +21,7 @@ import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.bukkit.EditSessionBlockChangeDelegate;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
@ -37,6 +38,9 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.event.world.ChunkPopulateEvent;
|
||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.primesoft.blockshub.BlocksHubBukkit;
|
||||
|
||||
@ -352,6 +356,21 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
return managers;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChunkLoad(ChunkLoadEvent event) {
|
||||
SetQueue.IMP.runMiscTasks();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChunkUnload(ChunkUnloadEvent event) {
|
||||
SetQueue.IMP.runMiscTasks();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChunkPopulate(ChunkPopulateEvent event) {
|
||||
SetQueue.IMP.runMiscTasks();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
@ -30,12 +30,10 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.server.v1_11_R1.*;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.craftbukkit.v1_11_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_11_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_11_R1.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.v1_11_R1.entity.CraftEntity;
|
||||
@ -47,11 +45,7 @@ public final class FaweAdapter_1_11 implements BukkitImplAdapter
|
||||
private final Field nbtListTagListField;
|
||||
private final Method nbtCreateTagMethod;
|
||||
|
||||
public FaweAdapter_1_11()
|
||||
throws NoSuchFieldException, NoSuchMethodException
|
||||
{
|
||||
CraftServer.class.cast(Bukkit.getServer());
|
||||
|
||||
public FaweAdapter_1_11() throws NoSuchFieldException, NoSuchMethodException {
|
||||
this.nbtListTagListField = NBTTagList.class.getDeclaredField("list");
|
||||
this.nbtListTagListField.setAccessible(true);
|
||||
|
||||
|
@ -40,7 +40,7 @@ public enum BBC {
|
||||
WORLDEDIT_BYPASSED("&7Currently bypassing WorldEdit restriction.", "Info"),
|
||||
WORLDEDIT_UNMASKED("&6Your WorldEdit is now unrestricted.", "Info"),
|
||||
WORLDEDIT_RESTRICTED("&6Your WorldEdit is now restricted.", "Info"),
|
||||
WORLDEDIT_OOM_ADMIN("&cPossible options:\n&8 - &7//fast\n&8 - &7Do smaller edits\n&8 - &7Allocate more memory\n&8 - &7Disable this safeguard", "Info"),
|
||||
WORLDEDIT_OOM_ADMIN("&cPossible options:\n&8 - &7//fast\n&8 - &7Do smaller edits\n&8 - &7Allocate more memory\n&8 - &7Disable `max-memory-percent`", "Info"),
|
||||
COMPRESSED("History compressed. Saved ~ %s0b (%s1x smaller)", "Info"),
|
||||
|
||||
ACTION_COMPLETE("Action completed in %s0 seconds", "Info"),
|
||||
|
@ -37,9 +37,9 @@ public class Settings extends Config {
|
||||
})
|
||||
public static boolean REGION_RESTRICTIONS = true;
|
||||
@Comment({
|
||||
"FAWE will start cancelling non-admin edits if used-memory % exceeds",
|
||||
"this value. Effects anyone who doesn't have bypass enabled",
|
||||
"(e.g. /wea , or fastmode //fast , or fawe.bypass permission )."
|
||||
"FAWE will cancel non admin edits when memory consumption exceeds this %",
|
||||
" - Bypass with `/wea` or `//fast` or `fawe.bypass`",
|
||||
" - Disable with 100 or -1."
|
||||
})
|
||||
public static int MAX_MEMORY_PERCENT = 95;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.object.brush;
|
||||
|
||||
import com.boydti.fawe.object.extent.TransformExtent;
|
||||
import com.boydti.fawe.object.extent.ResettableExtent;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.LocalConfiguration;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
@ -30,7 +30,7 @@ public class DoubleActionBrushTool implements DoubleActionTraceTool {
|
||||
protected static int MAX_RANGE = 500;
|
||||
protected int range = -1;
|
||||
private Mask mask = null;
|
||||
private TransformExtent transform = null;
|
||||
private ResettableExtent transform = null;
|
||||
private DoubleActionBrush brush = null;
|
||||
@Nullable
|
||||
private Pattern material;
|
||||
@ -52,11 +52,11 @@ public class DoubleActionBrushTool implements DoubleActionTraceTool {
|
||||
return player.hasPermission(permission);
|
||||
}
|
||||
|
||||
public TransformExtent getTransform() {
|
||||
public ResettableExtent getTransform() {
|
||||
return transform;
|
||||
}
|
||||
|
||||
public void setTransform(TransformExtent transform) {
|
||||
public void setTransform(ResettableExtent transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.object.clipboard;
|
||||
|
||||
import com.boydti.fawe.jnbt.NBTStreamer;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
@ -80,4 +81,19 @@ public class AbstractDelegateFaweClipboard extends FaweClipboard {
|
||||
public void forEach(RunnableVal2<Vector, BaseBlock> task, boolean air) {
|
||||
parent.forEach(task, air);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamIds(NBTStreamer.ByteReader task) {
|
||||
parent.streamIds(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamDatas(NBTStreamer.ByteReader task) {
|
||||
parent.streamDatas(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CompoundTag> getTileEntities() {
|
||||
return parent.getTileEntities();
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
package com.boydti.fawe.object.clipboard;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.jnbt.NBTStreamer;
|
||||
import com.boydti.fawe.object.IntegerTrio;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
@ -50,7 +54,7 @@ public class CPUOptimizedClipboard extends FaweClipboard {
|
||||
}
|
||||
for (Map.Entry<IntegerTrio, CompoundTag> entry : nbtMapLoc.entrySet()) {
|
||||
IntegerTrio key = entry.getKey();
|
||||
nbtMapIndex.put(getIndex(key.x, key.y, key.z), entry.getValue());
|
||||
setTile(getIndex(key.x, key.y, key.z), entry.getValue());
|
||||
}
|
||||
nbtMapLoc.clear();
|
||||
}
|
||||
@ -170,12 +174,78 @@ public class CPUOptimizedClipboard extends FaweClipboard {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamIds(NBTStreamer.ByteReader task) {
|
||||
int index = 0;
|
||||
if (add != null) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int id = getId(index) + (getAdd(index) << 8);
|
||||
task.run(index++, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int id = getId(index);
|
||||
task.run(index++, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamDatas(NBTStreamer.ByteReader task) {
|
||||
int index = 0;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int data = getData(index);
|
||||
task.run(index++, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CompoundTag> getTileEntities() {
|
||||
convertTilesToIndex();
|
||||
for (Map.Entry<Integer, CompoundTag> entry : nbtMapIndex.entrySet()) {
|
||||
int index = entry.getKey();
|
||||
CompoundTag tag = entry.getValue();
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
if (!values.containsKey("x")) {
|
||||
int y = index / area;
|
||||
index -= y * area;
|
||||
int z = index / width;
|
||||
int x = index - (z * width);
|
||||
values.put("x", new IntTag(x));
|
||||
values.put("y", new IntTag(y));
|
||||
values.put("z", new IntTag(z));
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(nbtMapIndex.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
nbtMapLoc.put(new IntegerTrio(x, y, z), tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean setTile(int index, CompoundTag tag) {
|
||||
nbtMapIndex.put(index, tag);
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
values.remove("x");
|
||||
values.remove("y");
|
||||
values.remove("z");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) {
|
||||
return setBlock(getIndex(x, y, z), block);
|
||||
@ -190,7 +260,7 @@ public class CPUOptimizedClipboard extends FaweClipboard {
|
||||
}
|
||||
CompoundTag tile = block.getNbtData();
|
||||
if (tile != null) {
|
||||
nbtMapIndex.put(index, tile);
|
||||
setTile(index, tile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -3,11 +3,15 @@ package com.boydti.fawe.object.clipboard;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.jnbt.NBTStreamer;
|
||||
import com.boydti.fawe.object.IntegerTrio;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
@ -20,12 +24,11 @@ import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
@ -51,7 +54,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
private final File file;
|
||||
private final byte[] buffer;
|
||||
|
||||
private volatile BufferedRandomAccessFile raf;
|
||||
private final BufferedRandomAccessFile raf;
|
||||
private long lastAccessed;
|
||||
private int last;
|
||||
|
||||
@ -59,21 +62,26 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
this(width, height, length, MainUtil.getFile(Fawe.imp().getDirectory(), Settings.PATHS.CLIPBOARD + File.separator + uuid + ".bd"));
|
||||
}
|
||||
|
||||
public DiskOptimizedClipboard(File file) throws IOException {
|
||||
nbtMap = new HashMap<>();
|
||||
entities = new HashSet<>();this.buffer = new byte[2];
|
||||
this.file = file;
|
||||
this.lastAccessed = System.currentTimeMillis();
|
||||
this.raf = new BufferedRandomAccessFile(file, "rw", Settings.HISTORY.BUFFER_SIZE);
|
||||
raf.setLength(file.length());
|
||||
long size = (raf.length() - HEADER_SIZE) >> 1;
|
||||
raf.seek(2);
|
||||
last = Integer.MIN_VALUE;
|
||||
width = (int) raf.readChar();
|
||||
height = (int) raf.readChar();
|
||||
length = (int) raf.readChar();
|
||||
area = width * length;
|
||||
autoCloseTask();
|
||||
public DiskOptimizedClipboard(File file) {
|
||||
try {
|
||||
nbtMap = new HashMap<>();
|
||||
entities = new HashSet<>();
|
||||
this.buffer = new byte[2];
|
||||
this.file = file;
|
||||
this.lastAccessed = System.currentTimeMillis();
|
||||
this.raf = new BufferedRandomAccessFile(file, "rw", 16);
|
||||
raf.setLength(file.length());
|
||||
long size = (raf.length() - HEADER_SIZE) >> 1;
|
||||
raf.seek(2);
|
||||
last = Integer.MIN_VALUE;
|
||||
width = (int) raf.readChar();
|
||||
height = (int) raf.readChar();
|
||||
length = (int) raf.readChar();
|
||||
area = width * length;
|
||||
autoCloseTask();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -89,9 +97,6 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
if (raf == null) {
|
||||
open();
|
||||
}
|
||||
raf.seek(8);
|
||||
last = Integer.MIN_VALUE;
|
||||
int ox = raf.readShort();
|
||||
@ -107,35 +112,41 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
}
|
||||
|
||||
public DiskOptimizedClipboard(int width, int height, int length, File file) {
|
||||
nbtMap = new HashMap<>();
|
||||
entities = new HashSet<>();
|
||||
this.file = file;
|
||||
this.buffer = new byte[2];
|
||||
this.lastAccessed = System.currentTimeMillis();
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.length = length;
|
||||
this.area = width * length;
|
||||
try {
|
||||
if (!file.exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
} else {
|
||||
PrintWriter writer = new PrintWriter(file);
|
||||
writer.print("");
|
||||
writer.close();
|
||||
nbtMap = new HashMap<>();
|
||||
entities = new HashSet<>();
|
||||
this.file = file;
|
||||
this.buffer = new byte[2];
|
||||
this.lastAccessed = System.currentTimeMillis();
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.length = length;
|
||||
this.area = width * length;
|
||||
try {
|
||||
if (!file.exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
MainUtil.handleError(e);
|
||||
this.raf = new BufferedRandomAccessFile(file, "rw", 16);
|
||||
long volume = width * height * length * 2l + HEADER_SIZE;
|
||||
raf.setLength(volume);
|
||||
// write length etc
|
||||
raf.seek(2);
|
||||
last = Integer.MIN_VALUE;
|
||||
raf.writeChar(width);
|
||||
raf.writeChar(height);
|
||||
raf.writeChar(length);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrigin(Vector offset) {
|
||||
try {
|
||||
if (raf == null) {
|
||||
open();
|
||||
}
|
||||
raf.seek(8);
|
||||
last = Integer.MIN_VALUE;
|
||||
raf.writeShort(offset.getBlockX());
|
||||
@ -149,9 +160,6 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
@Override
|
||||
public void setDimensions(Vector dimensions) {
|
||||
try {
|
||||
if (raf == null) {
|
||||
open();
|
||||
}
|
||||
width = dimensions.getBlockX();
|
||||
height = dimensions.getBlockY();
|
||||
length = dimensions.getBlockZ();
|
||||
@ -163,7 +171,6 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
raf.writeChar(width);
|
||||
raf.writeChar(height);
|
||||
raf.writeChar(length);
|
||||
raf.flush();
|
||||
} catch (IOException e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
@ -171,10 +178,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
|
||||
public void flush() {
|
||||
try {
|
||||
raf.close();
|
||||
raf = null;
|
||||
file.setWritable(true);
|
||||
System.gc();
|
||||
raf.flush();
|
||||
} catch (IOException e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
@ -186,36 +190,14 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
raf.flush();
|
||||
RandomAccessFile tmp = raf;
|
||||
raf = null;
|
||||
tmp.close();
|
||||
tmp = null;
|
||||
raf.close();
|
||||
file.setWritable(true);
|
||||
System.gc();
|
||||
} catch (IOException e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void open() throws IOException {
|
||||
if (raf != null) {
|
||||
close();
|
||||
}
|
||||
lastAccessed = System.currentTimeMillis();
|
||||
this.raf = new BufferedRandomAccessFile(file, "rw", Settings.HISTORY.BUFFER_SIZE);
|
||||
long size = width * height * length * 2l + HEADER_SIZE;
|
||||
if (raf.length() != size) {
|
||||
raf.setLength(size);
|
||||
// write length etc
|
||||
raf.seek(2);
|
||||
last = Integer.MIN_VALUE;
|
||||
raf.writeChar(width);
|
||||
raf.writeChar(height);
|
||||
raf.writeChar(length);
|
||||
}
|
||||
autoCloseTask();
|
||||
}
|
||||
|
||||
private void autoCloseTask() {
|
||||
// TaskManager.IMP.laterAsync(new Runnable() {
|
||||
// @Override
|
||||
@ -236,43 +218,97 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
private int zlast;
|
||||
private int zlasti;
|
||||
|
||||
@Override
|
||||
public void streamIds(NBTStreamer.ByteReader task) {
|
||||
try {
|
||||
raf.seek(HEADER_SIZE);
|
||||
int index = 0;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int combinedId = raf.readChar();
|
||||
task.run(index++, FaweCache.getId(combinedId));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamDatas(NBTStreamer.ByteReader task) {
|
||||
try {
|
||||
raf.seek(HEADER_SIZE);
|
||||
int index = 0;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int combinedId = raf.readChar();
|
||||
task.run(index++, FaweCache.getData(combinedId));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CompoundTag> getTileEntities() {
|
||||
return new ArrayList<>(nbtMap.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(final RunnableVal2<Vector,BaseBlock> task, boolean air) {
|
||||
try {
|
||||
if (raf == null) {
|
||||
open();
|
||||
}
|
||||
raf.seek(HEADER_SIZE);
|
||||
BlockVector pos = new BlockVector(0, 0, 0);
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int z = 0;
|
||||
long len = (raf.length());
|
||||
for (long i = HEADER_SIZE; i < len; i+=2) {
|
||||
pos.x = x;
|
||||
pos.y = y;
|
||||
pos.z = z;
|
||||
if (++x >= width) {
|
||||
x = 0;
|
||||
if (++z >= length) {
|
||||
z = 0;
|
||||
++y;
|
||||
IntegerTrio trio = new IntegerTrio();
|
||||
if (air) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int combinedId = raf.readChar();
|
||||
BaseBlock block = FaweCache.CACHE_BLOCK[combinedId];
|
||||
if (FaweCache.hasNBT(block.getId())) {
|
||||
trio.set(x, y, z);
|
||||
CompoundTag nbt = nbtMap.get(trio);
|
||||
if (nbt != null) {
|
||||
block = new BaseBlock(block.getId(), block.getData());
|
||||
block.setNbtData(nbt);
|
||||
}
|
||||
}
|
||||
pos.x = x;
|
||||
pos.y = y;
|
||||
pos.z = z;
|
||||
task.run(pos, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
raf.seek(i);
|
||||
int combinedId = raf.readChar();
|
||||
if (combinedId == 0 && !air) {
|
||||
continue;
|
||||
}
|
||||
BaseBlock block = FaweCache.CACHE_BLOCK[combinedId];
|
||||
if (FaweCache.hasNBT(block.getId())) {
|
||||
CompoundTag nbt = nbtMap.get(new IntegerTrio((int) pos.x, (int) pos.y, (int) pos.z));
|
||||
if (nbt != null) {
|
||||
block = new BaseBlock(block.getId(), block.getData());
|
||||
block.setNbtData(nbt);
|
||||
} else {
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int combinedId = raf.readChar();
|
||||
if (combinedId != 0) {
|
||||
BaseBlock block = FaweCache.CACHE_BLOCK[combinedId];
|
||||
if (FaweCache.hasNBT(block.getId())) {
|
||||
trio.set(x, y, z);
|
||||
CompoundTag nbt = nbtMap.get(trio);
|
||||
if (nbt != null) {
|
||||
block = new BaseBlock(block.getId(), block.getData());
|
||||
block.setNbtData(nbt);
|
||||
}
|
||||
}
|
||||
pos.x = x;
|
||||
pos.y = y;
|
||||
pos.z = z;
|
||||
task.run(pos, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
task.run(pos, block);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
MainUtil.handleError(e);
|
||||
@ -286,9 +322,6 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
@Override
|
||||
public BaseBlock getBlock(int x, int y, int z) {
|
||||
try {
|
||||
if (raf == null) {
|
||||
open();
|
||||
}
|
||||
int i = getIndex(x, y, z);
|
||||
if (i != last + 1) {
|
||||
raf.seek((HEADER_SIZE) + (i << 1));
|
||||
@ -314,15 +347,16 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
nbtMap.put(new IntegerTrio(x, y, z), tag);
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
values.put("x", new IntTag(x));
|
||||
values.put("y", new IntTag(y));
|
||||
values.put("z", new IntTag(z));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) {
|
||||
try {
|
||||
if (raf == null) {
|
||||
open();
|
||||
}
|
||||
int i = x + ((ylast == y) ? ylasti : (ylasti = ((ylast = y)) * area)) + ((zlast == z) ? zlasti : (zlasti = (zlast = z) * width));
|
||||
if (i != last + 1) {
|
||||
raf.seek((HEADER_SIZE) + (i << 1));
|
||||
@ -334,7 +368,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
int combined = (id << 4) + data;
|
||||
raf.writeChar(combined);
|
||||
if (FaweCache.hasNBT(id)) {
|
||||
nbtMap.put(new IntegerTrio(x, y, z), block.getNbtData());
|
||||
setTile(x, y, z, block.getNbtData());
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
@ -346,9 +380,6 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
@Override
|
||||
public void setId(int i, int id) {
|
||||
try {
|
||||
if (raf == null) {
|
||||
open();
|
||||
}
|
||||
if (i != last + 1) {
|
||||
raf.seek((HEADER_SIZE) + (i << 1));
|
||||
lastAccessed = System.currentTimeMillis();
|
||||
@ -367,9 +398,6 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
|
||||
public void setCombined(int i, int combined) {
|
||||
try {
|
||||
if (raf == null) {
|
||||
open();
|
||||
}
|
||||
if (i != last + 1) {
|
||||
raf.seek((HEADER_SIZE) + (i << 1));
|
||||
lastAccessed = System.currentTimeMillis();
|
||||
@ -384,9 +412,6 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
@Override
|
||||
public void setAdd(int i, int add) {
|
||||
try {
|
||||
if (raf == null) {
|
||||
open();
|
||||
}
|
||||
if (i != last + 1) {
|
||||
raf.seek((HEADER_SIZE) + (i << 1));
|
||||
lastAccessed = System.currentTimeMillis();
|
||||
@ -404,9 +429,6 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
|
||||
@Override
|
||||
public void setData(int i, int data) {
|
||||
try {
|
||||
if (raf == null) {
|
||||
open();
|
||||
}
|
||||
if (i != last + 1) {
|
||||
raf.seek((HEADER_SIZE) + (i << 1));
|
||||
lastAccessed = System.currentTimeMillis();
|
||||
|
@ -1,14 +1,20 @@
|
||||
package com.boydti.fawe.object.clipboard;
|
||||
|
||||
import com.boydti.fawe.jnbt.NBTStreamer;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
@ -46,6 +52,45 @@ public abstract class FaweClipboard {
|
||||
*/
|
||||
public abstract void forEach(final RunnableVal2<Vector,BaseBlock> task, boolean air);
|
||||
|
||||
public void streamIds(final NBTStreamer.ByteReader task) {
|
||||
forEach(new RunnableVal2<Vector, BaseBlock>() {
|
||||
private int index = 0;
|
||||
@Override
|
||||
public void run(Vector pos, BaseBlock block) {
|
||||
task.run(index++, block.getId());
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
public void streamDatas(final NBTStreamer.ByteReader task) {
|
||||
forEach(new RunnableVal2<Vector, BaseBlock>() {
|
||||
private int index = 0;
|
||||
@Override
|
||||
public void run(Vector pos, BaseBlock block) {
|
||||
task.run(index++, block.getData());
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
public List<CompoundTag> getTileEntities() {
|
||||
final List<CompoundTag> tiles = new ArrayList<>();
|
||||
forEach(new RunnableVal2<Vector, BaseBlock>() {
|
||||
private int index = 0;
|
||||
@Override
|
||||
public void run(Vector pos, BaseBlock block) {
|
||||
CompoundTag tag = block.getNbtData();
|
||||
if (tag != null) {
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
values.put("x", new IntTag((int) pos.x));
|
||||
values.put("y", new IntTag((int) pos.y));
|
||||
values.put("z", new IntTag((int) pos.z));
|
||||
tiles.add(tag);
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
return tiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores entity data.
|
||||
*/
|
||||
|
@ -2,10 +2,14 @@ package com.boydti.fawe.object.clipboard;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.jnbt.NBTStreamer;
|
||||
import com.boydti.fawe.object.IntegerTrio;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
@ -78,7 +82,7 @@ public class MemoryOptimizedClipboard extends FaweClipboard {
|
||||
}
|
||||
for (Map.Entry<IntegerTrio, CompoundTag> entry : nbtMapLoc.entrySet()) {
|
||||
IntegerTrio key = entry.getKey();
|
||||
nbtMapIndex.put(getIndex(key.x, key.y, key.z), entry.getValue());
|
||||
setTile(getIndex(key.x, key.y, key.z), entry.getValue());
|
||||
}
|
||||
nbtMapLoc.clear();
|
||||
}
|
||||
@ -276,6 +280,63 @@ public class MemoryOptimizedClipboard extends FaweClipboard {
|
||||
saveAdd = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamIds(NBTStreamer.ByteReader task) {
|
||||
int index = 0;
|
||||
if (add != null) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int id = getId(index) + (getAdd(index) << 8);
|
||||
task.run(index++, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int id = getId(index);
|
||||
task.run(index++, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamDatas(NBTStreamer.ByteReader task) {
|
||||
int index = 0;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int z = 0; z < length; z++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int data = getData(index);
|
||||
task.run(index++, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CompoundTag> getTileEntities() {
|
||||
convertTilesToIndex();
|
||||
for (Map.Entry<Integer, CompoundTag> entry : nbtMapIndex.entrySet()) {
|
||||
int index = entry.getKey();
|
||||
CompoundTag tag = entry.getValue();
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
if (!values.containsKey("x")) {
|
||||
int y = index / area;
|
||||
index -= y * area;
|
||||
int z = index / width;
|
||||
int x = index - (z * width);
|
||||
values.put("x", new IntTag(x));
|
||||
values.put("y", new IntTag(y));
|
||||
values.put("z", new IntTag(z));
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(nbtMapIndex.values());
|
||||
}
|
||||
|
||||
private int ylast;
|
||||
private int ylasti;
|
||||
private int zlast;
|
||||
@ -358,6 +419,15 @@ public class MemoryOptimizedClipboard extends FaweClipboard {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean setTile(int index, CompoundTag tag) {
|
||||
nbtMapIndex.put(index, tag);
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
values.remove("x");
|
||||
values.remove("y");
|
||||
values.remove("z");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) {
|
||||
return setBlock(getIndex(x, y, z), block);
|
||||
@ -372,7 +442,7 @@ public class MemoryOptimizedClipboard extends FaweClipboard {
|
||||
setData(index, block.getData());
|
||||
CompoundTag tile = block.getNbtData();
|
||||
if (tile != null) {
|
||||
nbtMapIndex.put(index, tile);
|
||||
setTile(index, tile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1,17 +1,20 @@
|
||||
package com.boydti.fawe.object.clipboard;
|
||||
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class ReadOnlyClipboard extends FaweClipboard {
|
||||
private final Region region;
|
||||
@ -42,17 +45,84 @@ public abstract class ReadOnlyClipboard extends FaweClipboard {
|
||||
|
||||
@Override
|
||||
public void forEach(RunnableVal2<Vector, BaseBlock> task, boolean air) {
|
||||
Iterator<BlockVector> iter = getRegion().iterator();
|
||||
while (iter.hasNext()) {
|
||||
BlockVector pos = iter.next();
|
||||
BaseBlock block = getBlockAbs((int) pos.x, (int) pos.y, (int) pos.z);
|
||||
if (!air && block == EditSession.nullBlock) {
|
||||
continue;
|
||||
Vector min = region.getMinimumPoint();
|
||||
Vector max = region.getMaximumPoint();
|
||||
Vector pos = new Vector();
|
||||
if (region instanceof CuboidRegion) {
|
||||
if (air) {
|
||||
for (int y = min.getBlockY(); y <= max.getBlockY(); y++) {
|
||||
for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
|
||||
for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
|
||||
BaseBlock block = getBlockAbs(x, y, z);
|
||||
pos.x = x - mx;
|
||||
pos.y = y - my;
|
||||
pos.z = z - mz;
|
||||
CompoundTag tag = block.getNbtData();
|
||||
if (tag != null) {
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
values.put("x", new IntTag((int) pos.x));
|
||||
values.put("y", new IntTag((int) pos.y));
|
||||
values.put("z", new IntTag((int) pos.z));
|
||||
}
|
||||
task.run(pos, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int y = min.getBlockY(); y <= max.getBlockY(); y++) {
|
||||
for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
|
||||
for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
|
||||
BaseBlock block = getBlockAbs(x, y, z);
|
||||
if (block == EditSession.nullBlock) {
|
||||
continue;
|
||||
}
|
||||
pos.x = x - mx;
|
||||
pos.y = y - my;
|
||||
pos.z = z - mz;
|
||||
CompoundTag tag = block.getNbtData();
|
||||
if (tag != null) {
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
values.put("x", new IntTag((int) pos.x));
|
||||
values.put("y", new IntTag((int) pos.y));
|
||||
values.put("z", new IntTag((int) pos.z));
|
||||
}
|
||||
task.run(pos, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int y = min.getBlockY(); y <= max.getBlockY(); y++) {
|
||||
for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
|
||||
for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
|
||||
pos.x = x;
|
||||
pos.y = y;
|
||||
pos.z = z;
|
||||
if (region.contains(pos)) {
|
||||
BaseBlock block = getBlockAbs(x, y, z);
|
||||
if (!air && block == EditSession.nullBlock) {
|
||||
continue;
|
||||
}
|
||||
pos.x -= mx;
|
||||
pos.y -= my;
|
||||
pos.z -= mz;
|
||||
CompoundTag tag = block.getNbtData();
|
||||
if (tag != null) {
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
values.put("x", new IntTag((int) pos.x));
|
||||
values.put("y", new IntTag((int) pos.y));
|
||||
values.put("z", new IntTag((int) pos.z));
|
||||
}
|
||||
task.run(pos, block);
|
||||
} else if (air) {
|
||||
pos.x -= mx;
|
||||
pos.y -= my;
|
||||
pos.z -= mz;
|
||||
task.run(pos, EditSession.nullBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pos.x -= mx;
|
||||
pos.y -= my;
|
||||
pos.z -= mz;
|
||||
task.run(pos, block);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,138 +0,0 @@
|
||||
package com.boydti.fawe.object.extent;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
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.extent.transform.BlockTransformExtent;
|
||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import com.sk89q.worldedit.world.registry.BlockRegistry;
|
||||
|
||||
public class AffineTransformExtent extends TransformExtent {
|
||||
private final Vector mutable = new Vector();
|
||||
private final BlockRegistry registry;
|
||||
private int maxy;
|
||||
private AffineTransform affine;
|
||||
private BaseBlock[] BLOCK_TRANSFORM;
|
||||
private BaseBlock[] BLOCK_TRANSFORM_INVERSE;
|
||||
|
||||
private Vector min;
|
||||
|
||||
public AffineTransformExtent(Extent parent, BlockRegistry registry) {
|
||||
super(parent);
|
||||
this.maxy = parent.getMaximumPoint().getBlockY();
|
||||
this.affine = new AffineTransform();
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
private void cache() {
|
||||
BLOCK_TRANSFORM = new BaseBlock[FaweCache.CACHE_BLOCK.length];
|
||||
BLOCK_TRANSFORM_INVERSE = new BaseBlock[FaweCache.CACHE_BLOCK.length];
|
||||
Transform inverse = affine.inverse();
|
||||
for (int i = 0; i < BLOCK_TRANSFORM.length; i++) {
|
||||
BaseBlock block = FaweCache.CACHE_BLOCK[i];
|
||||
if (block != null) {
|
||||
BLOCK_TRANSFORM[i] = BlockTransformExtent.transform(new BaseBlock(block), affine, registry);
|
||||
BLOCK_TRANSFORM_INVERSE[i] = BlockTransformExtent.transform(new BaseBlock(block), inverse, registry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformExtent setExtent(Extent extent) {
|
||||
min = null;
|
||||
maxy = extent.getMaximumPoint().getBlockY();
|
||||
return super.setExtent(extent);
|
||||
}
|
||||
|
||||
public AffineTransform getAffine() {
|
||||
return affine;
|
||||
}
|
||||
|
||||
public void setAffine(AffineTransform affine) {
|
||||
this.affine = affine;
|
||||
cache();
|
||||
}
|
||||
|
||||
private Vector getPos(Vector pos) {
|
||||
if (min == null) {
|
||||
min = new Vector(pos);
|
||||
}
|
||||
mutable.x = (pos.x - min.x);
|
||||
mutable.y = (pos.y - min.y);
|
||||
mutable.z = (pos.z - min.z);
|
||||
Vector tmp = affine.apply(mutable);
|
||||
tmp.x += min.x;
|
||||
tmp.y += min.y;
|
||||
tmp.z += min.z;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private Vector getPos(int x, int y, int z) {
|
||||
if (min == null) {
|
||||
min = new Vector(x, y, z);
|
||||
}
|
||||
mutable.x = (x - min.x);
|
||||
mutable.y = (y - min.y);
|
||||
mutable.z = (z - min.z);
|
||||
Vector tmp = affine.apply(mutable);
|
||||
tmp.x += min.x;
|
||||
tmp.y += min.y;
|
||||
tmp.z += min.z;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private final BaseBlock transformFast(BaseBlock block) {
|
||||
return BLOCK_TRANSFORM[FaweCache.getCombined(block)];
|
||||
}
|
||||
|
||||
private final BaseBlock transformFastInverse(BaseBlock block) {
|
||||
return BLOCK_TRANSFORM_INVERSE[FaweCache.getCombined(block)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(int x, int y, int z) {
|
||||
return transformFast(super.getLazyBlock(getPos(x, y, z)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(Vector position) {
|
||||
return transformFast(super.getLazyBlock(getPos(position)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlock(Vector position) {
|
||||
return transformFast(super.getBlock(getPos(position)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBiome getBiome(Vector2D position) {
|
||||
mutable.x = position.getBlockX();
|
||||
mutable.z = position.getBlockZ();
|
||||
mutable.y = 0;
|
||||
return super.getBiome(getPos(mutable).toVector2D());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
|
||||
return super.setBlock(getPos(x, y, z), transformFastInverse(block));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException {
|
||||
return super.setBlock(getPos(location), transformFastInverse(block));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(Vector2D position, BaseBiome biome) {
|
||||
mutable.x = position.getBlockX();
|
||||
mutable.z = position.getBlockZ();
|
||||
mutable.y = 0;
|
||||
return super.setBiome(getPos(mutable).toVector2D(), biome);
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.boydti.fawe.object.extent;
|
||||
|
||||
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.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
|
||||
public class BlockTranslateExtent extends AbstractDelegateExtent {
|
||||
private final int dx,dy,dz;
|
||||
private final Extent extent;
|
||||
private Vector mutable = new Vector();
|
||||
|
||||
public BlockTranslateExtent(Extent extent, int dx, int dy, int dz) {
|
||||
super(extent);
|
||||
this.dx = dx;
|
||||
this.dy = dy;
|
||||
this.dz = dz;
|
||||
this.extent = extent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException {
|
||||
mutable.x = location.x + dx;
|
||||
mutable.y = location.y + dy;
|
||||
mutable.z = location.z + dz;
|
||||
return extent.setBlock(mutable, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
|
||||
mutable.x = x + dx;
|
||||
mutable.y = y + dy;
|
||||
mutable.z = z + dz;
|
||||
return extent.setBlock(mutable, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(Vector2D position, BaseBiome biome) {
|
||||
return super.setBiome(position.add(dx, dz), biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBiome getBiome(Vector2D position) {
|
||||
return super.getBiome(position.add(dx, dz));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlock(Vector location) {
|
||||
return getLazyBlock((int) location.x, (int) location.y, (int) location.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(Vector location) {
|
||||
return getLazyBlock((int) location.x, (int) location.y, (int) location.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(int x, int y, int z) {
|
||||
return super.getLazyBlock(x + dx, y + dy, z + dz);
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.boydti.fawe.object.extent;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
|
||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class ClipboardExtent extends ResettableExtent {
|
||||
|
||||
private final Clipboard clipboard;
|
||||
private final Vector origin;
|
||||
private final boolean ignoreAir;
|
||||
private Extent extent;
|
||||
|
||||
private final Vector mutable = new Vector();
|
||||
|
||||
public ClipboardExtent(Extent parent, Clipboard clipboard, boolean ignoreAir) {
|
||||
super(parent);
|
||||
checkNotNull(clipboard);
|
||||
this.extent = parent;
|
||||
this.clipboard = clipboard;
|
||||
this.origin = clipboard.getOrigin();
|
||||
this.ignoreAir = ignoreAir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(Vector to, BaseBlock block) throws WorldEditException {
|
||||
Region region = clipboard.getRegion();
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, clipboard.getRegion(), clipboard.getOrigin(), extent, to);
|
||||
if (ignoreAir) {
|
||||
copy.setSourceMask(new ExistingBlockMask(clipboard));
|
||||
}
|
||||
Operations.completeLegacy(copy);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
|
||||
mutable.x = x;
|
||||
mutable.y = y;
|
||||
mutable.z = z;
|
||||
return setBlock(mutable, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResettableExtent setExtent(Extent extent) {
|
||||
this.extent = extent;
|
||||
return super.setExtent(extent);
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@ package com.boydti.fawe.object.extent;
|
||||
|
||||
import com.boydti.fawe.object.mask.CustomMask;
|
||||
import com.boydti.fawe.util.ExtentTraverser;
|
||||
import com.sk89q.worldedit.EmptyClipboardException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.factory.DefaultMaskParser;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
@ -9,11 +11,14 @@ import com.sk89q.worldedit.extension.input.NoMatchException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.NullExtent;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.ExpressionException;
|
||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -24,7 +29,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
/**
|
||||
* Parses mask input strings.
|
||||
*/
|
||||
public class DefaultTransformParser extends InputParser<TransformExtent> {
|
||||
public class DefaultTransformParser extends InputParser<ResettableExtent> {
|
||||
|
||||
public DefaultTransformParser(WorldEdit worldEdit) {
|
||||
super(worldEdit);
|
||||
@ -44,7 +49,7 @@ public class DefaultTransformParser extends InputParser<TransformExtent> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformExtent parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
public ResettableExtent parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
Extent extent = new NullExtent();
|
||||
for (String component : input.split(" ")) {
|
||||
if (component.isEmpty()) {
|
||||
@ -52,13 +57,13 @@ public class DefaultTransformParser extends InputParser<TransformExtent> {
|
||||
}
|
||||
extent = getTansformComponent(extent, component, context);
|
||||
}
|
||||
if (extent instanceof TransformExtent) {
|
||||
return (TransformExtent) extent;
|
||||
if (extent instanceof ResettableExtent) {
|
||||
return (ResettableExtent) extent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private TransformExtent getTansformComponent(Extent parent, String component, ParserContext context) throws InputParseException {
|
||||
private ResettableExtent getTansformComponent(Extent parent, String component, ParserContext context) throws InputParseException {
|
||||
final char firstChar = component.charAt(0);
|
||||
switch (firstChar) {
|
||||
case '#':
|
||||
@ -95,24 +100,41 @@ public class DefaultTransformParser extends InputParser<TransformExtent> {
|
||||
if (!rest.isEmpty()) {
|
||||
parent = parseFromInput(rest, context);
|
||||
}
|
||||
ExtentTraverser traverser = new ExtentTraverser(parent).find(AffineTransformExtent.class);
|
||||
AffineTransformExtent affine = (AffineTransformExtent) (traverser != null ? traverser.get() : null);
|
||||
ExtentTraverser traverser = new ExtentTraverser(parent).find(BlockTransformExtent.class);
|
||||
BlockTransformExtent affine = (BlockTransformExtent) (traverser != null ? traverser.get() : null);
|
||||
if (affine == null) {
|
||||
parent = affine = new AffineTransformExtent(parent, context.requireWorld().getWorldData().getBlockRegistry());
|
||||
parent = affine = new BlockTransformExtent(parent, context.requireWorld().getWorldData().getBlockRegistry());
|
||||
}
|
||||
AffineTransform transform = affine.getAffine();
|
||||
AffineTransform transform = (AffineTransform) affine.getTransform();
|
||||
transform = transform.rotateX(x);
|
||||
transform = transform.rotateY(y);
|
||||
transform = transform.rotateZ(z);
|
||||
affine.setAffine(transform);
|
||||
return (TransformExtent) parent;
|
||||
affine.setTransform(transform);
|
||||
return (ResettableExtent) parent;
|
||||
} catch (NumberFormatException | ExpressionException e) {
|
||||
throw new InputParseException("The correct format is #scale:<dx>:<dy>:<dz>");
|
||||
throw new InputParseException("The correct format is #rotate:<dx>:<dy>:<dz>");
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new NoMatchException("Unrecognized transform '" + component + "'");
|
||||
}
|
||||
} else {
|
||||
switch (component) {
|
||||
case "#clipboard": {
|
||||
LocalSession session = context.requireSession();
|
||||
if (session != null) {
|
||||
try {
|
||||
ClipboardHolder holder = session.getClipboard();
|
||||
Clipboard clipboard = holder.getClipboard();
|
||||
return new ClipboardExtent(parent, clipboard, true);
|
||||
} catch (EmptyClipboardException e) {
|
||||
throw new InputParseException("To use #clipboard, please first copy something to your clipboard");
|
||||
}
|
||||
} else {
|
||||
throw new InputParseException("No session is available, so no clipboard is available");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new NoMatchException("Unrecognized transform '" + component + "'");
|
||||
|
@ -0,0 +1,69 @@
|
||||
package com.boydti.fawe.object.extent;
|
||||
|
||||
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.Extent;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class EmptyExtent implements Extent {
|
||||
public EmptyExtent() {
|
||||
}
|
||||
|
||||
public Vector getMinimumPoint() {
|
||||
return Vector.ZERO;
|
||||
}
|
||||
|
||||
public Vector getMaximumPoint() {
|
||||
return Vector.ZERO;
|
||||
}
|
||||
|
||||
public List<Entity> getEntities(Region region) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public List<Entity> getEntities() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Entity createEntity(Location location, BaseEntity entity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public BaseBlock getBlock(Vector position) {
|
||||
return EditSession.nullBlock;
|
||||
}
|
||||
|
||||
public BaseBlock getLazyBlock(Vector position) {
|
||||
return EditSession.nullBlock;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BaseBiome getBiome(Vector2D position) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean setBlock(Vector position, BaseBlock block) throws WorldEditException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean setBiome(Vector2D position, BaseBiome biome) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Operation commit() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
|
||||
public class PatternTransform extends TransformExtent {
|
||||
public class PatternTransform extends ResettableExtent {
|
||||
private final Pattern pattern;
|
||||
|
||||
public PatternTransform(Extent parent, Pattern pattern) {
|
||||
|
@ -0,0 +1,24 @@
|
||||
package com.boydti.fawe.object.extent;
|
||||
|
||||
import com.boydti.fawe.util.ExtentTraverser;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class ResettableExtent extends AbstractDelegateExtent {
|
||||
public ResettableExtent(Extent parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
public ResettableExtent setExtent(Extent extent) {
|
||||
checkNotNull(extent);
|
||||
if (getExtent() instanceof ResettableExtent) {
|
||||
((ResettableExtent) getExtent()).setExtent(extent);
|
||||
} else {
|
||||
new ExtentTraverser(this).setNext(extent);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ScaleTransform extends TransformExtent {
|
||||
public class ScaleTransform extends ResettableExtent {
|
||||
private final Vector mutable = new Vector();
|
||||
private final double dx,dy,dz;
|
||||
private int maxy;
|
||||
@ -27,7 +27,7 @@ public class ScaleTransform extends TransformExtent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformExtent setExtent(Extent extent) {
|
||||
public ResettableExtent setExtent(Extent extent) {
|
||||
min = null;
|
||||
maxy = extent.getMaximumPoint().getBlockY();
|
||||
return super.setExtent(extent);
|
||||
|
@ -1,24 +1,103 @@
|
||||
package com.boydti.fawe.object.extent;
|
||||
|
||||
import com.boydti.fawe.util.ExtentTraverser;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
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.extent.transform.BlockTransformExtent;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import com.sk89q.worldedit.world.registry.BlockRegistry;
|
||||
|
||||
public class TransformExtent extends BlockTransformExtent {
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
private final Vector mutable = new Vector();
|
||||
private Vector min;
|
||||
private int maxy;
|
||||
|
||||
public class TransformExtent extends AbstractDelegateExtent {
|
||||
public TransformExtent(Extent parent) {
|
||||
super(parent);
|
||||
public TransformExtent(Extent parent, BlockRegistry registry) {
|
||||
super(parent, registry);
|
||||
this.maxy = parent.getMaximumPoint().getBlockY();
|
||||
}
|
||||
|
||||
public TransformExtent setExtent(Extent extent) {
|
||||
checkNotNull(extent);
|
||||
if (getExtent() instanceof TransformExtent) {
|
||||
((TransformExtent) getExtent()).setExtent(extent);
|
||||
} else {
|
||||
new ExtentTraverser(this).setNext(extent);
|
||||
@Override
|
||||
public ResettableExtent setExtent(Extent extent) {
|
||||
min = null;
|
||||
maxy = extent.getMaximumPoint().getBlockY();
|
||||
return super.setExtent(extent);
|
||||
}
|
||||
|
||||
public void setOrigin(Vector pos) {
|
||||
this.min = pos;
|
||||
}
|
||||
|
||||
private Vector getPos(Vector pos) {
|
||||
if (min == null) {
|
||||
min = new Vector(pos);
|
||||
}
|
||||
return this;
|
||||
mutable.x = (pos.x - min.x);
|
||||
mutable.y = (pos.y - min.y);
|
||||
mutable.z = (pos.z - min.z);
|
||||
Vector tmp = getTransform().apply(mutable);
|
||||
tmp.x += min.x;
|
||||
tmp.y += min.y;
|
||||
tmp.z += min.z;
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector getPos(int x, int y, int z) {
|
||||
if (min == null) {
|
||||
min = new Vector(x, y, z);
|
||||
}
|
||||
mutable.x = (x - min.x);
|
||||
mutable.y = (y - min.y);
|
||||
mutable.z = (z - min.z);
|
||||
Vector tmp = getTransform().apply(mutable);
|
||||
tmp.x += min.x;
|
||||
tmp.y += min.y;
|
||||
tmp.z += min.z;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(int x, int y, int z) {
|
||||
return transformFast(super.getLazyBlock(getPos(x, y, z)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(Vector position) {
|
||||
return transformFast(super.getLazyBlock(getPos(position)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlock(Vector position) {
|
||||
return transformFast(super.getBlock(getPos(position)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBiome getBiome(Vector2D position) {
|
||||
mutable.x = position.getBlockX();
|
||||
mutable.z = position.getBlockZ();
|
||||
mutable.y = 0;
|
||||
return super.getBiome(getPos(mutable).toVector2D());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
|
||||
return super.setBlock(getPos(x, y, z), transformFastInverse(block));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException {
|
||||
return super.setBlock(getPos(location), transformFastInverse(block));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(Vector2D position, BaseBiome biome) {
|
||||
mutable.x = position.getBlockX();
|
||||
mutable.z = position.getBlockZ();
|
||||
mutable.y = 0;
|
||||
return super.setBiome(getPos(mutable).toVector2D(), biome);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
package com.boydti.fawe.object.function.block;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
|
||||
public class SimpleBlockCopy implements RegionFunction {
|
||||
|
||||
private final Extent source;
|
||||
private final Extent destination;
|
||||
|
||||
public SimpleBlockCopy(Extent source, Extent destination) {
|
||||
this.source = source;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Vector position) throws WorldEditException {
|
||||
return destination.setBlock(position, source.getBlock(position));
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.boydti.fawe.object.pattern;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
|
||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.pattern.AbstractPattern;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* A pattern that reads from {@link Clipboard}.
|
||||
*/
|
||||
public class FullClipboardPattern extends AbstractPattern {
|
||||
private final Extent extent;
|
||||
private final Clipboard clipboard;
|
||||
private final BaseBlock block;
|
||||
|
||||
private final Vector mutable = new Vector();
|
||||
|
||||
/**
|
||||
* Create a new clipboard pattern.
|
||||
*
|
||||
* @param clipboard the clipboard
|
||||
*/
|
||||
public FullClipboardPattern(Extent extent, Clipboard clipboard) {
|
||||
checkNotNull(clipboard);
|
||||
this.clipboard = clipboard;
|
||||
this.extent = extent;
|
||||
Vector origin = clipboard.getOrigin();
|
||||
block = clipboard.getBlock(origin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock apply(Vector to) {
|
||||
Region region = clipboard.getRegion();
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(clipboard, clipboard.getRegion(), clipboard.getOrigin(), extent, to);
|
||||
copy.setSourceMask(new ExistingBlockMask(clipboard));
|
||||
Operations.completeBlindly(copy);
|
||||
return block;
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ package com.boydti.fawe.regions.general.plot;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.object.clipboard.ReadOnlyClipboard;
|
||||
import com.boydti.fawe.object.io.PGZIPOutputStream;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
@ -20,15 +19,16 @@ import com.intellectualcrafters.plot.util.block.LocalBlockQueue;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.SchematicWriter;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@ -61,42 +61,7 @@ public class FaweSchematicHandler extends SchematicHandler {
|
||||
final int my = pos1.getY();
|
||||
final int mz = pos1.getZ();
|
||||
|
||||
ReadOnlyClipboard clipboard = new ReadOnlyClipboard(region) {
|
||||
@Override
|
||||
public BaseBlock getBlock(int x, int y, int z) {
|
||||
return editSession.getLazyBlock(mx + x, my + y, mz + z);
|
||||
}
|
||||
|
||||
public BaseBlock getBlockAbs(int x, int y, int z) {
|
||||
return editSession.getLazyBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities() {
|
||||
return editSession.getEntities(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(RunnableVal2<Vector, BaseBlock> task, boolean air) {
|
||||
Vector mutable = new Vector(0, 0, 0);
|
||||
for (RegionWrapper region : regions) {
|
||||
for (int z = region.minZ; z <= region.maxZ; z++) {
|
||||
mutable.z = z - region.minZ;
|
||||
for (int y = region.minY; y <= Math.min(255, region.maxY); y++) {
|
||||
mutable.y = y - region.minY;
|
||||
for (int x = region.minX; x <= region.maxX; x++) {
|
||||
mutable.x = x - region.minX;
|
||||
BaseBlock block = editSession.getLazyBlock(x, y, z);
|
||||
if (!air && block == editSession.nullBlock) {
|
||||
continue;
|
||||
}
|
||||
task.run(mutable, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
ReadOnlyClipboard clipboard = ReadOnlyClipboard.of(editSession, region);
|
||||
|
||||
Clipboard holder = new BlockArrayClipboard(region, clipboard);
|
||||
com.sk89q.jnbt.CompoundTag weTag = SchematicWriter.writeTag(holder);
|
||||
|
@ -19,6 +19,7 @@ public class SetQueue {
|
||||
* The implementation specific queue
|
||||
*/
|
||||
public static final SetQueue IMP = new SetQueue();
|
||||
private double targetTPS = 18;
|
||||
|
||||
public enum QueueStage {
|
||||
INACTIVE, ACTIVE, NONE;
|
||||
@ -52,6 +53,17 @@ public class SetQueue {
|
||||
return completer;
|
||||
}
|
||||
|
||||
public void runMiscTasks() {
|
||||
while (Fawe.get().getTimer().isAbove(targetTPS)) {
|
||||
Runnable task = tasks.poll();
|
||||
if (task != null) {
|
||||
task.run();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SetQueue() {
|
||||
tasks = new ConcurrentLinkedDeque<>();
|
||||
activeQueues = new ConcurrentLinkedDeque();
|
||||
@ -60,7 +72,7 @@ public class SetQueue {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
double targetTPS = 18 - Math.max(Settings.QUEUE.EXTRA_TIME_MS * 0.05, 0);
|
||||
targetTPS = 18 - Math.max(Settings.QUEUE.EXTRA_TIME_MS * 0.05, 0);
|
||||
do {
|
||||
Runnable task = tasks.poll();
|
||||
if (task != null) {
|
||||
|
@ -57,6 +57,10 @@ public final class NBTOutputStream implements Closeable {
|
||||
this.os = new DataOutputStream(os);
|
||||
}
|
||||
|
||||
public DataOutputStream getOutputStream() {
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a tag.
|
||||
*
|
||||
@ -70,19 +74,33 @@ public final class NBTOutputStream implements Closeable {
|
||||
checkNotNull(tag);
|
||||
|
||||
int type = NBTUtils.getTypeCode(tag.getClass());
|
||||
byte[] nameBytes = name.getBytes(NBTConstants.CHARSET);
|
||||
|
||||
os.writeByte(type);
|
||||
os.writeShort(nameBytes.length);
|
||||
os.write(nameBytes);
|
||||
|
||||
writeNamedTagName(name, type);
|
||||
if (type == NBTConstants.TYPE_END) {
|
||||
throw new IOException("Named TAG_End not permitted.");
|
||||
}
|
||||
|
||||
writeTagPayload(tag);
|
||||
}
|
||||
|
||||
public void writeNamedTagName(String name, int type) throws IOException {
|
||||
byte[] nameBytes = name.getBytes(NBTConstants.CHARSET);
|
||||
os.writeByte(type);
|
||||
os.writeShort(nameBytes.length);
|
||||
os.write(nameBytes);
|
||||
}
|
||||
|
||||
public void writeLazyCompoundTag(String name, LazyWrite next) throws IOException{
|
||||
byte[] nameBytes = name.getBytes(NBTConstants.CHARSET);
|
||||
os.writeByte(NBTConstants.TYPE_COMPOUND);
|
||||
os.writeShort(nameBytes.length);
|
||||
os.write(nameBytes);
|
||||
next.write(this);
|
||||
os.writeByte(NBTConstants.TYPE_END);
|
||||
}
|
||||
|
||||
public interface LazyWrite {
|
||||
void write(NBTOutputStream out) throws IOException;
|
||||
}
|
||||
|
||||
public void writeTag(Tag tag) throws IOException {
|
||||
int type = NBTUtils.getTypeCode(tag.getClass());
|
||||
os.writeByte(type);
|
||||
@ -183,7 +201,7 @@ public final class NBTOutputStream implements Closeable {
|
||||
for (Map.Entry<String, Tag> entry : tag.getValue().entrySet()) {
|
||||
writeNamedTag(entry.getKey(), entry.getValue());
|
||||
}
|
||||
os.writeByte((byte) 0); // end tag - better way?
|
||||
os.writeByte(NBTConstants.TYPE_END); // end tag - better way?
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,8 +46,8 @@ import com.boydti.fawe.object.extent.FastWorldEditExtent;
|
||||
import com.boydti.fawe.object.extent.FaweRegionExtent;
|
||||
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.SlowExtent;
|
||||
import com.boydti.fawe.object.extent.TransformExtent;
|
||||
import com.boydti.fawe.object.mask.ResettableMask;
|
||||
import com.boydti.fawe.object.progress.DefaultProgressTracker;
|
||||
import com.boydti.fawe.util.ExtentTraverser;
|
||||
@ -584,11 +584,11 @@ public class EditSession extends AbstractWorld implements HasFaweQueue {
|
||||
return maskingExtent != null ? maskingExtent.get().getMask() : null;
|
||||
}
|
||||
|
||||
public void addTransform(TransformExtent transform) {
|
||||
public void addTransform(ResettableExtent transform) {
|
||||
if (transform == null) {
|
||||
ExtentTraverser<AbstractDelegateExtent> traverser = new ExtentTraverser(this.extent).find(TransformExtent.class);
|
||||
ExtentTraverser<AbstractDelegateExtent> traverser = new ExtentTraverser(this.extent).find(ResettableExtent.class);
|
||||
AbstractDelegateExtent next = extent;
|
||||
while (traverser != null && traverser.get() instanceof TransformExtent) {
|
||||
while (traverser != null && traverser.get() instanceof ResettableExtent) {
|
||||
traverser = traverser.next();
|
||||
next = traverser.get();
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ import com.boydti.fawe.object.brush.DoubleActionBrushTool;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
|
||||
import com.boydti.fawe.object.extent.TransformExtent;
|
||||
import com.boydti.fawe.object.extent.ResettableExtent;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.wrappers.WorldWrapper;
|
||||
@ -139,7 +139,7 @@ public class LocalSession {
|
||||
private transient int cuiVersion = -1;
|
||||
private transient boolean fastMode = false;
|
||||
private transient Mask mask;
|
||||
private TransformExtent transform = null;
|
||||
private ResettableExtent transform = null;
|
||||
private transient TimeZone timezone = TimeZone.getDefault();
|
||||
|
||||
private transient World currentWorld;
|
||||
@ -1270,11 +1270,11 @@ public class LocalSession {
|
||||
setMask(mask != null ? Masks.wrap(mask) : null);
|
||||
}
|
||||
|
||||
public TransformExtent getTransform() {
|
||||
public ResettableExtent getTransform() {
|
||||
return transform;
|
||||
}
|
||||
|
||||
public void setTransform(TransformExtent transform) {
|
||||
public void setTransform(ResettableExtent transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
||||
import com.sk89q.worldedit.function.block.BlockReplace;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.Masks;
|
||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
@ -64,7 +65,6 @@ import com.sk89q.worldedit.util.command.parametric.Optional;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
@ -110,37 +110,7 @@ public class ClipboardCommands {
|
||||
final int mx = origin.getBlockX();
|
||||
final int my = origin.getBlockY();
|
||||
final int mz = origin.getBlockZ();
|
||||
ReadOnlyClipboard lazyClipboard = new ReadOnlyClipboard(region) {
|
||||
@Override
|
||||
public BaseBlock getBlock(int x, int y, int z) {
|
||||
return editSession.getLazyBlock(mx + x, my + y, mz + z);
|
||||
}
|
||||
|
||||
public BaseBlock getBlockAbs(int x, int y, int z) {
|
||||
return editSession.getLazyBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities() {
|
||||
return editSession.getEntities(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(RunnableVal2<Vector, BaseBlock> task, boolean air) {
|
||||
Iterator<BlockVector> iter = region.iterator();
|
||||
while (iter.hasNext()) {
|
||||
BlockVector pos = iter.next();
|
||||
BaseBlock block = getBlockAbs((int) pos.x, (int) pos.y, (int) pos.z);
|
||||
if (!air && block == EditSession.nullBlock) {
|
||||
continue;
|
||||
}
|
||||
pos.x -= mx;
|
||||
pos.y -= my;
|
||||
pos.z -= mz;
|
||||
task.run(pos, block);
|
||||
}
|
||||
}
|
||||
};
|
||||
ReadOnlyClipboard lazyClipboard = ReadOnlyClipboard.of(editSession, region);
|
||||
|
||||
BlockArrayClipboard clipboard = new BlockArrayClipboard(region, lazyClipboard);
|
||||
clipboard.setOrigin(session.getPlacementPosition(player));
|
||||
@ -171,7 +141,7 @@ public class ClipboardCommands {
|
||||
|
||||
clipboard.setOrigin(session.getPlacementPosition(player));
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
|
||||
if (mask != null) {
|
||||
if (mask != null && mask != Masks.alwaysTrue()) {
|
||||
copy.setSourceMask(mask);
|
||||
}
|
||||
Operations.completeLegacy(copy);
|
||||
|
@ -2,7 +2,7 @@ package com.sk89q.worldedit.command;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.extent.DefaultTransformParser;
|
||||
import com.boydti.fawe.object.extent.TransformExtent;
|
||||
import com.boydti.fawe.object.extent.ResettableExtent;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||
@ -142,7 +142,7 @@ public class GeneralCommands {
|
||||
parserContext.setWorld(player.getWorld());
|
||||
parserContext.setSession(session);
|
||||
parserContext.setExtent(editSession);
|
||||
TransformExtent transform = transformParser.parseFromInput(context.getJoinedStrings(0), parserContext);
|
||||
ResettableExtent transform = transformParser.parseFromInput(context.getJoinedStrings(0), parserContext);
|
||||
session.setTransform(transform);
|
||||
BBC.TRANSFORM.send(player);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package com.sk89q.worldedit.command;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.brush.DoubleActionBrushTool;
|
||||
import com.boydti.fawe.object.extent.DefaultTransformParser;
|
||||
import com.boydti.fawe.object.extent.TransformExtent;
|
||||
import com.boydti.fawe.object.extent.ResettableExtent;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||
@ -122,7 +122,7 @@ public class ToolUtilCommands {
|
||||
parserContext.setWorld(player.getWorld());
|
||||
parserContext.setSession(session);
|
||||
parserContext.setExtent(editSession);
|
||||
TransformExtent transform = transformParser.parseFromInput(context.getJoinedStrings(0), parserContext);
|
||||
ResettableExtent transform = transformParser.parseFromInput(context.getJoinedStrings(0), parserContext);
|
||||
if (tool instanceof BrushTool) {
|
||||
((BrushTool) tool).setTransform(transform);
|
||||
} else if (tool instanceof DoubleActionBrushTool) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.sk89q.worldedit.command.tool;
|
||||
|
||||
import com.boydti.fawe.object.extent.TransformExtent;
|
||||
import com.boydti.fawe.object.extent.ResettableExtent;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.LocalConfiguration;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
@ -29,7 +29,7 @@ public class BrushTool implements TraceTool {
|
||||
protected static int MAX_RANGE = 500;
|
||||
protected int range = -1;
|
||||
private Mask mask = null;
|
||||
private TransformExtent transform = null;
|
||||
private ResettableExtent transform = null;
|
||||
private Brush brush = new SphereBrush();
|
||||
@Nullable
|
||||
private Pattern material;
|
||||
@ -51,11 +51,11 @@ public class BrushTool implements TraceTool {
|
||||
return player.hasPermission(permission);
|
||||
}
|
||||
|
||||
public TransformExtent getTransform() {
|
||||
public ResettableExtent getTransform() {
|
||||
return transform;
|
||||
}
|
||||
|
||||
public void setTransform(TransformExtent transform) {
|
||||
public void setTransform(ResettableExtent transform) {
|
||||
this.transform = transform;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,21 @@ public class HashTagPatternParser extends InputParser<Pattern> {
|
||||
switch (input) {
|
||||
case "#*":
|
||||
case "#existing": {
|
||||
return new ExistingPattern(context.requireExtent());
|
||||
return new ExistingPattern(Request.request().getEditSession());
|
||||
}
|
||||
case "#fullcopy": {
|
||||
LocalSession session = context.requireSession();
|
||||
if (session != null) {
|
||||
try {
|
||||
ClipboardHolder holder = session.getClipboard();
|
||||
Clipboard clipboard = holder.getClipboard();
|
||||
return new FullClipboardPattern(Request.request().getEditSession(), clipboard);
|
||||
} catch (EmptyClipboardException e) {
|
||||
throw new InputParseException("To use #fullcopy, please first copy something to your clipboard");
|
||||
}
|
||||
} else {
|
||||
throw new InputParseException("No session is available, so no clipboard is available");
|
||||
}
|
||||
}
|
||||
case "#clipboard":
|
||||
case "#copy": {
|
||||
@ -80,10 +94,10 @@ public class HashTagPatternParser extends InputParser<Pattern> {
|
||||
String rest = input.substring(split2[0].length() + 1);
|
||||
switch (split2[0].toLowerCase()) {
|
||||
case "#id": {
|
||||
return new IdPattern(context.requireExtent(), parseFromInput(rest, context));
|
||||
return new IdPattern(Request.request().getEditSession(), parseFromInput(rest, context));
|
||||
}
|
||||
case "#data": {
|
||||
return new DataPattern(context.requireExtent(), parseFromInput(rest, context));
|
||||
return new DataPattern(Request.request().getEditSession(), parseFromInput(rest, context));
|
||||
}
|
||||
case "#~":
|
||||
case "#r":
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.sk89q.worldedit.extent.clipboard.io;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.jnbt.NBTStreamer;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.object.clipboard.FaweClipboard;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
@ -10,6 +11,7 @@ import com.sk89q.jnbt.DoubleTag;
|
||||
import com.sk89q.jnbt.FloatTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.NBTConstants;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.jnbt.ShortTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
@ -23,11 +25,13 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
@ -106,8 +110,122 @@ public class SchematicWriter implements ClipboardWriter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Clipboard clipboard, WorldData data) throws IOException {
|
||||
outputStream.writeNamedTag("Schematic", writeTag(clipboard));
|
||||
public void write(final Clipboard clipboard, WorldData data) throws IOException {
|
||||
if (clipboard instanceof BlockArrayClipboard) {
|
||||
stream((BlockArrayClipboard) clipboard);
|
||||
} else {
|
||||
outputStream.writeNamedTag("Schematic", writeTag(clipboard));
|
||||
outputStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public void stream(final BlockArrayClipboard clipboard) throws IOException {
|
||||
final Region region = clipboard.getRegion();
|
||||
final Vector origin = clipboard.getOrigin();
|
||||
final Vector min = region.getMinimumPoint();
|
||||
final Vector offset = min.subtract(origin);
|
||||
final int width = region.getWidth();
|
||||
final int height = region.getHeight();
|
||||
final int length = region.getLength();
|
||||
if (width > MAX_SIZE) {
|
||||
throw new IllegalArgumentException("Width of region too large for a .schematic");
|
||||
}
|
||||
if (height > MAX_SIZE) {
|
||||
throw new IllegalArgumentException("Height of region too large for a .schematic");
|
||||
}
|
||||
if (length > MAX_SIZE) {
|
||||
throw new IllegalArgumentException("Length of region too large for a .schematic");
|
||||
}
|
||||
final DataOutputStream rawStream = outputStream.getOutputStream();
|
||||
outputStream.writeLazyCompoundTag("Schematic", new NBTOutputStream.LazyWrite() {
|
||||
@Override
|
||||
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.writeNamedTagName("Data", NBTConstants.TYPE_BYTE_ARRAY);
|
||||
out.getOutputStream().writeInt(volume);
|
||||
clipboard.IMP.streamDatas(new NBTStreamer.ByteReader() {
|
||||
@Override
|
||||
public void run(int index, int byteValue) {
|
||||
try {
|
||||
rawStream.writeByte(byteValue);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
out.writeNamedTagName("Blocks", NBTConstants.TYPE_BYTE_ARRAY);
|
||||
out.getOutputStream().writeInt(volume);
|
||||
final AtomicBoolean hasAdd = new AtomicBoolean(false);
|
||||
clipboard.IMP.streamIds(new NBTStreamer.ByteReader() {
|
||||
@Override
|
||||
public void run(int index, int byteValue) {
|
||||
try {
|
||||
if (byteValue >= 256) {
|
||||
hasAdd.set(true);
|
||||
}
|
||||
rawStream.writeByte(byteValue);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (hasAdd.get()) {
|
||||
out.writeNamedTagName("AddBlocks", NBTConstants.TYPE_BYTE_ARRAY);
|
||||
out.getOutputStream().writeInt(volume);
|
||||
clipboard.IMP.streamIds(new NBTStreamer.ByteReader() {
|
||||
@Override
|
||||
public void run(int index, int byteValue) {
|
||||
try {
|
||||
rawStream.writeByte(byteValue >> 8);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final List<CompoundTag> tileEntities = clipboard.IMP.getTileEntities();
|
||||
out.writeNamedTag("TileEntities", new ListTag(CompoundTag.class, tileEntities));
|
||||
|
||||
List<Tag> entities = new ArrayList<Tag>();
|
||||
for (Entity entity : clipboard.getEntities()) {
|
||||
BaseEntity state = entity.getState();
|
||||
|
||||
if (state != null) {
|
||||
Map<String, Tag> values = new HashMap<String, Tag>();
|
||||
|
||||
// Put NBT provided data
|
||||
CompoundTag rawTag = state.getNbtData();
|
||||
if (rawTag != null) {
|
||||
values.putAll(rawTag.getValue());
|
||||
}
|
||||
|
||||
// Store our location data, overwriting any
|
||||
values.put("id", new StringTag(state.getTypeId()));
|
||||
values.put("Pos", writeVector(entity.getLocation().toVector(), "Pos"));
|
||||
values.put("Rotation", writeRotation(entity.getLocation(), "Rotation"));
|
||||
|
||||
CompoundTag entityTag = new CompoundTag(values);
|
||||
entities.add(entityTag);
|
||||
}
|
||||
}
|
||||
out.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
|
||||
}
|
||||
});
|
||||
outputStream.flush();
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,16 @@
|
||||
package com.sk89q.worldedit.extent.transform;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.extent.ResettableExtent;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
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.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import com.sk89q.worldedit.world.registry.BlockRegistry;
|
||||
import com.sk89q.worldedit.world.registry.State;
|
||||
import com.sk89q.worldedit.world.registry.StateValue;
|
||||
@ -20,51 +24,113 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
* Transforms blocks themselves (but not their position) according to a
|
||||
* given transform.
|
||||
*/
|
||||
public class BlockTransformExtent extends AbstractDelegateExtent {
|
||||
public class BlockTransformExtent extends ResettableExtent {
|
||||
private final BlockRegistry registry;
|
||||
private Transform transform;
|
||||
private Transform transformInverse;
|
||||
private BaseBlock[] BLOCK_TRANSFORM;
|
||||
private BaseBlock[] BLOCK_TRANSFORM_INVERSE;
|
||||
|
||||
private static final double RIGHT_ANGLE = Math.toRadians(90);
|
||||
public BlockTransformExtent(Extent parent, BlockRegistry registry) {
|
||||
this(parent, new AffineTransform(), registry);
|
||||
}
|
||||
|
||||
private final Transform transform;
|
||||
private final BlockRegistry blockRegistry;
|
||||
private final BaseBlock[] BLOCK_TRANSFORM;
|
||||
private final BaseBlock[] BLOCK_TRANSFORM_INVERSE;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param extent the extent
|
||||
* @param blockRegistry the block registry used for block direction data
|
||||
*/
|
||||
public BlockTransformExtent(Extent extent, Transform transform, BlockRegistry blockRegistry) {
|
||||
super(extent);
|
||||
checkNotNull(transform);
|
||||
checkNotNull(blockRegistry);
|
||||
public BlockTransformExtent(Extent parent, Transform transform, BlockRegistry registry) {
|
||||
super(parent);
|
||||
this.transform = transform;
|
||||
this.blockRegistry = blockRegistry;
|
||||
this.transformInverse = this.transform.inverse();
|
||||
this.registry = registry;
|
||||
cache();
|
||||
}
|
||||
|
||||
private void cache() {
|
||||
BLOCK_TRANSFORM = new BaseBlock[FaweCache.CACHE_BLOCK.length];
|
||||
BLOCK_TRANSFORM_INVERSE = new BaseBlock[FaweCache.CACHE_BLOCK.length];
|
||||
Transform inverse = transform.inverse();
|
||||
for (int i = 0; i < BLOCK_TRANSFORM.length; i++) {
|
||||
BaseBlock block = FaweCache.CACHE_BLOCK[i];
|
||||
if (block != null) {
|
||||
BLOCK_TRANSFORM[i] = transform(new BaseBlock(block), transform, blockRegistry);
|
||||
BLOCK_TRANSFORM_INVERSE[i] = transform(new BaseBlock(block), inverse, blockRegistry);
|
||||
BLOCK_TRANSFORM[i] = BlockTransformExtent.transform(new BaseBlock(block), transform, registry);
|
||||
BLOCK_TRANSFORM_INVERSE[i] = BlockTransformExtent.transform(new BaseBlock(block), transformInverse, registry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the transform.
|
||||
*
|
||||
* @return the transform
|
||||
*/
|
||||
@Override
|
||||
public ResettableExtent setExtent(Extent extent) {
|
||||
return super.setExtent(extent);
|
||||
}
|
||||
|
||||
public Transform getTransform() {
|
||||
return transform;
|
||||
}
|
||||
|
||||
public void setTransform(Transform affine) {
|
||||
this.transform = affine;
|
||||
this.transformInverse = this.transform.inverse();
|
||||
cache();
|
||||
}
|
||||
|
||||
public final BaseBlock transformFast(BaseBlock block) {
|
||||
BaseBlock newBlock = BLOCK_TRANSFORM[FaweCache.getCombined(block)];
|
||||
CompoundTag tag = block.getNbtData();
|
||||
if (tag != null) {
|
||||
newBlock = new BaseBlock(newBlock.getId(), newBlock.getData(), tag);
|
||||
// if (tag.containsKey("Rot")) {
|
||||
// int rot = tag.asInt("Rot");
|
||||
//
|
||||
// Direction direction = MCDirections.fromRotation(rot);
|
||||
//
|
||||
// if (direction != null) {
|
||||
// Vector applyAbsolute = transform.apply(direction.toVector());
|
||||
// Vector applyOrigin = transform.apply(Vector.ZERO);
|
||||
// applyAbsolute.x -= applyOrigin.x;
|
||||
// applyAbsolute.y -= applyOrigin.y;
|
||||
// applyAbsolute.z -= applyOrigin.z;
|
||||
//
|
||||
// Direction newDirection = Direction.findClosest(applyAbsolute, Direction.Flag.CARDINAL | Direction.Flag.ORDINAL | Direction.Flag.SECONDARY_ORDINAL);
|
||||
//
|
||||
// if (newDirection != null) {
|
||||
// Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
// values.put("Rot", new ByteTag((byte) MCDirections.toRotation(newDirection)));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
return newBlock;
|
||||
}
|
||||
|
||||
public final BaseBlock transformFastInverse(BaseBlock block) {
|
||||
BaseBlock newBlock = BLOCK_TRANSFORM_INVERSE[FaweCache.getCombined(block)];
|
||||
CompoundTag tag = block.getNbtData();
|
||||
if (tag != null) {
|
||||
newBlock = new BaseBlock(newBlock.getId(), newBlock.getData(), tag);
|
||||
// if (tag.containsKey("Rot")) {
|
||||
// int rot = tag.asInt("Rot");
|
||||
//
|
||||
// Direction direction = MCDirections.fromRotation(rot);
|
||||
//
|
||||
// if (direction != null) {
|
||||
// Vector applyAbsolute = transformInverse.apply(direction.toVector());
|
||||
// Vector applyOrigin = transformInverse.apply(Vector.ZERO);
|
||||
// applyAbsolute.x -= applyOrigin.x;
|
||||
// applyAbsolute.y -= applyOrigin.y;
|
||||
// applyAbsolute.z -= applyOrigin.z;
|
||||
//
|
||||
// Direction newDirection = Direction.findClosest(applyAbsolute, Direction.Flag.CARDINAL | Direction.Flag.ORDINAL | Direction.Flag.SECONDARY_ORDINAL);
|
||||
//
|
||||
// if (newDirection != null) {
|
||||
// Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
// values.put("Rot", new ByteTag((byte) MCDirections.toRotation(newDirection)));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
return newBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlock(Vector position) {
|
||||
return transformFast(super.getBlock(position));
|
||||
public BaseBlock getLazyBlock(int x, int y, int z) {
|
||||
return transformFast(super.getLazyBlock(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -72,25 +138,30 @@ public class BlockTransformExtent extends AbstractDelegateExtent {
|
||||
return transformFast(super.getLazyBlock(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlock(Vector position) {
|
||||
return transformFast(super.getBlock(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBiome getBiome(Vector2D position) {
|
||||
return super.getBiome(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
|
||||
return super.setBlock(x, y, z, transformFastInverse(block));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException {
|
||||
return super.setBlock(location, transformFastInverse(block));
|
||||
}
|
||||
|
||||
private final BaseBlock transformFast(BaseBlock block) {
|
||||
BaseBlock newBlock = BLOCK_TRANSFORM[FaweCache.getCombined(block)];
|
||||
if (block.hasNbtData()) {
|
||||
newBlock.setNbtData(block.getNbtData());
|
||||
}
|
||||
return newBlock;
|
||||
}
|
||||
|
||||
private final BaseBlock transformFastInverse(BaseBlock block) {
|
||||
BaseBlock newBlock = BLOCK_TRANSFORM_INVERSE[FaweCache.getCombined(block)];
|
||||
if (block.hasNbtData()) {
|
||||
newBlock.setNbtData(block.getNbtData());
|
||||
}
|
||||
return newBlock;
|
||||
@Override
|
||||
public boolean setBiome(Vector2D position, BaseBiome biome) {
|
||||
return super.setBiome(position, biome);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.sk89q.worldedit.function.block;
|
||||
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.ByteTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.internal.helper.MCDirections;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.util.Direction.Flag;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Copies blocks from one extent to another.
|
||||
*/
|
||||
public class ExtentBlockCopy implements RegionFunction {
|
||||
|
||||
private final Extent source;
|
||||
private final Extent destination;
|
||||
private final Vector from;
|
||||
private final Vector to;
|
||||
private final Transform transform;
|
||||
|
||||
/**
|
||||
* Make a new copy.
|
||||
*
|
||||
* @param source the source extent
|
||||
* @param from the source offset
|
||||
* @param destination the destination extent
|
||||
* @param to the destination offset
|
||||
* @param transform a transform to apply to positions (after source offset, before destination offset)
|
||||
*/
|
||||
public ExtentBlockCopy(Extent source, Vector from, Extent destination, Vector to, Transform transform) {
|
||||
checkNotNull(source);
|
||||
checkNotNull(from);
|
||||
checkNotNull(destination);
|
||||
checkNotNull(to);
|
||||
checkNotNull(transform);
|
||||
this.source = source;
|
||||
this.from = from;
|
||||
this.destination = destination;
|
||||
this.to = to;
|
||||
this.transform = transform;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Vector position) throws WorldEditException {
|
||||
BaseBlock block = source.getBlock(position);
|
||||
Vector orig = position.subtract(from);
|
||||
Vector transformed = transform.apply(orig);
|
||||
|
||||
// Apply transformations to NBT data if necessary
|
||||
block = transformNbtData(block);
|
||||
|
||||
return destination.setBlock(transformed.add(to), block);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform NBT data in the given block state and return a new instance
|
||||
* if the NBT data needs to be transformed.
|
||||
*
|
||||
* @param state the existing state
|
||||
* @return a new state or the existing one
|
||||
*/
|
||||
private BaseBlock transformNbtData(BaseBlock state) {
|
||||
CompoundTag tag = state.getNbtData();
|
||||
if (tag != null) {
|
||||
// Handle blocks which store their rotation in NBT
|
||||
if (tag.containsKey("Rot")) {
|
||||
int rot = tag.asInt("Rot");
|
||||
|
||||
Direction direction = MCDirections.fromRotation(rot);
|
||||
|
||||
if (direction != null) {
|
||||
Vector applyAbsolute = transform.apply(direction.toVector());
|
||||
Vector applyOrigin = transform.apply(Vector.ZERO);
|
||||
applyAbsolute.x -= applyOrigin.x;
|
||||
applyAbsolute.y -= applyOrigin.y;
|
||||
applyAbsolute.z -= applyOrigin.z;
|
||||
|
||||
Direction newDirection = Direction.findClosest(applyAbsolute, Flag.CARDINAL | Flag.ORDINAL | Flag.SECONDARY_ORDINAL);
|
||||
|
||||
if (newDirection != null) {
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
values.put("Rot", new ByteTag((byte) MCDirections.toRotation(newDirection)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
}
|
@ -19,14 +19,17 @@
|
||||
|
||||
package com.sk89q.worldedit.function.operation;
|
||||
|
||||
import com.boydti.fawe.object.extent.BlockTranslateExtent;
|
||||
import com.boydti.fawe.object.extent.TransformExtent;
|
||||
import com.boydti.fawe.object.function.block.SimpleBlockCopy;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.CombinedRegionFunction;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.RegionMaskingFilter;
|
||||
import com.sk89q.worldedit.function.block.ExtentBlockCopy;
|
||||
import com.sk89q.worldedit.function.entity.ExtentEntityCopy;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.Masks;
|
||||
@ -35,9 +38,12 @@ import com.sk89q.worldedit.function.visitor.RegionVisitor;
|
||||
import com.sk89q.worldedit.math.transform.Identity;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.registry.BlockRegistry;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -215,22 +221,53 @@ public class ForwardExtentCopy implements Operation {
|
||||
currentTransform = transform;
|
||||
}
|
||||
|
||||
Extent finalDest = destination;
|
||||
TransformExtent transExt;
|
||||
if (!currentTransform.isIdentity()) {
|
||||
WorldData wd;
|
||||
if (destination instanceof World) {
|
||||
wd = ((World) destination).getWorldData();
|
||||
} else if (source instanceof World) {
|
||||
wd = ((World) source).getWorldData();
|
||||
} else {
|
||||
wd = WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData();
|
||||
}
|
||||
BlockRegistry registry = wd.getBlockRegistry();
|
||||
transExt = new TransformExtent(finalDest, registry);
|
||||
transExt.setTransform(currentTransform);
|
||||
transExt.setOrigin(from);
|
||||
finalDest = transExt;
|
||||
} else {
|
||||
transExt = null;
|
||||
}
|
||||
Vector translation = to.subtract(from);
|
||||
if (!translation.equals(Vector.ZERO)) {
|
||||
finalDest = new BlockTranslateExtent(finalDest, translation.getBlockX(), translation.getBlockY(), translation.getBlockZ());
|
||||
}
|
||||
RegionFunction copy = new SimpleBlockCopy(source, finalDest);
|
||||
if (sourceMask != Masks.alwaysTrue()) {
|
||||
copy = new RegionMaskingFilter(sourceMask, copy);
|
||||
}
|
||||
if (sourceFunction != null) {
|
||||
copy = new CombinedRegionFunction(copy, sourceFunction);
|
||||
}
|
||||
RegionVisitor blockVisitor = new RegionVisitor(region, copy);
|
||||
|
||||
List<? extends Entity> entities = source.getEntities(region);
|
||||
|
||||
for (int i = 0; i < repetitions; i++) {
|
||||
ExtentBlockCopy blockCopy = new ExtentBlockCopy(source, from, destination, to, currentTransform);
|
||||
RegionMaskingFilter filter = new RegionMaskingFilter(sourceMask, blockCopy);
|
||||
RegionFunction function = sourceFunction != null ? new CombinedRegionFunction(filter, sourceFunction) : filter;
|
||||
RegionVisitor blockVisitor = new RegionVisitor(region, function);
|
||||
|
||||
ExtentEntityCopy entityCopy = new ExtentEntityCopy(from, destination, to, currentTransform);
|
||||
entityCopy.setRemoving(removingEntities);
|
||||
EntityVisitor entityVisitor = new EntityVisitor(entities.iterator(), entityCopy);
|
||||
|
||||
currentTransform = currentTransform.combine(transform);
|
||||
Operations.completeBlindly(blockVisitor);
|
||||
Operations.completeBlindly(entityVisitor);
|
||||
|
||||
if (transExt != null) {
|
||||
currentTransform = currentTransform.combine(transform);
|
||||
transExt.setTransform(currentTransform);
|
||||
}
|
||||
|
||||
affected += blockVisitor.getAffected();
|
||||
}
|
||||
return null;
|
||||
|
Loading…
Reference in New Issue
Block a user