mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-11-24 11:36:52 +01:00
Various
Update to PS 3.4.1 - Added various optimizations for PlotSquared - Support full schematic exporting (includes NBT now) Added compression level option: 0 is no compression 1-9 = varying levels of compression at the expense of CPU 3 = Good fast compression 5 = Good high compression 8 = Lots of compression (going further has diminishing returns) Add EditSession builder (for extra control over optimizations) Added compression option to FaweChangeSet constructor Added FAWE format (used for history / clipboard on disk) Various minor optimizations TODO bug fixes
This commit is contained in:
parent
fbb4ae9ddf
commit
9bf2d2b0c3
@ -37,7 +37,7 @@ subprojects {
|
||||
exclude(module: 'bukkit-classloader-check')
|
||||
}
|
||||
compile 'com.sk89q:worldguard:6.0.0-SNAPSHOT'
|
||||
compile 'com.intellectualcrafters.plot:plotsquared:3.3.1'
|
||||
compile 'com.plotsquared:PlotSquared:3.4.1-SNAPSHOT'
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
@ -3,6 +3,7 @@ package com.boydti.fawe.bukkit;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.FaweLocation;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.wrappers.PlayerWrapper;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Bukkit;
|
||||
@ -92,7 +93,7 @@ public class BukkitPlayer extends FawePlayer<Player> {
|
||||
|
||||
@Override
|
||||
public com.sk89q.worldedit.entity.Player getPlayer() {
|
||||
return Fawe.<FaweBukkit> imp().getWorldEditPlugin().wrapPlayer(this.parent);
|
||||
return PlayerWrapper.wrap(Fawe.<FaweBukkit> imp().getWorldEditPlugin().wrapPlayer(this.parent));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import com.boydti.fawe.util.StringMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.entity.BukkitEntity;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
|
@ -399,7 +399,7 @@ public class Sniper {
|
||||
FawePlayer<Object> fp = FawePlayer.wrap(getPlayer());
|
||||
LocalSession session = fp.getSession();
|
||||
baseQueue.enqueue();
|
||||
session.remember(changeSet.toEditSession(fp.getPlayer()));
|
||||
session.remember(changeSet.toEditSession(fp));
|
||||
changeQueue.flush();
|
||||
com.sk89q.worldedit.world.World worldEditWorld = fp.getWorld();
|
||||
changeQueue.setChangeSet(Settings.STORE_HISTORY_ON_DISK ? new DiskStorageHistory(worldEditWorld, fp.getUUID()) : new MemoryOptimizedHistory(worldEditWorld));
|
||||
|
@ -131,7 +131,7 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], DataP
|
||||
return;
|
||||
}
|
||||
HashSet<EntityTrackerEntry> entities = new HashSet<>();
|
||||
List<Entity>[] entitieSlices = playerChunk.chunk.getEntitySlices();
|
||||
List<Entity>[] entitieSlices = nmsChunk.getEntitySlices();
|
||||
for (List<Entity> slice : entitieSlices) {
|
||||
if (slice == null) {
|
||||
continue;
|
||||
@ -152,7 +152,7 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], DataP
|
||||
player.playerConnection.networkManager.a();
|
||||
}
|
||||
// Send chunks
|
||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(playerChunk.chunk, 65535);
|
||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65535);
|
||||
for (EntityPlayer player : players) {
|
||||
player.playerConnection.sendPacket(packet);
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import com.boydti.fawe.command.WorldEditRegion;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.regions.general.PlotSquaredFeature;
|
||||
import com.boydti.fawe.regions.general.plot.PlotSquaredFeature;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
@ -36,6 +36,7 @@ import com.sk89q.worldedit.extension.platform.PlatformManager;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.SchematicReader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.SchematicWriter;
|
||||
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.visitor.BreadthFirstSearch;
|
||||
@ -259,7 +260,7 @@ public class Fawe {
|
||||
HistoryCommands.inject(); // Translations
|
||||
// Schematic
|
||||
SchematicReader.inject();
|
||||
// SchematicWriter.inject(); TODO
|
||||
SchematicWriter.inject();
|
||||
ClipboardFormat.inject();
|
||||
// Brushes
|
||||
GravityBrush.inject(); // Fix for instant placement assumption
|
||||
|
@ -10,11 +10,13 @@ import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.boydti.fawe.wrappers.WorldWrapper;
|
||||
import com.sk89q.jnbt.ByteArrayTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
@ -27,6 +29,7 @@ import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
||||
import com.sk89q.worldedit.world.AbstractWorld;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@ -59,30 +62,14 @@ import org.bukkit.Location;
|
||||
* FaweAPI.[some method]
|
||||
*/
|
||||
public class FaweAPI {
|
||||
|
||||
/**
|
||||
* Get a new EditSessionfor a player<br>
|
||||
* - The EditSession can be used from another thread<br>
|
||||
* - FAWE will handle
|
||||
* @see com.boydti.fawe.object.FawePlayer#wrap(Object)
|
||||
* @param player
|
||||
* @return
|
||||
*/
|
||||
public static EditSession getNewEditSession(@Nonnull FawePlayer player) {
|
||||
if (player == null) {
|
||||
throw new IllegalArgumentException("Player may not be null");
|
||||
}
|
||||
return player.getNewEditSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new non-player EditSession
|
||||
* @see #getWorld(String)
|
||||
* Offers a lot of options for building an EditSession
|
||||
* @see com.boydti.fawe.util.EditSessionBuilder
|
||||
* @param world
|
||||
* @return
|
||||
* @return A new EditSessionBuilder
|
||||
*/
|
||||
public static EditSession getNewEditSession(World world) {
|
||||
return WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, -1);
|
||||
public static EditSessionBuilder getEditSessionBuilder(World world) {
|
||||
return new EditSessionBuilder(world);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -124,7 +111,7 @@ public class FaweAPI {
|
||||
public static World getWorld(String worldName) {
|
||||
for (World current : WorldEdit.getInstance().getServer().getWorlds()) {
|
||||
if (Fawe.imp().getWorldName(current).equals(worldName)) {
|
||||
return current;
|
||||
return WorldWrapper.wrap((AbstractWorld) current);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -325,7 +312,7 @@ public class FaweAPI {
|
||||
|
||||
/**
|
||||
* The DiskStorageHistory class is what FAWE uses to represent the undo on disk.
|
||||
* @see com.boydti.fawe.object.changeset.DiskStorageHistory#toEditSession(com.sk89q.worldedit.entity.Player)
|
||||
* @see com.boydti.fawe.object.changeset.DiskStorageHistory#toEditSession(com.boydti.fawe.object.FawePlayer)
|
||||
* @param world
|
||||
* @param uuid
|
||||
* @param index
|
||||
@ -403,6 +390,7 @@ public class FaweAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Since I haven't finished it yet
|
||||
* If a schematic is too large to be pasted normally<br>
|
||||
* - Skips any block history
|
||||
* - Ignores nbt
|
||||
@ -421,6 +409,7 @@ public class FaweAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Since I haven't finished it yet
|
||||
* If a schematic is too large to be pasted normally<br>
|
||||
* - Skips any block history
|
||||
* - Ignores some block data
|
||||
@ -449,9 +438,6 @@ public class FaweAPI {
|
||||
final int y_offset = loc.y + IntTag.class.cast(tagMap.get("WEOffsetY")).getValue();
|
||||
final int z_offset = loc.z + IntTag.class.cast(tagMap.get("WEOffsetZ")).getValue();
|
||||
|
||||
tagMap = null;
|
||||
tag = null;
|
||||
|
||||
FaweQueue queue = SetQueue.IMP.getNewQueue(loc.world, true, true);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
@ -477,9 +463,6 @@ public class FaweAPI {
|
||||
}
|
||||
|
||||
queue.enqueue();
|
||||
|
||||
ids = null;
|
||||
datas = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -513,4 +496,26 @@ public class FaweAPI {
|
||||
public static BBC[] getTranslations() {
|
||||
return BBC.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @see #getEditSessionBuilder(com.sk89q.worldedit.world.World)
|
||||
*/
|
||||
@Deprecated
|
||||
public static EditSession getNewEditSession(@Nonnull FawePlayer player) {
|
||||
if (player == null) {
|
||||
throw new IllegalArgumentException("Player may not be null");
|
||||
}
|
||||
return player.getNewEditSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @see #getEditSessionBuilder(com.sk89q.worldedit.world.World)
|
||||
*/
|
||||
@Deprecated
|
||||
public static EditSession getNewEditSession(World world) {
|
||||
return WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, -1);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,9 @@ import com.sk89q.jnbt.ByteArrayTag;
|
||||
import com.sk89q.jnbt.ByteTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.DoubleTag;
|
||||
import com.sk89q.jnbt.EndTag;
|
||||
import com.sk89q.jnbt.FloatTag;
|
||||
import com.sk89q.jnbt.IntArrayTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.LongTag;
|
||||
@ -14,6 +16,7 @@ import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.CuboidClipboard;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
@ -332,6 +335,10 @@ public class FaweCache {
|
||||
return new ByteArrayTag(value);
|
||||
}
|
||||
|
||||
public static IntArrayTag asTag(int[] value) {
|
||||
return new IntArrayTag(value);
|
||||
}
|
||||
|
||||
public static StringTag asTag(String value) {
|
||||
return new StringTag(value);
|
||||
}
|
||||
@ -369,7 +376,22 @@ public class FaweCache {
|
||||
return asTag((byte[]) value);
|
||||
} else if (value instanceof Tag) {
|
||||
return (Tag) value;
|
||||
} else if (value == null) {
|
||||
return null;
|
||||
} else {
|
||||
Class<? extends Object> clazz = value.getClass();
|
||||
if (clazz.getName().startsWith("com.intellectualcrafters.jnbt")) {
|
||||
try {
|
||||
if (clazz.getName().equals("com.intellectualcrafters.jnbt.EndTag")) {
|
||||
return new EndTag();
|
||||
}
|
||||
Field field = clazz.getDeclaredField("value");
|
||||
field.setAccessible(true);
|
||||
return asTag(field.get(value));
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@ -28,11 +27,8 @@ public class Cancel extends FaweCommand {
|
||||
for (FaweQueue queue : queues) {
|
||||
Set<EditSession> sessions = queue.getEditSessions();
|
||||
for (EditSession session : sessions) {
|
||||
Actor actor = session.getActor();
|
||||
if (actor == null) {
|
||||
continue;
|
||||
}
|
||||
if (uuid.equals(actor.getUniqueId())) {
|
||||
FawePlayer currentPlayer = session.getPlayer();
|
||||
if (currentPlayer == player) {
|
||||
if (session.cancel()) {
|
||||
cancelled++;
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public class Settings {
|
||||
|
||||
// Maybe confusing?
|
||||
// - `compression: false` just uses cheaper compression, but still compresses
|
||||
public static int COMPRESSION_LEVEL = 0;
|
||||
public static int COMPRESSION_LEVEL = 1;
|
||||
public static boolean COMBINE_HISTORY_STAGE = false;
|
||||
public static int PARALLEL_THREADS = 1;
|
||||
|
||||
@ -96,11 +96,12 @@ public class Settings {
|
||||
options.put("clipboard.use-disk", STORE_CLIPBOARD_ON_DISK);
|
||||
options.put("clipboard.delete-after-days", DELETE_CLIPBOARD_AFTER_DAYS);
|
||||
options.put("history.use-disk", STORE_HISTORY_ON_DISK);
|
||||
options.put("history.compress", false);
|
||||
options.put("history.chunk-wait-ms", CHUNK_WAIT);
|
||||
options.put("history.delete-after-days", DELETE_HISTORY_AFTER_DAYS);
|
||||
options.put("history.delete-on-logout", CLEAN_HISTORY_ON_LOGOUT);
|
||||
options.put("history.enable-for-console", CONSOLE_HISTORY);
|
||||
options.put("history.compression-level", config.getBoolean("history.compress", false) ? 4 : COMPRESSION_LEVEL);
|
||||
options.put("history.compress", null);
|
||||
options.put("region-restrictions", REGION_RESTRICTIONS);
|
||||
options.put("queue.extra-time-ms", ALLOCATE);
|
||||
options.put("queue.progress.display", DISPLAY_PROGRESS);
|
||||
@ -144,7 +145,7 @@ public class Settings {
|
||||
ENABLE_HARD_LIMIT = config.getBoolean("crash-mitigation");
|
||||
REGION_RESTRICTIONS = config.getBoolean("region-restrictions");
|
||||
METRICS = config.getBoolean("metrics");
|
||||
COMPRESSION_LEVEL = config.getInt("history.compression-level", config.getBoolean("history.compress") ? 1 : 0);
|
||||
COMPRESSION_LEVEL = config.getInt("history.compression-level");
|
||||
DELETE_HISTORY_AFTER_DAYS = config.getInt("history.delete-after-days");
|
||||
CLEAN_HISTORY_ON_LOGOUT = config.getBoolean("history.delete-on-logout");
|
||||
CHUNK_WAIT = config.getInt("history.chunk-wait-ms");
|
||||
|
@ -0,0 +1,86 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NamedTag;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class FaweInputStream extends InputStream {
|
||||
|
||||
private final InputStream parent;
|
||||
|
||||
public FaweInputStream(InputStream parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public InputStream getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return parent.read();
|
||||
}
|
||||
|
||||
public long readLong() throws IOException {
|
||||
return (long)
|
||||
(read() << 64) +
|
||||
(read() << 56) +
|
||||
(read() << 48) +
|
||||
(read() << 36) +
|
||||
(read() << 24) +
|
||||
(read() << 16) +
|
||||
(read() << 8) +
|
||||
(read());
|
||||
}
|
||||
|
||||
public int readInt() throws IOException {
|
||||
return (int)
|
||||
(read() << 24) +
|
||||
(read() << 16) +
|
||||
(read() << 8) +
|
||||
(read());
|
||||
}
|
||||
|
||||
public short readShort() throws IOException {
|
||||
return (short) (
|
||||
(read() << 8) +
|
||||
read());
|
||||
}
|
||||
|
||||
public byte readByte() throws IOException {
|
||||
return (byte) read();
|
||||
}
|
||||
|
||||
public int readUnsignedByte() throws IOException {
|
||||
return read();
|
||||
}
|
||||
|
||||
public int readUnsignedShort() throws IOException {
|
||||
return (int) readShort() & 0xFFFF;
|
||||
}
|
||||
|
||||
public int readMedium() throws IOException {
|
||||
return (int) (
|
||||
(read() << 16) +
|
||||
(read() << 8) +
|
||||
read());
|
||||
}
|
||||
|
||||
private NBTInputStream nbtIn;
|
||||
|
||||
public NamedTag readNBT() throws IOException {
|
||||
if (nbtIn == null) {
|
||||
nbtIn = new NBTInputStream(parent);
|
||||
}
|
||||
return nbtIn.readNamedTag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (nbtIn != null) {
|
||||
nbtIn.close();
|
||||
}
|
||||
parent.close();
|
||||
}
|
||||
}
|
@ -17,7 +17,32 @@ public class FaweLimit {
|
||||
|
||||
public static FaweLimit MAX;
|
||||
static {
|
||||
MAX = new FaweLimit();
|
||||
MAX = new FaweLimit() {
|
||||
@Override
|
||||
public boolean MAX_CHANGES() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean MAX_BLOCKSTATES() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean MAX_CHECKS() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean MAX_ENTITIES() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean MAX_FAILS() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean MAX_ITERATIONS() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
MAX.MAX_CHANGES = Integer.MAX_VALUE;
|
||||
MAX.MAX_FAILS = Integer.MAX_VALUE;
|
||||
MAX.MAX_CHECKS = Integer.MAX_VALUE;
|
||||
@ -26,6 +51,30 @@ public class FaweLimit {
|
||||
MAX.MAX_ENTITIES = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public boolean MAX_CHANGES() {
|
||||
return MAX_CHANGES-- > 0;
|
||||
}
|
||||
|
||||
public boolean MAX_FAILS() {
|
||||
return MAX_FAILS-- > 0;
|
||||
}
|
||||
|
||||
public boolean MAX_CHECKS() {
|
||||
return MAX_CHECKS-- > 0;
|
||||
}
|
||||
|
||||
public boolean MAX_ITERATIONS() {
|
||||
return MAX_ITERATIONS-- > 0;
|
||||
}
|
||||
|
||||
public boolean MAX_BLOCKSTATES() {
|
||||
return MAX_BLOCKSTATES-- > 0;
|
||||
}
|
||||
|
||||
public boolean MAX_ENTITIES() {
|
||||
return MAX_ENTITIES-- > 0;
|
||||
}
|
||||
|
||||
public boolean load(ConfigurationSection section, FaweLimit defaultLimit, boolean save) {
|
||||
this.MAX_CHANGES = section.getInt("max-changes", defaultLimit == null ? MAX_CHANGES : defaultLimit.MAX_CHANGES);
|
||||
this.MAX_FAILS = section.getInt("max-fails", defaultLimit == null ? MAX_FAILS : defaultLimit.MAX_FAILS);
|
||||
|
@ -0,0 +1,76 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class FaweOutputStream extends OutputStream {
|
||||
|
||||
private final OutputStream parent;
|
||||
|
||||
public FaweOutputStream(OutputStream parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public OutputStream getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
parent.write(b);
|
||||
}
|
||||
|
||||
public void write(int b, int amount) throws IOException {
|
||||
for (int i = 0; i < amount; i++) {
|
||||
write(b);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeLong(long l) throws IOException {
|
||||
write((byte) (l >>> 64));
|
||||
write((byte) (l >>> 56));
|
||||
write((byte) (l >>> 48));
|
||||
write((byte) (l >>> 36));
|
||||
write((byte) (l >>> 24));
|
||||
write((byte) (l >>> 16));
|
||||
write((byte) (l >>> 8));
|
||||
write((byte) (l));
|
||||
}
|
||||
|
||||
public void writeInt(int i) throws IOException {
|
||||
write((byte) (i >>> 24));
|
||||
write((byte) (i >>> 16));
|
||||
write((byte) (i >>> 8));
|
||||
write((byte) (i));
|
||||
}
|
||||
|
||||
public void writeShort(short s) throws IOException {
|
||||
write((byte) (s >>> 8));
|
||||
write((byte) (s));
|
||||
}
|
||||
|
||||
public void writeMedium(int m) throws IOException {
|
||||
write((byte) (m >>> 16));
|
||||
write((byte) (m >>> 8));
|
||||
write((byte) (m));
|
||||
}
|
||||
|
||||
private NBTOutputStream nbtOut;
|
||||
|
||||
public void writeNBT(String name, Tag tag) throws IOException {
|
||||
if (nbtOut == null) {
|
||||
nbtOut = new NBTOutputStream(parent);
|
||||
}
|
||||
nbtOut.writeNamedTag(name,tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (nbtOut != null) {
|
||||
nbtOut.close();
|
||||
}
|
||||
parent.close();
|
||||
}
|
||||
}
|
@ -178,7 +178,7 @@ public abstract class FawePlayer<T> {
|
||||
for (int i = editIds.size() - 1; i >= 0; i--) {
|
||||
int index = editIds.get(i);
|
||||
FaweStreamChangeSet set = new DiskStorageHistory(world, uuid, index);
|
||||
EditSession edit = set.toEditSession(getPlayer());
|
||||
EditSession edit = set.toEditSession(FawePlayer.this);
|
||||
if (world.equals(getWorld())) {
|
||||
session.remember(edit, false, false);
|
||||
} else {
|
||||
|
@ -200,6 +200,7 @@ public abstract class FaweQueue {
|
||||
if (Fawe.get().isMainThread()) {
|
||||
SetQueue.IMP.flush(this);
|
||||
} else {
|
||||
enqueue();
|
||||
final AtomicBoolean running = new AtomicBoolean(true);
|
||||
addNotifyTask(new Runnable() {
|
||||
@Override
|
||||
|
@ -26,9 +26,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
*/
|
||||
public class HistoryExtent extends AbstractDelegateExtent {
|
||||
|
||||
private com.boydti.fawe.object.changeset.FaweChangeSet changeSet;
|
||||
private FaweChangeSet changeSet;
|
||||
private final FaweQueue queue;
|
||||
private final FaweLimit limit;
|
||||
private final EditSession session;
|
||||
|
||||
/**
|
||||
@ -37,15 +36,18 @@ public class HistoryExtent extends AbstractDelegateExtent {
|
||||
* @param extent the extent
|
||||
* @param changeSet the change set
|
||||
*/
|
||||
public HistoryExtent(final EditSession session, FaweLimit limit, final Extent extent, final FaweChangeSet changeSet, FaweQueue queue) {
|
||||
public HistoryExtent(final EditSession session, final Extent extent, final FaweChangeSet changeSet, FaweQueue queue) {
|
||||
super(extent);
|
||||
checkNotNull(changeSet);
|
||||
this.limit = limit;
|
||||
this.queue = queue;
|
||||
this.changeSet = changeSet;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public FaweChangeSet getChangeSet() {
|
||||
return changeSet;
|
||||
}
|
||||
|
||||
public void setChangeSet(FaweChangeSet fcs) {
|
||||
this.changeSet = fcs;
|
||||
}
|
||||
|
@ -13,42 +13,42 @@ public class NullChangeSet extends FaweChangeSet {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean flush() {
|
||||
public final boolean flush() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int x, int y, int z, int combinedFrom, int combinedTo) {
|
||||
public final void add(int x, int y, int z, int combinedFrom, int combinedTo) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTileCreate(CompoundTag tag) {
|
||||
public final void addTileCreate(CompoundTag tag) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTileRemove(CompoundTag tag) {
|
||||
public final void addTileRemove(CompoundTag tag) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntityRemove(CompoundTag tag) {
|
||||
public final void addEntityRemove(CompoundTag tag) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntityCreate(CompoundTag tag) {
|
||||
public final void addEntityCreate(CompoundTag tag) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Change> getIterator(boolean undo) {
|
||||
public final Iterator<Change> getIterator(boolean undo) {
|
||||
return new ArrayList<Change>().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
public final int size() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,10 @@ public class RegionWrapper {
|
||||
public int minZ;
|
||||
public int maxZ;
|
||||
|
||||
public static RegionWrapper GLOBAL() {
|
||||
return new RegionWrapper(Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public RegionWrapper(final int minX, final int maxX, final int minZ, final int maxZ) {
|
||||
this.maxX = maxX;
|
||||
this.minX = minX;
|
||||
@ -82,6 +86,10 @@ public class RegionWrapper {
|
||||
return new Vector(this.maxX, 255, this.maxZ);
|
||||
}
|
||||
|
||||
public boolean isGlobal() {
|
||||
return minX == Integer.MIN_VALUE && minZ == Integer.MIN_VALUE && maxX == Integer.MAX_VALUE && maxZ == Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public boolean contains(RegionWrapper current) {
|
||||
return current.minX >= minX && current.maxX <= maxX && current.minZ >= minZ && current.maxZ <= maxZ;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.boydti.fawe.object.changeset;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweInputStream;
|
||||
import com.boydti.fawe.object.IntegerPair;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
@ -17,9 +18,6 @@ import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import net.jpountz.lz4.LZ4Compressor;
|
||||
import net.jpountz.lz4.LZ4Factory;
|
||||
import net.jpountz.lz4.LZ4InputStream;
|
||||
|
||||
/**
|
||||
* Store the change on disk
|
||||
@ -163,6 +161,9 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
bdFile.getParentFile().mkdirs();
|
||||
bdFile.createNewFile();
|
||||
osBD = getCompressedOS(new FileOutputStream(bdFile));
|
||||
// Mode
|
||||
osBD.write((byte) MODE);
|
||||
// Origin
|
||||
setOrigin(x, z);
|
||||
osBD.write((byte) (x >> 24));
|
||||
osBD.write((byte) (x >> 16));
|
||||
@ -224,7 +225,10 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
if (!bdFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
InputStream is = getCompressedIS(new FileInputStream(bdFile));
|
||||
InputStream is = MainUtil.getCompressedIS(new FileInputStream(bdFile));
|
||||
// skip mode
|
||||
is.skip(1);
|
||||
// origin
|
||||
int x = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + (is.read() << 0));
|
||||
int z = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + (is.read() << 0));
|
||||
setOrigin(x, z);
|
||||
@ -236,7 +240,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
if (!enttFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
return new NBTInputStream(getCompressedIS(new FileInputStream(enttFile)));
|
||||
return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(enttFile)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -244,7 +248,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
if (!entfFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
return new NBTInputStream(getCompressedIS(new FileInputStream(entfFile)));
|
||||
return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(entfFile)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -252,7 +256,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
if (!nbttFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
return new NBTInputStream(getCompressedIS(new FileInputStream(nbttFile)));
|
||||
return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(nbttFile)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -260,7 +264,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
if (!nbtfFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
return new NBTInputStream(getCompressedIS(new FileInputStream(nbtfFile)));
|
||||
return new NBTInputStream(MainUtil.getCompressedIS(new FileInputStream(nbtfFile)));
|
||||
}
|
||||
|
||||
public DiskStorageSummary summarize(RegionWrapper requiredRegion, boolean shallow) {
|
||||
@ -274,14 +278,10 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
return summary = new DiskStorageSummary(ox, oz);
|
||||
}
|
||||
try (FileInputStream fis = new FileInputStream(bdFile)) {
|
||||
LZ4Factory factory = LZ4Factory.fastestInstance();
|
||||
LZ4Compressor compressor = factory.fastCompressor();
|
||||
final LZ4InputStream gis;
|
||||
if (Settings.COMPRESSION_LEVEL > 0) {
|
||||
gis = new LZ4InputStream(new LZ4InputStream(fis));
|
||||
} else {
|
||||
gis = new LZ4InputStream(fis);
|
||||
}
|
||||
FaweInputStream gis = MainUtil.getCompressedIS(fis);
|
||||
// skip mode
|
||||
gis.skip(1);
|
||||
// origin
|
||||
ox = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
|
||||
oz = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
|
||||
setOrigin(ox, oz);
|
||||
@ -293,7 +293,8 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
}
|
||||
byte[] buffer = new byte[9];
|
||||
int i = 0;
|
||||
while (!shallow || gis.hasBytesAvailableInDecompressedBuffer(9)) {
|
||||
while (!shallow && i < Settings.BUFFER_SIZE) {
|
||||
i++;
|
||||
if (gis.read(buffer) == -1) {
|
||||
fis.close();
|
||||
gis.close();
|
||||
@ -316,16 +317,11 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
int ox = getOriginX();
|
||||
int oz = getOriginZ();
|
||||
if (ox == 0 && oz == 0 && bdFile.exists()) {
|
||||
try {
|
||||
FileInputStream fis = new FileInputStream(bdFile);
|
||||
LZ4Factory factory = LZ4Factory.fastestInstance();
|
||||
LZ4Compressor compressor = factory.fastCompressor();
|
||||
final InputStream gis;
|
||||
if (Settings.COMPRESSION_LEVEL > 0) {
|
||||
gis = new LZ4InputStream(new LZ4InputStream(fis));
|
||||
} else {
|
||||
gis = new LZ4InputStream(fis);
|
||||
}
|
||||
try (FileInputStream fis = new FileInputStream(bdFile)) {
|
||||
final InputStream gis = MainUtil.getCompressedIS(fis);
|
||||
// skip mode
|
||||
gis.skip(1);
|
||||
// origin
|
||||
ox = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
|
||||
oz = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
|
||||
setOrigin(ox, oz);
|
||||
|
@ -4,18 +4,17 @@ import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.BytePair;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.EditSessionFactory;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.history.change.BlockChange;
|
||||
import com.sk89q.worldedit.history.change.Change;
|
||||
import com.sk89q.worldedit.history.change.EntityCreate;
|
||||
@ -70,12 +69,8 @@ public abstract class FaweChangeSet implements ChangeSet {
|
||||
public abstract void addEntityCreate(CompoundTag tag);
|
||||
public abstract Iterator<Change> getIterator(boolean redo);
|
||||
|
||||
public EditSession toEditSession(Player player) {
|
||||
EditSessionFactory factory = WorldEdit.getInstance().getEditSessionFactory();
|
||||
EditSession edit = factory.getEditSession(world, -1, null, player);
|
||||
edit.setChangeSet(this);
|
||||
edit.dequeue();
|
||||
return edit;
|
||||
public EditSession toEditSession(FawePlayer player) {
|
||||
return new EditSessionBuilder(world).player(player).autoQueue(false).fastmode(true).checkMemory(false).changeSet(this).build();
|
||||
}
|
||||
|
||||
public void add(EntityCreate change) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.boydti.fawe.object.changeset;
|
||||
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.object.change.MutableBlockChange;
|
||||
import com.boydti.fawe.object.change.MutableEntityChange;
|
||||
import com.boydti.fawe.object.change.MutableTileChange;
|
||||
@ -15,15 +16,25 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import net.jpountz.lz4.LZ4Compressor;
|
||||
import net.jpountz.lz4.LZ4Factory;
|
||||
import net.jpountz.lz4.LZ4InputStream;
|
||||
import net.jpountz.lz4.LZ4OutputStream;
|
||||
|
||||
public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
||||
|
||||
public static final int MODE = 3;
|
||||
public static final int HEADER_SIZE = 9;
|
||||
|
||||
private final int compression;
|
||||
|
||||
public FaweStreamChangeSet(World world) {
|
||||
this(world, Settings.COMPRESSION_LEVEL);
|
||||
}
|
||||
|
||||
public FaweStreamChangeSet(World world, int compression) {
|
||||
super(world);
|
||||
this.compression = compression;
|
||||
}
|
||||
|
||||
public FaweOutputStream getCompressedOS(OutputStream os) throws IOException {
|
||||
return MainUtil.getCompressedOS(os, compression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -69,25 +80,6 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
||||
return originZ;
|
||||
}
|
||||
|
||||
public InputStream getCompressedIS(InputStream is) {
|
||||
if (Settings.COMPRESSION_LEVEL > 0) {
|
||||
is = new LZ4InputStream(new LZ4InputStream(is));
|
||||
} else {
|
||||
is = new LZ4InputStream(is);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
public OutputStream getCompressedOS(OutputStream os) throws IOException {
|
||||
LZ4Factory factory = LZ4Factory.fastestInstance();
|
||||
LZ4Compressor compressor = factory.fastCompressor();
|
||||
os = new LZ4OutputStream(os, Settings.BUFFER_SIZE, factory.fastCompressor());
|
||||
if (Settings.COMPRESSION_LEVEL > 0) {
|
||||
os = new LZ4OutputStream(os, Settings.BUFFER_SIZE, factory.highCompressor());
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
public void add(int x, int y, int z, int combinedFrom, int combinedTo) {
|
||||
blockSize++;
|
||||
try {
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.boydti.fawe.object.changeset;
|
||||
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweInputStream;
|
||||
import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
@ -21,7 +23,7 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet {
|
||||
|
||||
private byte[] ids;
|
||||
private ByteArrayOutputStream idsStream;
|
||||
private OutputStream idsStreamZip;
|
||||
private FaweOutputStream idsStreamZip;
|
||||
|
||||
private byte[] entC;
|
||||
private ByteArrayOutputStream entCStream;
|
||||
@ -96,12 +98,18 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet {
|
||||
}
|
||||
setOrigin(x, z);
|
||||
idsStream = new ByteArrayOutputStream(Settings.BUFFER_SIZE);
|
||||
return idsStreamZip = getCompressedOS(idsStream);
|
||||
idsStreamZip = getCompressedOS(idsStream);
|
||||
idsStreamZip.write(FaweStreamChangeSet.MODE);
|
||||
idsStreamZip.writeInt(x);
|
||||
idsStreamZip.writeInt(z);
|
||||
return idsStreamZip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBlockIS() {
|
||||
return ids == null ? null : getCompressedIS(new ByteArrayInputStream(ids));
|
||||
public InputStream getBlockIS() throws IOException {
|
||||
FaweInputStream result = ids == null ? null : MainUtil.getCompressedIS(new ByteArrayInputStream(ids));
|
||||
result.skip(FaweStreamChangeSet.HEADER_SIZE);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -142,21 +150,21 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet {
|
||||
|
||||
@Override
|
||||
public NBTInputStream getEntityCreateIS() throws IOException {
|
||||
return entC == null ? null : new NBTInputStream(getCompressedIS(new ByteArrayInputStream(entC)));
|
||||
return entC == null ? null : new NBTInputStream(MainUtil.getCompressedIS(new ByteArrayInputStream(entC)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTInputStream getEntityRemoveIS() throws IOException {
|
||||
return entR == null ? null : new NBTInputStream(getCompressedIS(new ByteArrayInputStream(entR)));
|
||||
return entR == null ? null : new NBTInputStream(MainUtil.getCompressedIS(new ByteArrayInputStream(entR)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTInputStream getTileCreateIS() throws IOException {
|
||||
return tileC == null ? null : new NBTInputStream(getCompressedIS(new ByteArrayInputStream(tileC)));
|
||||
return tileC == null ? null : new NBTInputStream(MainUtil.getCompressedIS(new ByteArrayInputStream(tileC)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTInputStream getTileRemoveIS() throws IOException {
|
||||
return tileR == null ? null : new NBTInputStream(getCompressedIS(new ByteArrayInputStream(tileR)));
|
||||
return tileR == null ? null : new NBTInputStream(MainUtil.getCompressedIS(new ByteArrayInputStream(tileR)));
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,9 @@ import java.util.UUID;
|
||||
*/
|
||||
public class DiskOptimizedClipboard extends FaweClipboard {
|
||||
|
||||
private static int HEADER_SIZE = 10;
|
||||
public static int COMPRESSION = 0;
|
||||
public static int MODE = 0;
|
||||
public static int HEADER_SIZE = 14;
|
||||
|
||||
protected int length;
|
||||
protected int height;
|
||||
@ -53,7 +55,7 @@ public class DiskOptimizedClipboard extends FaweClipboard {
|
||||
private int last;
|
||||
|
||||
public DiskOptimizedClipboard(int width, int height, int length, UUID uuid) {
|
||||
this(width, height, length, new File(Fawe.imp().getDirectory(), "clipboard" + File.separator + uuid));
|
||||
this(width, height, length, new File(Fawe.imp().getDirectory(), "clipboard" + File.separator + uuid + ".bd"));
|
||||
}
|
||||
|
||||
public DiskOptimizedClipboard(File file) throws IOException {
|
||||
@ -64,13 +66,14 @@ public class DiskOptimizedClipboard extends FaweClipboard {
|
||||
this.raf = new BufferedRandomAccessFile(file, "rw", Settings.BUFFER_SIZE);
|
||||
raf.setLength(file.length());
|
||||
long size = (raf.length() - HEADER_SIZE) >> 1;
|
||||
raf.seek(0);
|
||||
raf.seek(2);
|
||||
last = -1;
|
||||
raf.read(buffer);
|
||||
width = (((buffer[1] & 0xFF) << 8) + ((buffer[0] & 0xFF)));
|
||||
raf.read(buffer);
|
||||
height = (((buffer[1] & 0xFF) << 8) + ((buffer[0] & 0xFF)));
|
||||
raf.read(buffer);
|
||||
length = (((buffer[1] & 0xFF) << 8) + ((buffer[0] & 0xFF)));
|
||||
height = (int) (size / (width * length));
|
||||
area = width * length;
|
||||
autoCloseTask();
|
||||
}
|
||||
@ -86,7 +89,7 @@ public class DiskOptimizedClipboard extends FaweClipboard {
|
||||
if (raf == null) {
|
||||
open();
|
||||
}
|
||||
raf.seek(4);
|
||||
raf.seek(8);
|
||||
last = -1;
|
||||
int ox = (((byte) raf.read() << 8) | ((byte) raf.read()) & 0xFF);
|
||||
int oy = (((byte) raf.read() << 8) | ((byte) raf.read()) & 0xFF);
|
||||
@ -126,7 +129,7 @@ public class DiskOptimizedClipboard extends FaweClipboard {
|
||||
if (raf == null) {
|
||||
open();
|
||||
}
|
||||
raf.seek(4);
|
||||
raf.seek(8);
|
||||
last = -1;
|
||||
raf.write((byte) (offset.getBlockX() >> 8));
|
||||
raf.write((byte) (offset.getBlockX()));
|
||||
@ -178,10 +181,12 @@ public class DiskOptimizedClipboard extends FaweClipboard {
|
||||
if (raf.length() != size) {
|
||||
raf.setLength(size);
|
||||
// write length etc
|
||||
raf.seek(0);
|
||||
raf.seek(1);
|
||||
last = 0;
|
||||
raf.write((width) & 0xff);
|
||||
raf.write(((width) >> 8) & 0xff);
|
||||
raf.write((height) & 0xff);
|
||||
raf.write(((height) >> 8) & 0xff);
|
||||
raf.write((length) & 0xff);
|
||||
raf.write(((length) >> 8) & 0xff);
|
||||
}
|
||||
@ -291,6 +296,12 @@ public class DiskOptimizedClipboard extends FaweClipboard {
|
||||
return EditSession.nullBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
nbtMap.put(new IntegerTrio(x, y, z), tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) {
|
||||
try {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.boydti.fawe.object.clipboard;
|
||||
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
@ -18,6 +19,8 @@ public abstract class FaweClipboard {
|
||||
|
||||
public abstract boolean setBlock(int x, int y, int z, BaseBlock block);
|
||||
|
||||
public abstract boolean setTile(int x, int y, int z, CompoundTag tag);
|
||||
|
||||
public abstract Entity createEntity(Extent world, double x, double y, double z, float yaw, float pitch, BaseEntity entity);
|
||||
|
||||
public abstract List<? extends Entity> getEntities();
|
||||
|
@ -1,32 +1,66 @@
|
||||
package com.boydti.fawe.object.clipboard;
|
||||
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
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.Region;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class LazyClipboard extends FaweClipboard {
|
||||
private final Region region;
|
||||
|
||||
// private final int width, height, length;
|
||||
//
|
||||
// public LazyClipboard(int width, int height, int length) {
|
||||
// this.width = width;
|
||||
// this.height = height;
|
||||
// this.length = length;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void forEach(RunnableVal2<Vector, BaseBlock> task, boolean air) {
|
||||
// BlockVector pos = new BlockVector(0, 0, 0);
|
||||
// for (pos.x = 0; pos.x < width; pos.x++) {
|
||||
// for (pos.z = 0; pos.z < width; pos.z++) {
|
||||
// for (pos.y = 0; pos.y < width; pos.y++) {
|
||||
// task.run(pos, getBlock((int) pos.x, (int) pos.y, (int) pos.z));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
public LazyClipboard(Region region) {
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
public static LazyClipboard of(final EditSession editSession, Region region) {
|
||||
final Vector origin = region.getMinimumPoint();
|
||||
final int mx = origin.getBlockX();
|
||||
final int my = origin.getBlockY();
|
||||
final int mz = origin.getBlockZ();
|
||||
return new LazyClipboard(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(getRegion());
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
pos.x -= mx;
|
||||
pos.y -= my;
|
||||
pos.z -= mz;
|
||||
task.run(pos, block);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Region getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract BaseBlock getBlock(int x, int y, int z);
|
||||
@ -39,6 +73,11 @@ public abstract class LazyClipboard extends FaweClipboard {
|
||||
throw new UnsupportedOperationException("Clipboard is immutable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
throw new UnsupportedOperationException("Clipboard is immutable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity createEntity(Extent world, double x, double y, double z, float yaw, float pitch, BaseEntity entity) {
|
||||
throw new UnsupportedOperationException("Clipboard is immutable");
|
||||
|
@ -135,6 +135,12 @@ public class MemoryOptimizedClipboard extends FaweClipboard {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
nbtMap.put(new IntegerTrio(x, y, z), tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) {
|
||||
final int id = block.getId();
|
||||
|
@ -30,7 +30,7 @@ public class ProcessedWEExtent extends FaweRegionExtent {
|
||||
|
||||
@Override
|
||||
public Entity createEntity(final Location location, final BaseEntity entity) {
|
||||
if (limit.MAX_ENTITIES-- < 0 || entity == null) {
|
||||
if (!limit.MAX_ENTITIES() || entity == null) {
|
||||
return null;
|
||||
}
|
||||
return super.createEntity(location, entity);
|
||||
@ -67,18 +67,18 @@ public class ProcessedWEExtent extends FaweRegionExtent {
|
||||
@Override
|
||||
public boolean setBlock(final Vector location, final BaseBlock block) throws WorldEditException {
|
||||
if (block.hasNbtData() && FaweCache.hasNBT(block.getType())) {
|
||||
if (limit.MAX_BLOCKSTATES-- < 0) {
|
||||
if (!limit.MAX_BLOCKSTATES()) {
|
||||
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_TILES);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (WEManager.IMP.maskContains(this.mask, (int) location.x, (int) location.z)) {
|
||||
if (limit.MAX_CHANGES-- < 0) {
|
||||
if (!limit.MAX_CHANGES()) {
|
||||
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES);
|
||||
return false;
|
||||
}
|
||||
return super.setBlock(location, block);
|
||||
} else if (limit.MAX_FAILS-- < 0) {
|
||||
} else if (!limit.MAX_FAILS()) {
|
||||
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return false;
|
||||
|
@ -8,6 +8,9 @@ import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
|
||||
/**
|
||||
* The default progress tracker uses titles
|
||||
*/
|
||||
public class DefaultProgressTracker extends RunnableVal2<FaweQueue.ProgressType, Integer> {
|
||||
|
||||
private final FawePlayer player;
|
||||
@ -18,9 +21,12 @@ public class DefaultProgressTracker extends RunnableVal2<FaweQueue.ProgressType,
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
// Number of times a chunk was queued
|
||||
private int totalQueue = 0;
|
||||
// Current size of the queue
|
||||
private int amountQueue = 0;
|
||||
// Number of chunks dispatched
|
||||
private int amountDispatch = 0;
|
||||
private long lastTick = 0;
|
||||
|
||||
@Override
|
||||
public void run(FaweQueue.ProgressType type, Integer amount) {
|
||||
@ -29,47 +35,60 @@ public class DefaultProgressTracker extends RunnableVal2<FaweQueue.ProgressType,
|
||||
amountDispatch = amount;
|
||||
break;
|
||||
case QUEUE:
|
||||
totalQueue++;
|
||||
amountQueue = amount;
|
||||
break;
|
||||
case DONE:
|
||||
if (amountDispatch > 64) {
|
||||
if (totalQueue > 64) {
|
||||
done();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (amountQueue > 64 || amountDispatch > 64) {
|
||||
// Only send a message after 64 chunks (i.e. ignore smaller edits)
|
||||
if (totalQueue > 64) {
|
||||
send();
|
||||
}
|
||||
}
|
||||
|
||||
private void done() {
|
||||
private final void done() {
|
||||
TaskManager.IMP.task(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final long time = System.currentTimeMillis() - start;
|
||||
player.sendTitle("", BBC.PROGRESS_DONE.format(time / 1000d));
|
||||
TaskManager.IMP.later(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
player.resetTitle();
|
||||
}
|
||||
}, 60);
|
||||
doneTask();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void send() {
|
||||
TaskManager.IMP.task(new Runnable() {
|
||||
private long lastTick = 0;
|
||||
|
||||
private final void send() {
|
||||
// Avoid duplicates
|
||||
long currentTick = System.currentTimeMillis() / 50;
|
||||
if (currentTick > lastTick + Settings.DISPLAY_PROGRESS_INTERVAL) {
|
||||
lastTick = currentTick;
|
||||
TaskManager.IMP.task(new Runnable() { // Run on main thread
|
||||
@Override
|
||||
public void run() {
|
||||
sendTask();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void doneTask() {
|
||||
final long time = System.currentTimeMillis() - start;
|
||||
player.sendTitle("", BBC.PROGRESS_DONE.format(time / 1000d));
|
||||
TaskManager.IMP.later(new Runnable() { // Run on main thread
|
||||
@Override
|
||||
public void run() {
|
||||
long currentTick = System.currentTimeMillis() / 50;
|
||||
if (currentTick > lastTick + Settings.DISPLAY_PROGRESS_INTERVAL) {
|
||||
lastTick = currentTick;
|
||||
String queue = StringMan.padRight("" + amountQueue, 3);
|
||||
String dispatch = StringMan.padRight("" + amountDispatch, 3);
|
||||
player.sendTitle("", BBC.PROGRESS_MESSAGE.format(queue, dispatch));
|
||||
}
|
||||
doneTask();
|
||||
}
|
||||
});
|
||||
}, 60);
|
||||
}
|
||||
|
||||
public void sendTask() {
|
||||
String queue = StringMan.padRight("" + amountQueue, 3);
|
||||
String dispatch = StringMan.padRight("" + amountDispatch, 3);
|
||||
player.sendTitle("", BBC.PROGRESS_MESSAGE.format(queue, dispatch));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,377 @@
|
||||
package com.boydti.fawe.object.schematic;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweInputStream;
|
||||
import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.DoubleTag;
|
||||
import com.sk89q.jnbt.FloatTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.NamedTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
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.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
import com.sk89q.worldedit.world.storage.NBTConversions;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class FaweFormat implements ClipboardReader, ClipboardWriter {
|
||||
private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE;
|
||||
|
||||
private FaweInputStream in;
|
||||
private FaweOutputStream out;
|
||||
private int mode;
|
||||
|
||||
public FaweFormat(FaweInputStream in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
public FaweFormat(FaweOutputStream out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
private boolean compressed = false;
|
||||
|
||||
public boolean compress(int i) throws IOException {
|
||||
if (compressed) {
|
||||
return false;
|
||||
}
|
||||
compressed = true;
|
||||
if (in != null) {
|
||||
in = MainUtil.getCompressedIS(in.getParent());
|
||||
} else if (out != null) {
|
||||
out = MainUtil.getCompressedOS(out.getParent());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setWriteMode(int mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clipboard read(WorldData data) throws IOException {
|
||||
return read(data, UUID.randomUUID());
|
||||
}
|
||||
|
||||
public Clipboard read(WorldData worldData, UUID clipboardId) throws IOException {
|
||||
int mode = in.read();
|
||||
|
||||
BlockArrayClipboard clipboard;
|
||||
int ox, oy, oz;
|
||||
oy = 0;
|
||||
|
||||
boolean from = false;
|
||||
boolean small = true;
|
||||
switch (mode) {
|
||||
default:
|
||||
return null;
|
||||
case 3:
|
||||
from = true;
|
||||
case 2:
|
||||
small = false;
|
||||
case 1: {
|
||||
ox = in.readInt();
|
||||
oz = in.readInt();
|
||||
FaweOutputStream tmp = new FaweOutputStream(new ByteArrayOutputStream(Settings.BUFFER_SIZE));
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int length = 0;
|
||||
while (true) {
|
||||
int x, y, z;
|
||||
if (small) {
|
||||
tmp.write(x = in.read());
|
||||
tmp.write(y = in.read());
|
||||
tmp.write(z = in.read());
|
||||
} else {
|
||||
tmp.writeShort((short) (x = in.readUnsignedShort()));
|
||||
tmp.write(y = in.read());
|
||||
tmp.writeShort((short) (z = in.readUnsignedShort()));
|
||||
}
|
||||
if (from) {
|
||||
in.skip(2);
|
||||
}
|
||||
short combined;
|
||||
tmp.writeShort(combined = in.readShort());
|
||||
if (combined == 0 || y == -1) {
|
||||
break;
|
||||
}
|
||||
if (x > width) {
|
||||
width = x;
|
||||
}
|
||||
if (y > height) {
|
||||
height = y;
|
||||
}
|
||||
if(z > length) {
|
||||
length = z;
|
||||
}
|
||||
}
|
||||
Vector origin = new Vector(0, 0, 0);
|
||||
CuboidRegion region = new CuboidRegion(origin, origin.add(width, height, length));
|
||||
clipboard = new BlockArrayClipboard(region, clipboardId);
|
||||
width++;
|
||||
height++;
|
||||
length++;
|
||||
byte[] array = ((ByteArrayOutputStream) tmp.getParent()).toByteArray();
|
||||
FaweInputStream part = new FaweInputStream(new ByteArrayInputStream(array));
|
||||
try {
|
||||
for (int i = 0; i< array.length; i+= 9) {
|
||||
int x, y, z;
|
||||
if (small) {
|
||||
x = in.read();
|
||||
y = in.read();
|
||||
z = in.read();
|
||||
} else {
|
||||
x = in.readUnsignedShort();
|
||||
y = in.read();
|
||||
z = in.readUnsignedShort();
|
||||
}
|
||||
if (from) {
|
||||
in.skip(2);
|
||||
}
|
||||
int combined = in.readShort();
|
||||
int id = FaweCache.getId(combined);
|
||||
int data = FaweCache.getData(combined);
|
||||
BaseBlock block = FaweCache.getBlock(id, data);
|
||||
clipboard.setBlock(x, y, z, block);
|
||||
}
|
||||
} catch (WorldEditException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0: {
|
||||
int width = in.readUnsignedShort();
|
||||
int height = in.readUnsignedShort();
|
||||
int length = in.readUnsignedShort();
|
||||
ox = in.readShort();
|
||||
oy = in.readShort();
|
||||
oz = in.readShort();
|
||||
|
||||
Vector origin = new Vector(0, 0, 0);
|
||||
CuboidRegion region = new CuboidRegion(origin, origin.add(width, height, length).subtract(Vector.ONE));
|
||||
clipboard = new BlockArrayClipboard(region, clipboardId);
|
||||
try {
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int z = 0; z < length; z++) {
|
||||
int combined = in.readUnsignedShort();
|
||||
int id = FaweCache.getId(combined);
|
||||
int data = FaweCache.getData(combined);
|
||||
BaseBlock block = FaweCache.getBlock(id, data);
|
||||
clipboard.setBlock(x, y, z, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (WorldEditException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
try {
|
||||
NamedTag namedTag;
|
||||
while ((namedTag = in.readNBT()) != null) {
|
||||
CompoundTag compound = (CompoundTag) namedTag.getTag();
|
||||
Map<String, Tag> map = compound.getValue();
|
||||
if (map.containsKey("Rotation")) {
|
||||
// Entity
|
||||
String id = compound.getString("id");
|
||||
Location location = NBTConversions.toLocation(clipboard, compound.getListTag("Pos"), compound.getListTag("Rotation"));
|
||||
if (!id.isEmpty()) {
|
||||
BaseEntity state = new BaseEntity(id, compound);
|
||||
clipboard.createEntity(location, state);
|
||||
}
|
||||
} else {
|
||||
// Tile
|
||||
int x = compound.getInt("x");
|
||||
int y = compound.getInt("y");
|
||||
int z = compound.getInt("z");
|
||||
clipboard.setTile(x, y, z, compound);
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignore) {}
|
||||
clipboard.setOrigin(new Vector(ox, oy, oz));
|
||||
return clipboard;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Clipboard clipboard, WorldData worldData) throws IOException {
|
||||
write(clipboard, worldData, "FAWE");
|
||||
}
|
||||
|
||||
public void write(Clipboard clipboard, WorldData worldData, String owner) throws IOException {
|
||||
Region region = clipboard.getRegion();
|
||||
int width = region.getWidth();
|
||||
int height = region.getHeight();
|
||||
int length = region.getLength();
|
||||
|
||||
if (width > MAX_SIZE) {
|
||||
throw new IllegalArgumentException("Width of region too large for a .nbt");
|
||||
}
|
||||
if (height > MAX_SIZE) {
|
||||
throw new IllegalArgumentException("Height of region too large for a .nbt");
|
||||
}
|
||||
if (length > MAX_SIZE) {
|
||||
throw new IllegalArgumentException("Length of region too large for a .nbt");
|
||||
}
|
||||
|
||||
Vector min = clipboard.getMinimumPoint();
|
||||
Vector max = clipboard.getMaximumPoint();
|
||||
Vector origin = clipboard.getOrigin().subtract(min);
|
||||
|
||||
// Mode
|
||||
out.write(mode);
|
||||
ArrayDeque<CompoundTag> tiles = new ArrayDeque<>();
|
||||
boolean from = false;
|
||||
boolean small = true;
|
||||
switch (mode) {
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid mode: " + mode);
|
||||
case 3:
|
||||
from = true;
|
||||
case 2:
|
||||
small = false;
|
||||
case 1: {
|
||||
out.writeInt(origin.getBlockX());
|
||||
out.writeInt(origin.getBlockZ());
|
||||
for (Vector pt : clipboard.getRegion()) {
|
||||
BaseBlock block = clipboard.getBlock(pt);
|
||||
if (block == EditSession.nullBlock) {
|
||||
continue;
|
||||
}
|
||||
int x = pt.getBlockX() - min.getBlockX();
|
||||
int y = pt.getBlockY() - min.getBlockY();
|
||||
int z = pt.getBlockZ() - min.getBlockZ();
|
||||
if (block.hasNbtData()) {
|
||||
CompoundTag tile = block.getNbtData();
|
||||
Map<String, Tag> map = ReflectionUtils.getMap(tile.getValue());
|
||||
map.put("id", new StringTag(block.getNbtId()));
|
||||
map.put("x", new IntTag(x));
|
||||
map.put("y", new IntTag(y));
|
||||
map.put("z", new IntTag(z));
|
||||
tiles.add(tile);
|
||||
}
|
||||
if (small) {
|
||||
out.write((byte) x);
|
||||
out.write((byte) y);
|
||||
out.write((byte) z);
|
||||
} else {
|
||||
out.writeShort((short) x);
|
||||
out.write((byte) y);
|
||||
out.writeShort((short) z);
|
||||
}
|
||||
if (from) {
|
||||
out.writeShort((short) 0);
|
||||
}
|
||||
out.writeShort((short) FaweCache.getCombined(block));
|
||||
break;
|
||||
}
|
||||
int i = (small ? 3 : 5) + (from ? 4 : 2);
|
||||
out.write(0, i);
|
||||
}
|
||||
case 0: {
|
||||
// Dimensions
|
||||
out.writeShort((short) width);
|
||||
out.writeShort((short) height);
|
||||
out.writeShort((short) length);
|
||||
out.writeShort((short) origin.getBlockX());
|
||||
out.writeShort((short) origin.getBlockY());
|
||||
out.writeShort((short) origin.getBlockZ());
|
||||
Vector mutable = new Vector(0, 0, 0);
|
||||
for (int y = min.getBlockY(); y <= max.getBlockY(); y++) {
|
||||
mutable.y = y;
|
||||
for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
|
||||
mutable.x = x;
|
||||
for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
|
||||
mutable.z = z;
|
||||
BaseBlock block = clipboard.getBlock(mutable);
|
||||
if (block == EditSession.nullBlock) {
|
||||
out.writeShort((short) 0);
|
||||
} else {
|
||||
out.writeShort((short) FaweCache.getCombined(block));
|
||||
if (block.hasNbtData()) {
|
||||
CompoundTag tile = block.getNbtData();
|
||||
Map<String, Tag> map = ReflectionUtils.getMap(tile.getValue());
|
||||
map.put("id", new StringTag(block.getNbtId()));
|
||||
map.put("x", new IntTag(x - min.getBlockX()));
|
||||
map.put("y", new IntTag(y - min.getBlockY()));
|
||||
map.put("z", new IntTag(z - min.getBlockZ()));
|
||||
tiles.add(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (CompoundTag tile : tiles) {
|
||||
out.writeNBT("", FaweCache.asTag(tile));
|
||||
}
|
||||
for (Entity entity : clipboard.getEntities()) {
|
||||
BaseEntity state = entity.getState();
|
||||
if (state != null) {
|
||||
CompoundTag entityTag = state.getNbtData();
|
||||
Map<String, Tag> map = ReflectionUtils.getMap(entityTag.getValue());
|
||||
map.put("id", new StringTag(state.getTypeId()));
|
||||
map.put("Pos", writeVector(entity.getLocation().toVector(), "Pos"));
|
||||
map.put("Rotation", writeRotation(entity.getLocation(), "Rotation"));
|
||||
out.writeNBT("", entityTag);
|
||||
}
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
if (out != null) {
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
private Tag writeVector(Vector vector, String name) {
|
||||
List<DoubleTag> list = new ArrayList<DoubleTag>();
|
||||
list.add(new DoubleTag(vector.getX()));
|
||||
list.add(new DoubleTag(vector.getY()));
|
||||
list.add(new DoubleTag(vector.getZ()));
|
||||
return new ListTag(DoubleTag.class, list);
|
||||
}
|
||||
|
||||
private Tag writeRotation(Location location, String name) {
|
||||
List<FloatTag> list = new ArrayList<FloatTag>();
|
||||
list.add(new FloatTag(location.getYaw()));
|
||||
list.add(new FloatTag(location.getPitch()));
|
||||
return new ListTag(FloatTag.class, list);
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package com.boydti.fawe.regions.general.plot;
|
||||
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.intellectualcrafters.plot.object.ChunkLoc;
|
||||
import com.intellectualcrafters.plot.object.Location;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.util.ChunkManager;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
public class FaweChunkManager extends ChunkManager {
|
||||
|
||||
private ChunkManager parent;
|
||||
|
||||
public FaweChunkManager(ChunkManager parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] countEntities(Plot plot) {
|
||||
return parent.countEntities(plot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean loadChunk(String world, ChunkLoc loc, boolean force) {
|
||||
return parent.loadChunk(world, loc, force);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadChunk(String world, ChunkLoc loc, boolean save, boolean safe) {
|
||||
parent.unloadChunk(world, loc, save, safe);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllEntities(Location pos1, Location pos2) {
|
||||
parent.clearAllEntities(pos1, pos2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swap(final Location pos1, final Location pos2, final Location pos3, final Location pos4, final Runnable whenDone) {
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
EditSession sessionA = new EditSessionBuilder(pos1.getWorld()).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
EditSession sessionB = new EditSessionBuilder(pos3.getWorld()).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
CuboidRegion regionA = new CuboidRegion(new Vector(pos1.getX(), pos1.getY(), pos1.getZ()), new Vector(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
CuboidRegion regionB = new CuboidRegion(new Vector(pos3.getX(), pos3.getY(), pos3.getZ()), new Vector(pos4.getX(), pos4.getY(), pos4.getZ()));
|
||||
ForwardExtentCopy copyA = new ForwardExtentCopy(sessionA, regionA, sessionB, regionB.getMinimumPoint());
|
||||
ForwardExtentCopy copyB = new ForwardExtentCopy(sessionB, regionB, sessionA, regionA.getMinimumPoint());
|
||||
try {
|
||||
Operations.completeLegacy(copyA);
|
||||
Operations.completeLegacy(copyB);
|
||||
sessionA.flushQueue();
|
||||
sessionB.flushQueue();
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean copyRegion(final Location pos1, final Location pos2, final Location pos3, final Runnable whenDone) {
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
EditSession from = new EditSessionBuilder(pos1.getWorld()).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
EditSession to = new EditSessionBuilder(pos3.getWorld()).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
CuboidRegion region = new CuboidRegion(new Vector(pos1.getX(), pos1.getY(), pos1.getZ()), new Vector(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(from, region, to, new Vector(pos3.getX(), pos3.getY(), pos3.getZ()));
|
||||
try {
|
||||
Operations.completeLegacy(copy);
|
||||
to.flushQueue();
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateRegion(final Location pos1, final Location pos2, boolean ignore, final Runnable whenDone) {
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
EditSession editSession = new EditSessionBuilder(pos1.getWorld()).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
World world = editSession.getWorld();
|
||||
CuboidRegion region = new CuboidRegion(new Vector(pos1.getX(), pos1.getY(), pos1.getZ()), new Vector(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
world.regenerate(region, editSession);
|
||||
editSession.flushQueue();
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
package com.boydti.fawe.regions.general.plot;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.intellectualcrafters.jnbt.CompoundTag;
|
||||
import com.intellectualcrafters.plot.object.PlotBlock;
|
||||
import com.intellectualcrafters.plot.util.StringMan;
|
||||
import com.intellectualcrafters.plot.util.block.LocalBlockQueue;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import com.sk89q.worldedit.world.biome.Biomes;
|
||||
import com.sk89q.worldedit.world.registry.BiomeRegistry;
|
||||
import java.util.List;
|
||||
|
||||
public class FaweLocalBlockQueue extends LocalBlockQueue {
|
||||
|
||||
private FaweQueue IMP;
|
||||
|
||||
|
||||
public FaweLocalBlockQueue(String world) {
|
||||
super(world);
|
||||
IMP = SetQueue.IMP.getNewQueue(world, true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean next() {
|
||||
return IMP.next() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSet(boolean parallel) {
|
||||
IMP.startSet(parallel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endSet(boolean parallel) {
|
||||
IMP.endSet(parallel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return IMP.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void optimize() {
|
||||
IMP.optimize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified(long l) {
|
||||
IMP.setModified(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getModified() {
|
||||
return IMP.getModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, int id, int data) {
|
||||
return IMP.setBlock(x, y, z, (short) id ,(byte) data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlotBlock getBlock(int x, int y, int z) {
|
||||
int combined = IMP.getCombinedId4Data(x, y, z);
|
||||
return PlotBlock.get(FaweCache.getId(combined), FaweCache.getData(combined));
|
||||
}
|
||||
|
||||
private BaseBiome biome;
|
||||
private String lastBiome;
|
||||
private BiomeRegistry reg;
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int z, String biome) {
|
||||
if (!StringMan.isEqual(biome, lastBiome)) {
|
||||
if (reg == null) {
|
||||
World weWorld = FaweAPI.getWorld(IMP.getWorldName());
|
||||
reg = weWorld.getWorldData().getBiomeRegistry();
|
||||
}
|
||||
List<BaseBiome> biomes = reg.getBiomes();
|
||||
lastBiome = biome;
|
||||
this.biome = Biomes.findBiomeByName(biomes, biome, reg);
|
||||
}
|
||||
return IMP.setBiome(x, z, this.biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWorld() {
|
||||
return IMP.getWorldName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
IMP.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshChunk(int x, int z) {
|
||||
IMP.sendChunk(IMP.getFaweChunk(x, z), FaweQueue.RelightMode.NONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fixChunkLighting(int x, int z) {
|
||||
IMP.fixLighting(IMP.getFaweChunk(x, z), FaweQueue.RelightMode.OPTIMAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void regenChunk(int x, int z) {
|
||||
IMP.regenerateChunk(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
IMP.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.asTag(tag));
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
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.LazyClipboard;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.intellectualcrafters.jnbt.CompoundTag;
|
||||
import com.intellectualcrafters.jnbt.Tag;
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.object.Location;
|
||||
import com.intellectualcrafters.plot.object.RegionWrapper;
|
||||
import com.intellectualcrafters.plot.object.RunnableVal;
|
||||
import com.intellectualcrafters.plot.util.MainUtil;
|
||||
import com.intellectualcrafters.plot.util.SchematicHandler;
|
||||
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.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;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class FaweSchematicHandler extends SchematicHandler {
|
||||
@Override
|
||||
public boolean restoreTile(LocalBlockQueue queue, CompoundTag compoundTag, int x, int y, int z) {
|
||||
if (queue instanceof FaweLocalBlockQueue) {
|
||||
queue.setTile(x, y, z, compoundTag);
|
||||
return true;
|
||||
}
|
||||
FaweQueue faweQueue = SetQueue.IMP.getNewQueue(queue.getWorld(), true, false);
|
||||
faweQueue.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.asTag(compoundTag));
|
||||
faweQueue.flush();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getCompoundTag(final String world, final Set<RegionWrapper> regions, final RunnableVal<CompoundTag> whenDone) {
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Location[] corners = MainUtil.getCorners(world, regions);
|
||||
Location pos1 = corners[0];
|
||||
Location pos2 = corners[1];
|
||||
final CuboidRegion region = new CuboidRegion(new Vector(pos1.getX(), pos1.getY(), pos1.getZ()), new Vector(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
final EditSession editSession = new EditSessionBuilder(pos1.getWorld()).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
|
||||
final int mx = pos1.getX();
|
||||
final int my = pos1.getY();
|
||||
final int mz = pos1.getZ();
|
||||
|
||||
LazyClipboard clipboard = new LazyClipboard(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 = 0; y < 256; y++) {
|
||||
mutable.y = y;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Clipboard holder = new BlockArrayClipboard(region, clipboard);
|
||||
com.sk89q.jnbt.CompoundTag weTag = SchematicWriter.writeTag(holder);
|
||||
CompoundTag tag = new CompoundTag((Map<String, Tag>) (Map<?,?>) weTag.getValue());
|
||||
whenDone.run(tag);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean save(CompoundTag tag, String path) {
|
||||
if (tag == null) {
|
||||
PS.debug("&cCannot save empty tag");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
File tmp = MainUtil.getFile(PS.get().IMP.getDirectory(), path);
|
||||
tmp.getParentFile().mkdirs();
|
||||
com.sk89q.jnbt.CompoundTag weTag = (com.sk89q.jnbt.CompoundTag) FaweCache.asTag(tag);
|
||||
try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new GZIPOutputStream(stream))) {
|
||||
Map<String, com.sk89q.jnbt.Tag> map = weTag.getValue();
|
||||
output.writeNamedTag("Schematic", map.containsKey("Schematic") ? map.get("Schematic") : weTag);
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(final CompoundTag tag, final UUID uuid, final String file, final RunnableVal<URL> whenDone) {
|
||||
if (tag == null) {
|
||||
PS.debug("&cCannot save empty tag");
|
||||
com.intellectualcrafters.plot.util.TaskManager.runTask(whenDone);
|
||||
return;
|
||||
}
|
||||
MainUtil.upload(uuid, file, "schematic", new RunnableVal<OutputStream>() {
|
||||
@Override
|
||||
public void run(OutputStream output) {
|
||||
try {
|
||||
GZIPOutputStream gzip = new GZIPOutputStream(output, true);
|
||||
com.sk89q.jnbt.CompoundTag weTag = (com.sk89q.jnbt.CompoundTag) FaweCache.asTag(tag);
|
||||
NBTOutputStream nos = new NBTOutputStream(gzip);
|
||||
Map<String, com.sk89q.jnbt.Tag> map = weTag.getValue();
|
||||
nos.writeNamedTag("Schematic", map.containsKey("Schematic") ? map.get("Schematic") : weTag);
|
||||
gzip.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, whenDone);
|
||||
}
|
||||
}
|
@ -1,12 +1,18 @@
|
||||
package com.boydti.fawe.regions.general;
|
||||
package com.boydti.fawe.regions.general.plot;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.generator.HybridPlotManager;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
import com.intellectualcrafters.plot.object.RegionWrapper;
|
||||
import com.intellectualcrafters.plot.util.ChunkManager;
|
||||
import com.intellectualcrafters.plot.util.SchematicHandler;
|
||||
import com.intellectualcrafters.plot.util.block.GlobalBlockQueue;
|
||||
import com.intellectualcrafters.plot.util.block.QueueProvider;
|
||||
import com.plotsquared.listener.WEManager;
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import java.util.HashSet;
|
||||
@ -15,7 +21,43 @@ import org.bukkit.entity.Player;
|
||||
public class PlotSquaredFeature extends FaweMaskManager {
|
||||
public PlotSquaredFeature() {
|
||||
super("PlotSquared");
|
||||
Fawe.debug("Optimizing PlotSquared");
|
||||
PS.get().worldedit = null;
|
||||
setupBlockQueue();
|
||||
setupSchematicHandler();
|
||||
setupChunkManager();
|
||||
}
|
||||
|
||||
private void setupBlockQueue() {
|
||||
try {
|
||||
// If it's going to fail, throw an error now rather than later
|
||||
new FaweLocalBlockQueue(null);
|
||||
QueueProvider provider = QueueProvider.of(FaweLocalBlockQueue.class, null);
|
||||
GlobalBlockQueue.IMP.setProvider(provider);
|
||||
HybridPlotManager.REGENERATIVE_CLEAR = false;
|
||||
Fawe.debug(" - QueueProvider: " + FaweLocalBlockQueue.class);
|
||||
Fawe.debug(" - HybridPlotManager.REGENERATIVE_CLEAR: " + HybridPlotManager.REGENERATIVE_CLEAR);
|
||||
} catch (Throwable e) {
|
||||
Fawe.debug("Please update PlotSquared: http://ci.athion.net/job/PlotSquared/");
|
||||
}
|
||||
}
|
||||
|
||||
private void setupChunkManager() {
|
||||
try {
|
||||
ChunkManager.manager = new FaweChunkManager(ChunkManager.manager);
|
||||
Fawe.debug(" - ChunkManager: " + ChunkManager.manager);
|
||||
} catch (Throwable e) {
|
||||
Fawe.debug("Please update PlotSquared: http://ci.athion.net/job/PlotSquared/");
|
||||
}
|
||||
}
|
||||
|
||||
private void setupSchematicHandler() {
|
||||
try {
|
||||
SchematicHandler.manager = new FaweSchematicHandler();
|
||||
Fawe.debug(" - SchematicHandler: " + SchematicHandler.manager);
|
||||
} catch (Throwable e) {
|
||||
Fawe.debug("Please update PlotSquared: http://ci.athion.net/job/PlotSquared/");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
146
core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java
Normal file
146
core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java
Normal file
@ -0,0 +1,146 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.NullChangeSet;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.boydti.fawe.object.changeset.MemoryOptimizedHistory;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.event.extent.EditSessionEvent;
|
||||
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||
import com.sk89q.worldedit.util.eventbus.EventBus;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class EditSessionBuilder {
|
||||
private World world;
|
||||
private FawePlayer player;
|
||||
private FaweLimit limit;
|
||||
private FaweChangeSet changeSet;
|
||||
private RegionWrapper[] allowedRegions;
|
||||
private Boolean autoQueue;
|
||||
private Boolean fastmode;
|
||||
private Boolean checkMemory;
|
||||
private Boolean combineStages;
|
||||
private BlockBag blockBag;
|
||||
private EventBus eventBus;
|
||||
private EditSessionEvent event;
|
||||
|
||||
/**
|
||||
* An EditSession builder<br>
|
||||
* - Unset values will revert to their default<br>
|
||||
* <br>
|
||||
* player: The player doing the edit (defaults to to console)<br>
|
||||
* limit: Block/Entity/Action limit (defaults to unlimited)<br>
|
||||
* changeSet: Stores changes (defaults to config.yml value)<br>
|
||||
* allowedRegions: Allowed editable regions (defaults to player's allowed regions, or everywhere)<br>
|
||||
* autoQueue: Changes can occur before flushQueue() (defaults true)<br>
|
||||
* fastmode: bypasses history (defaults to player fastmode or config.yml console history)<br>
|
||||
* checkMemory: If low memory checks are enabled (defaults to player's fastmode or true)<br>
|
||||
* combineStages: If history is combined with dispatching
|
||||
*
|
||||
* @param world A world must be provided for all EditSession(s)
|
||||
*/
|
||||
public EditSessionBuilder(@Nonnull World world){
|
||||
checkNotNull(world);
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public EditSessionBuilder(@Nonnull String world) {
|
||||
this(FaweAPI.getWorld(world));
|
||||
}
|
||||
|
||||
public EditSessionBuilder player(@Nullable FawePlayer player) {
|
||||
this.player = player;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EditSessionBuilder limit(@Nullable FaweLimit limit) {
|
||||
this.limit = limit;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EditSessionBuilder limitUnlimited() {
|
||||
return limit(FaweLimit.MAX.copy());
|
||||
}
|
||||
|
||||
public EditSessionBuilder changeSet(@Nullable FaweChangeSet changeSet) {
|
||||
this.changeSet = changeSet;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EditSessionBuilder changeSetNull() {
|
||||
return changeSet(new NullChangeSet(world));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param disk If it should be stored on disk
|
||||
* @param uuid The uuid to store it under (if on disk)
|
||||
* @param compression Compression level (0-9)
|
||||
* @return
|
||||
*/
|
||||
public EditSessionBuilder changeSet(boolean disk, @Nullable UUID uuid, int compression) {
|
||||
if (disk) {
|
||||
this.changeSet = new DiskStorageHistory(world, uuid);
|
||||
} else {
|
||||
this.changeSet = new MemoryOptimizedHistory(world);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public EditSessionBuilder allowedRegions(@Nullable RegionWrapper[] allowedRegions) {
|
||||
this.allowedRegions = allowedRegions;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EditSessionBuilder allowedRegionsEverywhere() {
|
||||
return allowedRegions(new RegionWrapper[]{RegionWrapper.GLOBAL()});
|
||||
}
|
||||
|
||||
public EditSessionBuilder autoQueue(@Nullable Boolean autoQueue) {
|
||||
this.autoQueue = autoQueue;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EditSessionBuilder fastmode(@Nullable Boolean fastmode) {
|
||||
this.fastmode = fastmode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EditSessionBuilder checkMemory(@Nullable Boolean checkMemory) {
|
||||
this.checkMemory = checkMemory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EditSessionBuilder combineStages(@Nullable Boolean combineStages) {
|
||||
this.combineStages = combineStages;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EditSessionBuilder blockBag(@Nullable BlockBag blockBag) {
|
||||
this.blockBag = blockBag;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EditSessionBuilder eventBus(@Nullable EventBus eventBus) {
|
||||
this.eventBus = eventBus;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EditSessionBuilder event(@Nullable EditSessionEvent event) {
|
||||
this.event = event;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EditSession build() {
|
||||
return new EditSession(world, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, eventBus, event);
|
||||
}
|
||||
}
|
106
core/src/main/java/com/boydti/fawe/util/ExtentTraverser.java
Normal file
106
core/src/main/java/com/boydti/fawe/util/ExtentTraverser.java
Normal file
@ -0,0 +1,106 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class ExtentTraverser<T extends Extent> {
|
||||
private T root;
|
||||
private ExtentTraverser<T> parent;
|
||||
|
||||
public ExtentTraverser(T root) {
|
||||
this(root, null);
|
||||
}
|
||||
|
||||
public ExtentTraverser(T root, ExtentTraverser<T> parent) {
|
||||
this.root = root;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
return root != null;
|
||||
}
|
||||
|
||||
public T get() {
|
||||
return root;
|
||||
}
|
||||
|
||||
public boolean setNext(T next) {
|
||||
try {
|
||||
Field field = AbstractDelegateExtent.class.getDeclaredField("extent");
|
||||
field.setAccessible(true);
|
||||
field.set(root, next);
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean insert(T extent) {
|
||||
try {
|
||||
Field field = AbstractDelegateExtent.class.getDeclaredField("extent");
|
||||
field.setAccessible(true);
|
||||
field.set(extent, field.get(root));
|
||||
field.set(root, extent);
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public <U extends Extent> ExtentTraverser<U> find(Class<U> clazz) {
|
||||
try {
|
||||
ExtentTraverser<T> value = this;
|
||||
while (value != null) {
|
||||
if (clazz.isInstance(value.root)) {
|
||||
return (ExtentTraverser<U>) value;
|
||||
}
|
||||
value = value.next();
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public <U extends Extent> ExtentTraverser<U> find(Object object) {
|
||||
try {
|
||||
ExtentTraverser<T> value = this;
|
||||
while (value != null) {
|
||||
if (value.root == object) {
|
||||
return (ExtentTraverser<U>) value;
|
||||
}
|
||||
value = value.next();
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ExtentTraverser<T> previous() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public ExtentTraverser<T> next() {
|
||||
try {
|
||||
if (root instanceof AbstractDelegateExtent) {
|
||||
Field field = AbstractDelegateExtent.class.getDeclaredField("extent");
|
||||
field.setAccessible(true);
|
||||
T value = (T) field.get(root);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return new ExtentTraverser<>(value, this);
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
public class ExtentWrapper extends AbstractDelegateExtent {
|
||||
|
||||
public ExtentWrapper(final Extent extent) {
|
||||
super(extent);
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@ package com.boydti.fawe.util;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweInputStream;
|
||||
import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
@ -15,8 +17,9 @@ import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@ -38,8 +41,13 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import net.jpountz.lz4.LZ4Factory;
|
||||
import net.jpountz.lz4.LZ4InputStream;
|
||||
import net.jpountz.lz4.LZ4OutputStream;
|
||||
|
||||
public class MainUtil {
|
||||
/*
|
||||
@ -75,6 +83,50 @@ public class MainUtil {
|
||||
return getFile(base, path.endsWith("." + extension) ? path : path + "." + extension);
|
||||
}
|
||||
|
||||
public static FaweOutputStream getCompressedOS(OutputStream os) throws IOException {
|
||||
return getCompressedOS(os, Settings.COMPRESSION_LEVEL);
|
||||
}
|
||||
|
||||
public static FaweOutputStream getCompressedOS(OutputStream os, int amount) throws IOException {
|
||||
os.write((byte) amount);
|
||||
os = new BufferedOutputStream(os, Settings.BUFFER_SIZE);
|
||||
if (amount == 0) {
|
||||
return new FaweOutputStream(os);
|
||||
}
|
||||
int gzipAmount = amount > 6 ? 1 : 0;
|
||||
for (int i = 0; i < gzipAmount; i++) {
|
||||
os = new GZIPOutputStream(os, true);
|
||||
}
|
||||
LZ4Factory factory = LZ4Factory.fastestInstance();
|
||||
int fastAmount = 1 + ((amount - 1) % 3);
|
||||
for (int i = 0; i < fastAmount; i++) {
|
||||
os = new LZ4OutputStream(os, Settings.BUFFER_SIZE, factory.fastCompressor());
|
||||
}
|
||||
int highAmount = amount > 3 ? 1 : 0;
|
||||
for (int i = 0; i < highAmount; i++) {
|
||||
os = new LZ4OutputStream(os, Settings.BUFFER_SIZE, factory.highCompressor());
|
||||
}
|
||||
return new FaweOutputStream(os);
|
||||
}
|
||||
|
||||
public static FaweInputStream getCompressedIS(InputStream is) throws IOException {
|
||||
int amount = is.read();
|
||||
is = new BufferedInputStream(is, Settings.BUFFER_SIZE);
|
||||
if (amount == 0) {
|
||||
return new FaweInputStream(is);
|
||||
}
|
||||
LZ4Factory factory = LZ4Factory.fastestInstance();
|
||||
boolean gzip = amount > 6;
|
||||
if (gzip) {
|
||||
is = new GZIPInputStream(is);
|
||||
}
|
||||
amount = (1 + ((amount - 1) % 3)) + (amount > 3 ? 1 : 0);
|
||||
for (int i = 0; i < amount; i++) {
|
||||
is = new LZ4InputStream(is);
|
||||
}
|
||||
return new FaweInputStream(is);
|
||||
}
|
||||
|
||||
public static URL upload(UUID uuid, String file, String extension, final RunnableVal<OutputStream> writeTask) {
|
||||
if (writeTask == null) {
|
||||
Fawe.debug("&cWrite task cannot be null");
|
||||
@ -157,6 +209,46 @@ public class MainUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendCompressedMessage(FaweStreamChangeSet set, FawePlayer actor)
|
||||
{
|
||||
try {
|
||||
int elements = set.size();
|
||||
int compressedSize = set.getCompressedSize();
|
||||
if (compressedSize == 0) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* BlockVector
|
||||
* - reference to the object --> 8 bytes
|
||||
* - object header (java internals) --> 8 bytes
|
||||
* - double x, y, z --> 24 bytes
|
||||
*
|
||||
* BaseBlock
|
||||
* - reference to the object --> 8 bytes
|
||||
* - object header (java internals) --> 8 bytes
|
||||
* - short id, data --> 4 bytes
|
||||
* - NBTCompound (assuming null) --> 4 bytes
|
||||
*
|
||||
* There are usually two lists for the block changes:
|
||||
* 2 * BlockVector + 2 * BaseBlock = 128b
|
||||
*
|
||||
* WE has a lot more overhead, this is just a generous lower bound
|
||||
*
|
||||
* This compares FAWE's usage to standard WE.
|
||||
*/
|
||||
int total = 128 * elements;
|
||||
|
||||
int ratio = total / compressedSize;
|
||||
int saved = total - compressedSize;
|
||||
|
||||
if (ratio > 3 && Thread.currentThread() != Fawe.get().getMainThread() && actor != null) {
|
||||
BBC.COMPRESSED.send(actor, saved, ratio);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static File copyFile(File jar, String resource, File output) {
|
||||
try {
|
||||
if (output == null) {
|
||||
@ -209,46 +301,6 @@ public class MainUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void sendCompressedMessage(FaweStreamChangeSet set, Actor actor)
|
||||
{
|
||||
try {
|
||||
int elements = set.size();
|
||||
int compressedSize = set.getCompressedSize();
|
||||
if (compressedSize == 0) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* BlockVector
|
||||
* - reference to the object --> 8 bytes
|
||||
* - object header (java internals) --> 8 bytes
|
||||
* - double x, y, z --> 24 bytes
|
||||
*
|
||||
* BaseBlock
|
||||
* - reference to the object --> 8 bytes
|
||||
* - object header (java internals) --> 8 bytes
|
||||
* - short id, data --> 4 bytes
|
||||
* - NBTCompound (assuming null) --> 4 bytes
|
||||
*
|
||||
* There are usually two lists for the block changes:
|
||||
* 2 * BlockVector + 2 * BaseBlock = 128b
|
||||
*
|
||||
* WE has a lot more overhead, this is just a generous lower bound
|
||||
*
|
||||
* This compares FAWE's usage to standard WE.
|
||||
*/
|
||||
int total = 128 * elements;
|
||||
|
||||
int ratio = total / compressedSize;
|
||||
int saved = total - compressedSize;
|
||||
|
||||
if (ratio > 3 && Thread.currentThread() != Fawe.get().getMainThread() && actor != null && actor.isPlayer() && actor.getSessionKey().isActive()) {
|
||||
BBC.COMPRESSED.send(actor, saved, ratio);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleError(Throwable e) {
|
||||
handleError(e, true);
|
||||
}
|
||||
|
@ -17,6 +17,16 @@ public class MemUtil {
|
||||
return memory.get();
|
||||
}
|
||||
|
||||
public static boolean isMemoryLimitedSlow() {
|
||||
if (memory.get()) {
|
||||
System.gc();
|
||||
System.gc();
|
||||
calculateMemory();
|
||||
return memory.get();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int calculateMemory() {
|
||||
final long heapSize = Runtime.getRuntime().totalMemory();
|
||||
final long heapMaxSize = Runtime.getRuntime().maxMemory();
|
||||
@ -46,6 +56,8 @@ public class MemUtil {
|
||||
}
|
||||
|
||||
public static void memoryLimitedTask() {
|
||||
System.gc();
|
||||
System.gc();
|
||||
for (Runnable task : memoryLimitedTasks) {
|
||||
task.run();
|
||||
}
|
||||
|
@ -188,6 +188,15 @@ public static <T> List<T> getList(List<T> list) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void setField(String fieldName, Object instance, Object value) {
|
||||
try {
|
||||
Field field = instance.getClass().getDeclaredField(fieldName);
|
||||
setField(field, instance, value);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setField(final Field field, final Object instance, final Object value) {
|
||||
if (field == null) {
|
||||
throw new RuntimeException("No such field");
|
||||
|
@ -23,7 +23,6 @@ import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.EditSessionWrapper;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
@ -38,27 +37,22 @@ import com.boydti.fawe.object.changeset.MemoryOptimizedHistory;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.boydti.fawe.object.extent.FastWorldEditExtent;
|
||||
import com.boydti.fawe.object.extent.FaweRegionExtent;
|
||||
import com.boydti.fawe.object.extent.MemoryCheckingExtent;
|
||||
import com.boydti.fawe.object.extent.NullExtent;
|
||||
import com.boydti.fawe.object.extent.ProcessedWEExtent;
|
||||
import com.boydti.fawe.object.progress.DefaultProgressTracker;
|
||||
import com.boydti.fawe.util.ExtentTraverser;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.boydti.fawe.util.Perm;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.boydti.fawe.wrappers.WorldWrapper;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.blocks.BlockID;
|
||||
import com.sk89q.worldedit.blocks.BlockType;
|
||||
import com.sk89q.worldedit.command.tool.BrushTool;
|
||||
import com.sk89q.worldedit.command.tool.Tool;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.event.extent.EditSessionEvent;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.ChangeSetExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.MaskingExtent;
|
||||
@ -133,8 +127,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
@ -153,9 +146,6 @@ import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
|
||||
* using the {@link ChangeSetExtent}.</p>
|
||||
*/
|
||||
public class EditSession implements Extent {
|
||||
|
||||
private final Logger log = Logger.getLogger(EditSession.class.getCanonicalName());
|
||||
|
||||
/**
|
||||
* Used by {@link #setBlock(Vector, BaseBlock, Stage)} to
|
||||
* determine which {@link Extent}s should be bypassed.
|
||||
@ -165,25 +155,113 @@ public class EditSession implements Extent {
|
||||
}
|
||||
|
||||
private World world;
|
||||
private Actor actor;
|
||||
private FaweChangeSet changeSet;
|
||||
private EditSessionWrapper wrapper;
|
||||
private MaskingExtent maskingExtent;
|
||||
private FaweRegionExtent regionExtent;
|
||||
private Extent primaryExtent;
|
||||
private HistoryExtent history;
|
||||
private Extent bypassReorderHistory;
|
||||
private Extent bypassHistory;
|
||||
private Extent bypassNone;
|
||||
private SurvivalModeExtent lazySurvivalExtent;
|
||||
private boolean fastmode;
|
||||
private Mask oldMask;
|
||||
private FaweLimit limit = FaweLimit.MAX.copy();
|
||||
private FaweQueue queue;
|
||||
private Extent bypassNone;
|
||||
private HistoryExtent history;
|
||||
private Extent bypassHistory;
|
||||
private Extent bypassAll;
|
||||
private FaweLimit limit;
|
||||
private FawePlayer player;
|
||||
private FaweChangeSet changeTask;
|
||||
|
||||
private int changes = 0;
|
||||
private BlockBag blockBag;
|
||||
|
||||
public static final UUID CONSOLE = UUID.fromString("1-1-3-3-7");
|
||||
public static final BaseBiome nullBiome = new BaseBiome(0);
|
||||
public static final BaseBlock nullBlock = FaweCache.CACHE_BLOCK[0];
|
||||
private static final Vector[] recurseDirections = {
|
||||
PlayerDirection.NORTH.vector(),
|
||||
PlayerDirection.EAST.vector(),
|
||||
PlayerDirection.SOUTH.vector(),
|
||||
PlayerDirection.WEST.vector(),
|
||||
PlayerDirection.UP.vector(),
|
||||
PlayerDirection.DOWN.vector(), };
|
||||
|
||||
public EditSession(@Nonnull World world, @Nullable FawePlayer player, @Nullable FaweLimit limit, @Nullable FaweChangeSet changeSet, @Nullable RegionWrapper[] allowedRegions, @Nullable Boolean autoQueue, @Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages, @Nullable BlockBag blockBag, @Nullable EventBus bus, @Nullable EditSessionEvent event) {
|
||||
checkNotNull(world);
|
||||
this.world = world = WorldWrapper.wrap((AbstractWorld) world);
|
||||
if (bus == null) {
|
||||
bus = WorldEdit.getInstance().getEventBus();
|
||||
}
|
||||
if (event == null) {
|
||||
event = new EditSessionEvent(world, player == null ? null : (player.getPlayer()), -1, null);
|
||||
}
|
||||
event.setEditSession(this);
|
||||
if (player == null) {
|
||||
player = FawePlayer.wrap(event.getActor());
|
||||
}
|
||||
this.player = player;
|
||||
if (changeSet == null) {
|
||||
if (Settings.STORE_HISTORY_ON_DISK) {
|
||||
UUID uuid = player == null ? CONSOLE : player.getUUID();
|
||||
changeSet = new DiskStorageHistory(world, uuid);
|
||||
} else if (Settings.COMBINE_HISTORY_STAGE && Settings.COMPRESSION_LEVEL == 0) {
|
||||
changeSet = new CPUOptimizedChangeSet(world);
|
||||
} else {
|
||||
changeSet = new MemoryOptimizedHistory(world);
|
||||
}
|
||||
}
|
||||
if (limit == null) {
|
||||
if (player == null) {
|
||||
limit = FaweLimit.MAX.copy();
|
||||
} else {
|
||||
limit = player.getLimit();
|
||||
}
|
||||
}
|
||||
if (allowedRegions == null) {
|
||||
if (player != null && !player.hasWorldEditBypass()) {
|
||||
allowedRegions = player.getCurrentRegions();
|
||||
if (allowedRegions.length == 1 && allowedRegions[0].isGlobal()) {
|
||||
allowedRegions = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (autoQueue == null) {
|
||||
autoQueue = true;
|
||||
}
|
||||
if (fastmode == null) {
|
||||
if (player == null) {
|
||||
fastmode = Settings.CONSOLE_HISTORY;
|
||||
} else {
|
||||
fastmode = player.getSession().hasFastMode();
|
||||
}
|
||||
}
|
||||
if (checkMemory == null) {
|
||||
checkMemory = player != null && !fastmode;
|
||||
}
|
||||
if (combineStages == null) {
|
||||
combineStages = Settings.COMBINE_HISTORY_STAGE;
|
||||
}
|
||||
if (checkMemory) {
|
||||
if (MemUtil.isMemoryLimitedSlow()) {
|
||||
if (Perm.hasPermission(player, "worldedit.fast")) {
|
||||
BBC.WORLDEDIT_OOM_ADMIN.send(player);
|
||||
}
|
||||
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_LOW_MEMORY);
|
||||
}
|
||||
}
|
||||
if (allowedRegions != null && allowedRegions.length == 0) {
|
||||
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_NO_REGION);
|
||||
}
|
||||
this.blockBag = blockBag;
|
||||
this.limit = limit;
|
||||
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), fastmode, autoQueue);
|
||||
this.bypassAll = wrapExtent(new FastWorldEditExtent(world, queue), bus, event, Stage.BEFORE_CHANGE);
|
||||
this.bypassHistory = (bypassNone = wrapExtent(bypassAll, bus, event, Stage.BEFORE_REORDER));
|
||||
if (!fastmode && !(changeSet instanceof NullChangeSet)) {
|
||||
if (combineStages) {
|
||||
changeTask = changeSet;
|
||||
changeSet.addChangeTask(queue);
|
||||
} else {
|
||||
this.bypassNone = (history = new HistoryExtent(this, bypassHistory, changeSet, queue));
|
||||
}
|
||||
}
|
||||
if (allowedRegions != null) {
|
||||
this.bypassNone = new ProcessedWEExtent(bypassNone, allowedRegions, limit);
|
||||
}
|
||||
bypassNone = wrapExtent(bypassNone, bus, event, Stage.BEFORE_HISTORY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
@ -210,9 +288,6 @@ public class EditSession implements Extent {
|
||||
this(WorldEdit.getInstance().getEventBus(), world, maxBlocks, blockBag, new EditSessionEvent(world, null, maxBlocks, null));
|
||||
}
|
||||
|
||||
private int changes = 0;
|
||||
private BlockBag blockBag;
|
||||
|
||||
/**
|
||||
* Construct the object with a maximum number of blocks and a block bag.
|
||||
*
|
||||
@ -223,167 +298,12 @@ public class EditSession implements Extent {
|
||||
* @param event the event to call with the extent
|
||||
*/
|
||||
public EditSession(final EventBus eventBus, World world, final int maxBlocks, @Nullable final BlockBag blockBag, EditSessionEvent event) {
|
||||
checkNotNull(eventBus);
|
||||
checkArgument(maxBlocks >= -1, "maxBlocks >= -1 required");
|
||||
checkNotNull(event);
|
||||
event.setEditSession(this);
|
||||
|
||||
this.actor = event.getActor();
|
||||
// TODO block bag
|
||||
this.blockBag = blockBag;
|
||||
|
||||
// Invalid world: return null extent
|
||||
if (world == null) {
|
||||
Extent extent = this.regionExtent = new NullExtent(world, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
this.bypassReorderHistory = extent;
|
||||
this.bypassHistory = extent;
|
||||
this.bypassNone = extent;
|
||||
this.changeSet = new NullChangeSet(world);
|
||||
this.wrapper = Fawe.imp().getEditSessionWrapper(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Wrap the world
|
||||
this.world = (world = WorldWrapper.wrap((AbstractWorld) world));
|
||||
|
||||
// Delegate some methods to an implementation specific class
|
||||
this.wrapper = Fawe.imp().getEditSessionWrapper(this);
|
||||
|
||||
// Not a player; bypass history
|
||||
if ((actor == null) || !actor.isPlayer()) {
|
||||
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), true, true);
|
||||
queue.addEditSession(this);
|
||||
Extent extent = primaryExtent = new FastWorldEditExtent(world, queue);
|
||||
// Everything bypasses
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER);
|
||||
// History
|
||||
if (Settings.CONSOLE_HISTORY) {
|
||||
this.changeSet = Settings.STORE_HISTORY_ON_DISK ? new DiskStorageHistory(world, CONSOLE) : (Settings.COMBINE_HISTORY_STAGE && Settings.COMPRESSION_LEVEL == 0) ? new CPUOptimizedChangeSet(world) : new MemoryOptimizedHistory(world);
|
||||
if (Settings.COMBINE_HISTORY_STAGE) {
|
||||
changeSet.addChangeTask(queue);
|
||||
} else {
|
||||
extent = history = new HistoryExtent(this, limit, extent, changeSet, queue);
|
||||
}
|
||||
}
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_HISTORY);
|
||||
this.bypassReorderHistory = primaryExtent;
|
||||
this.bypassHistory = primaryExtent;
|
||||
this.bypassNone = extent;
|
||||
this.changeSet = new NullChangeSet(world);
|
||||
return;
|
||||
}
|
||||
|
||||
Extent extent;
|
||||
RegionWrapper[] mask;
|
||||
final FawePlayer fp = FawePlayer.wrap(actor);
|
||||
final LocalSession session = fp.getSession();
|
||||
this.fastmode = session.hasFastMode();
|
||||
boolean bypass = fp.hasWorldEditBypass();
|
||||
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), bypass, true);
|
||||
queue.setProgressTracker(new DefaultProgressTracker(fp));
|
||||
if (bypass) {
|
||||
queue.addEditSession(this);
|
||||
// Bypass skips processing and area restrictions
|
||||
extent = primaryExtent = new FastWorldEditExtent(world, queue);
|
||||
if (this.hasFastMode()) {
|
||||
// Fastmode skips history and memory checks
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER);
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_HISTORY);
|
||||
this.bypassReorderHistory = extent;
|
||||
this.bypassHistory = extent;
|
||||
this.bypassNone = extent;
|
||||
return;
|
||||
}
|
||||
mask = null;
|
||||
} else {
|
||||
queue.addEditSession(this);
|
||||
this.limit = fp.getLimit();
|
||||
mask = WEManager.IMP.getMask(fp);
|
||||
if (mask.length == 0) {
|
||||
// No allowed area; return null extent
|
||||
extent = this.regionExtent = new NullExtent(world, BBC.WORLDEDIT_CANCEL_REASON_NO_REGION);
|
||||
this.bypassReorderHistory = extent;
|
||||
this.bypassHistory = extent;
|
||||
this.bypassNone = extent;
|
||||
return;
|
||||
}
|
||||
extent = primaryExtent = new FastWorldEditExtent(world, queue);
|
||||
if (this.hasFastMode()) {
|
||||
// Fastmode skips history, masking, and memory checks
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER);
|
||||
// Restrictions
|
||||
extent = new ProcessedWEExtent(extent, mask, limit);
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_HISTORY);
|
||||
this.bypassReorderHistory = extent;
|
||||
this.bypassHistory = extent;
|
||||
this.bypassNone = extent;
|
||||
return;
|
||||
} else {
|
||||
if (MemUtil.isMemoryLimited()) {
|
||||
fp.sendMessage(BBC.WORLDEDIT_CANCEL_REASON.format(BBC.WORLDEDIT_CANCEL_REASON_LOW_MEMORY.s()));
|
||||
if (Perm.hasPermission(fp, "worldedit.fast")) {
|
||||
BBC.WORLDEDIT_OOM_ADMIN.send(fp);
|
||||
}
|
||||
// Memory limit reached; return null extent
|
||||
extent = this.regionExtent = new NullExtent(world, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
this.bypassReorderHistory = extent;
|
||||
this.bypassHistory = extent;
|
||||
this.bypassNone = extent;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Perform memory checks after reorder
|
||||
extent = new MemoryCheckingExtent(fp, extent);
|
||||
}
|
||||
// Include history, masking and memory checking.
|
||||
Extent wrapped;
|
||||
// First two events
|
||||
extent = wrapped = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER);
|
||||
|
||||
// History
|
||||
this.changeSet = Settings.STORE_HISTORY_ON_DISK ? new DiskStorageHistory(world, actor.getUniqueId()) : (Settings.COMBINE_HISTORY_STAGE && Settings.COMPRESSION_LEVEL == 0) ? new CPUOptimizedChangeSet(world) : new MemoryOptimizedHistory(world);
|
||||
this.changeSet = this.wrapper.wrapChangeSet(this, limit, extent, this.changeSet, queue, fp);
|
||||
if (Settings.COMBINE_HISTORY_STAGE) {
|
||||
changeSet.addChangeTask(queue);
|
||||
} else {
|
||||
extent = history = new HistoryExtent(this, limit, extent, changeSet, queue);
|
||||
}
|
||||
// Region restrictions if mask is not null
|
||||
if (mask != null) {
|
||||
extent = this.regionExtent = new ProcessedWEExtent(extent, mask, limit);
|
||||
}
|
||||
|
||||
// Masking
|
||||
final Player skp = (Player) actor;
|
||||
final int item = skp.getItemInHand();
|
||||
boolean hasMask = session.getMask() != null;
|
||||
if ((item != 0) && (!hasMask)) {
|
||||
try {
|
||||
final Tool tool = session.getTool(item);
|
||||
if ((tool != null) && (tool instanceof BrushTool)) {
|
||||
hasMask = ((BrushTool) tool).getMask() != null;
|
||||
}
|
||||
} catch (final Exception e) {}
|
||||
}
|
||||
if (hasMask) {
|
||||
extent = this.maskingExtent = new MaskingExtent(extent, Masks.alwaysTrue());
|
||||
}
|
||||
|
||||
// Before history event
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_HISTORY);
|
||||
|
||||
this.bypassReorderHistory = wrapped;
|
||||
this.bypassHistory = wrapped;
|
||||
this.bypassNone = extent;
|
||||
return;
|
||||
this(world, null, null, null, null, true, null, null, null, blockBag, eventBus, event);
|
||||
}
|
||||
|
||||
public FaweRegionExtent getRegionExtent() {
|
||||
return regionExtent;
|
||||
ExtentTraverser<FaweRegionExtent> traverser = new ExtentTraverser(bypassNone).find(FaweRegionExtent.class);
|
||||
return traverser == null ? null : traverser.get();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -391,27 +311,24 @@ public class EditSession implements Extent {
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public Actor getActor() {
|
||||
return actor;
|
||||
public FawePlayer getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public boolean cancel() {
|
||||
// Cancel this
|
||||
if (primaryExtent != null && queue != null) {
|
||||
try {
|
||||
WEManager.IMP.cancelEdit(primaryExtent, BBC.WORLDEDIT_CANCEL_REASON_MANUAL);
|
||||
} catch (Throwable ignore) {}
|
||||
NullExtent nullExtent = new NullExtent(world, BBC.WORLDEDIT_CANCEL_REASON_MANUAL);
|
||||
primaryExtent = nullExtent;
|
||||
regionExtent = nullExtent;
|
||||
bypassReorderHistory = nullExtent;
|
||||
bypassHistory = nullExtent;
|
||||
bypassNone = nullExtent;
|
||||
dequeue();
|
||||
queue.clear();
|
||||
return true;
|
||||
ExtentTraverser traverser = new ExtentTraverser(bypassNone);
|
||||
NullExtent nullExtent = new NullExtent(world, BBC.WORLDEDIT_CANCEL_REASON_MANUAL);
|
||||
while (traverser != null) {
|
||||
ExtentTraverser next = traverser.next();
|
||||
traverser.setNext(nullExtent);
|
||||
traverser = next;
|
||||
}
|
||||
return false;
|
||||
bypassHistory = nullExtent;
|
||||
bypassNone = nullExtent;
|
||||
bypassAll = nullExtent;
|
||||
dequeue();
|
||||
queue.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void dequeue() {
|
||||
@ -426,12 +343,8 @@ public class EditSession implements Extent {
|
||||
}
|
||||
}
|
||||
|
||||
public FastWorldEditExtent getPrimaryExtent() {
|
||||
return (FastWorldEditExtent) primaryExtent;
|
||||
}
|
||||
|
||||
public void debug(BBC message, Object... args) {
|
||||
message.send(actor, args);
|
||||
message.send(player, args);
|
||||
}
|
||||
|
||||
public FaweQueue getQueue() {
|
||||
@ -474,15 +387,21 @@ public class EditSession implements Extent {
|
||||
* @return the change set
|
||||
*/
|
||||
public ChangeSet getChangeSet() {
|
||||
return this.changeSet;
|
||||
return history != null ? history.getChangeSet() : changeTask;
|
||||
}
|
||||
|
||||
public void setChangeSet(FaweChangeSet set) {
|
||||
if (history != null) {
|
||||
history.setChangeSet(set);
|
||||
if (set == null) {
|
||||
disableHistory(true);
|
||||
} else {
|
||||
if (history != null) {
|
||||
history.setChangeSet(set);
|
||||
} else {
|
||||
changeTask = set;
|
||||
set.addChangeTask(queue);
|
||||
}
|
||||
}
|
||||
changes++;
|
||||
this.changeSet = set;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -510,14 +429,13 @@ public class EditSession implements Extent {
|
||||
* @return whether the queue is enabled
|
||||
*/
|
||||
public boolean isQueueEnabled() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue certain types of block for better reproduction of those blocks.
|
||||
*/
|
||||
public void enableQueue() {
|
||||
}
|
||||
public void enableQueue() {}
|
||||
|
||||
/**
|
||||
* Disable the queue. This will flush the queue.
|
||||
@ -534,7 +452,8 @@ public class EditSession implements Extent {
|
||||
* @return mask, may be null
|
||||
*/
|
||||
public Mask getMask() {
|
||||
return this.oldMask;
|
||||
ExtentTraverser<MaskingExtent> maskingExtent = new ExtentTraverser(bypassNone).find(MaskingExtent.class);
|
||||
return maskingExtent != null ? maskingExtent.get().getMask() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -542,15 +461,15 @@ public class EditSession implements Extent {
|
||||
*
|
||||
* @param mask mask or null
|
||||
*/
|
||||
public void setMask(final Mask mask) {
|
||||
if (this.maskingExtent == null) {
|
||||
return;
|
||||
}
|
||||
this.oldMask = mask;
|
||||
public void setMask(Mask mask) {
|
||||
if (mask == null) {
|
||||
this.maskingExtent.setMask(Masks.alwaysTrue());
|
||||
} else {
|
||||
this.maskingExtent.setMask(mask);
|
||||
mask = Masks.alwaysTrue();
|
||||
}
|
||||
ExtentTraverser<MaskingExtent> maskingExtent = new ExtentTraverser(bypassNone).find(MaskingExtent.class);
|
||||
if (maskingExtent != null) {
|
||||
maskingExtent.get().setMask(mask);
|
||||
} else if (mask != Masks.alwaysTrue()) {
|
||||
bypassNone = new MaskingExtent(bypassNone, mask);
|
||||
}
|
||||
}
|
||||
|
||||
@ -575,10 +494,12 @@ public class EditSession implements Extent {
|
||||
* @return the survival simulation extent
|
||||
*/
|
||||
public SurvivalModeExtent getSurvivalExtent() {
|
||||
if (this.lazySurvivalExtent == null) {
|
||||
this.lazySurvivalExtent = new SurvivalModeExtent(bypassReorderHistory, world);
|
||||
ExtentTraverser<SurvivalModeExtent> survivalExtent = new ExtentTraverser(bypassNone).find(SurvivalModeExtent.class);
|
||||
if (survivalExtent != null) {
|
||||
return survivalExtent.get();
|
||||
} else {
|
||||
return (SurvivalModeExtent) (bypassNone = new SurvivalModeExtent(bypassNone, getWorld()));
|
||||
}
|
||||
return lazySurvivalExtent;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -590,7 +511,31 @@ public class EditSession implements Extent {
|
||||
* @param enabled true to enable
|
||||
*/
|
||||
public void setFastMode(final boolean enabled) {
|
||||
this.fastmode = enabled;
|
||||
disableHistory(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable history (or re-enable)
|
||||
* @param disableHistory
|
||||
*/
|
||||
public void disableHistory(boolean disableHistory) {
|
||||
if (history == null) {
|
||||
return;
|
||||
}
|
||||
ExtentTraverser traverseHistory = new ExtentTraverser(bypassNone).find(HistoryExtent.class);
|
||||
if (disableHistory) {
|
||||
if (traverseHistory != null) {
|
||||
ExtentTraverser beforeHistory = traverseHistory.previous();
|
||||
ExtentTraverser afterHistory = traverseHistory.next();
|
||||
beforeHistory.setNext(afterHistory.get());
|
||||
}
|
||||
} else if (traverseHistory == null) {
|
||||
ExtentTraverser traverseBypass = new ExtentTraverser(bypassNone).find(bypassHistory);
|
||||
if (traverseBypass != null) {
|
||||
ExtentTraverser beforeHistory = traverseBypass.previous();
|
||||
beforeHistory.setNext(history);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -602,7 +547,7 @@ public class EditSession implements Extent {
|
||||
* @return true if enabled
|
||||
*/
|
||||
public boolean hasFastMode() {
|
||||
return this.fastmode;
|
||||
return history == null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -661,16 +606,17 @@ public class EditSession implements Extent {
|
||||
}
|
||||
|
||||
public BaseBlock getLazyBlock(int x, int y, int z) {
|
||||
if (limit != null && limit.MAX_CHECKS-- < 0) {
|
||||
if (!limit.MAX_CHECKS()) {
|
||||
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS);
|
||||
}
|
||||
int combinedId4Data = queue.getCombinedId4DataDebug(x, y, z, 0, this);
|
||||
if (!FaweCache.hasNBT(combinedId4Data >> 4)) {
|
||||
int id = FaweCache.getId(combinedId4Data);
|
||||
if (!FaweCache.hasNBT(id)) {
|
||||
return FaweCache.CACHE_BLOCK[combinedId4Data];
|
||||
}
|
||||
try {
|
||||
BaseBlock block = this.world.getBlock(new Vector(x, y, z));
|
||||
return block;
|
||||
CompoundTag tile = queue.getTileEntity(x, y, z);
|
||||
return new BaseBlock(id, FaweCache.getData(combinedId4Data), tile);
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
return FaweCache.CACHE_BLOCK[combinedId4Data];
|
||||
@ -691,7 +637,7 @@ public class EditSession implements Extent {
|
||||
*/
|
||||
@Deprecated
|
||||
public int getBlockType(final Vector position) {
|
||||
if (limit != null && limit.MAX_CHECKS-- < 0) {
|
||||
if (!limit.MAX_CHECKS()) {
|
||||
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS);
|
||||
}
|
||||
int combinedId4Data = queue.getCombinedId4DataDebug(position.getBlockX(), position.getBlockY(), position.getBlockZ(), 0, this);
|
||||
@ -707,7 +653,7 @@ public class EditSession implements Extent {
|
||||
*/
|
||||
@Deprecated
|
||||
public int getBlockData(final Vector position) {
|
||||
if (limit != null && limit.MAX_CHECKS-- < 0) {
|
||||
if (!limit.MAX_CHECKS()) {
|
||||
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS);
|
||||
}
|
||||
int combinedId4Data = queue.getCombinedId4DataDebug(position.getBlockX(), position.getBlockY(), position.getBlockZ(), 0, this);
|
||||
@ -750,7 +696,104 @@ public class EditSession implements Extent {
|
||||
* @return height of highest block found or 'minY'
|
||||
*/
|
||||
public int getHighestTerrainBlock(final int x, final int z, final int minY, final int maxY, final boolean naturalOnly) {
|
||||
return this.wrapper.getHighestTerrainBlock(x, z, minY, maxY, naturalOnly);
|
||||
Vector pt = new Vector(x, 0, z);
|
||||
for (int y = maxY; y >= minY; --y) {
|
||||
BaseBlock block = getLazyBlock(x, y, z);
|
||||
final int id = block.getId();
|
||||
int data;
|
||||
switch (id) {
|
||||
case 0: {
|
||||
continue;
|
||||
}
|
||||
case 2:
|
||||
case 4:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 25:
|
||||
case 30:
|
||||
case 32:
|
||||
case 37:
|
||||
case 39:
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
case 45:
|
||||
case 46:
|
||||
case 47:
|
||||
case 48:
|
||||
case 49:
|
||||
case 51:
|
||||
case 52:
|
||||
case 54:
|
||||
case 55:
|
||||
case 56:
|
||||
case 57:
|
||||
case 58:
|
||||
case 60:
|
||||
case 61:
|
||||
case 62:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 73:
|
||||
case 74:
|
||||
case 78:
|
||||
case 79:
|
||||
case 80:
|
||||
case 81:
|
||||
case 82:
|
||||
case 83:
|
||||
case 84:
|
||||
case 85:
|
||||
case 87:
|
||||
case 88:
|
||||
case 101:
|
||||
case 102:
|
||||
case 103:
|
||||
case 110:
|
||||
case 112:
|
||||
case 113:
|
||||
case 117:
|
||||
case 121:
|
||||
case 122:
|
||||
case 123:
|
||||
case 124:
|
||||
case 129:
|
||||
case 133:
|
||||
case 138:
|
||||
case 137:
|
||||
case 140:
|
||||
case 165:
|
||||
case 166:
|
||||
case 169:
|
||||
case 170:
|
||||
case 172:
|
||||
case 173:
|
||||
case 174:
|
||||
case 176:
|
||||
case 177:
|
||||
case 181:
|
||||
case 182:
|
||||
case 188:
|
||||
case 189:
|
||||
case 190:
|
||||
case 191:
|
||||
case 192:
|
||||
return y;
|
||||
default:
|
||||
data = 0;
|
||||
}
|
||||
if (naturalOnly ? BlockType.isNaturalTerrainBlock(id, data) : !BlockType.canPassThrough(id, data)) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
return minY;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -770,7 +813,7 @@ public class EditSession implements Extent {
|
||||
case BEFORE_CHANGE:
|
||||
return this.bypassHistory.setBlock(position, block);
|
||||
case BEFORE_REORDER:
|
||||
return this.bypassReorderHistory.setBlock(position, block);
|
||||
return this.bypassAll.setBlock(position, block);
|
||||
}
|
||||
|
||||
throw new RuntimeException("New enum entry added that is unhandled here");
|
||||
@ -802,7 +845,7 @@ public class EditSession implements Extent {
|
||||
public boolean smartSetBlock(final Vector position, final BaseBlock block) {
|
||||
this.changes++;
|
||||
try {
|
||||
return this.bypassReorderHistory.setBlock(position, block);
|
||||
return this.bypassAll.setBlock(position, block);
|
||||
} catch (final WorldEditException e) {
|
||||
throw new RuntimeException("Unexpected exception", e);
|
||||
}
|
||||
@ -894,7 +937,10 @@ public class EditSession implements Extent {
|
||||
*/
|
||||
@Deprecated
|
||||
public void rememberChange(final Vector position, final BaseBlock existing, final BaseBlock block) {
|
||||
this.changeSet.add(new BlockChange(position.toBlockVector(), existing, block));
|
||||
ChangeSet changeSet = getChangeSet();
|
||||
if (changeSet != null) {
|
||||
changeSet.add(new BlockChange(position.toBlockVector(), existing, block));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -904,9 +950,9 @@ public class EditSession implements Extent {
|
||||
*/
|
||||
public void undo(final EditSession editSession) {
|
||||
final UndoContext context = new UndoContext();
|
||||
context.setExtent(editSession.primaryExtent);
|
||||
context.setExtent(editSession.bypassAll);
|
||||
editSession.getQueue().setChangeTask(null);
|
||||
Operations.completeSmart(ChangeSetExecutor.createUndo(this.changeSet, context), new Runnable() {
|
||||
Operations.completeSmart(ChangeSetExecutor.createUndo(getChangeSet(), context), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
editSession.flushQueue();
|
||||
@ -922,9 +968,9 @@ public class EditSession implements Extent {
|
||||
*/
|
||||
public void redo(final EditSession editSession) {
|
||||
final UndoContext context = new UndoContext();
|
||||
context.setExtent(editSession.primaryExtent);
|
||||
context.setExtent(editSession.bypassAll);
|
||||
editSession.getQueue().setChangeTask(null);
|
||||
Operations.completeSmart(ChangeSetExecutor.createRedo(this.changeSet, context), new Runnable() {
|
||||
Operations.completeSmart(ChangeSetExecutor.createRedo(getChangeSet(), context), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
editSession.flushQueue();
|
||||
@ -973,7 +1019,7 @@ public class EditSession implements Extent {
|
||||
} else {
|
||||
queue.dequeue();
|
||||
}
|
||||
if (changeSet != null) {
|
||||
if (getChangeSet() != null) {
|
||||
if (Settings.COMBINE_HISTORY_STAGE && queue.size() > 0) {
|
||||
if (Fawe.get().isMainThread()) {
|
||||
SetQueue.IMP.flush(queue);
|
||||
@ -988,13 +1034,13 @@ public class EditSession implements Extent {
|
||||
TaskManager.IMP.wait(running, Settings.QUEUE_DISCARD_AFTER);
|
||||
}
|
||||
}
|
||||
changeSet.flush();
|
||||
((FaweChangeSet) getChangeSet()).flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Operation commit() {
|
||||
return this.bypassNone.commit();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1708,8 +1754,8 @@ public class EditSession implements Extent {
|
||||
|
||||
if (pos.getBlockY() < 0) {
|
||||
pos = pos.setY(0);
|
||||
} else if (((pos.getBlockY() + height) - 1) > this.world.getMaxY()) {
|
||||
height = (this.world.getMaxY() - pos.getBlockY()) + 1;
|
||||
} else if (((pos.getBlockY() + height) - 1) > 255) {
|
||||
height = (255 - pos.getBlockY()) + 1;
|
||||
}
|
||||
|
||||
final double invRadiusX = 1 / radiusX;
|
||||
@ -1892,7 +1938,7 @@ public class EditSession implements Extent {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int y = this.world.getMaxY(); y >= 1; --y) {
|
||||
for (int y = 255; y >= 1; --y) {
|
||||
final Vector pt = new Vector(x, y, z);
|
||||
final int id = this.getBlockType(pt);
|
||||
|
||||
@ -1946,7 +1992,7 @@ public class EditSession implements Extent {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int y = this.world.getMaxY(); y >= 1; --y) {
|
||||
for (int y = 255; y >= 1; --y) {
|
||||
final Vector pt = new Vector(x, y, z);
|
||||
final int id = this.getBlockType(pt);
|
||||
|
||||
@ -1966,7 +2012,7 @@ public class EditSession implements Extent {
|
||||
}
|
||||
|
||||
// Too high?
|
||||
if (y == this.world.getMaxY()) {
|
||||
if (y == 255) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2020,7 +2066,7 @@ public class EditSession implements Extent {
|
||||
continue;
|
||||
}
|
||||
|
||||
loop: for (int y = this.world.getMaxY(); y >= 1; --y) {
|
||||
loop: for (int y = 255; y >= 1; --y) {
|
||||
final Vector pt = new Vector(x, y, z);
|
||||
final int id = this.getBlockType(pt);
|
||||
final int data = this.getBlockData(pt);
|
||||
@ -2279,7 +2325,7 @@ public class EditSession implements Extent {
|
||||
|
||||
return FaweCache.getBlock((int) typeVariable.getValue(), (int) dataVariable.getValue());
|
||||
} catch (final Exception e) {
|
||||
EditSession.this.log.log(Level.WARNING, "Failed to create shape", e);
|
||||
Fawe.debug("Failed to create shape: " + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -2594,7 +2640,7 @@ public class EditSession implements Extent {
|
||||
|
||||
return defaultBiomeType;
|
||||
} catch (final Exception e) {
|
||||
EditSession.this.log.log(Level.WARNING, "Failed to create shape", e);
|
||||
Fawe.debug("Failed to create shape: " + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -2603,14 +2649,6 @@ public class EditSession implements Extent {
|
||||
return shape.generate(this, biomeType, hollow);
|
||||
}
|
||||
|
||||
private final Vector[] recurseDirections = {
|
||||
PlayerDirection.NORTH.vector(),
|
||||
PlayerDirection.EAST.vector(),
|
||||
PlayerDirection.SOUTH.vector(),
|
||||
PlayerDirection.WEST.vector(),
|
||||
PlayerDirection.UP.vector(),
|
||||
PlayerDirection.DOWN.vector(), };
|
||||
|
||||
private double lengthSq(final double x, final double y, final double z) {
|
||||
return (x * x) + (y * y) + (z * z);
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ public class ClipboardCommands {
|
||||
final int mx = origin.getBlockX();
|
||||
final int my = origin.getBlockY();
|
||||
final int mz = origin.getBlockZ();
|
||||
LazyClipboard lazyClipboard = new LazyClipboard() {
|
||||
LazyClipboard lazyClipboard = new LazyClipboard(region) {
|
||||
@Override
|
||||
public BaseBlock getBlock(int x, int y, int z) {
|
||||
return editSession.getLazyBlock(mx + x, my + y, mz + z);
|
||||
|
@ -117,9 +117,7 @@ public class SchematicCommands {
|
||||
in = new FileInputStream(f);
|
||||
}
|
||||
in = new BufferedInputStream(in);
|
||||
|
||||
final ClipboardReader reader = format.getReader(in);
|
||||
|
||||
final WorldData worldData = player.getWorld().getWorldData();
|
||||
final Clipboard clipboard;
|
||||
if (reader instanceof SchematicReader) {
|
||||
|
@ -78,26 +78,21 @@ public class SelectionCommand extends SimpleCommand<Operation> {
|
||||
if (!testPermission(locals)) {
|
||||
throw new CommandPermissionsException();
|
||||
}
|
||||
|
||||
Contextual<? extends Operation> operationFactory = delegate.call(args, locals);
|
||||
|
||||
Actor actor = locals.get(Actor.class);
|
||||
if (actor instanceof Player) {
|
||||
try {
|
||||
Player player = (Player) actor;
|
||||
LocalSession session = WorldEdit.getInstance().getSessionManager().get(player);
|
||||
Region selection = session.getSelection(player.getWorld());
|
||||
|
||||
EditSession editSession = session.createEditSession(player);
|
||||
editSession.enableQueue();
|
||||
locals.put(EditSession.class, editSession);
|
||||
session.tellVersion(player);
|
||||
|
||||
EditContext editContext = new EditContext();
|
||||
editContext.setDestination(locals.get(EditSession.class));
|
||||
editContext.setRegion(selection);
|
||||
Operation operation = operationFactory.createFromContext(editContext);
|
||||
|
||||
// Shortcut
|
||||
if (selection instanceof CuboidRegion && editSession.hasFastMode() && operation instanceof RegionVisitor) {
|
||||
CuboidRegion cuboid = (CuboidRegion) selection;
|
||||
|
@ -302,7 +302,7 @@ public final class CommandManager {
|
||||
BBC.ACTION_COMPLETE.send(actor, (time / 1000d));
|
||||
ChangeSet fcs = editSession.getChangeSet();
|
||||
if (fcs != null && fcs instanceof FaweStreamChangeSet) {
|
||||
MainUtil.sendCompressedMessage((FaweStreamChangeSet) fcs, editSession.getActor());
|
||||
MainUtil.sendCompressedMessage((FaweStreamChangeSet) fcs, editSession.getPlayer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
|
||||
import com.boydti.fawe.object.clipboard.FaweClipboard;
|
||||
import com.boydti.fawe.object.clipboard.MemoryOptimizedClipboard;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
@ -189,6 +190,13 @@ public class BlockArrayClipboard implements Clipboard {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
x -= mx;
|
||||
y -= my;
|
||||
z -= mz;
|
||||
return IMP.setTile(x, y, z, tag);
|
||||
}
|
||||
|
||||
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
|
||||
x -= mx;
|
||||
y -= my;
|
||||
|
@ -19,12 +19,14 @@
|
||||
|
||||
package com.sk89q.worldedit.extent.clipboard.io;
|
||||
|
||||
import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
|
||||
import com.boydti.fawe.object.schematic.FaweFormat;
|
||||
import com.boydti.fawe.object.schematic.StructureFormat;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.sk89q.jnbt.NBTConstants;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@ -40,6 +42,8 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -99,7 +103,10 @@ public enum ClipboardFormat {
|
||||
return "schematic";
|
||||
}
|
||||
},
|
||||
// Added
|
||||
/**
|
||||
* The structure block format:
|
||||
* http://minecraft.gamepedia.com/Structure_block_file_format
|
||||
*/
|
||||
STRUCTURE("structure", "nbt") {
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
@ -128,10 +135,91 @@ public enum ClipboardFormat {
|
||||
public String getExtension() {
|
||||
return "nbt";
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// TODO add the FAWE clipboard / history formats
|
||||
// .bd, .nbtf, .nbtt, .rabd
|
||||
/**
|
||||
* The FAWE file format:
|
||||
* - Streamable for known dimensions with mode 0
|
||||
* - Streamable for unknown dimensions
|
||||
* - 1: Max size 256 x 256 x 256
|
||||
* - 2: Max size 65535 x 65535 x 65535
|
||||
* - 3: Includes BlockChange information
|
||||
* - O(1) Access to blocks if using compression level 0 and mode 0
|
||||
*
|
||||
* DiskOptimizedClipboard: compression/mode -> 0/0
|
||||
* DiskStorageHistory: compression/mode -> Any/3
|
||||
* MemoryOptimizedHistory: compression/mode -> Any/3
|
||||
* FaweFormat: compression/mode -> Any/Any (slower)
|
||||
*
|
||||
*/
|
||||
FAWE("fawe") {
|
||||
/**
|
||||
* Read a clipboard from a compressed stream (the first byte indicates the compression level)
|
||||
* @param inputStream the input stream
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
return new FaweFormat(MainUtil.getCompressedIS(inputStream));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a clipboard to a stream with compression level 8
|
||||
* @param outputStream the output stream
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
|
||||
return getWriter(outputStream, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a clipboard to a stream
|
||||
* @param os
|
||||
* @param compression
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public ClipboardWriter getWriter(OutputStream os, int compression) throws IOException {
|
||||
FaweFormat writer = new FaweFormat(new FaweOutputStream(os));
|
||||
writer.compress(compression);
|
||||
return writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read or write blocks ids to a file
|
||||
* @param file
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public DiskOptimizedClipboard getUncompressedReadWrite(File file) throws IOException {
|
||||
return new DiskOptimizedClipboard(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read or write block ids to a new file
|
||||
* @param width
|
||||
* @param height
|
||||
* @param length
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
public DiskOptimizedClipboard createUncompressedReadWrite(int width, int height, int length, File file) {
|
||||
return new DiskOptimizedClipboard(width, height, length, file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
return file.getName().endsWith(".fawe") || file.getName().endsWith(".bd");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtension() {
|
||||
return "fawe";
|
||||
}
|
||||
},
|
||||
|
||||
;
|
||||
|
||||
@ -144,7 +232,7 @@ public enum ClipboardFormat {
|
||||
*
|
||||
* @param aliases an array of aliases by which this format may be referred to
|
||||
*/
|
||||
private ClipboardFormat(String ... aliases) {
|
||||
ClipboardFormat(String ... aliases) {
|
||||
this.aliases = aliases;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,242 @@
|
||||
package com.sk89q.worldedit.extent.clipboard.io;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.object.clipboard.FaweClipboard;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.ByteArrayTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.DoubleTag;
|
||||
import com.sk89q.jnbt.FloatTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.jnbt.ShortTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
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.clipboard.BlockArrayClipboard;
|
||||
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.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Writes schematic files based that are compatible with MCEdit and other editors.
|
||||
*/
|
||||
public class SchematicWriter implements ClipboardWriter {
|
||||
|
||||
private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE;
|
||||
private final NBTOutputStream outputStream;
|
||||
|
||||
/**
|
||||
* Create a new schematic writer.
|
||||
*
|
||||
* @param outputStream the output stream to write to
|
||||
*/
|
||||
public SchematicWriter(NBTOutputStream outputStream) {
|
||||
checkNotNull(outputStream);
|
||||
this.outputStream = outputStream;
|
||||
}
|
||||
|
||||
private static class ForEach extends RunnableVal2<Vector, BaseBlock> {
|
||||
int x = -1;
|
||||
int y = 0;
|
||||
int z = 0;
|
||||
int index = 0;
|
||||
|
||||
public int[] yarea;
|
||||
public int[] zwidth;
|
||||
public byte[] blocks;
|
||||
public byte[] blockData;
|
||||
public byte[] addBlocks;
|
||||
public List<Tag> tileEntities;
|
||||
|
||||
public ForEach(int[] yarea, int[] zwidth, byte[] blocks, byte[] blockData, List<Tag> tileEntities) {
|
||||
this.yarea = yarea;
|
||||
this.zwidth = zwidth;
|
||||
this.blocks = blocks;
|
||||
this.blockData = blockData;
|
||||
this.tileEntities = tileEntities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Vector point, BaseBlock block) {
|
||||
int x = (int) point.x;
|
||||
int y = (int) point.y;
|
||||
int z = (int) point.z;
|
||||
if (this.x == x - 1 && this.y == y && this.z == z) {
|
||||
index++;
|
||||
x++;
|
||||
} else {
|
||||
index = yarea[y] + zwidth[z] + x;
|
||||
}
|
||||
int id = block.getId();
|
||||
blocks[index] = (byte) id;
|
||||
if (FaweCache.hasData(id)) {
|
||||
blockData[index] = (byte) block.getData();
|
||||
if (id > 255) {
|
||||
if (addBlocks == null) { // Lazily create section
|
||||
addBlocks = new byte[(blocks.length >> 1) + 1];
|
||||
}
|
||||
addBlocks[index >> 1] = (byte) (((index & 1) == 0) ? addBlocks[index >> 1] & 0xF0 | (id >> 8) & 0xF : addBlocks[index >> 1] & 0xF | ((id >> 8) & 0xF) << 4);
|
||||
}
|
||||
}
|
||||
CompoundTag rawTag = block.getNbtData();
|
||||
if (rawTag != null) {
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(rawTag.getValue());
|
||||
values.put("id", new StringTag(block.getNbtId()));
|
||||
values.put("x", new IntTag(x));
|
||||
values.put("y", new IntTag(y));
|
||||
values.put("z", new IntTag(z));
|
||||
tileEntities.add(rawTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Clipboard clipboard, WorldData data) throws IOException {
|
||||
outputStream.writeNamedTag("Schematic", writeTag(clipboard));
|
||||
}
|
||||
|
||||
public static CompoundTag writeTag(Clipboard clipboard) {
|
||||
Region region = clipboard.getRegion();
|
||||
Vector origin = clipboard.getOrigin();
|
||||
Vector min = region.getMinimumPoint();
|
||||
Vector offset = min.subtract(origin);
|
||||
int width = region.getWidth();
|
||||
int height = region.getHeight();
|
||||
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");
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// Metadata
|
||||
// ====================================================================
|
||||
|
||||
HashMap<String, Tag> schematic = new HashMap<String, Tag>();
|
||||
schematic.put("Width", new ShortTag((short) width));
|
||||
schematic.put("Length", new ShortTag((short) length));
|
||||
schematic.put("Height", new ShortTag((short) height));
|
||||
schematic.put("Materials", new StringTag("Alpha"));
|
||||
schematic.put("WEOriginX", new IntTag(min.getBlockX()));
|
||||
schematic.put("WEOriginY", new IntTag(min.getBlockY()));
|
||||
schematic.put("WEOriginZ", new IntTag(min.getBlockZ()));
|
||||
schematic.put("WEOffsetX", new IntTag(offset.getBlockX()));
|
||||
schematic.put("WEOffsetY", new IntTag(offset.getBlockY()));
|
||||
schematic.put("WEOffsetZ", new IntTag(offset.getBlockZ()));
|
||||
|
||||
final byte[] blocks = new byte[width * height * length];
|
||||
byte[] addBlocks = null;
|
||||
final byte[] blockData = new byte[width * height * length];
|
||||
final List<Tag> tileEntities = new ArrayList<Tag>();
|
||||
// Precalculate index vars
|
||||
int area = width * length;
|
||||
final int[] yarea = new int[height];
|
||||
final int[] zwidth = new int[width];
|
||||
for (int i = 0; i < height; i++) {
|
||||
yarea[i] = i * area;
|
||||
}
|
||||
for (int i = 0; i < width; i++) {
|
||||
zwidth[i] = i * width;
|
||||
}
|
||||
if (clipboard instanceof BlockArrayClipboard) {
|
||||
FaweClipboard faweClip = ((BlockArrayClipboard) clipboard).IMP;
|
||||
ForEach forEach = new ForEach(yarea, zwidth, blocks, blockData, tileEntities);
|
||||
faweClip.forEach(forEach, false);
|
||||
addBlocks = forEach.addBlocks;
|
||||
} else {
|
||||
final int mx = (int) min.x;
|
||||
final int my = (int) min.y;
|
||||
final int mz = (int) min.z;
|
||||
Vector mutable = new Vector(0, 0, 0);
|
||||
ForEach forEach = new ForEach(yarea, zwidth, blocks, blockData, tileEntities);
|
||||
for (Vector point : region) {
|
||||
mutable.x = point.x - mx;
|
||||
mutable.y = point.y - my;
|
||||
mutable.z = point.z - mz;
|
||||
forEach.run(mutable, clipboard.getBlock(point));
|
||||
}
|
||||
addBlocks = forEach.addBlocks;
|
||||
}
|
||||
|
||||
schematic.put("Blocks", new ByteArrayTag(blocks));
|
||||
schematic.put("Data", new ByteArrayTag(blockData));
|
||||
schematic.put("TileEntities", new ListTag(CompoundTag.class, tileEntities));
|
||||
|
||||
if (addBlocks != null) {
|
||||
schematic.put("AddBlocks", new ByteArrayTag(addBlocks));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
schematic.put("Entities", new ListTag(CompoundTag.class, entities));
|
||||
|
||||
CompoundTag schematicTag = new CompoundTag(schematic);
|
||||
return schematicTag;
|
||||
}
|
||||
|
||||
private static Tag writeVector(Vector vector, String name) {
|
||||
List<DoubleTag> list = new ArrayList<DoubleTag>();
|
||||
list.add(new DoubleTag(vector.getX()));
|
||||
list.add(new DoubleTag(vector.getY()));
|
||||
list.add(new DoubleTag(vector.getZ()));
|
||||
return new ListTag(DoubleTag.class, list);
|
||||
}
|
||||
|
||||
private static Tag writeRotation(Location location, String name) {
|
||||
List<FloatTag> list = new ArrayList<FloatTag>();
|
||||
list.add(new FloatTag(location.getYaw()));
|
||||
list.add(new FloatTag(location.getPitch()));
|
||||
return new ListTag(FloatTag.class, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return SchematicWriter.class;
|
||||
}
|
||||
}
|
@ -38,11 +38,9 @@ public final class Operations {
|
||||
* @throws WorldEditException WorldEdit exception
|
||||
*/
|
||||
public static void complete(Operation operation) throws WorldEditException {
|
||||
try {
|
||||
while (true) {
|
||||
operation = operation.resume(context);
|
||||
}
|
||||
} catch (NullPointerException ignore) {}
|
||||
while (operation != null) {
|
||||
operation = operation.resume(context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -65,12 +63,12 @@ public final class Operations {
|
||||
*/
|
||||
public static void completeBlindly(Operation operation) {
|
||||
try {
|
||||
while (true) {
|
||||
while (operation != null) {
|
||||
operation = operation.resume(context);
|
||||
}
|
||||
} catch (WorldEditException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (NullPointerException ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
public static void completeSmart(final Operation op, final Runnable whenDone, final boolean threadsafe) {
|
||||
|
@ -71,7 +71,6 @@ public class LZ4InputStream extends InputStream {
|
||||
numBytesRemainingToSkip -= numBytesToSkip;
|
||||
decompressedBufferPosition += numBytesToSkip;
|
||||
}
|
||||
|
||||
return n - numBytesRemainingToSkip;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweLocation;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.wrappers.PlayerWrapper;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.forge.ForgeWorldEdit;
|
||||
import java.util.UUID;
|
||||
@ -73,6 +74,6 @@ public class ForgePlayer extends FawePlayer<EntityPlayerMP> {
|
||||
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
return ForgeWorldEdit.inst.wrap(this.parent);
|
||||
return PlayerWrapper.wrap(ForgeWorldEdit.inst.wrap(this.parent));
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ buildscript {
|
||||
}
|
||||
dependencies {
|
||||
classpath 'net.minecrell:VanillaGradle:2.0.3_1'
|
||||
classpath 'net.minecraftforge.gradle:ForgeGradle:2.1-SNAPSHOT'
|
||||
classpath 'net.minecraftforge.gradle:ForgeGradle:2.2-SNAPSHOT'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.FaweLocation;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.wrappers.PlayerWrapper;
|
||||
import java.util.UUID;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import org.spongepowered.api.Sponge;
|
||||
@ -71,6 +72,6 @@ public class SpongePlayer extends FawePlayer<Player> {
|
||||
|
||||
@Override
|
||||
public com.sk89q.worldedit.entity.Player getPlayer() {
|
||||
return (com.sk89q.worldedit.entity.Player) Fawe.<FaweSponge> imp().getWorldEditPlugin().wrap((EntityPlayerMP) this.parent);
|
||||
return PlayerWrapper.wrap(Fawe.<FaweSponge> imp().getWorldEditPlugin().wrap((EntityPlayerMP) this.parent));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user