mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-04 03:56:41 +00:00
Plenty of changes to core block behavior to become more compatible with upstream WorldEdit (still more to be done!)
This commit is contained in:
@ -81,7 +81,7 @@ public class AbstractDelegateExtent implements LightingExtent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getFullBlock(BlockVector3 position) {
|
||||
public BaseBlock getFullBlock(BlockVector3 position) {
|
||||
return extent.getFullBlock(position);
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ public class AbstractDelegateExtent implements LightingExtent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BlockStateHolder block) throws WorldEditException {
|
||||
public <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T block) throws WorldEditException {
|
||||
// mutable.mutX(x);
|
||||
// mutable.mutY(y);
|
||||
// mutable.mutZ(z);
|
||||
@ -150,7 +150,7 @@ public class AbstractDelegateExtent implements LightingExtent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(BlockVector3 location, BlockStateHolder block) throws WorldEditException {
|
||||
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 location, T block) throws WorldEditException {
|
||||
return extent.setBlock(location, block);
|
||||
}
|
||||
|
||||
|
@ -118,19 +118,19 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
|
||||
@Override
|
||||
default BlockState getBlock(BlockVector3 position) {
|
||||
return getFullBlock(position);
|
||||
return getFullBlock(position).toImmutableState();
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockState getLazyBlock(BlockVector3 position) {
|
||||
return getFullBlock(position);
|
||||
return getFullBlock(position).toImmutableState();
|
||||
}
|
||||
|
||||
default BlockState getLazyBlock(int x, int y, int z) {
|
||||
return getLazyBlock(BlockVector3.at(x, y, z));
|
||||
}
|
||||
|
||||
default boolean setBlock(int x, int y, int z, BlockStateHolder state) throws WorldEditException {
|
||||
default <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T state) throws WorldEditException {
|
||||
return setBlock(BlockVector3.at(x, y, z), state);
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ public interface InputExtent {
|
||||
* @param position position of the block
|
||||
* @return the block
|
||||
*/
|
||||
BlockState getFullBlock(BlockVector3 position);
|
||||
BaseBlock getFullBlock(BlockVector3 position);
|
||||
|
||||
/**
|
||||
* Get the biome at the given location.
|
||||
|
@ -50,7 +50,7 @@ public interface OutputExtent {
|
||||
* @return true if the block was successfully set (return value may not be accurate)
|
||||
* @throws WorldEditException thrown on an error
|
||||
*/
|
||||
boolean setBlock(BlockVector3 position, BlockStateHolder block) throws WorldEditException;
|
||||
<T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block) throws WorldEditException;
|
||||
|
||||
/**
|
||||
* Set the biome.
|
||||
|
@ -234,8 +234,8 @@ public class BlockArrayClipboard implements Clipboard, LightingExtent, Closeable
|
||||
//>>>>>>> 399e0ad5... Refactor vector system to be cleaner
|
||||
|
||||
@Override
|
||||
public BlockState getFullBlock(BlockVector3 position) {
|
||||
return getLazyBlock(position);
|
||||
public BaseBlock getFullBlock(BlockVector3 position) {
|
||||
return getLazyBlock(position).toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,28 +19,220 @@
|
||||
|
||||
package com.sk89q.worldedit.extent.clipboard.io;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import com.boydti.fawe.object.clipboard.AbstractClipboardFormat;
|
||||
import com.boydti.fawe.object.io.PGZIPOutputStream;
|
||||
import com.boydti.fawe.object.io.ResettableFileInputStream;
|
||||
import com.boydti.fawe.object.schematic.PNGWriter;
|
||||
import com.boydti.fawe.object.schematic.StructureFormat;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.NBTConstants;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.jnbt.NamedTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
|
||||
/**
|
||||
* A collection of supported clipboard formats.
|
||||
*/
|
||||
@Deprecated
|
||||
public class BuiltInClipboardFormat {
|
||||
public static final ClipboardFormat MCEDIT_SCHEMATIC = ClipboardFormat.SCHEMATIC;
|
||||
public static final ClipboardFormat SPONGE_SCHEMATIC = ClipboardFormat.SPONGE_SCHEMATIC;
|
||||
public static final ClipboardFormat STRUCTURE = ClipboardFormat.STRUCTURE;
|
||||
public static final ClipboardFormat PNG = ClipboardFormat.PNG;
|
||||
|
||||
public enum BuiltInClipboardFormat implements ClipboardFormat{
|
||||
/**
|
||||
* The Schematic format used by many software.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final ClipboardFormat[] values() {
|
||||
return ClipboardFormat.values;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static ClipboardFormat valueOf(String value) {
|
||||
switch (value) {
|
||||
case "MCEDIT_SCHEMATIC":
|
||||
value = "SCHEMATIC";
|
||||
break;
|
||||
MCEDIT_SCHEMATIC("mcedit", "mce", "schematic") {
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
if (inputStream instanceof FileInputStream) {
|
||||
inputStream = new ResettableFileInputStream((FileInputStream) inputStream);
|
||||
}
|
||||
BufferedInputStream buffered = new BufferedInputStream(inputStream);
|
||||
NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered)));
|
||||
SchematicReader input = new SchematicReader(nbtStream);
|
||||
input.setUnderlyingStream(inputStream);
|
||||
return input;
|
||||
}
|
||||
return ClipboardFormat.valueOf(value);
|
||||
|
||||
@Override
|
||||
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
|
||||
throw new UnsupportedOperationException("No longer supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
try (NBTInputStream str = new NBTInputStream(new GZIPInputStream(new FileInputStream(file)))) {
|
||||
NamedTag rootTag = str.readNamedTag();
|
||||
if (!rootTag.getName().equals("Schematic")) {
|
||||
return false;
|
||||
}
|
||||
CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
|
||||
|
||||
// Check
|
||||
Map<String, Tag> schematic = schematicTag.getValue();
|
||||
if (!schematic.containsKey("Materials")) {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrimaryFileExtension() {
|
||||
return "schematic";
|
||||
}
|
||||
},
|
||||
|
||||
@Deprecated
|
||||
SPONGE_SCHEMATIC("sponge", "schem") {
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
if (inputStream instanceof FileInputStream) {
|
||||
inputStream = new ResettableFileInputStream((FileInputStream) inputStream);
|
||||
}
|
||||
BufferedInputStream buffered = new BufferedInputStream(inputStream);
|
||||
NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered)));
|
||||
SpongeSchematicReader input = new SpongeSchematicReader(nbtStream);
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
|
||||
OutputStream gzip;
|
||||
if (outputStream instanceof PGZIPOutputStream || outputStream instanceof GZIPOutputStream) {
|
||||
gzip = outputStream;
|
||||
} else {
|
||||
outputStream = new BufferedOutputStream(outputStream);
|
||||
PGZIPOutputStream pigz = new PGZIPOutputStream(outputStream);
|
||||
gzip = pigz;
|
||||
}
|
||||
NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip));
|
||||
return new SpongeSchematicWriter(nbtStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
try (NBTInputStream str = new NBTInputStream(new GZIPInputStream(new FileInputStream(file)))) {
|
||||
NamedTag rootTag = str.readNamedTag();
|
||||
if (!rootTag.getName().equals("Schematic")) {
|
||||
return false;
|
||||
}
|
||||
CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
|
||||
|
||||
// Check
|
||||
Map<String, Tag> schematic = schematicTag.getValue();
|
||||
if (!schematic.containsKey("Version")) {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrimaryFileExtension() {
|
||||
return "schem";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The structure block format:
|
||||
* http://minecraft.gamepedia.com/Structure_block_file_format
|
||||
*/
|
||||
STRUCTURE("structure", "nbt") {
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
inputStream = new BufferedInputStream(inputStream);
|
||||
NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(inputStream)));
|
||||
return new StructureFormat(nbtStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
|
||||
outputStream = new BufferedOutputStream(outputStream);
|
||||
OutputStream gzip;
|
||||
if (outputStream instanceof PGZIPOutputStream || outputStream instanceof GZIPOutputStream) {
|
||||
gzip = outputStream;
|
||||
} else {
|
||||
PGZIPOutputStream pigz = new PGZIPOutputStream(outputStream);
|
||||
gzip = pigz;
|
||||
}
|
||||
NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip));
|
||||
return new StructureFormat(nbtStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
return file.getName().endsWith(".nbt");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrimaryFileExtension() {
|
||||
return "nbt";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Isometric PNG writer
|
||||
*/
|
||||
PNG("png", "image") {
|
||||
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
|
||||
return new PNGWriter(new BufferedOutputStream(outputStream));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
return file.getName().endsWith(".png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrimaryFileExtension() {
|
||||
return "png";
|
||||
}
|
||||
};
|
||||
|
||||
private final ImmutableSet<String> aliases;
|
||||
|
||||
BuiltInClipboardFormat(String... aliases) {
|
||||
this.aliases = ImmutableSet.copyOf(aliases);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAliases() {
|
||||
return this.aliases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getFileExtensions() {
|
||||
return ImmutableSet.of(getPrimaryFileExtension());
|
||||
}
|
||||
|
||||
}
|
@ -19,275 +19,84 @@
|
||||
|
||||
package com.sk89q.worldedit.extent.clipboard.io;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.jnbt.NBTStreamer;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.clipboard.*;
|
||||
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
||||
import com.boydti.fawe.object.clipboard.URIClipboardHolder;
|
||||
import com.boydti.fawe.object.io.PGZIPOutputStream;
|
||||
import com.boydti.fawe.object.io.ResettableFileInputStream;
|
||||
import com.boydti.fawe.object.schematic.PNGWriter;
|
||||
import com.boydti.fawe.object.schematic.Schematic;
|
||||
import com.boydti.fawe.object.schematic.StructureFormat;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.gson.Gson;
|
||||
import com.sk89q.jnbt.*;
|
||||
import com.sk89q.worldedit.LocalConfiguration;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Array;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* A collection of supported clipboard formats.
|
||||
*/
|
||||
public enum ClipboardFormat {
|
||||
|
||||
/**
|
||||
* The Schematic format used by many software.
|
||||
*/
|
||||
@Deprecated
|
||||
SCHEMATIC(new AbstractClipboardFormat("SCHEMATIC", "mcedit", "mce", "schematic") {
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
if (inputStream instanceof FileInputStream) {
|
||||
inputStream = new ResettableFileInputStream((FileInputStream) inputStream);
|
||||
}
|
||||
BufferedInputStream buffered = new BufferedInputStream(inputStream);
|
||||
NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered)));
|
||||
SchematicReader input = new SchematicReader(nbtStream);
|
||||
input.setUnderlyingStream(inputStream);
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
|
||||
throw new UnsupportedOperationException("No longer supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
if (!file.getName().toLowerCase().endsWith(".schematic")) return false;
|
||||
DataInputStream str = null;
|
||||
try {
|
||||
str = new DataInputStream(new GZIPInputStream(new FileInputStream(file)));
|
||||
if ((str.readByte() & 0xFF) != NBTConstants.TYPE_COMPOUND) {
|
||||
return false;
|
||||
}
|
||||
byte[] nameBytes = new byte[str.readShort() & 0xFFFF];
|
||||
str.readFully(nameBytes);
|
||||
String name = new String(nameBytes, NBTConstants.CHARSET);
|
||||
return name.equals("Schematic");
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
} finally {
|
||||
if (str != null) {
|
||||
try {
|
||||
str.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtension() {
|
||||
return "schematic";
|
||||
}
|
||||
}),
|
||||
|
||||
@Deprecated
|
||||
SPONGE_SCHEMATIC(new AbstractClipboardFormat("SPONGE", "sponge", "schem") {
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
if (inputStream instanceof FileInputStream) {
|
||||
inputStream = new ResettableFileInputStream((FileInputStream) inputStream);
|
||||
}
|
||||
BufferedInputStream buffered = new BufferedInputStream(inputStream);
|
||||
NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered)));
|
||||
SpongeSchematicReader input = new SpongeSchematicReader(nbtStream);
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
|
||||
OutputStream gzip;
|
||||
if (outputStream instanceof PGZIPOutputStream || outputStream instanceof GZIPOutputStream) {
|
||||
gzip = outputStream;
|
||||
} else {
|
||||
outputStream = new BufferedOutputStream(outputStream);
|
||||
PGZIPOutputStream pigz = new PGZIPOutputStream(outputStream);
|
||||
gzip = pigz;
|
||||
}
|
||||
NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip));
|
||||
return new SpongeSchematicWriter(nbtStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
if (!file.getName().toLowerCase().endsWith(".schem")) return false;
|
||||
DataInputStream str = null;
|
||||
try {
|
||||
str = new DataInputStream(new GZIPInputStream(new FileInputStream(file)));
|
||||
if ((str.readByte() & 0xFF) != NBTConstants.TYPE_COMPOUND) {
|
||||
return false;
|
||||
}
|
||||
byte[] nameBytes = new byte[str.readShort() & 0xFFFF];
|
||||
str.readFully(nameBytes);
|
||||
String name = new String(nameBytes, NBTConstants.CHARSET);
|
||||
return name.equals("Schematic");
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
} finally {
|
||||
if (str != null) {
|
||||
try {
|
||||
str.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtension() {
|
||||
return "schem";
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* The structure block format:
|
||||
* http://minecraft.gamepedia.com/Structure_block_file_format
|
||||
*/
|
||||
STRUCTURE(new AbstractClipboardFormat("STRUCTURE", "structure", "nbt") {
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
inputStream = new BufferedInputStream(inputStream);
|
||||
NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(inputStream)));
|
||||
return new StructureFormat(nbtStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
|
||||
outputStream = new BufferedOutputStream(outputStream);
|
||||
OutputStream gzip;
|
||||
if (outputStream instanceof PGZIPOutputStream || outputStream instanceof GZIPOutputStream) {
|
||||
gzip = outputStream;
|
||||
} else {
|
||||
PGZIPOutputStream pigz = new PGZIPOutputStream(outputStream);
|
||||
gzip = pigz;
|
||||
}
|
||||
NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip));
|
||||
return new StructureFormat(nbtStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
return file.getName().endsWith(".nbt");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtension() {
|
||||
return "nbt";
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Isometric PNG writer
|
||||
*/
|
||||
PNG(new AbstractClipboardFormat("PNG", "png", "image") {
|
||||
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
|
||||
return new PNGWriter(new BufferedOutputStream(outputStream));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
return file.getName().endsWith(".png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtension() {
|
||||
return "png";
|
||||
}
|
||||
}),
|
||||
|
||||
;
|
||||
|
||||
public static final ClipboardFormat[] values;
|
||||
|
||||
private static final Map<String, ClipboardFormat> aliasMap;
|
||||
|
||||
static {
|
||||
aliasMap = new ConcurrentHashMap<>(8, 0.9f, 1);
|
||||
for (ClipboardFormat emum : ClipboardFormat.values()) {
|
||||
for (String alias : emum.getAliases()) {
|
||||
aliasMap.put(alias, emum);
|
||||
}
|
||||
}
|
||||
values = values();
|
||||
}
|
||||
|
||||
private IClipboardFormat format;
|
||||
|
||||
ClipboardFormat() {
|
||||
|
||||
}
|
||||
|
||||
ClipboardFormat(IClipboardFormat format) {
|
||||
this.format = format;
|
||||
}
|
||||
public interface ClipboardFormat {
|
||||
|
||||
/**
|
||||
* Returns the name of this format.
|
||||
*
|
||||
* @return The name of the format
|
||||
*/
|
||||
public String getName() {
|
||||
return name();
|
||||
}
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Get a set of aliases.
|
||||
*
|
||||
* @return a set of aliases
|
||||
*/
|
||||
Set<String> getAliases();
|
||||
|
||||
/**
|
||||
* Create a reader.
|
||||
*
|
||||
* @param inputStream the input stream
|
||||
* @return a reader
|
||||
* @throws IOException thrown on I/O error
|
||||
*/
|
||||
ClipboardReader getReader(InputStream inputStream) throws IOException;
|
||||
|
||||
/**
|
||||
* Create a writer.
|
||||
*
|
||||
* @param outputStream the output stream
|
||||
* @return a writer
|
||||
* @throws IOException thrown on I/O error
|
||||
*/
|
||||
ClipboardWriter getWriter(OutputStream outputStream) throws IOException;
|
||||
|
||||
/**
|
||||
* Return whether the given file is of this format.
|
||||
*
|
||||
* @param file the file
|
||||
* @return true if the given file is of this format
|
||||
*/
|
||||
boolean isFormat(File file);
|
||||
|
||||
/**
|
||||
* Get the file extension this format primarily uses.
|
||||
*
|
||||
* @return The primary file extension
|
||||
*/
|
||||
public String getPrimaryFileExtension() {
|
||||
return getExtension();
|
||||
}
|
||||
String getPrimaryFileExtension();
|
||||
|
||||
/**
|
||||
* Get the file extensions this format is commonly known to use. This should
|
||||
@ -295,12 +104,43 @@ public enum ClipboardFormat {
|
||||
*
|
||||
* @return The file extensions this format might be known by
|
||||
*/
|
||||
public Set<String> getFileExtensions() {
|
||||
return Collections.singleton(getPrimaryFileExtension());
|
||||
Set<String> getFileExtensions();
|
||||
|
||||
/**
|
||||
* Set the player's clipboard
|
||||
* @param player
|
||||
* @param uri
|
||||
* @param in
|
||||
* @return the held clipboard
|
||||
* @throws IOException
|
||||
*/
|
||||
default ClipboardHolder hold(Player player, URI uri, InputStream in) throws IOException {
|
||||
checkNotNull(player);
|
||||
checkNotNull(uri);
|
||||
checkNotNull(in);
|
||||
|
||||
final ClipboardReader reader = getReader(in);
|
||||
|
||||
final Clipboard clipboard;
|
||||
|
||||
LocalSession session = WorldEdit.getInstance().getSessionManager().get(player);
|
||||
session.setClipboard(null);
|
||||
clipboard = reader.read(player.getUniqueId());
|
||||
URIClipboardHolder holder = new URIClipboardHolder(uri, clipboard);
|
||||
session.setClipboard(holder);
|
||||
return holder;
|
||||
}
|
||||
|
||||
default Schematic load(File file) throws IOException {
|
||||
return load(new FileInputStream(file));
|
||||
}
|
||||
|
||||
|
||||
public URL uploadPublic(final Clipboard clipboard, String category, String user) {
|
||||
default Schematic load(InputStream stream) throws IOException {
|
||||
return new Schematic(getReader(stream).read());
|
||||
}
|
||||
|
||||
|
||||
default URL uploadPublic(final Clipboard clipboard, String category, String user) {
|
||||
// summary
|
||||
// blocks
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
@ -318,158 +158,20 @@ public enum ClipboardFormat {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static MultiClipboardHolder loadAllFromInput(Actor player, String input, ClipboardFormat format, boolean message) throws IOException {
|
||||
checkNotNull(player);
|
||||
checkNotNull(input);
|
||||
WorldEdit worldEdit = WorldEdit.getInstance();
|
||||
LocalConfiguration config = worldEdit.getConfiguration();
|
||||
if (input.startsWith("url:")) {
|
||||
if (!player.hasPermission("worldedit.schematic.load.web")) {
|
||||
if (message) BBC.NO_PERM.send(player, "worldedit.schematic.load.web");
|
||||
return null;
|
||||
|
||||
default URL uploadAnonymous(final Clipboard clipboard) {
|
||||
return MainUtil.upload(null, null, getPrimaryFileExtension(), new RunnableVal<OutputStream>() {
|
||||
@Override
|
||||
public void run(OutputStream value) {
|
||||
write(value, clipboard);
|
||||
}
|
||||
URL base = new URL(Settings.IMP.WEB.URL);
|
||||
input = new URL(base, "uploads/" + input.substring(4) + ".schematic").toString();
|
||||
}
|
||||
if (input.startsWith("http")) {
|
||||
if (!player.hasPermission("worldedit.schematic.load.asset")) {
|
||||
if (message) BBC.NO_PERM.send(player, "worldedit.schematic.load.asset");
|
||||
return null;
|
||||
}
|
||||
URL url = new URL(input);
|
||||
URL webInterface = new URL(Settings.IMP.WEB.ASSETS);
|
||||
if (!url.getHost().equalsIgnoreCase(webInterface.getHost())) {
|
||||
if (message) BBC.WEB_UNAUTHORIZED.send(player, url);
|
||||
return null;
|
||||
}
|
||||
MultiClipboardHolder clipboards = loadAllFromUrl(url);
|
||||
return clipboards;
|
||||
} else {
|
||||
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}").matcher(input).find() && !player.hasPermission("worldedit.schematic.load.other")) {
|
||||
BBC.NO_PERM.send(player, "worldedit.schematic.load.other");
|
||||
return null;
|
||||
}
|
||||
File working = worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||
File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working;
|
||||
File f;
|
||||
if (input.startsWith("#")) {
|
||||
String[] extensions;
|
||||
if (format != null) {
|
||||
extensions = format.getFileExtensions().toArray(new String[0]);
|
||||
} else {
|
||||
extensions = ClipboardFormats.getFileExtensionArray();
|
||||
}
|
||||
f = player.openFileOpenDialog(extensions);
|
||||
if (f == null || !f.exists()) {
|
||||
if (message) player.printError("Schematic " + input + " does not exist! (" + f + ")");
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}").matcher(input).find() && !player.hasPermission("worldedit.schematic.load.other")) {
|
||||
if (message) BBC.NO_PERM.send(player, "worldedit.schematic.load.other");
|
||||
return null;
|
||||
}
|
||||
if (format == null && input.matches(".*\\.[\\w].*")) {
|
||||
String extension = input.substring(input.lastIndexOf('.') + 1, input.length());
|
||||
format = ClipboardFormat.findByExtension(extension);
|
||||
}
|
||||
f = MainUtil.resolve(dir, input, format, true);
|
||||
}
|
||||
if (f == null || !f.exists()) {
|
||||
if (!input.contains("../")) {
|
||||
dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||
f = MainUtil.resolve(dir, input, format, true);
|
||||
}
|
||||
}
|
||||
if (f == null || !f.exists() || !MainUtil.isInSubDirectory(working, f)) {
|
||||
if (message) player.printError("Schematic " + input + " does not exist! (" + ((f == null) ? false : f.exists()) + "|" + f + "|" + (f == null ? false : !MainUtil.isInSubDirectory(working, f)) + ")");
|
||||
return null;
|
||||
}
|
||||
if (format == null && f.isFile()) {
|
||||
format = ClipboardFormat.findByFile(f);
|
||||
if (format == null) {
|
||||
BBC.CLIPBOARD_INVALID_FORMAT.send(player, f.getName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (!f.exists()) {
|
||||
if (message) BBC.SCHEMATIC_NOT_FOUND.send(player, input);
|
||||
return null;
|
||||
}
|
||||
if (!f.isDirectory()) {
|
||||
ByteSource source = Files.asByteSource(f);
|
||||
URI uri = f.toURI();
|
||||
return new MultiClipboardHolder(uri, new LazyClipboardHolder(f.toURI(), source, format, null));
|
||||
}
|
||||
URIClipboardHolder[] clipboards = loadAllFromDirectory(f);
|
||||
if (clipboards.length < 1) {
|
||||
if (message) BBC.SCHEMATIC_NOT_FOUND.send(player, input);
|
||||
return null;
|
||||
}
|
||||
return new MultiClipboardHolder(f.toURI(), clipboards);
|
||||
}
|
||||
}
|
||||
|
||||
public static URIClipboardHolder[] loadAllFromDirectory(File dir) {
|
||||
HashSet<String> extensions = new HashSet<>(Arrays.asList(ClipboardFormats.getFileExtensionArray()));
|
||||
File[] files = dir.listFiles(pathname -> {
|
||||
String input = pathname.getName();
|
||||
String extension = input.substring(input.lastIndexOf('.') + 1, input.length());
|
||||
return (extensions.contains(extension.toLowerCase()));
|
||||
});
|
||||
LazyClipboardHolder[] clipboards = new LazyClipboardHolder[files.length];
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
File file = files[i];
|
||||
ByteSource source = Files.asByteSource(file);
|
||||
ClipboardFormat format = ClipboardFormat.findByFile(file);
|
||||
clipboards[i] = new LazyClipboardHolder(file.toURI(), source, format, null);
|
||||
}
|
||||
return clipboards;
|
||||
}
|
||||
|
||||
public static MultiClipboardHolder loadAllFromUrl(URL url) throws IOException {
|
||||
List<LazyClipboardHolder> clipboards = new ArrayList<>();
|
||||
try (ReadableByteChannel rbc = Channels.newChannel(url.openStream())) {
|
||||
try (InputStream in = Channels.newInputStream(rbc)) {
|
||||
try (ZipInputStream zip = new ZipInputStream(in)) {
|
||||
ZipEntry entry;
|
||||
byte[] buffer = new byte[8192];
|
||||
while ((entry = zip.getNextEntry()) != null) {
|
||||
String filename = entry.getName();
|
||||
String extension = filename.substring(filename.lastIndexOf('.') + 1, filename.length());
|
||||
ClipboardFormat format = findByExtension(filename);
|
||||
if (format != null) {
|
||||
FastByteArrayOutputStream out = new FastByteArrayOutputStream();
|
||||
int len = 0;
|
||||
while ((len = zip.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
byte[] array = out.toByteArray();
|
||||
ByteSource source = ByteSource.wrap(array);
|
||||
LazyClipboardHolder clipboard = new LazyClipboardHolder(url.toURI(), source, format, null);
|
||||
clipboards.add(clipboard);
|
||||
}
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
LazyClipboardHolder[] arr = clipboards.toArray(new LazyClipboardHolder[clipboards.size()]);
|
||||
try {
|
||||
MultiClipboardHolder multi = new MultiClipboardHolder(url.toURI());
|
||||
for (LazyClipboardHolder h : arr) multi.add(h);
|
||||
return multi;
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void write(OutputStream value, Clipboard clipboard) {
|
||||
|
||||
default void write(OutputStream value, Clipboard clipboard) {
|
||||
try {
|
||||
try (PGZIPOutputStream gzip = new PGZIPOutputStream(value)) {
|
||||
try (ClipboardWriter writer = format.getWriter(gzip)) {
|
||||
try (ClipboardWriter writer = getWriter(gzip)) {
|
||||
writer.write(clipboard);
|
||||
}
|
||||
}
|
||||
@ -477,164 +179,4 @@ public enum ClipboardFormat {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public URL uploadAnonymous(final Clipboard clipboard) {
|
||||
return MainUtil.upload(null, null, format.getExtension(), new RunnableVal<OutputStream>() {
|
||||
@Override
|
||||
public void run(OutputStream value) {
|
||||
write(value, clipboard);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public IClipboardFormat getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a set of aliases.
|
||||
*
|
||||
* @return a set of aliases
|
||||
*/
|
||||
public Set<String> getAliases() {
|
||||
return format.getAliases();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a reader.
|
||||
*
|
||||
* @param inputStream the input stream
|
||||
* @return a reader
|
||||
* @throws IOException thrown on I/O error
|
||||
*/
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
return format.getReader(inputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a writer.
|
||||
*
|
||||
* @param outputStream the output stream
|
||||
* @return a writer
|
||||
* @throws IOException thrown on I/O error
|
||||
*/
|
||||
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
|
||||
return format.getWriter(outputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the player's clipboard
|
||||
* @param player
|
||||
* @param uri
|
||||
* @param in
|
||||
* @return the held clipboard
|
||||
* @throws IOException
|
||||
*/
|
||||
public ClipboardHolder hold(Player player, URI uri, InputStream in) throws IOException {
|
||||
checkNotNull(player);
|
||||
checkNotNull(uri);
|
||||
checkNotNull(in);
|
||||
|
||||
final ClipboardReader reader = getReader(in);
|
||||
|
||||
final Clipboard clipboard;
|
||||
|
||||
LocalSession session = WorldEdit.getInstance().getSessionManager().get(player);
|
||||
session.setClipboard(null);
|
||||
clipboard = reader.read(player.getUniqueId());
|
||||
URIClipboardHolder holder = new URIClipboardHolder(uri, clipboard);
|
||||
session.setClipboard(holder);
|
||||
return holder;
|
||||
}
|
||||
|
||||
public Schematic load(File file) throws IOException {
|
||||
return load(new FileInputStream(file));
|
||||
}
|
||||
|
||||
public Schematic load(InputStream stream) throws IOException {
|
||||
return new Schematic(this.getReader(stream).read());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file extension used
|
||||
*
|
||||
* @return file extension string
|
||||
*/
|
||||
public String getExtension() {
|
||||
return format.getExtension();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given file is of this format.
|
||||
*
|
||||
* @param file the file
|
||||
* @return true if the given file is of this format
|
||||
*/
|
||||
public boolean isFormat(File file) {
|
||||
return format.isFormat(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the clipboard format named by the given alias.
|
||||
*
|
||||
* @param alias the alias
|
||||
* @return the format, otherwise null if none is matched
|
||||
*/
|
||||
@Nullable
|
||||
public static ClipboardFormat findByAlias(String alias) {
|
||||
checkNotNull(alias);
|
||||
return aliasMap.get(alias.toLowerCase(Locale.ENGLISH).trim());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ClipboardFormat findByExtension(String extension) {
|
||||
checkNotNull(extension);
|
||||
extension = extension.toLowerCase();
|
||||
for (ClipboardFormat format : values) {
|
||||
if (format.getFileExtensions().contains(extension)) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the format given a file.
|
||||
*
|
||||
* @param file the file
|
||||
* @return the format, otherwise null if one cannot be detected
|
||||
*/
|
||||
@Nullable
|
||||
public static ClipboardFormat findByFile(File file) {
|
||||
checkNotNull(file);
|
||||
for (ClipboardFormat format : EnumSet.allOf(ClipboardFormat.class)) {
|
||||
if (format.isFormat(file)) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ClipboardFormat addFormat(IClipboardFormat instance) {
|
||||
ClipboardFormat newEnum = ReflectionUtils.addEnum(ClipboardFormat.class, instance.getName());
|
||||
newEnum.format = instance;
|
||||
for (String alias : newEnum.getAliases()) {
|
||||
aliasMap.put(alias, newEnum);
|
||||
}
|
||||
|
||||
ArrayList<ClipboardFormat> newValues = new ArrayList<>(Arrays.asList(values));
|
||||
newValues.add(newEnum);
|
||||
ClipboardFormat[] newValuesArray = newValues.toArray(new ClipboardFormat[newValues.size()]);
|
||||
try {
|
||||
ReflectionUtils.setFailsafeFieldValue(ClipboardFormat.class.getDeclaredField("values"), null, newValuesArray);
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return newEnum;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -19,17 +19,77 @@
|
||||
|
||||
package com.sk89q.worldedit.extent.clipboard.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.clipboard.LazyClipboardHolder;
|
||||
import com.boydti.fawe.object.clipboard.MultiClipboardHolder;
|
||||
import com.boydti.fawe.object.clipboard.URIClipboardHolder;
|
||||
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.google.common.io.Files;
|
||||
import com.sk89q.worldedit.LocalConfiguration;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class ClipboardFormats {
|
||||
|
||||
private static final Map<String, ClipboardFormat> aliasMap = new HashMap<>();
|
||||
private static final Multimap<String, ClipboardFormat> fileExtensionMap = HashMultimap.create();
|
||||
private static final List<ClipboardFormat> registeredFormats = new ArrayList<>();
|
||||
|
||||
public static void registerClipboardFormat(ClipboardFormat format) {
|
||||
checkNotNull(format);
|
||||
|
||||
for (String key : format.getAliases()) {
|
||||
String lowKey = key.toLowerCase(Locale.ENGLISH);
|
||||
ClipboardFormat old = aliasMap.put(lowKey, format);
|
||||
if (old != null) {
|
||||
aliasMap.put(lowKey, old);
|
||||
WorldEdit.logger.warning(format.getClass().getName() + " cannot override existing alias '" + lowKey + "' used by " + old.getClass().getName());
|
||||
}
|
||||
}
|
||||
for (String ext : format.getFileExtensions()) {
|
||||
String lowExt = ext.toLowerCase(Locale.ENGLISH);
|
||||
fileExtensionMap.put(lowExt, format);
|
||||
}
|
||||
registeredFormats.add(format);
|
||||
}
|
||||
|
||||
static {
|
||||
for (BuiltInClipboardFormat format : BuiltInClipboardFormat.values()) {
|
||||
registerClipboardFormat(format);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the clipboard format named by the given alias.
|
||||
*
|
||||
@ -39,7 +99,8 @@ public class ClipboardFormats {
|
||||
*/
|
||||
@Nullable
|
||||
public static ClipboardFormat findByAlias(String alias) {
|
||||
return ClipboardFormat.findByAlias(alias);
|
||||
checkNotNull(alias);
|
||||
return aliasMap.get(alias.toLowerCase(Locale.ENGLISH).trim());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -53,7 +114,7 @@ public class ClipboardFormats {
|
||||
public static ClipboardFormat findByFile(File file) {
|
||||
checkNotNull(file);
|
||||
|
||||
for (ClipboardFormat format : ClipboardFormat.values) {
|
||||
for (ClipboardFormat format : registeredFormats) {
|
||||
if (format.isFormat(file)) {
|
||||
return format;
|
||||
}
|
||||
@ -61,22 +122,36 @@ public class ClipboardFormats {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the format using the given extension
|
||||
* @param string
|
||||
* the extension
|
||||
* @return the format, otherwise null if one cannot be detected
|
||||
*/
|
||||
@Nullable
|
||||
public static ClipboardFormat findByExtension(String extension) {
|
||||
checkNotNull(extension);
|
||||
|
||||
Collection<Entry<String, ClipboardFormat>> entries = getFileExtensionMap().entries();
|
||||
for(Map.Entry<String, ClipboardFormat> entry : entries) {
|
||||
if(entry.getKey().equalsIgnoreCase(extension)) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a multimap from a file extension to the potential matching formats.
|
||||
*/
|
||||
public static Multimap<String, ClipboardFormat> getFileExtensionMap() {
|
||||
HashMultimap<String, ClipboardFormat> map = HashMultimap.create();
|
||||
for (ClipboardFormat format : ClipboardFormat.values) {
|
||||
for (String ext : format.getFileExtensions()) {
|
||||
map.put(ext, format);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
return Multimaps.unmodifiableMultimap(fileExtensionMap);
|
||||
}
|
||||
|
||||
public static Collection<ClipboardFormat> getAll() {
|
||||
return Arrays.asList(ClipboardFormat.values);
|
||||
return Collections.unmodifiableCollection(registeredFormats);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,13 +159,156 @@ public class ClipboardFormats {
|
||||
* It is not in SchematicCommands because it may rely on internal register calls.
|
||||
*/
|
||||
public static String[] getFileExtensionArray() {
|
||||
List<String> exts = new ArrayList<>();
|
||||
HashMultimap<String, ClipboardFormat> map = HashMultimap.create();
|
||||
for (ClipboardFormat format : ClipboardFormat.values) {
|
||||
exts.addAll(format.getFileExtensions());
|
||||
}
|
||||
return exts.toArray(new String[exts.size()]);
|
||||
return fileExtensionMap.keySet().toArray(new String[fileExtensionMap.keySet().size()]);
|
||||
}
|
||||
|
||||
private ClipboardFormats() {}
|
||||
private ClipboardFormats() {
|
||||
}
|
||||
|
||||
public static MultiClipboardHolder loadAllFromInput(Actor player, String input, ClipboardFormat format, boolean message) throws IOException {
|
||||
checkNotNull(player);
|
||||
checkNotNull(input);
|
||||
WorldEdit worldEdit = WorldEdit.getInstance();
|
||||
LocalConfiguration config = worldEdit.getConfiguration();
|
||||
if (input.startsWith("url:")) {
|
||||
if (!player.hasPermission("worldedit.schematic.load.web")) {
|
||||
if (message) BBC.NO_PERM.send(player, "worldedit.schematic.load.web");
|
||||
return null;
|
||||
}
|
||||
URL base = new URL(Settings.IMP.WEB.URL);
|
||||
input = new URL(base, "uploads/" + input.substring(4) + ".schematic").toString();
|
||||
}
|
||||
if (input.startsWith("http")) {
|
||||
if (!player.hasPermission("worldedit.schematic.load.asset")) {
|
||||
if (message) BBC.NO_PERM.send(player, "worldedit.schematic.load.asset");
|
||||
return null;
|
||||
}
|
||||
URL url = new URL(input);
|
||||
URL webInterface = new URL(Settings.IMP.WEB.ASSETS);
|
||||
if (!url.getHost().equalsIgnoreCase(webInterface.getHost())) {
|
||||
if (message) BBC.WEB_UNAUTHORIZED.send(player, url);
|
||||
return null;
|
||||
}
|
||||
MultiClipboardHolder clipboards = loadAllFromUrl(url);
|
||||
return clipboards;
|
||||
} else {
|
||||
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}").matcher(input).find() && !player.hasPermission("worldedit.schematic.load.other")) {
|
||||
BBC.NO_PERM.send(player, "worldedit.schematic.load.other");
|
||||
return null;
|
||||
}
|
||||
File working = worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||
File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working;
|
||||
File f;
|
||||
if (input.startsWith("#")) {
|
||||
String[] extensions;
|
||||
if (format != null) {
|
||||
extensions = format.getFileExtensions().toArray(new String[0]);
|
||||
} else {
|
||||
extensions = ClipboardFormats.getFileExtensionArray();
|
||||
}
|
||||
f = player.openFileOpenDialog(extensions);
|
||||
if (f == null || !f.exists()) {
|
||||
if (message) player.printError("Schematic " + input + " does not exist! (" + f + ")");
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}").matcher(input).find() && !player.hasPermission("worldedit.schematic.load.other")) {
|
||||
if (message) BBC.NO_PERM.send(player, "worldedit.schematic.load.other");
|
||||
return null;
|
||||
}
|
||||
if (format == null && input.matches(".*\\.[\\w].*")) {
|
||||
String extension = input.substring(input.lastIndexOf('.') + 1, input.length());
|
||||
format = findByExtension(extension);
|
||||
}
|
||||
f = MainUtil.resolve(dir, input, format, true);
|
||||
}
|
||||
if (f == null || !f.exists()) {
|
||||
if (!input.contains("../")) {
|
||||
dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||
f = MainUtil.resolve(dir, input, format, true);
|
||||
}
|
||||
}
|
||||
if (f == null || !f.exists() || !MainUtil.isInSubDirectory(working, f)) {
|
||||
if (message) player.printError("Schematic " + input + " does not exist! (" + ((f == null) ? false : f.exists()) + "|" + f + "|" + (f == null ? false : !MainUtil.isInSubDirectory(working, f)) + ")");
|
||||
return null;
|
||||
}
|
||||
if (format == null && f.isFile()) {
|
||||
format = findByFile(f);
|
||||
if (format == null) {
|
||||
BBC.CLIPBOARD_INVALID_FORMAT.send(player, f.getName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (!f.exists()) {
|
||||
if (message) BBC.SCHEMATIC_NOT_FOUND.send(player, input);
|
||||
return null;
|
||||
}
|
||||
if (!f.isDirectory()) {
|
||||
ByteSource source = Files.asByteSource(f);
|
||||
URI uri = f.toURI();
|
||||
return new MultiClipboardHolder(uri, new LazyClipboardHolder(f.toURI(), source, format, null));
|
||||
}
|
||||
URIClipboardHolder[] clipboards = loadAllFromDirectory(f);
|
||||
if (clipboards.length < 1) {
|
||||
if (message) BBC.SCHEMATIC_NOT_FOUND.send(player, input);
|
||||
return null;
|
||||
}
|
||||
return new MultiClipboardHolder(f.toURI(), clipboards);
|
||||
}
|
||||
}
|
||||
|
||||
public static URIClipboardHolder[] loadAllFromDirectory(File dir) {
|
||||
HashSet<String> extensions = new HashSet<>(Arrays.asList(ClipboardFormats.getFileExtensionArray()));
|
||||
File[] files = dir.listFiles(pathname -> {
|
||||
String input = pathname.getName();
|
||||
String extension = input.substring(input.lastIndexOf('.') + 1, input.length());
|
||||
return (extensions.contains(extension.toLowerCase()));
|
||||
});
|
||||
LazyClipboardHolder[] clipboards = new LazyClipboardHolder[files.length];
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
File file = files[i];
|
||||
ByteSource source = Files.asByteSource(file);
|
||||
ClipboardFormat format = findByFile(file);
|
||||
clipboards[i] = new LazyClipboardHolder(file.toURI(), source, format, null);
|
||||
}
|
||||
return clipboards;
|
||||
}
|
||||
|
||||
public static MultiClipboardHolder loadAllFromUrl(URL url) throws IOException {
|
||||
List<LazyClipboardHolder> clipboards = new ArrayList<>();
|
||||
try (ReadableByteChannel rbc = Channels.newChannel(url.openStream())) {
|
||||
try (InputStream in = Channels.newInputStream(rbc)) {
|
||||
try (ZipInputStream zip = new ZipInputStream(in)) {
|
||||
ZipEntry entry;
|
||||
byte[] buffer = new byte[8192];
|
||||
while ((entry = zip.getNextEntry()) != null) {
|
||||
String filename = entry.getName();
|
||||
String extension = filename.substring(filename.lastIndexOf('.') + 1, filename.length());
|
||||
ClipboardFormat format = findByExtension(filename);
|
||||
if (format != null) {
|
||||
FastByteArrayOutputStream out = new FastByteArrayOutputStream();
|
||||
int len = 0;
|
||||
while ((len = zip.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
byte[] array = out.toByteArray();
|
||||
ByteSource source = ByteSource.wrap(array);
|
||||
LazyClipboardHolder clipboard = new LazyClipboardHolder(url.toURI(), source, format, null);
|
||||
clipboards.add(clipboard);
|
||||
}
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
LazyClipboardHolder[] arr = clipboards.toArray(new LazyClipboardHolder[clipboards.size()]);
|
||||
try {
|
||||
MultiClipboardHolder multi = new MultiClipboardHolder(url.toURI());
|
||||
for (LazyClipboardHolder h : arr) multi.add(h);
|
||||
return multi;
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,335 +1,330 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.extent.transform;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.object.extent.ResettableExtent;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.jnbt.ByteTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.helper.MCDirections;
|
||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.registry.state.AbstractProperty;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.registry.state.BooleanProperty;
|
||||
import com.sk89q.worldedit.registry.state.DirectionalProperty;
|
||||
import com.sk89q.worldedit.registry.state.EnumProperty;
|
||||
import com.sk89q.worldedit.registry.state.IntegerProperty;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Transforms blocks themselves (but not their position) according to a
|
||||
* given transform.
|
||||
*/
|
||||
public class BlockTransformExtent extends ResettableExtent {
|
||||
private Transform transform;
|
||||
private Transform transformInverse;
|
||||
private int[] BLOCK_ROTATION_BITMASK;
|
||||
private int[][] BLOCK_TRANSFORM;
|
||||
private int[][] BLOCK_TRANSFORM_INVERSE;
|
||||
private int[] ALL = new int[0];
|
||||
|
||||
private Transform transform;
|
||||
|
||||
|
||||
public BlockTransformExtent(Extent parent) {
|
||||
this(parent, new AffineTransform());
|
||||
}
|
||||
|
||||
public BlockTransformExtent(Extent parent, Transform transform) {
|
||||
super(parent);
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param extent the extent
|
||||
*/
|
||||
public BlockTransformExtent(Extent extent, Transform transform) {
|
||||
super(extent);
|
||||
checkNotNull(transform);
|
||||
this.transform = transform;
|
||||
this.transformInverse = this.transform.inverse();
|
||||
cache();
|
||||
}
|
||||
|
||||
private List<Direction> getDirections(AbstractProperty property) {
|
||||
if (property instanceof DirectionalProperty) {
|
||||
DirectionalProperty directional = (DirectionalProperty) property;
|
||||
directional.getValues();
|
||||
} else {
|
||||
switch (property.getKey()) {
|
||||
case HALF:
|
||||
|
||||
case ROTATION:
|
||||
|
||||
case AXIS:
|
||||
|
||||
case FACING:
|
||||
|
||||
case SHAPE:
|
||||
|
||||
case NORTH:
|
||||
case EAST:
|
||||
case SOUTH:
|
||||
case WEST:
|
||||
}
|
||||
}
|
||||
return null;
|
||||
/**
|
||||
* Get the transform.
|
||||
*
|
||||
* @return the transform
|
||||
*/
|
||||
public Transform getTransform() {
|
||||
return transform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transform
|
||||
* @param affine
|
||||
*/
|
||||
public void setTransform(Transform affine) {
|
||||
this.transform = affine;
|
||||
}
|
||||
// @Override
|
||||
// public BlockState getBlock(BlockVector3 position) {
|
||||
// return transformBlock(super.getBlock(position), false);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public BaseBlock getFullBlock(BlockVector3 position) {
|
||||
// return transformBlock(super.getFullBlock(position), false);
|
||||
// }
|
||||
|
||||
// @Override
|
||||
// public boolean setBlock(BlockVector3 location, BlockStateHolder block) throws WorldEditException {
|
||||
// return super.setBlock(location, transformBlock(block, true));
|
||||
// }
|
||||
|
||||
|
||||
// /**
|
||||
// * Transform the given block using the given transform.
|
||||
// *
|
||||
// * <p>The provided block is modified.</p>
|
||||
// *
|
||||
// * @param block the block
|
||||
// * @param transform the transform
|
||||
// * @return the same block
|
||||
// */
|
||||
// public static <T extends BlockStateHolder> T transform(T block, Transform transform) {
|
||||
// return transform(block, transform, block);
|
||||
// }
|
||||
/**
|
||||
* Transform a block without making a copy.
|
||||
*
|
||||
* @param block the block
|
||||
* @param reverse true to transform in the opposite direction
|
||||
* @return the same block
|
||||
*/
|
||||
private <T extends BlockStateHolder<T>> T transformBlock(T block, boolean reverse) {
|
||||
return transform(block, reverse ? transform.inverse() : transform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getLazyBlock(BlockVector3 position) {
|
||||
return transformFast(super.getLazyBlock(position)).toImmutableState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getLazyBlock(int x, int y, int z) {
|
||||
return transformFast(super.getLazyBlock(x, y, z)).toImmutableState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(BlockVector3 position) {
|
||||
return transformFast(super.getBlock(position)).toImmutableState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(BlockVector3 position) {
|
||||
return transformFast(super.getFullBlock(position).toImmutableState());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> boolean setBlock(int x, int y, int z, B block) throws WorldEditException {
|
||||
return super.setBlock(x, y, z, transformFastInverse((BlockState)block));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
|
||||
return super.setBlock(location, transformFastInverse((BlockState)block));
|
||||
}
|
||||
|
||||
private static final Set<String> directionNames = Sets.newHashSet("north", "south", "east", "west");
|
||||
|
||||
// /**
|
||||
// * Transform the given block using the given transform.
|
||||
// *
|
||||
// * @param block the block
|
||||
// * @param transform the transform
|
||||
// * @param changedBlock the block to change
|
||||
// * @return the changed block
|
||||
// */
|
||||
// private static <T extends BlockStateHolder> T transform(T block, Transform transform, T changedBlock) {
|
||||
// checkNotNull(block);
|
||||
// checkNotNull(transform);
|
||||
//
|
||||
// List<? extends Property> properties = block.getBlockType().getProperties();
|
||||
//
|
||||
// for (Property property : properties) {
|
||||
// if (property instanceof DirectionalProperty) {
|
||||
// Direction value = (Direction) block.getState(property);
|
||||
// if (value != null) {
|
||||
// Vector3 newValue = getNewStateValue((DirectionalProperty) property, transform, value.toVector());
|
||||
// if (newValue != null) {
|
||||
// changedBlock = (T) changedBlock.with(property, Direction.findClosest(newValue, Direction.Flag.ALL));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
/**
|
||||
* Transform the given block using the given transform.
|
||||
*
|
||||
* <p>The provided block is <em>not</em> modified.</p>
|
||||
*
|
||||
* @param block the block
|
||||
* @param transform the transform
|
||||
* @return the same block
|
||||
*/
|
||||
public static <B extends BlockStateHolder<B>> B transform(B block, Transform transform) {
|
||||
checkNotNull(block);
|
||||
checkNotNull(transform);
|
||||
B result = block;
|
||||
List<? extends Property<?>> properties = block.getBlockType().getProperties();
|
||||
|
||||
for (Property<?> property : properties) {
|
||||
if (property instanceof DirectionalProperty) {
|
||||
DirectionalProperty dirProp = (DirectionalProperty) property;
|
||||
Direction value = (Direction) block.getState(property);
|
||||
if (value != null) {
|
||||
Vector3 newValue = getNewStateValue(dirProp.getValues(), transform, value.toVector());
|
||||
if (newValue != null) {
|
||||
result = result.with(dirProp, Direction.findClosest(newValue, Direction.Flag.ALL));
|
||||
}
|
||||
}
|
||||
} else if (property instanceof EnumProperty) {
|
||||
EnumProperty enumProp = (EnumProperty) property;
|
||||
if (property.getName().equals("axis")) {
|
||||
// We have an axis - this is something we can do the rotations to :sunglasses:
|
||||
Direction value = null;
|
||||
switch ((String) block.getState(property)) {
|
||||
case "x":
|
||||
value = Direction.EAST;
|
||||
break;
|
||||
case "y":
|
||||
value = Direction.UP;
|
||||
break;
|
||||
case "z":
|
||||
value = Direction.NORTH;
|
||||
break;
|
||||
}
|
||||
if (value != null) {
|
||||
Vector3 newValue = getNewStateValue(Direction.valuesOf(Direction.Flag.UPRIGHT | Direction.Flag.CARDINAL), transform, value.toVector());
|
||||
if (newValue != null) {
|
||||
String axis = null;
|
||||
Direction newDir = Direction.findClosest(newValue, Direction.Flag.UPRIGHT | Direction.Flag.CARDINAL);
|
||||
if (newDir == Direction.NORTH || newDir == Direction.SOUTH) {
|
||||
axis = "z";
|
||||
} else if (newDir == Direction.EAST || newDir == Direction.WEST) {
|
||||
axis = "x";
|
||||
} else if (newDir == Direction.UP || newDir == Direction.DOWN) {
|
||||
axis = "y";
|
||||
}
|
||||
if (axis != null) {
|
||||
result = result.with(enumProp, axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (property instanceof IntegerProperty) {
|
||||
IntegerProperty intProp = (IntegerProperty) property;
|
||||
if (property.getName().equals("rotation")) {
|
||||
if (intProp.getValues().size() == 16) {
|
||||
Optional<Direction> direction = Direction.fromRotationIndex(block.getState(intProp));
|
||||
int horizontalFlags = Direction.Flag.CARDINAL | Direction.Flag.ORDINAL | Direction.Flag.SECONDARY_ORDINAL;
|
||||
if (direction.isPresent()) {
|
||||
Vector3 vec = getNewStateValue(Direction.valuesOf(horizontalFlags), transform, direction.get().toVector());
|
||||
if (vec != null) {
|
||||
OptionalInt newRotation = Direction.findClosest(vec, horizontalFlags).toRotationIndex();
|
||||
if (newRotation.isPresent()) {
|
||||
result = result.with(intProp, newRotation.getAsInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> directionalProperties = properties.stream()
|
||||
.filter(prop -> prop instanceof BooleanProperty)
|
||||
.filter(prop -> directionNames.contains(prop.getName()))
|
||||
.filter(property -> (Boolean) block.getState(property))
|
||||
.map(Property::getName)
|
||||
.map(String::toUpperCase)
|
||||
.map(Direction::valueOf)
|
||||
.map(dir -> Direction.findClosest(transform.apply(dir.toVector()), Direction.Flag.CARDINAL))
|
||||
.filter(Objects::nonNull)
|
||||
.map(Direction::name)
|
||||
.map(String::toLowerCase)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (directionalProperties.size() > 0) {
|
||||
for (String directionName : directionNames) {
|
||||
result = result.with(block.getBlockType().getProperty(directionName), directionalProperties.contains(directionName));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public final BaseBlock transformFast(BlockState block) {
|
||||
BaseBlock transformed = transformBlock(block, false).toBaseBlock();
|
||||
if (block.hasNbtData()) {
|
||||
CompoundTag tag = block.getNbtData();
|
||||
if (tag.containsKey("Rot")) {
|
||||
int rot = tag.asInt("Rot");
|
||||
|
||||
Direction direction = Direction.fromRotationIndex(rot).get();
|
||||
|
||||
if (direction != null) {
|
||||
Vector3 applyAbsolute = transform.apply(direction.toVector());
|
||||
Vector3 applyOrigin = transform.apply(Vector3.ZERO);
|
||||
Vector3 newAbsolute = Vector3.at(applyAbsolute.getX() - applyOrigin.getX(), applyAbsolute.getY() - applyOrigin.getY(), applyAbsolute.getZ() - applyOrigin.getZ());
|
||||
|
||||
Direction newDirection = Direction.findClosest(newAbsolute, Direction.Flag.CARDINAL | Direction.Flag.ORDINAL | Direction.Flag.SECONDARY_ORDINAL);
|
||||
|
||||
if (newDirection != null) {
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
values.put("Rot", new ByteTag((byte) newDirection.toRotationIndex().getAsInt()));
|
||||
}
|
||||
}
|
||||
transformed.setNbtData(tag);
|
||||
}
|
||||
}
|
||||
return transformed;
|
||||
}
|
||||
|
||||
public final BaseBlock transformFastInverse(BlockState block) {
|
||||
BaseBlock transformed = transformBlock(block, true).toBaseBlock();
|
||||
if (block.hasNbtData()) {
|
||||
CompoundTag tag = block.getNbtData();
|
||||
if (tag.containsKey("Rot")) {
|
||||
int rot = tag.asInt("Rot");
|
||||
|
||||
Direction direction = Direction.fromRotationIndex(rot).get();
|
||||
|
||||
if (direction != null) {
|
||||
Vector3 applyAbsolute = getTransform().inverse().apply(direction.toVector());
|
||||
Vector3 applyOrigin = getTransform().inverse().apply(Vector3.ZERO);
|
||||
|
||||
Vector3 newAbsolute = Vector3.at(applyAbsolute.getX() - applyOrigin.getX(), applyAbsolute.getY() - applyOrigin.getY(), applyAbsolute.getZ() - applyOrigin.getZ());
|
||||
|
||||
Direction newDirection = Direction.findClosest(newAbsolute, Direction.Flag.CARDINAL | Direction.Flag.ORDINAL | Direction.Flag.SECONDARY_ORDINAL);
|
||||
|
||||
if (newDirection != null) {
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
values.put("Rot", new ByteTag((byte) newDirection.toRotationIndex().getAsInt()));
|
||||
}
|
||||
}
|
||||
}
|
||||
transformed.setNbtData(tag);
|
||||
}
|
||||
return transformed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the new value with the transformed direction.
|
||||
*
|
||||
* @param allowedStates the allowed states
|
||||
* @param transform the transform
|
||||
* @param oldDirection the old direction to transform
|
||||
* @return a new state or null if none could be found
|
||||
*/
|
||||
@Nullable
|
||||
//<<<<<<< HEAD
|
||||
private static Integer getNewStateIndex(Transform transform, List<Direction> directions, int oldIndex) {
|
||||
Direction oldDirection = directions.get(oldIndex);
|
||||
Vector3 oldVector = oldDirection.toVector();
|
||||
Vector3 newVector = transform.apply(oldVector).subtract(transform.apply(Vector3.ZERO)).normalize();
|
||||
int newIndex = oldIndex;
|
||||
double closest = oldVector.normalize().dot(newVector);
|
||||
//=======
|
||||
// private static Vector3 getNewStateValue(DirectionalProperty state, Transform transform, Vector3 oldDirection) {
|
||||
// Vector3 newDirection = transform.apply(oldDirection).subtract(transform.apply(Vector3.ZERO)).normalize();
|
||||
// Vector3 newValue = null;
|
||||
// double closest = -2;
|
||||
//>>>>>>> 399e0ad5... Refactor vector system to be cleaner
|
||||
private static Vector3 getNewStateValue(List<Direction> allowedStates, Transform transform, Vector3 oldDirection) {
|
||||
Vector3 newDirection = transform.apply(oldDirection).subtract(transform.apply(Vector3.ZERO)).normalize();
|
||||
Vector3 newValue = null;
|
||||
double closest = -2;
|
||||
boolean found = false;
|
||||
|
||||
for (int i = 0; i < directions.size(); i++) {
|
||||
Direction v = directions.get(i);
|
||||
double dot = v.toVector().normalize().dot(newVector);
|
||||
if (dot > closest) {
|
||||
for (Direction v : allowedStates) {
|
||||
double dot = v.toVector().normalize().dot(newDirection);
|
||||
if (dot >= closest) {
|
||||
closest = dot;
|
||||
newIndex = i;
|
||||
newValue = v.toVector();
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
return newIndex;
|
||||
return newValue;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void cache() {
|
||||
BLOCK_ROTATION_BITMASK = new int[BlockTypes.size()];
|
||||
BLOCK_TRANSFORM = new int[BlockTypes.size()][];
|
||||
BLOCK_TRANSFORM_INVERSE = new int[BlockTypes.size()][];
|
||||
outer:
|
||||
for (int i = 0; i < BLOCK_TRANSFORM.length; i++) {
|
||||
BLOCK_TRANSFORM[i] = ALL;
|
||||
BLOCK_TRANSFORM_INVERSE[i] = ALL;
|
||||
BlockTypes type = BlockTypes.get(i);
|
||||
int bitMask = 0;
|
||||
for (AbstractProperty property : (Collection<AbstractProperty>) type.getProperties()) {
|
||||
Collection<Direction> directions = getDirections(property);
|
||||
if (directions != null) {
|
||||
BLOCK_TRANSFORM[i] = null;
|
||||
BLOCK_TRANSFORM_INVERSE[i] = null;
|
||||
bitMask |= property.getBitMask();
|
||||
}
|
||||
}
|
||||
if (bitMask != 0) {
|
||||
BLOCK_ROTATION_BITMASK[i] = bitMask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResettableExtent setExtent(Extent extent) {
|
||||
return super.setExtent(extent);
|
||||
}
|
||||
|
||||
public Transform getTransform() {
|
||||
return transform;
|
||||
}
|
||||
|
||||
public void setTransform(Transform affine) {
|
||||
this.transform = affine;
|
||||
this.transformInverse = this.transform.inverse();
|
||||
cache();
|
||||
}
|
||||
|
||||
private final BlockState transform(BlockState state, int[][] transformArray, Transform transform) {
|
||||
int typeId = state.getInternalBlockTypeId();
|
||||
int[] arr = transformArray[typeId];
|
||||
if (arr == ALL) return state;
|
||||
if (arr == null) {
|
||||
arr = transformArray[typeId] = new int[state.getBlockType().getMaxStateId() + 1];
|
||||
Arrays.fill(arr, -1);
|
||||
}
|
||||
int mask = BLOCK_ROTATION_BITMASK[typeId];
|
||||
int internalId = state.getInternalId();
|
||||
|
||||
int maskedId = internalId & mask;
|
||||
int newMaskedId = arr[maskedId];
|
||||
if (newMaskedId != -1) {
|
||||
return BlockState.getFromInternalId(newMaskedId | (internalId & (~mask)));
|
||||
}
|
||||
newMaskedId = state.getInternalId();
|
||||
|
||||
BlockTypes type = state.getBlockType();
|
||||
for (AbstractProperty property : (Collection<AbstractProperty>) type.getProperties()) {
|
||||
List<Direction> directions = getDirections(property);
|
||||
if (directions != null) {
|
||||
Integer newIndex = getNewStateIndex(transform, directions, property.getIndex(state.getInternalId()));
|
||||
if (newIndex != null) {
|
||||
newMaskedId = property.modifyIndex(newMaskedId, newIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
arr[maskedId] = newMaskedId & mask;
|
||||
return BlockState.getFromInternalId(newMaskedId);
|
||||
}
|
||||
|
||||
public final BlockState transformFast(BlockState block) {
|
||||
BlockState transformed = transform(block, BLOCK_TRANSFORM, transform);
|
||||
if (block.hasNbtData()) {
|
||||
CompoundTag tag = block.getNbtData();
|
||||
if (tag.containsKey("Rot")) {
|
||||
int rot = tag.asInt("Rot");
|
||||
|
||||
Direction direction = MCDirections.fromRotation(rot);
|
||||
|
||||
if (direction != null) {
|
||||
Vector3 applyAbsolute = transform.apply(direction.toVector());
|
||||
Vector3 applyOrigin = transform.apply(Vector3.ZERO);
|
||||
|
||||
Direction newDirection = Direction.findClosest(applyAbsolute.subtract(applyOrigin), Direction.Flag.CARDINAL | Direction.Flag.ORDINAL | Direction.Flag.SECONDARY_ORDINAL);
|
||||
|
||||
if (newDirection != null) {
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
values.put("Rot", new ByteTag((byte) MCDirections.toRotation(newDirection)));
|
||||
}
|
||||
}
|
||||
transformed = new BaseBlock(transformed, tag);
|
||||
}
|
||||
}
|
||||
return transformed;
|
||||
}
|
||||
|
||||
public final BlockState transformFastInverse(BlockState block) {
|
||||
BlockState transformed = transform(block, BLOCK_TRANSFORM_INVERSE, transformInverse);
|
||||
if (block.hasNbtData()) {
|
||||
CompoundTag tag = block.getNbtData();
|
||||
if (tag.containsKey("Rot")) {
|
||||
int rot = tag.asInt("Rot");
|
||||
|
||||
Direction direction = MCDirections.fromRotation(rot);
|
||||
|
||||
if (direction != null) {
|
||||
Vector3 applyAbsolute = transformInverse.apply(direction.toVector());
|
||||
Vector3 applyOrigin = transformInverse.apply(Vector3.ZERO);
|
||||
|
||||
Direction newDirection = Direction.findClosest(applyAbsolute.subtract(applyOrigin), Direction.Flag.CARDINAL | Direction.Flag.ORDINAL | Direction.Flag.SECONDARY_ORDINAL);
|
||||
|
||||
if (newDirection != null) {
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
values.put("Rot", new ByteTag((byte) MCDirections.toRotation(newDirection)));
|
||||
}
|
||||
}
|
||||
}
|
||||
transformed = new BaseBlock(transformed, tag);
|
||||
}
|
||||
return transformed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getLazyBlock(int x, int y, int z) {
|
||||
return transformFast(super.getLazyBlock(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getLazyBlock(BlockVector3 position) {
|
||||
return transformFast(super.getLazyBlock(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(BlockVector3 position) {
|
||||
return transformFast(super.getBlock(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBiome getBiome(BlockVector2 position) {
|
||||
return super.getBiome(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BlockStateHolder block) throws WorldEditException {
|
||||
return super.setBlock(x, y, z, transformFastInverse((BlockState) block));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean setBlock(BlockVector3 location, BlockStateHolder block) throws WorldEditException {
|
||||
return super.setBlock(location, transformFastInverse((BlockState) block));
|
||||
}
|
||||
|
||||
|
||||
}
|
Reference in New Issue
Block a user