mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-04 03:56:41 +00:00
This commit is contained in:
@ -46,7 +46,6 @@ dependencies {
|
||||
implementation(libs.findbugs)
|
||||
implementation(libs.rhino)
|
||||
compileOnly(libs.adventureApi)
|
||||
compileOnlyApi(libs.adventureNbt)
|
||||
compileOnlyApi(libs.adventureMiniMessage)
|
||||
implementation(libs.zstd) { isTransitive = false }
|
||||
compileOnly(libs.paster)
|
||||
@ -56,10 +55,10 @@ dependencies {
|
||||
antlr(libs.antlr4)
|
||||
implementation(libs.antlr4Runtime)
|
||||
implementation(libs.jsonSimple) { isTransitive = false }
|
||||
implementation(platform(libs.linBus.bom))
|
||||
|
||||
// Tests
|
||||
testRuntimeOnly(libs.log4jCore)
|
||||
testImplementation(libs.adventureNbt)
|
||||
testImplementation(libs.parallelgzip)
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ public class MobSpawnerBlock extends BaseBlock {
|
||||
|
||||
@Override
|
||||
public CompoundTag getNbtData() {
|
||||
Map<String, Tag> values = new HashMap<>();
|
||||
Map<String, Tag<?, ?>> values = new HashMap<>();
|
||||
values.put("Delay", new ShortTag(delay));
|
||||
values.put("SpawnCount", new ShortTag(spawnCount));
|
||||
values.put("SpawnRange", new ShortTag(spawnRange));
|
||||
@ -170,7 +170,7 @@ public class MobSpawnerBlock extends BaseBlock {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Tag> values = rootTag.getValue();
|
||||
Map<String, Tag<?, ?>> values = rootTag.getValue();
|
||||
|
||||
Tag t = values.get("id");
|
||||
if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals(getNbtId())) {
|
||||
|
@ -104,7 +104,7 @@ public class SignBlock extends BaseBlock {
|
||||
|
||||
@Override
|
||||
public CompoundTag getNbtData() {
|
||||
Map<String, Tag> values = new HashMap<>();
|
||||
Map<String, Tag<?, ?>> values = new HashMap<>();
|
||||
if (isLegacy()) {
|
||||
values.put("Text1", new StringTag(text[0]));
|
||||
values.put("Text2", new StringTag(text[1]));
|
||||
@ -112,7 +112,7 @@ public class SignBlock extends BaseBlock {
|
||||
values.put("Text4", new StringTag(text[3]));
|
||||
} else {
|
||||
ListTag messages = new ListTag(StringTag.class, Arrays.stream(text).map(StringTag::new).collect(Collectors.toList()));
|
||||
Map<String, Tag> frontTextTag = new HashMap<>();
|
||||
Map<String, Tag<?, ?>> frontTextTag = new HashMap<>();
|
||||
frontTextTag.put("messages", messages);
|
||||
values.put("front_text", new CompoundTag(frontTextTag));
|
||||
}
|
||||
@ -125,9 +125,9 @@ public class SignBlock extends BaseBlock {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Tag> values = rootTag.getValue();
|
||||
Map<String, Tag<?, ?>> values = rootTag.getValue();
|
||||
|
||||
Tag t;
|
||||
Tag<?, ?> t;
|
||||
|
||||
text = new String[]{EMPTY, EMPTY, EMPTY, EMPTY};
|
||||
|
||||
|
@ -100,8 +100,8 @@ public class SkullBlock extends BaseBlock {
|
||||
|
||||
@Override
|
||||
public CompoundTag getNbtData() {
|
||||
Map<String, Tag> values = new HashMap<>();
|
||||
Map<String, Tag> inner = new HashMap<>();
|
||||
Map<String, Tag<?, ?>> values = new HashMap<>();
|
||||
Map<String, Tag<?, ?>> inner = new HashMap<>();
|
||||
inner.put("Name", new StringTag(owner));
|
||||
values.put(DeprecationUtil.getHeadOwnerKey(), new CompoundTag(inner));
|
||||
return new CompoundTag(values);
|
||||
@ -113,7 +113,7 @@ public class SkullBlock extends BaseBlock {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Tag> values = rootTag.getValue();
|
||||
Map<String, Tag<?, ?>> values = rootTag.getValue();
|
||||
|
||||
Tag t;
|
||||
|
||||
|
@ -116,7 +116,10 @@ public class FaweAPI {
|
||||
* @param file the file to load
|
||||
* @return a clipboard containing the schematic
|
||||
* @see ClipboardFormat
|
||||
* @deprecated Opens streams that are not then closed. Use {@link ClipboardFormats#findByFile(File)} and its relevant
|
||||
* methods to allow closing created streams/closing the reader (which will close the stream(s))
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2.11.1")
|
||||
public static Clipboard load(File file) throws IOException {
|
||||
return ClipboardFormats.findByFile(file).load(file);
|
||||
}
|
||||
|
@ -532,7 +532,7 @@ public enum FaweCache implements Trimable {
|
||||
}
|
||||
|
||||
public CompoundTag asTag(Map<String, Object> value) {
|
||||
HashMap<String, Tag> map = new HashMap<>();
|
||||
HashMap<String, Tag<?, ?>> map = new HashMap<>();
|
||||
for (Map.Entry<String, Object> entry : value.entrySet()) {
|
||||
Object child = entry.getValue();
|
||||
Tag tag = asTag(child);
|
||||
|
@ -91,7 +91,7 @@ public class CopyPastaBrush implements Brush, ResettableTool {
|
||||
newClipboard.setOrigin(position);
|
||||
ClipboardHolder holder = new ClipboardHolder(newClipboard);
|
||||
session.setClipboard(holder);
|
||||
int blocks = builder.size();
|
||||
long blocks = builder.longSize();
|
||||
player.print(Caption.of("fawe.worldedit.copy.command.copy", blocks));
|
||||
} else {
|
||||
AffineTransform transform = null;
|
||||
|
@ -24,7 +24,8 @@ public record PopulateSchem(Mask mask, List<ClipboardHolder> clipboards, int rar
|
||||
CuboidRegion cuboid = new CuboidRegion(
|
||||
editSession.getWorld(),
|
||||
position.subtract(size1, size1, size1),
|
||||
position.add(size1, size1, size1)
|
||||
position.add(size1, size1, size1),
|
||||
true
|
||||
);
|
||||
try {
|
||||
editSession.addSchems(cuboid, mask, clipboards, rarity, randomRotate);
|
||||
|
@ -51,6 +51,7 @@ public abstract class Scroll implements ScrollTool {
|
||||
parserContext.setActor(player);
|
||||
parserContext.setWorld(player.getWorld());
|
||||
parserContext.setSession(session);
|
||||
parserContext.setTryLegacy(player.getLimit().ALLOW_LEGACY);
|
||||
switch (mode) {
|
||||
case CLIPBOARD:
|
||||
if (arguments.size() != 2) {
|
||||
|
@ -6,6 +6,7 @@ import com.sk89q.util.StringUtil;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
@ -18,6 +19,7 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -31,10 +33,15 @@ public class Config {
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final Map<String, Object> removedKeyVals = new HashMap<>();
|
||||
@Nullable
|
||||
private Map<String, Map.Entry<String, Object>> copyTo = new HashMap<>();
|
||||
private boolean performCopyTo = false;
|
||||
private List<String> existingMigrateNodes = null;
|
||||
|
||||
public Config() {
|
||||
save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0);
|
||||
// This is now definitely required as the save -> load -> save order means the @CopiedFrom annotated fields work
|
||||
save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0, null);
|
||||
performCopyTo = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,11 +67,12 @@ public class Config {
|
||||
|
||||
/**
|
||||
* Set the value of a specific node. Probably throws some error if you supply non existing keys or invalid values.
|
||||
* This should only be called during loading of a config file
|
||||
*
|
||||
* @param key config node
|
||||
* @param value value
|
||||
*/
|
||||
private void set(String key, Object value, Class<?> root) {
|
||||
private void setLoadedNode(String key, Object value, Class<?> root) {
|
||||
String[] split = key.split("\\.");
|
||||
Object instance = getInstance(split, root);
|
||||
if (instance != null) {
|
||||
@ -74,8 +82,18 @@ public class Config {
|
||||
if (field.getAnnotation(Final.class) != null) {
|
||||
return;
|
||||
}
|
||||
if (copyTo != null) {
|
||||
copyTo.remove(key); // Remove if the config field is already written
|
||||
final Object finalValue = value;
|
||||
copyTo.replaceAll((copyToNode, entry) -> {
|
||||
if (!key.equals(entry.getKey())) {
|
||||
return entry;
|
||||
}
|
||||
return new AbstractMap.SimpleEntry<>(key, finalValue);
|
||||
});
|
||||
}
|
||||
Migrate migrate = field.getAnnotation(Migrate.class);
|
||||
if (existingMigrateNodes != null && migrate != null) {
|
||||
if (migrate != null) {
|
||||
existingMigrateNodes.add(migrate.value());
|
||||
}
|
||||
if (field.getType() == String.class && !(value instanceof String)) {
|
||||
@ -90,8 +108,9 @@ public class Config {
|
||||
}
|
||||
}
|
||||
removedKeyVals.put(key, value);
|
||||
LOGGER.error(
|
||||
"Failed to set config option: {}: {} | {} | {}.yml. This is likely because it was removed.",
|
||||
LOGGER.warn(
|
||||
"Failed to set config option: {}: {} | {} | {}.yml. This is likely because it was removed or was set with an " +
|
||||
"invalid value.",
|
||||
key,
|
||||
value,
|
||||
instance,
|
||||
@ -110,7 +129,7 @@ public class Config {
|
||||
if (value instanceof MemorySection) {
|
||||
continue;
|
||||
}
|
||||
set(key, value, getClass());
|
||||
setLoadedNode(key, value, getClass());
|
||||
}
|
||||
for (String node : existingMigrateNodes) {
|
||||
removedKeyVals.remove(node);
|
||||
@ -133,7 +152,7 @@ public class Config {
|
||||
}
|
||||
PrintWriter writer = new PrintWriter(file);
|
||||
Object instance = this;
|
||||
save(writer, getClass(), instance, 0);
|
||||
save(writer, getClass(), instance, 0, null);
|
||||
writer.close();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Failed to save config file: {}", file, e);
|
||||
@ -190,7 +209,7 @@ public class Config {
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that a field should be instantiated / created.
|
||||
* Indicates that a field should be migrated from a node that is deleted
|
||||
*
|
||||
* @since 2.10.0
|
||||
*/
|
||||
@ -202,6 +221,19 @@ public class Config {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that a field's default value should match another input if the config is otherwise already generated
|
||||
*
|
||||
* @since 2.11.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD})
|
||||
public @interface CopiedFrom {
|
||||
|
||||
String value();
|
||||
|
||||
}
|
||||
|
||||
@Ignore // This is not part of the config
|
||||
public static class ConfigBlock<T> {
|
||||
|
||||
@ -254,7 +286,7 @@ public class Config {
|
||||
return value != null ? value.toString() : "null";
|
||||
}
|
||||
|
||||
private void save(PrintWriter writer, Class<?> clazz, final Object instance, int indent) {
|
||||
private void save(PrintWriter writer, Class<?> clazz, final Object instance, int indent, String parentNode) {
|
||||
try {
|
||||
String CTRF = System.lineSeparator();
|
||||
String spacing = StringMan.repeat(" ", indent);
|
||||
@ -274,7 +306,7 @@ public class Config {
|
||||
}
|
||||
if (current == ConfigBlock.class) {
|
||||
current = (Class<?>) ((ParameterizedType) (field.getGenericType())).getActualTypeArguments()[0];
|
||||
handleConfigBlockSave(writer, instance, indent, field, spacing, CTRF, current);
|
||||
handleConfigBlockSave(writer, instance, indent, field, spacing, CTRF, current, parentNode);
|
||||
continue;
|
||||
} else if (!removedKeyVals.isEmpty()) {
|
||||
Migrate migrate = field.getAnnotation(Migrate.class);
|
||||
@ -283,6 +315,18 @@ public class Config {
|
||||
field.set(instance, value);
|
||||
}
|
||||
}
|
||||
CopiedFrom copiedFrom;
|
||||
if (copyTo != null && (copiedFrom = field.getAnnotation(CopiedFrom.class)) != null) {
|
||||
String node = toNodeName(field.getName());
|
||||
node = parentNode == null ? node : parentNode + "." + node;
|
||||
Map.Entry<String, Object> entry = copyTo.remove(node);
|
||||
Object copiedVal;
|
||||
if (entry == null) {
|
||||
copyTo.put(node, new AbstractMap.SimpleEntry<>(copiedFrom.value(), null));
|
||||
} else if ((copiedVal = entry.getValue()) != null) {
|
||||
field.set(instance, copiedVal);
|
||||
}
|
||||
}
|
||||
Create create = field.getAnnotation(Create.class);
|
||||
if (create != null) {
|
||||
Object value = field.get(instance);
|
||||
@ -296,11 +340,12 @@ public class Config {
|
||||
writer.write(spacing + "# " + commentLine + CTRF);
|
||||
}
|
||||
}
|
||||
writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF);
|
||||
String node = toNodeName(current.getSimpleName());
|
||||
writer.write(spacing + node + ":" + CTRF);
|
||||
if (value == null) {
|
||||
field.set(instance, value = current.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
save(writer, current, value, indent + 2);
|
||||
save(writer, current, value, indent + 2, parentNode == null ? node : parentNode + "." + node);
|
||||
} else {
|
||||
writer.write(spacing + toNodeName(field.getName() + ": ") + toYamlString(
|
||||
field.get(instance),
|
||||
@ -311,6 +356,10 @@ public class Config {
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Failed to save config file", e);
|
||||
}
|
||||
if (parentNode == null && performCopyTo) {
|
||||
performCopyTo = false;
|
||||
copyTo = null;
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void handleConfigBlockSave(
|
||||
@ -320,7 +369,8 @@ public class Config {
|
||||
Field field,
|
||||
String spacing,
|
||||
String CTRF,
|
||||
Class<T> current
|
||||
Class<T> current,
|
||||
String parentNode
|
||||
) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
|
||||
Comment comment = current.getAnnotation(Comment.class);
|
||||
if (comment != null) {
|
||||
@ -330,6 +380,7 @@ public class Config {
|
||||
}
|
||||
BlockName blockNames = current.getAnnotation(BlockName.class);
|
||||
if (blockNames != null) {
|
||||
String node = toNodeName(current.getSimpleName());
|
||||
writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF);
|
||||
ConfigBlock<T> configBlock = (ConfigBlock<T>) field.get(instance);
|
||||
if (configBlock == null || configBlock.getInstances().isEmpty()) {
|
||||
@ -343,7 +394,7 @@ public class Config {
|
||||
for (Map.Entry<String, T> entry : configBlock.getRaw().entrySet()) {
|
||||
String key = entry.getKey();
|
||||
writer.write(spacing + " " + toNodeName(key) + ":" + CTRF);
|
||||
save(writer, current, entry.getValue(), indent + 4);
|
||||
save(writer, current, entry.getValue(), indent + 4, parentNode == null ? node : parentNode + "." + node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -191,6 +191,7 @@ public class Settings extends Config {
|
||||
}
|
||||
}
|
||||
limit.UNIVERSAL_DISALLOWED_BLOCKS &= newLimit.UNIVERSAL_DISALLOWED_BLOCKS;
|
||||
limit.ALLOW_LEGACY &= newLimit.ALLOW_LEGACY;
|
||||
|
||||
if (limit.DISALLOWED_BLOCKS == null) {
|
||||
limit.DISALLOWED_BLOCKS = newLimit.DISALLOWED_BLOCKS.isEmpty() ? Collections.emptySet() : new HashSet<>(
|
||||
@ -439,6 +440,10 @@ public class Settings extends Config {
|
||||
" - If fast-placement is disabled, this may cause edits to be slower."
|
||||
})
|
||||
public boolean UNIVERSAL_DISALLOWED_BLOCKS = true;
|
||||
@Comment({
|
||||
"If legacy, mumerical, blocks IDs should be able to be used (i.e. 12:2),"
|
||||
})
|
||||
public boolean ALLOW_LEGACY = true;
|
||||
@Comment({
|
||||
"List of blocks to deny use of. Can be either an entire block type or a block with a specific property value.",
|
||||
"Where block properties are specified, any blockstate with the property will be disallowed (e.g. all directions",
|
||||
@ -518,6 +523,9 @@ public class Settings extends Config {
|
||||
public int DELETE_AFTER_DAYS = 7;
|
||||
@Comment("Delete history in memory on logout (does not effect disk)")
|
||||
public boolean DELETE_ON_LOGOUT = true;
|
||||
@Comment("Delete history on disk on logout")
|
||||
@CopiedFrom("history.delete-on-logout")
|
||||
public boolean DELETE_DISK_ON_LOGOUT = false;
|
||||
@Comment({
|
||||
"If history should be enabled by default for plugins using WorldEdit:",
|
||||
" - It is faster to have disabled",
|
||||
|
@ -64,26 +64,47 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
||||
public Future<Boolean> init() {
|
||||
return call(() -> {
|
||||
try (PreparedStatement stmt = connection.prepareStatement("CREATE TABLE IF NOT EXISTS`" + this.prefix +
|
||||
"edits` (`player` BLOB(16) NOT NULL,`id` INT NOT NULL, `time` INT NOT NULL,`x1`" +
|
||||
"INT NOT NULL,`x2` INT NOT NULL,`z1` INT NOT NULL,`z2` INT NOT NULL,`y1`" +
|
||||
"INT NOT NULL, `y2` INT NOT NULL, `size` INT NOT NULL, `command` VARCHAR, PRIMARY KEY (player, id))")) {
|
||||
"_edits` (`player` BLOB(16) NOT NULL,`id` INT NOT NULL, `time` INT NOT NULL,`x1` " +
|
||||
"INT NOT NULL,`x2` INT NOT NULL,`z1` INT NOT NULL,`z2` INT NOT NULL,`y1` " +
|
||||
"INT NOT NULL, `y2` INT NOT NULL, `size` BIGINT NOT NULL, `command` VARCHAR, PRIMARY KEY (player, id))")) {
|
||||
stmt.executeUpdate();
|
||||
}
|
||||
try (PreparedStatement stmt = connection.prepareStatement("ALTER TABLE`" + this.prefix + "edits` ADD COLUMN `command` VARCHAR")) {
|
||||
String alterTablePrefix = "ALTER TABLE`" + this.prefix + "edits` ";
|
||||
try (PreparedStatement stmt =
|
||||
connection.prepareStatement(alterTablePrefix + "ADD COLUMN `command` VARCHAR")) {
|
||||
stmt.executeUpdate();
|
||||
} catch (SQLException ignored) {
|
||||
} // Already updated
|
||||
try (PreparedStatement stmt = connection.prepareStatement("ALTER TABLE`" + this.prefix + "edits` ADD SIZE INT DEFAULT 0 NOT NULL")) {
|
||||
try (PreparedStatement stmt =
|
||||
connection.prepareStatement(alterTablePrefix + "ADD COLUMN `size` BIGINT DEFAULT 0 NOT NULL")) {
|
||||
stmt.executeUpdate();
|
||||
} catch (SQLException ignored) {
|
||||
} // Already updated
|
||||
|
||||
boolean migrated = false;
|
||||
try (PreparedStatement stmt =
|
||||
connection.prepareStatement("INSERT INTO `" + this.prefix + "_edits` " +
|
||||
"(player, id, time, x1, x2, z1, z2, y1, y2, size, command) " +
|
||||
"SELECT player, id, time, x1, x2, z1, z2, y1, y2, size, command " +
|
||||
"FROM `" + this.prefix + "edits`")) {
|
||||
|
||||
stmt.executeUpdate();
|
||||
migrated = true;
|
||||
} catch (SQLException ignored) {
|
||||
} // Already updated
|
||||
if (migrated) {
|
||||
try (PreparedStatement stmt = connection.prepareStatement("DROP TABLE `" + this.prefix + "edits`")) {
|
||||
stmt.executeUpdate();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public Future<Integer> delete(UUID uuid, int id) {
|
||||
return call(() -> {
|
||||
try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "edits` WHERE `player`=? AND `id`=?")) {
|
||||
try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "_edits` WHERE `player`=? " +
|
||||
"AND `id`=?")) {
|
||||
stmt.setBytes(1, toBytes(uuid));
|
||||
stmt.setInt(2, id);
|
||||
return stmt.executeUpdate();
|
||||
@ -94,7 +115,7 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
||||
public Future<RollbackOptimizedHistory> getEdit(@Nonnull UUID uuid, int id) {
|
||||
return call(() -> {
|
||||
try (PreparedStatement stmt = connection.prepareStatement("SELECT * FROM`" + this.prefix +
|
||||
"edits` WHERE `player`=? AND `id`=?")) {
|
||||
"_edits` WHERE `player`=? AND `id`=?")) {
|
||||
stmt.setBytes(1, toBytes(uuid));
|
||||
stmt.setInt(2, id);
|
||||
ResultSet result = stmt.executeQuery();
|
||||
@ -119,7 +140,7 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
||||
CuboidRegion region = new CuboidRegion(BlockVector3.at(x1, y1, z1), BlockVector3.at(x2, y2, z2));
|
||||
|
||||
long time = result.getInt("time") * 1000L;
|
||||
long size = result.getInt("size");
|
||||
long size = result.getLong("size");
|
||||
|
||||
String command = result.getString("command");
|
||||
|
||||
@ -135,7 +156,7 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
||||
long now = System.currentTimeMillis() / 1000;
|
||||
final int then = (int) (now - diff);
|
||||
return call(() -> {
|
||||
try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "edits` WHERE `time`<?")) {
|
||||
try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "_edits` WHERE `time`<?")) {
|
||||
stmt.setInt(1, then);
|
||||
return stmt.executeUpdate();
|
||||
}
|
||||
@ -160,7 +181,7 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
||||
try {
|
||||
int count = 0;
|
||||
String stmtStr = """
|
||||
SELECT * FROM `%sedits`
|
||||
SELECT * FROM `%s_edits`
|
||||
WHERE `time` > ?
|
||||
AND `x2` >= ?
|
||||
AND `x1` <= ?
|
||||
@ -202,7 +223,8 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
||||
}
|
||||
if (delete && uuid != null) {
|
||||
try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix +
|
||||
"edits` WHERE `player`=? AND `time`>? AND `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=?")) {
|
||||
"_edits` WHERE `player`=? AND `time`>? AND `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? " +
|
||||
"AND `z1`<=?")) {
|
||||
byte[] uuidBytes = ByteBuffer
|
||||
.allocate(16)
|
||||
.putLong(uuid.getMostSignificantBits())
|
||||
@ -249,7 +271,7 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
||||
RollbackOptimizedHistory[] copy = IntStream.range(0, size)
|
||||
.mapToObj(i -> historyChanges.poll()).toArray(RollbackOptimizedHistory[]::new);
|
||||
|
||||
try (PreparedStatement stmt = connection.prepareStatement("INSERT OR REPLACE INTO`" + this.prefix + "edits`" +
|
||||
try (PreparedStatement stmt = connection.prepareStatement("INSERT OR REPLACE INTO`" + this.prefix + "_edits`" +
|
||||
" (`player`,`id`,`time`,`x1`,`x2`,`z1`,`z2`,`y1`,`y2`,`command`,`size`) VALUES(?,?,?,?,?,?,?,?,?,?,?)")) {
|
||||
// `player`,`id`,`time`,`x1`,`x2`,`z1`,`z2`,`y1`,`y2`,`command`,`size`) VALUES(?,?,?,?,?,?,?,?,?,?,?)"
|
||||
for (RollbackOptimizedHistory change : copy) {
|
||||
@ -270,7 +292,7 @@ public class RollbackDatabase extends AsyncNotifyQueue {
|
||||
stmt.setInt(8, pos1.y() - 128);
|
||||
stmt.setInt(9, pos2.y() - 128);
|
||||
stmt.setString(10, change.getCommand());
|
||||
stmt.setInt(11, change.size());
|
||||
stmt.setLong(11, change.longSize());
|
||||
stmt.executeUpdate();
|
||||
stmt.clearParameters();
|
||||
}
|
||||
|
@ -3,25 +3,25 @@ package com.fastasyncworldedit.core.entity;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LazyBaseEntity extends BaseEntity {
|
||||
|
||||
private Supplier<CompoundBinaryTag> saveTag;
|
||||
private Supplier<LinCompoundTag> saveTag;
|
||||
|
||||
public LazyBaseEntity(EntityType type, Supplier<CompoundBinaryTag> saveTag) {
|
||||
public LazyBaseEntity(EntityType type, Supplier<LinCompoundTag> saveTag) {
|
||||
super(type);
|
||||
this.saveTag = saveTag;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CompoundBinaryTag getNbt() {
|
||||
Supplier<CompoundBinaryTag> tmp = saveTag;
|
||||
public LinCompoundTag getNbt() {
|
||||
Supplier<LinCompoundTag> tmp = saveTag;
|
||||
if (tmp != null) {
|
||||
saveTag = null;
|
||||
if (Fawe.isMainThread()) {
|
||||
|
@ -0,0 +1,17 @@
|
||||
package com.fastasyncworldedit.core.exception;
|
||||
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
|
||||
public class OutsideWorldBoundsException extends WorldEditException {
|
||||
|
||||
private final int y;
|
||||
|
||||
public OutsideWorldBoundsException(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public int y() {
|
||||
return y;
|
||||
}
|
||||
|
||||
}
|
@ -143,7 +143,7 @@ public class RichMaskParser extends FaweParser<Mask> {
|
||||
int end = command.lastIndexOf(']');
|
||||
mask = parseFromInput(command.substring(1, end == -1 ? command.length() : end), context);
|
||||
} else {
|
||||
BlockMaskBuilder builder = new BlockMaskBuilder();
|
||||
BlockMaskBuilder builder = new BlockMaskBuilder(context);
|
||||
try {
|
||||
builder.addRegex(full);
|
||||
} catch (InputParseException ignored) {
|
||||
|
@ -200,6 +200,7 @@ public class ConsumeBindings extends Bindings {
|
||||
public BaseBlock baseBlock(Actor actor, String argument) {
|
||||
ParserContext parserContext = new ParserContext();
|
||||
parserContext.setActor(actor);
|
||||
parserContext.setTryLegacy(actor.getLimit().ALLOW_LEGACY);
|
||||
if (actor instanceof Entity) {
|
||||
Extent extent = ((Entity) actor).getExtent();
|
||||
if (extent instanceof World) {
|
||||
|
@ -101,7 +101,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
if (!contains(x, z)) {
|
||||
if (!contains(x, y, z)) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
WEManager.weManager().cancelEditSafe(this, FaweCache.OUTSIDE_REGION);
|
||||
}
|
||||
|
@ -29,8 +29,6 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -81,7 +79,7 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc
|
||||
return block;
|
||||
}
|
||||
CompoundTag nbt = localBlock.getNbtData();
|
||||
Map<String, Tag> value = new HashMap<>(nbt.getValue());
|
||||
Map<String, Tag<?, ?>> value = new HashMap<>(nbt.getValue());
|
||||
for (String key : strip) {
|
||||
value.remove(key);
|
||||
}
|
||||
@ -93,7 +91,7 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc
|
||||
return entity;
|
||||
}
|
||||
CompoundTag nbt = entity.getNbtData();
|
||||
Map<String, Tag> value = new HashMap<>(nbt.getValue());
|
||||
Map<String, Tag<?, ?>> value = new HashMap<>(nbt.getValue());
|
||||
for (String key : strip) {
|
||||
value.remove(key);
|
||||
}
|
||||
@ -110,7 +108,7 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc
|
||||
}
|
||||
boolean isBv3ChunkMap = tiles instanceof BlockVector3ChunkMap;
|
||||
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
||||
ImmutableMap.Builder<String, Tag> map = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<String, Tag<?, ?>> map = ImmutableMap.builder();
|
||||
final AtomicBoolean isStripped = new AtomicBoolean(false);
|
||||
entry.getValue().getValue().forEach((k, v) -> {
|
||||
if (strip.contains(k.toLowerCase())) {
|
||||
@ -132,7 +130,7 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc
|
||||
Iterator<CompoundTag> iterator = entities.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
CompoundTag entity = iterator.next();
|
||||
ImmutableMap.Builder<String, Tag> map = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<String, Tag<?, ?>> map = ImmutableMap.builder();
|
||||
final AtomicBoolean isStripped = new AtomicBoolean(false);
|
||||
entity.getValue().forEach((k, v) -> {
|
||||
if (strip.contains(k.toUpperCase(Locale.ROOT))) {
|
||||
|
@ -93,7 +93,7 @@ public class TransformExtent extends BlockTransformExtent {
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BlockVector3 p = getPos(x, y, z);
|
||||
return super.getBiomeType(p.x(), y, p.z());
|
||||
return super.getBiomeType(p.x(), p.y(), p.z());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -152,7 +152,7 @@ public class CPUOptimizedClipboard extends LinearClipboard {
|
||||
public Collection<CompoundTag> getTileEntities() {
|
||||
convertTilesToIndex();
|
||||
nbtMapIndex.replaceAll((index, tag) -> {
|
||||
Map<String, Tag> values = new HashMap<>(tag.getValue());
|
||||
Map<String, Tag<?, ?>> values = new HashMap<>(tag.getValue());
|
||||
if (!values.containsKey("x")) {
|
||||
int y = index / getArea();
|
||||
index -= y * getArea();
|
||||
@ -176,7 +176,7 @@ public class CPUOptimizedClipboard extends LinearClipboard {
|
||||
}
|
||||
|
||||
private boolean setTile(int index, CompoundTag tag) {
|
||||
final Map<String, Tag> values = new HashMap<>(tag.getValue());
|
||||
final Map<String, Tag<?, ?>> values = new HashMap<>(tag.getValue());
|
||||
values.remove("x");
|
||||
values.remove("y");
|
||||
values.remove("z");
|
||||
|
@ -586,7 +586,7 @@ public class DiskOptimizedClipboard extends LinearClipboard {
|
||||
for (BlockArrayClipboard.ClipboardEntity entity : entities) {
|
||||
if (entity.getState() != null && entity.getState().getNbtData() != null) {
|
||||
CompoundTag data = entity.getState().getNbtData();
|
||||
HashMap<String, Tag> value = new HashMap<>(data.getValue());
|
||||
HashMap<String, Tag<?, ?>> value = new HashMap<>(data.getValue());
|
||||
List<DoubleTag> pos = new ArrayList<>(3);
|
||||
pos.add(new DoubleTag(entity.getLocation().x()));
|
||||
pos.add(new DoubleTag(entity.getLocation().x()));
|
||||
@ -710,7 +710,7 @@ public class DiskOptimizedClipboard extends LinearClipboard {
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
final Map<String, Tag> values = new HashMap<>(tag.getValue());
|
||||
final Map<String, Tag<?, ?>> values = new HashMap<>(tag.getValue());
|
||||
values.put("x", new IntTag(x));
|
||||
values.put("y", new IntTag(y));
|
||||
values.put("z", new IntTag(z));
|
||||
|
@ -106,7 +106,7 @@ public abstract class LinearClipboard extends SimpleClipboard {
|
||||
@Nullable
|
||||
@Override
|
||||
public Entity createEntity(Location location, BaseEntity entity, UUID uuid) {
|
||||
Map<String, Tag> map = new HashMap<>(entity.getNbtData().getValue());
|
||||
Map<String, Tag<?, ?>> map = new HashMap<>(entity.getNbtData().getValue());
|
||||
NBTUtils.addUUIDToMap(map, uuid);
|
||||
entity.setNbtData(new CompoundTag(map));
|
||||
BlockArrayClipboard.ClipboardEntity ret = new BlockArrayClipboard.ClipboardEntity(location, entity);
|
||||
|
@ -254,7 +254,7 @@ public class MemoryOptimizedClipboard extends LinearClipboard {
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
final Map<String, Tag> values = new HashMap<>(tag.getValue());
|
||||
final Map<String, Tag<?, ?>> values = new HashMap<>(tag.getValue());
|
||||
values.put("x", new IntTag(x));
|
||||
values.put("y", new IntTag(y));
|
||||
values.put("z", new IntTag(z));
|
||||
|
@ -2,13 +2,10 @@ package com.fastasyncworldedit.core.extent.clipboard;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.NBTUtils;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.session.request.Request;
|
||||
@ -18,9 +15,7 @@ import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@ -77,6 +72,16 @@ public abstract class ReadOnlyClipboard extends SimpleClipboard {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector3 getMinimumPoint() {
|
||||
return region.getMinimumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector3 getMaximumPoint() {
|
||||
return region.getMaximumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region getRegion() {
|
||||
return region;
|
||||
|
@ -9,7 +9,7 @@ import com.fastasyncworldedit.core.internal.io.FaweInputStream;
|
||||
import com.fastasyncworldedit.core.internal.io.FaweOutputStream;
|
||||
import com.fastasyncworldedit.core.jnbt.streamer.StreamDelegate;
|
||||
import com.fastasyncworldedit.core.jnbt.streamer.ValueReader;
|
||||
import com.sk89q.jnbt.AdventureNBTConverter;
|
||||
import com.sk89q.jnbt.LinBusConverter;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
@ -53,7 +53,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
/**
|
||||
* Reads schematic files using the Sponge Schematic Specification.
|
||||
*/
|
||||
public class FastSchematicReader extends NBTSchematicReader {
|
||||
public class FastSchematicReaderV2 extends NBTSchematicReader {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
private final NBTInputStream inputStream;
|
||||
@ -88,7 +88,7 @@ public class FastSchematicReader extends NBTSchematicReader {
|
||||
*
|
||||
* @param inputStream the input stream to read from
|
||||
*/
|
||||
public FastSchematicReader(NBTInputStream inputStream) {
|
||||
public FastSchematicReaderV2(NBTInputStream inputStream) {
|
||||
checkNotNull(inputStream);
|
||||
this.inputStream = inputStream;
|
||||
this.fixer = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataFixer();
|
||||
@ -109,26 +109,22 @@ public class FastSchematicReader extends NBTSchematicReader {
|
||||
if (fixer == null || dataVersion == -1) {
|
||||
return tag;
|
||||
}
|
||||
//FAWE start - BinaryTag
|
||||
return (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp(
|
||||
return (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp(
|
||||
DataFixer.FixTypes.BLOCK_ENTITY,
|
||||
tag.asBinaryTag(),
|
||||
tag.toLinTag(),
|
||||
dataVersion
|
||||
));
|
||||
//FAWE end
|
||||
}
|
||||
|
||||
private CompoundTag fixEntity(CompoundTag tag) {
|
||||
if (fixer == null || dataVersion == -1) {
|
||||
return tag;
|
||||
}
|
||||
//FAWE start - BinaryTag
|
||||
return (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp(
|
||||
return (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp(
|
||||
DataFixer.FixTypes.ENTITY,
|
||||
tag.asBinaryTag(),
|
||||
tag.toLinTag(),
|
||||
dataVersion
|
||||
));
|
||||
//FAWE end
|
||||
}
|
||||
|
||||
private String fixBiome(String biomePalettePart) {
|
||||
@ -251,7 +247,7 @@ public class FastSchematicReader extends NBTSchematicReader {
|
||||
throw new IOException("This schematic version is not supported; Version: " + version
|
||||
+ ", DataVersion: " + dataVersion + ". It's very likely your schematic has an invalid file extension," +
|
||||
" if the schematic has been created on a version lower than 1.13.2, the extension MUST be `.schematic`," +
|
||||
" elsewise the schematic can't be read properly.");
|
||||
" elsewise the schematic can't be read properly. If you are using a litematica schematic, it is not supported!");
|
||||
}
|
||||
|
||||
if (blocks != null) {
|
||||
@ -344,7 +340,7 @@ public class FastSchematicReader extends NBTSchematicReader {
|
||||
y = pos[1];
|
||||
z = pos[2];
|
||||
}
|
||||
Map<String, Tag> values = new HashMap<>(tile.getValue());
|
||||
Map<String, Tag<?, ?>> values = new HashMap<>(tile.getValue());
|
||||
Tag id = values.get("Id");
|
||||
if (id != null) {
|
||||
values.put("x", new IntTag(x));
|
||||
@ -371,7 +367,7 @@ public class FastSchematicReader extends NBTSchematicReader {
|
||||
// entities
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
for (Map<String, Object> entRaw : entities) {
|
||||
Map<String, Tag> value = new HashMap<>(FaweCache.INSTANCE.asTag(entRaw).getValue());
|
||||
Map<String, Tag<?, ?>> value = new HashMap<>(FaweCache.INSTANCE.asTag(entRaw).getValue());
|
||||
StringTag id = (StringTag) value.get("Id");
|
||||
if (id == null) {
|
||||
id = (StringTag) value.get("id");
|
@ -0,0 +1,818 @@
|
||||
package com.fastasyncworldedit.core.extent.clipboard.io;
|
||||
|
||||
import com.fastasyncworldedit.core.extent.clipboard.LinearClipboard;
|
||||
import com.fastasyncworldedit.core.extent.clipboard.SimpleClipboard;
|
||||
import com.fastasyncworldedit.core.internal.io.ResettableFileInputStream;
|
||||
import com.fastasyncworldedit.core.internal.io.VarIntStreamIterator;
|
||||
import com.fastasyncworldedit.core.math.MutableBlockVector3;
|
||||
import com.fastasyncworldedit.core.util.IOUtil;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.NBTConstants;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
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.sponge.ReaderUtil;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.sponge.VersionedDataFixer;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.util.concurrency.LazyReference;
|
||||
import com.sk89q.worldedit.world.DataFixer;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import it.unimi.dsi.fastutil.io.FastBufferedInputStream;
|
||||
import it.unimi.dsi.fastutil.io.FastBufferedOutputStream;
|
||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||
import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Function;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* ClipboardReader for the Sponge Schematic Format v3.
|
||||
* Not necessarily much faster than {@link com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader}, but uses a
|
||||
* stream based approach to keep the memory overhead minimal (especially in larger schematics)
|
||||
*
|
||||
* @since 2.11.1
|
||||
*/
|
||||
@SuppressWarnings("removal") // JNBT
|
||||
public class FastSchematicReaderV3 implements ClipboardReader {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
private static final byte CACHE_IDENTIFIER_END = 0x00;
|
||||
private static final byte CACHE_IDENTIFIER_BLOCK = 0x01;
|
||||
private static final byte CACHE_IDENTIFIER_BIOMES = 0x02;
|
||||
private static final byte CACHE_IDENTIFIER_ENTITIES = 0x03;
|
||||
private static final byte CACHE_IDENTIFIER_BLOCK_TILE_ENTITIES = 0x04;
|
||||
|
||||
private final InputStream parentStream;
|
||||
private final MutableBlockVector3 dimensions = MutableBlockVector3.at(0, 0, 0);
|
||||
private final Set<Byte> remainingTags;
|
||||
|
||||
private DataInputStream dataInputStream;
|
||||
private NBTInputStream nbtInputStream;
|
||||
|
||||
private VersionedDataFixer dataFixer;
|
||||
private BlockVector3 offset;
|
||||
private BlockState[] blockPalette;
|
||||
private BiomeType[] biomePalette;
|
||||
private int dataVersion = -1;
|
||||
|
||||
// Only used if the InputStream is not file based (and therefor does not support resets based on FileChannels)
|
||||
// and the file is unordered
|
||||
// Data and Palette cache is separated, as the data requires a fully populated palette - and the order is not guaranteed
|
||||
private byte[] dataCache;
|
||||
private byte[] paletteCache;
|
||||
private OutputStream dataCacheWriter;
|
||||
private OutputStream paletteCacheWriter;
|
||||
|
||||
|
||||
public FastSchematicReaderV3(@NonNull InputStream stream) {
|
||||
Objects.requireNonNull(stream, "stream");
|
||||
if (stream instanceof ResettableFileInputStream) {
|
||||
stream.mark(Integer.MAX_VALUE);
|
||||
this.remainingTags = new HashSet<>();
|
||||
} else if (stream instanceof FileInputStream fileInputStream) {
|
||||
stream = new ResettableFileInputStream(fileInputStream);
|
||||
stream.mark(Integer.MAX_VALUE);
|
||||
this.remainingTags = new HashSet<>();
|
||||
} else if (stream instanceof FastBufferedInputStream || stream instanceof BufferedInputStream) {
|
||||
this.remainingTags = null;
|
||||
} else {
|
||||
stream = new FastBufferedInputStream(stream);
|
||||
this.remainingTags = null;
|
||||
}
|
||||
this.parentStream = stream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clipboard read(final UUID uuid, final Function<BlockVector3, Clipboard> createOutput) throws IOException {
|
||||
Clipboard clipboard = null;
|
||||
|
||||
this.setSubStreams();
|
||||
skipHeader(this.dataInputStream);
|
||||
|
||||
byte type;
|
||||
String tag;
|
||||
while ((type = dataInputStream.readByte()) != NBTConstants.TYPE_END) {
|
||||
tag = this.dataInputStream.readUTF();
|
||||
switch (tag) {
|
||||
case "DataVersion" -> {
|
||||
final Platform platform =
|
||||
WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING);
|
||||
this.dataVersion = this.dataInputStream.readInt();
|
||||
this.dataFixer = ReaderUtil.getVersionedDataFixer(this.dataVersion, platform, platform.getDataVersion());
|
||||
}
|
||||
case "Offset" -> {
|
||||
this.dataInputStream.skipNBytes(4); // Array Length field (4 byte int)
|
||||
this.offset = BlockVector3.at(
|
||||
this.dataInputStream.readInt(),
|
||||
this.dataInputStream.readInt(),
|
||||
this.dataInputStream.readInt()
|
||||
);
|
||||
}
|
||||
case "Width" -> this.dimensions.mutX(this.dataInputStream.readShort() & 0xFFFF);
|
||||
case "Height" -> this.dimensions.mutY(this.dataInputStream.readShort() & 0xFFFF);
|
||||
case "Length" -> this.dimensions.mutZ(this.dataInputStream.readShort() & 0xFFFF);
|
||||
case "Blocks" -> readBlocks(clipboard);
|
||||
case "Biomes" -> readBiomes(clipboard);
|
||||
case "Entities" -> readEntities(clipboard);
|
||||
default -> this.nbtInputStream.readTagPayloadLazy(type, 0);
|
||||
}
|
||||
if (clipboard == null && this.areDimensionsAvailable()) {
|
||||
clipboard = createOutput.apply(this.dimensions);
|
||||
}
|
||||
}
|
||||
|
||||
if (clipboard == null) {
|
||||
throw new IOException("Invalid schematic - missing dimensions");
|
||||
}
|
||||
if (dataFixer == null) {
|
||||
throw new IOException("Invalid schematic - missing DataVersion");
|
||||
}
|
||||
|
||||
if (this.supportsReset() && !remainingTags.isEmpty()) {
|
||||
readRemainingDataReset(clipboard);
|
||||
} else if (this.dataCacheWriter != null || this.paletteCacheWriter != null) {
|
||||
readRemainingDataCache(clipboard);
|
||||
}
|
||||
|
||||
clipboard.setOrigin(this.offset.multiply(-1));
|
||||
if (clipboard instanceof SimpleClipboard simpleClipboard && !this.offset.equals(BlockVector3.ZERO)) {
|
||||
clipboard = new BlockArrayClipboard(simpleClipboard, this.offset);
|
||||
}
|
||||
return clipboard;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads all locally cached data (due to reset not being available) and applies them to the clipboard.
|
||||
* <p>
|
||||
* Firstly, closes all cache writers (which adds the END identifier to each and fills the cache byte arrays on this instance)
|
||||
* If required, creates all missing palettes first (as needed by all remaining data).
|
||||
* At last writes all missing data (block states, tile entities, biomes, entities).
|
||||
*
|
||||
* @param clipboard The clipboard to write into.
|
||||
* @throws IOException on I/O error.
|
||||
*/
|
||||
private void readRemainingDataCache(Clipboard clipboard) throws IOException {
|
||||
byte identifier;
|
||||
if (this.paletteCacheWriter != null) {
|
||||
this.paletteCacheWriter.close();
|
||||
}
|
||||
if (this.dataCacheWriter != null) {
|
||||
this.dataCacheWriter.close();
|
||||
}
|
||||
if (this.paletteCache != null) {
|
||||
try (final DataInputStream cacheStream = new DataInputStream(new FastBufferedInputStream(
|
||||
new LZ4BlockInputStream(new FastBufferedInputStream(new ByteArrayInputStream(this.paletteCache)))))) {
|
||||
while ((identifier = cacheStream.readByte()) != CACHE_IDENTIFIER_END) {
|
||||
if (identifier == CACHE_IDENTIFIER_BLOCK) {
|
||||
this.readPaletteMap(cacheStream, this.provideBlockPaletteInitializer());
|
||||
continue;
|
||||
}
|
||||
if (identifier == CACHE_IDENTIFIER_BIOMES) {
|
||||
this.readPaletteMap(cacheStream, this.provideBiomePaletteInitializer());
|
||||
continue;
|
||||
}
|
||||
throw new IOException("invalid cache state - got identifier: 0x" + identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
try (final DataInputStream cacheStream = new DataInputStream(new FastBufferedInputStream(
|
||||
new LZ4BlockInputStream(new FastBufferedInputStream(new ByteArrayInputStream(this.dataCache)))));
|
||||
final NBTInputStream cacheNbtIn = new NBTInputStream(cacheStream)) {
|
||||
while ((identifier = cacheStream.readByte()) != CACHE_IDENTIFIER_END) {
|
||||
switch (identifier) {
|
||||
case CACHE_IDENTIFIER_BLOCK -> this.readPaletteData(cacheStream, this.getBlockWriter(clipboard));
|
||||
case CACHE_IDENTIFIER_BIOMES -> this.readPaletteData(cacheStream, this.getBiomeWriter(clipboard));
|
||||
case CACHE_IDENTIFIER_ENTITIES -> {
|
||||
cacheStream.skipNBytes(1); // list child type (TAG_Compound)
|
||||
this.readEntityContainers(
|
||||
cacheStream,
|
||||
cacheNbtIn,
|
||||
DataFixer.FixTypes.ENTITY,
|
||||
this.provideEntityTransformer(clipboard)
|
||||
);
|
||||
}
|
||||
case CACHE_IDENTIFIER_BLOCK_TILE_ENTITIES -> {
|
||||
cacheStream.skipNBytes(1); // list child type (TAG_Compound)
|
||||
this.readEntityContainers(
|
||||
cacheStream,
|
||||
cacheNbtIn,
|
||||
DataFixer.FixTypes.BLOCK_ENTITY,
|
||||
this.provideTileEntityTransformer(clipboard)
|
||||
);
|
||||
}
|
||||
default -> throw new IOException("invalid cache state - got identifier: 0x" + identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the main stream of this clipboard and reads all remaining data that could not be read or fixed yet.
|
||||
* Might need two iterations if the DataVersion tag is after the Blocks tag while the Palette inside the Blocks tag is not
|
||||
* at the first position.
|
||||
*
|
||||
* @param clipboard The clipboard to write into.
|
||||
* @throws IOException on I/O error.
|
||||
*/
|
||||
private void readRemainingDataReset(Clipboard clipboard) throws IOException {
|
||||
byte type;
|
||||
String tag;
|
||||
outer:
|
||||
while (!this.remainingTags.isEmpty()) {
|
||||
this.reset();
|
||||
skipHeader(this.dataInputStream);
|
||||
while ((type = dataInputStream.readByte()) != NBTConstants.TYPE_END) {
|
||||
tag = dataInputStream.readUTF();
|
||||
byte b = tag.equals("Blocks") ? CACHE_IDENTIFIER_BLOCK :
|
||||
tag.equals("Biomes") ? CACHE_IDENTIFIER_BIOMES :
|
||||
tag.equals("Entities") ? CACHE_IDENTIFIER_ENTITIES :
|
||||
CACHE_IDENTIFIER_END;
|
||||
if (!this.remainingTags.remove(b)) {
|
||||
this.nbtInputStream.readTagPayloadLazy(type, 0);
|
||||
continue;
|
||||
}
|
||||
switch (tag) {
|
||||
case "Blocks" -> readBlocks(clipboard);
|
||||
case "Biomes" -> readBiomes(clipboard);
|
||||
case "Entities" -> readEntities(clipboard);
|
||||
default -> this.nbtInputStream.readTagPayloadLazy(type, 0); // Should never happen, but just in case
|
||||
}
|
||||
if (this.remainingTags.isEmpty()) {
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* Requires {@link #read()}, {@link #read(UUID)} or {@link #read(UUID, Function)} to be called before.
|
||||
*/
|
||||
@Override
|
||||
public OptionalInt getDataVersion() {
|
||||
return this.dataVersion > -1 ? OptionalInt.of(this.dataVersion) : OptionalInt.empty();
|
||||
}
|
||||
|
||||
private void readBlocks(Clipboard target) throws IOException {
|
||||
this.blockPalette = new BlockState[BlockTypesCache.states.length];
|
||||
readPalette(
|
||||
target != null,
|
||||
CACHE_IDENTIFIER_BLOCK,
|
||||
() -> this.blockPalette[0] != null,
|
||||
this.provideBlockPaletteInitializer(),
|
||||
this.getBlockWriter(target),
|
||||
(type, tag) -> {
|
||||
if (!tag.equals("BlockEntities")) {
|
||||
try {
|
||||
this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_LIST, 0);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to skip additional tag", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.readTileEntities(target);
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn("Failed to read tile entities", e);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void readBiomes(Clipboard target) throws IOException {
|
||||
this.biomePalette = new BiomeType[BiomeType.REGISTRY.size()];
|
||||
readPalette(
|
||||
target != null,
|
||||
CACHE_IDENTIFIER_BIOMES,
|
||||
() -> this.biomePalette[0] != null,
|
||||
this.provideBiomePaletteInitializer(),
|
||||
this.getBiomeWriter(target),
|
||||
(type, tag) -> {
|
||||
try {
|
||||
this.nbtInputStream.readTagPayloadLazy(type, 0);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to skip additional tag in biome container: {}", tag, e);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void readEntities(@Nullable Clipboard target) throws IOException {
|
||||
if (target == null || this.dataFixer == null) {
|
||||
if (supportsReset()) {
|
||||
this.remainingTags.add(CACHE_IDENTIFIER_ENTITIES);
|
||||
this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_LIST, 0);
|
||||
return;
|
||||
}
|
||||
// Easier than streaming for now
|
||||
final NBTOutputStream cacheStream = new NBTOutputStream(this.getDataCacheWriter());
|
||||
cacheStream.writeByte(CACHE_IDENTIFIER_ENTITIES);
|
||||
cacheStream.writeTagPayload(this.nbtInputStream.readTagPayload(NBTConstants.TYPE_LIST, 0));
|
||||
return;
|
||||
}
|
||||
if (this.dataInputStream.read() != NBTConstants.TYPE_COMPOUND) {
|
||||
throw new IOException("Expected a compound block for entity");
|
||||
}
|
||||
this.readEntityContainers(
|
||||
this.dataInputStream, this.nbtInputStream, DataFixer.FixTypes.ENTITY, this.provideEntityTransformer(target)
|
||||
);
|
||||
}
|
||||
|
||||
private void readTileEntities(Clipboard target) throws IOException {
|
||||
if (target == null || this.dataFixer == null) {
|
||||
if (supportsReset()) {
|
||||
this.remainingTags.add(CACHE_IDENTIFIER_BLOCK); // use block identifier, as this method will be called by
|
||||
// readBlocks again
|
||||
this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_LIST, 0);
|
||||
return;
|
||||
}
|
||||
// Easier than streaming for now
|
||||
final NBTOutputStream cacheStream = new NBTOutputStream(this.getDataCacheWriter());
|
||||
cacheStream.writeByte(CACHE_IDENTIFIER_BLOCK_TILE_ENTITIES);
|
||||
cacheStream.writeTagPayload(this.nbtInputStream.readTagPayload(NBTConstants.TYPE_LIST, 0));
|
||||
return;
|
||||
}
|
||||
if (this.dataInputStream.read() != NBTConstants.TYPE_COMPOUND) {
|
||||
throw new IOException("Expected a compound block for tile entity");
|
||||
}
|
||||
this.readEntityContainers(
|
||||
this.dataInputStream,
|
||||
this.nbtInputStream,
|
||||
DataFixer.FixTypes.BLOCK_ENTITY,
|
||||
this.provideTileEntityTransformer(target)
|
||||
);
|
||||
}
|
||||
|
||||
private void readEntityContainers(
|
||||
DataInputStream stream,
|
||||
NBTInputStream nbtStream,
|
||||
DataFixer.FixType<LinCompoundTag> fixType,
|
||||
EntityTransformer transformer
|
||||
) throws IOException {
|
||||
double x, y, z;
|
||||
LinCompoundTag tag;
|
||||
String id;
|
||||
byte type;
|
||||
int count = stream.readInt();
|
||||
while (count-- > 0) {
|
||||
x = -1;
|
||||
y = -1;
|
||||
z = -1;
|
||||
tag = null;
|
||||
id = null;
|
||||
while ((type = stream.readByte()) != NBTConstants.TYPE_END) {
|
||||
switch (type) {
|
||||
// Depending on the type of entity container (tile vs "normal") the pos consists of either doubles or ints
|
||||
case NBTConstants.TYPE_INT_ARRAY -> {
|
||||
if (!stream.readUTF().equals("Pos")) {
|
||||
throw new IOException("Expected INT_ARRAY tag to be Pos");
|
||||
}
|
||||
stream.skipNBytes(4); // count of following ints - for pos = 3
|
||||
x = stream.readInt();
|
||||
y = stream.readInt();
|
||||
z = stream.readInt();
|
||||
}
|
||||
case NBTConstants.TYPE_LIST -> {
|
||||
if (!stream.readUTF().equals("Pos")) {
|
||||
throw new IOException("Expected LIST tag to be Pos");
|
||||
}
|
||||
if (stream.readByte() != NBTConstants.TYPE_DOUBLE) {
|
||||
throw new IOException("Expected LIST Pos tag to contain DOUBLE");
|
||||
}
|
||||
stream.skipNBytes(4); // count of following doubles - for pos = 3
|
||||
x = stream.readDouble();
|
||||
y = stream.readDouble();
|
||||
z = stream.readDouble();
|
||||
}
|
||||
case NBTConstants.TYPE_STRING -> {
|
||||
if (!stream.readUTF().equals("Id")) {
|
||||
throw new IOException("Expected STRING tag to be Id");
|
||||
}
|
||||
id = stream.readUTF();
|
||||
}
|
||||
case NBTConstants.TYPE_COMPOUND -> {
|
||||
if (!stream.readUTF().equals("Data")) {
|
||||
throw new IOException("Expected COMPOUND tag to be Data");
|
||||
}
|
||||
if (!(nbtStream.readTagPayload(NBTConstants.TYPE_COMPOUND, 0).toLinTag() instanceof LinCompoundTag lin)) {
|
||||
throw new IOException("Data tag could not be read into LinCompoundTag");
|
||||
}
|
||||
tag = lin;
|
||||
}
|
||||
default -> throw new IOException("Unexpected tag in compound: " + type);
|
||||
}
|
||||
}
|
||||
if (id == null) {
|
||||
throw new IOException("Missing Id tag in compound");
|
||||
}
|
||||
if (x < 0 || y < 0 || z < 0) {
|
||||
throw new IOException("Missing position for entity " + id);
|
||||
}
|
||||
if (tag == null) {
|
||||
transformer.transform(x, y, z, id, LinCompoundTag.of(Map.of()));
|
||||
continue;
|
||||
}
|
||||
tag = this.dataFixer.fixUp(fixType, tag);
|
||||
if (tag == null) {
|
||||
LOGGER.warn("Failed to fix-up entity for {} @ {},{},{} - skipping", id, x, y, z);
|
||||
continue;
|
||||
}
|
||||
transformer.transform(x, y, z, id, tag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `Palette` tag is required first, as that contains the information of the actual palette size.
|
||||
* Keeping the whole Data block in memory - which *could* be compressed - is just not it
|
||||
*
|
||||
* @param paletteInitializer Invoked for each 'Palette' entry using the actual palette value (e.g. block state) + index
|
||||
* @param paletteDataApplier Invoked for each 'Data' entry using the data index and the palette index at the data index
|
||||
*/
|
||||
private void readPalette(
|
||||
boolean hasClipboard,
|
||||
byte paletteType,
|
||||
BooleanSupplier paletteAlreadyInitialized,
|
||||
PaletteInitializer paletteInitializer,
|
||||
PaletteDataApplier paletteDataApplier,
|
||||
AdditionalTagConsumer additionalTag
|
||||
) throws IOException {
|
||||
boolean hasPalette = paletteAlreadyInitialized.getAsBoolean();
|
||||
byte type;
|
||||
String tag;
|
||||
while ((type = this.dataInputStream.readByte()) != NBTConstants.TYPE_END) {
|
||||
tag = this.dataInputStream.readUTF();
|
||||
if (tag.equals("Palette")) {
|
||||
if (hasPalette) {
|
||||
// Skip palette, as already exists
|
||||
this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_COMPOUND, 0);
|
||||
continue;
|
||||
}
|
||||
if (!this.readPaletteMap(this.dataInputStream, paletteInitializer)) {
|
||||
if (this.supportsReset()) {
|
||||
// Couldn't read - skip palette for now
|
||||
this.remainingTags.add(paletteType);
|
||||
this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_COMPOUND, 0);
|
||||
continue;
|
||||
}
|
||||
// Reset not possible, write into cache
|
||||
final NBTOutputStream cacheWriter = new NBTOutputStream(this.getPaletteCacheWriter());
|
||||
cacheWriter.write(paletteType);
|
||||
cacheWriter.writeTagPayload(this.nbtInputStream.readTagPayload(NBTConstants.TYPE_COMPOUND, 0));
|
||||
continue;
|
||||
}
|
||||
hasPalette = true;
|
||||
continue;
|
||||
}
|
||||
if (tag.equals("Data")) {
|
||||
// No palette or dimensions are yet available
|
||||
if (!hasPalette || this.dataFixer == null || !hasClipboard) {
|
||||
if (this.supportsReset()) {
|
||||
this.remainingTags.add(paletteType);
|
||||
this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_BYTE_ARRAY, 0);
|
||||
continue;
|
||||
}
|
||||
// Reset not possible, write into cache
|
||||
int byteLen = this.dataInputStream.readInt();
|
||||
final DataOutputStream cacheWriter = new DataOutputStream(this.getDataCacheWriter());
|
||||
cacheWriter.write(paletteType);
|
||||
cacheWriter.writeInt(byteLen);
|
||||
IOUtil.copy(this.dataInputStream, cacheWriter, byteLen);
|
||||
continue;
|
||||
}
|
||||
this.readPaletteData(this.dataInputStream, paletteDataApplier);
|
||||
continue;
|
||||
}
|
||||
additionalTag.accept(type, tag);
|
||||
}
|
||||
}
|
||||
|
||||
private void readPaletteData(DataInputStream stream, PaletteDataApplier applier) throws IOException {
|
||||
int length = stream.readInt();
|
||||
// Write data into clipboard
|
||||
int i = 0;
|
||||
if (needsVarIntReading(length)) {
|
||||
for (var iter = new VarIntStreamIterator(stream, length); iter.hasNext(); i++) {
|
||||
applier.apply(i, (char) iter.nextInt());
|
||||
}
|
||||
return;
|
||||
}
|
||||
while (i < length) {
|
||||
applier.apply(i++, (char) stream.readUnsignedByte());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the CompoundTag containing the palette mapping ({@code index: value}) and passes each entry to the
|
||||
* {@link PaletteInitializer}.
|
||||
* <p>
|
||||
* This method expects that the identifier ({@link NBTConstants#TYPE_COMPOUND}) is already consumed from the stream.
|
||||
*
|
||||
* @param stream The stream to read the data from.
|
||||
* @param initializer The initializer called for each entry with its index and backed value.
|
||||
* @return {@code true} if the mapping could be read, {@code false} otherwise (e.g. DataFixer is not yet available).
|
||||
* @throws IOException on I/O error.
|
||||
*/
|
||||
private boolean readPaletteMap(DataInputStream stream, PaletteInitializer initializer) throws IOException {
|
||||
if (this.dataFixer == null) {
|
||||
return false;
|
||||
}
|
||||
while (stream.readByte() != NBTConstants.TYPE_END) {
|
||||
String value = stream.readUTF();
|
||||
char index = (char) stream.readInt();
|
||||
initializer.initialize(index, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void indexToPosition(int index, PositionConsumer supplier) {
|
||||
int y = index / (dimensions.x() * dimensions.z());
|
||||
int remainder = index - (y * dimensions.x() * dimensions.z());
|
||||
int z = remainder / dimensions.x();
|
||||
int x = remainder - z * dimensions.x();
|
||||
supplier.accept(x, y, z);
|
||||
}
|
||||
|
||||
private PaletteDataApplier getBlockWriter(Clipboard target) {
|
||||
if (target instanceof LinearClipboard linearClipboard) {
|
||||
return (index, ordinal) -> linearClipboard.setBlock(index, this.blockPalette[ordinal]);
|
||||
}
|
||||
return (index, ordinal) -> indexToPosition(index, (x, y, z) -> target.setBlock(x, y, z, this.blockPalette[ordinal]));
|
||||
}
|
||||
|
||||
private PaletteDataApplier getBiomeWriter(Clipboard target) {
|
||||
return (index, ordinal) -> indexToPosition(index, (x, y, z) -> target.setBiome(x, y, z, this.biomePalette[ordinal]));
|
||||
}
|
||||
|
||||
private PaletteInitializer provideBlockPaletteInitializer() {
|
||||
return (index, value) -> {
|
||||
if (this.dataFixer == null) {
|
||||
throw new IllegalStateException("Can't read block palette map if DataFixer is not yet available");
|
||||
}
|
||||
value = dataFixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, value);
|
||||
try {
|
||||
this.blockPalette[index] = BlockState.get(value);
|
||||
} catch (InputParseException e) {
|
||||
LOGGER.warn("Invalid BlockState in palette: {}. Block will be replaced with air.", value);
|
||||
this.blockPalette[index] = BlockTypes.AIR.getDefaultState();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private PaletteInitializer provideBiomePaletteInitializer() {
|
||||
return (index, value) -> {
|
||||
if (this.dataFixer == null) {
|
||||
throw new IllegalStateException("Can't read biome palette map if DataFixer is not yet available");
|
||||
}
|
||||
value = dataFixer.fixUp(DataFixer.FixTypes.BIOME, value);
|
||||
BiomeType biomeType = BiomeTypes.get(value);
|
||||
if (biomeType == null) {
|
||||
biomeType = BiomeTypes.PLAINS;
|
||||
LOGGER.warn("Invalid biome type in palette: {}. Biome will be replaced with plains.", value);
|
||||
}
|
||||
this.biomePalette[index] = biomeType;
|
||||
};
|
||||
}
|
||||
|
||||
private EntityTransformer provideEntityTransformer(Clipboard clipboard) {
|
||||
return (x, y, z, id, tag) -> {
|
||||
EntityType type = EntityType.REGISTRY.get(id);
|
||||
if (type == null) {
|
||||
LOGGER.warn("Invalid entity id: {} - skipping", id);
|
||||
return;
|
||||
}
|
||||
clipboard.createEntity(
|
||||
new Location(clipboard, Location.at(x, y, z).add(clipboard.getMinimumPoint().toVector3())),
|
||||
new BaseEntity(type, LazyReference.computed(tag))
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
private EntityTransformer provideTileEntityTransformer(Clipboard clipboard) {
|
||||
//noinspection deprecation
|
||||
return (x, y, z, id, tag) -> clipboard.setTile(
|
||||
MathMan.roundInt(x + clipboard.getMinimumPoint().x()),
|
||||
MathMan.roundInt(y + clipboard.getMinimumPoint().y()),
|
||||
MathMan.roundInt(z + clipboard.getMinimumPoint().z()),
|
||||
new CompoundTag(tag)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if {@code Width}, {@code Length} and {@code Height} are already read from the stream
|
||||
*/
|
||||
private boolean areDimensionsAvailable() {
|
||||
return this.dimensions.x() != 0 && this.dimensions.y() != 0 && this.dimensions.z() != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this reader instance and all underlying resources.
|
||||
*
|
||||
* @throws IOException on I/O error.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
parentStream.close(); // closes all underlying resources implicitly
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the main stream to the previously marked position ({@code 0}), if supported (see {@link #supportsReset()}).
|
||||
* If the stream is reset, the sub streams (for DataInput and NBT) are re-created to respect the new position.
|
||||
*
|
||||
* @throws IOException on I/O error.
|
||||
*/
|
||||
private void reset() throws IOException {
|
||||
if (this.supportsReset()) {
|
||||
this.parentStream.reset();
|
||||
this.parentStream.mark(Integer.MAX_VALUE);
|
||||
this.setSubStreams();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if the stream used while instantiating the reader supports resets (without memory overhead).
|
||||
*/
|
||||
private boolean supportsReset() {
|
||||
return this.remainingTags != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites the DataInput- and NBT-InputStreams (e.g. when the marker of the backed stream updated).
|
||||
*
|
||||
* @throws IOException on I/O error.
|
||||
*/
|
||||
private void setSubStreams() throws IOException {
|
||||
final FastBufferedInputStream buffer = new FastBufferedInputStream(new GZIPInputStream(this.parentStream));
|
||||
this.dataInputStream = new DataInputStream(buffer);
|
||||
this.nbtInputStream = new NBTInputStream(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new cache writer for non-palette data, if none exists yet.
|
||||
* Returns either the already created or new one.
|
||||
*
|
||||
* @return the output stream for non-palette cache data.
|
||||
*/
|
||||
private OutputStream getDataCacheWriter() {
|
||||
if (this.dataCacheWriter == null) {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(512);
|
||||
this.dataCacheWriter = new FastBufferedOutputStream(new LZ4BlockOutputStream(byteArrayOutputStream)) {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
this.write(CACHE_IDENTIFIER_END);
|
||||
super.close();
|
||||
FastSchematicReaderV3.this.dataCache = byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
};
|
||||
}
|
||||
return this.dataCacheWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new cache writer for palette data, if none exists yet.
|
||||
* Returns either the already created or new one.
|
||||
*
|
||||
* @return the output stream for palette cache data.
|
||||
*/
|
||||
private OutputStream getPaletteCacheWriter() {
|
||||
if (this.paletteCacheWriter == null) {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(256);
|
||||
this.paletteCacheWriter = new FastBufferedOutputStream(new LZ4BlockOutputStream(byteArrayOutputStream)) {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
this.write(CACHE_IDENTIFIER_END);
|
||||
super.close();
|
||||
FastSchematicReaderV3.this.paletteCache = byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
};
|
||||
}
|
||||
return this.paletteCacheWriter;
|
||||
}
|
||||
|
||||
private boolean needsVarIntReading(int byteArrayLength) {
|
||||
return byteArrayLength > this.dimensions.x() * this.dimensions.y() * this.dimensions.z();
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips the schematic header including the root compound (empty name) and the root's child compound ("Schematic")
|
||||
*
|
||||
* @param dataInputStream The stream containing the schematic data to skip
|
||||
* @throws IOException on I/O error
|
||||
*/
|
||||
private static void skipHeader(DataInputStream dataInputStream) throws IOException {
|
||||
dataInputStream.skipNBytes(1 + 2); // 1 Byte = TAG_Compound, 2 Bytes = Short (Length of tag name = "")
|
||||
dataInputStream.skipNBytes(1 + 2 + 9); // as above + 9 bytes = "Schematic"
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@FunctionalInterface
|
||||
private interface PositionConsumer {
|
||||
|
||||
/**
|
||||
* Called with block location coordinates.
|
||||
*
|
||||
* @param x the x coordinate.
|
||||
* @param y the y coordinate.
|
||||
* @param z the z coordinate.
|
||||
*/
|
||||
void accept(int x, int y, int z);
|
||||
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@FunctionalInterface
|
||||
private interface EntityTransformer {
|
||||
|
||||
/**
|
||||
* Called for each entity from the Schematics {@code Entities} compound list.
|
||||
*
|
||||
* @param x the relative x coordinate of the entity.
|
||||
* @param y the relative y coordinate of the entity.
|
||||
* @param z the relative z coordinate of the entity.
|
||||
* @param id the entity id as a resource location (e.g. {@code minecraft:sheep}).
|
||||
* @param tag the - already fixed, if required - nbt data of the entity.
|
||||
*/
|
||||
void transform(double x, double y, double z, String id, LinCompoundTag tag);
|
||||
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@FunctionalInterface
|
||||
private interface PaletteInitializer {
|
||||
|
||||
/**
|
||||
* Called for each palette entry (the mapping part, not data).
|
||||
*
|
||||
* @param index the index of the entry, as used in the Data byte array.
|
||||
* @param value the value for this entry (either biome type as resource location or the block state as a string).
|
||||
*/
|
||||
void initialize(char index, String value);
|
||||
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@FunctionalInterface
|
||||
private interface PaletteDataApplier {
|
||||
|
||||
/**
|
||||
* Called for each palette data entry (not the mapping part, but the var-int byte array).
|
||||
*
|
||||
* @param index The index of this data entry (due to var-int behaviour not necessarily the index in the data byte array).
|
||||
* @param ordinal The ordinal of this entry as defined in the palette mapping.
|
||||
*/
|
||||
void apply(int index, char ordinal);
|
||||
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@FunctionalInterface
|
||||
private interface AdditionalTagConsumer {
|
||||
|
||||
/**
|
||||
* Called for each unknown nbt tag.
|
||||
*
|
||||
* @param type The type of the tag (as defined by the constants in {@link NBTConstants}).
|
||||
* @param name The name of the tag.
|
||||
*/
|
||||
void accept(byte type, String name);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -48,9 +48,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
/**
|
||||
* Writes schematic files using the Sponge schematic format.
|
||||
*/
|
||||
public class FastSchematicWriter implements ClipboardWriter {
|
||||
public class FastSchematicWriterV2 implements ClipboardWriter {
|
||||
|
||||
private static final int CURRENT_VERSION = 2;
|
||||
public static final int CURRENT_VERSION = 2;
|
||||
|
||||
private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE;
|
||||
private final NBTOutputStream outputStream;
|
||||
@ -61,7 +61,7 @@ public class FastSchematicWriter implements ClipboardWriter {
|
||||
*
|
||||
* @param outputStream the output stream to write to
|
||||
*/
|
||||
public FastSchematicWriter(NBTOutputStream outputStream) {
|
||||
public FastSchematicWriterV2(NBTOutputStream outputStream) {
|
||||
checkNotNull(outputStream);
|
||||
this.outputStream = outputStream;
|
||||
}
|
||||
@ -103,11 +103,11 @@ public class FastSchematicWriter implements ClipboardWriter {
|
||||
|
||||
final DataOutput rawStream = outputStream.getOutputStream();
|
||||
outputStream.writeLazyCompoundTag("Schematic", out -> {
|
||||
out.writeNamedTag("Version", CURRENT_VERSION);
|
||||
out.writeNamedTag(
|
||||
"DataVersion",
|
||||
WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion()
|
||||
);
|
||||
out.writeNamedTag("Version", CURRENT_VERSION);
|
||||
out.writeNamedTag("Width", (short) width);
|
||||
out.writeNamedTag("Height", (short) height);
|
||||
out.writeNamedTag("Length", (short) length);
|
||||
@ -149,7 +149,7 @@ public class FastSchematicWriter implements ClipboardWriter {
|
||||
BaseBlock block = pos.getFullBlock(finalClipboard);
|
||||
CompoundTag nbt = block.getNbtData();
|
||||
if (nbt != null) {
|
||||
Map<String, Tag> values = new HashMap<>(nbt.getValue());
|
||||
Map<String, Tag<?, ?>> values = new HashMap<>(nbt.getValue());
|
||||
|
||||
// Positions are kept in NBT, we don't want that.
|
||||
values.remove("x");
|
||||
@ -223,7 +223,7 @@ public class FastSchematicWriter implements ClipboardWriter {
|
||||
BaseEntity state = entity.getState();
|
||||
|
||||
if (state != null) {
|
||||
Map<String, Tag> values = new HashMap<>();
|
||||
Map<String, Tag<?, ?>> values = new HashMap<>();
|
||||
|
||||
// Put NBT provided data
|
||||
CompoundTag rawTag = state.getNbtData();
|
@ -0,0 +1,295 @@
|
||||
package com.fastasyncworldedit.core.extent.clipboard.io;
|
||||
|
||||
import com.fastasyncworldedit.core.function.visitor.Order;
|
||||
import com.fastasyncworldedit.core.util.IOUtil;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.NBTConstants;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||
import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Faster, stream-based implementation of {@link com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Writer} for
|
||||
* writing schematics conforming the sponge schematic v3 format.
|
||||
*
|
||||
* @since 2.11.1
|
||||
*/
|
||||
@SuppressWarnings("removal") // Yes, JNBT is deprecated - we know
|
||||
public class FastSchematicWriterV3 implements ClipboardWriter {
|
||||
|
||||
public static final int CURRENT_VERSION = 3;
|
||||
|
||||
private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE;
|
||||
private final NBTOutputStream outputStream;
|
||||
|
||||
|
||||
public FastSchematicWriterV3(final NBTOutputStream outputStream) {
|
||||
this.outputStream = Objects.requireNonNull(outputStream, "outputStream");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final Clipboard clipboard) throws IOException {
|
||||
clipboard.flush();
|
||||
|
||||
// Validate dimensions before starting to write into stream
|
||||
final Region region = clipboard.getRegion();
|
||||
if (region.getWidth() > MAX_SIZE) {
|
||||
throw new IllegalArgumentException("Region width too large for schematic: " + region.getWidth());
|
||||
}
|
||||
if (region.getHeight() > MAX_SIZE) {
|
||||
throw new IllegalArgumentException("Region height too large for schematic: " + region.getHeight());
|
||||
}
|
||||
if (region.getLength() > MAX_SIZE) {
|
||||
throw new IllegalArgumentException("Region length too large for schematic: " + region.getLength());
|
||||
}
|
||||
|
||||
this.outputStream.writeLazyCompoundTag(
|
||||
"", root -> root.writeLazyCompoundTag("Schematic", out -> this.write2(out, clipboard))
|
||||
);
|
||||
}
|
||||
|
||||
private void write2(NBTOutputStream schematic, Clipboard clipboard) throws IOException {
|
||||
final Region region = clipboard.getRegion();
|
||||
final BlockVector3 origin = clipboard.getOrigin();
|
||||
final BlockVector3 min = clipboard.getMinimumPoint();
|
||||
final BlockVector3 offset = min.subtract(origin);
|
||||
|
||||
schematic.writeNamedTag("Version", CURRENT_VERSION);
|
||||
schematic.writeNamedTag(
|
||||
"DataVersion",
|
||||
WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion()
|
||||
);
|
||||
schematic.writeLazyCompoundTag("Metadata", out -> this.writeMetadata(out, clipboard));
|
||||
|
||||
schematic.writeNamedTag("Width", (short) region.getWidth());
|
||||
schematic.writeNamedTag("Height", (short) region.getHeight());
|
||||
schematic.writeNamedTag("Length", (short) region.getLength());
|
||||
|
||||
schematic.writeNamedTag("Offset", new int[]{
|
||||
offset.x(), offset.y(), offset.z()
|
||||
});
|
||||
|
||||
schematic.writeLazyCompoundTag("Blocks", out -> this.writeBlocks(out, clipboard));
|
||||
if (clipboard.hasBiomes()) {
|
||||
schematic.writeLazyCompoundTag("Biomes", out -> this.writeBiomes(out, clipboard));
|
||||
}
|
||||
// Some clipboards have quite heavy operations on the getEntities method - only call once
|
||||
List<? extends Entity> entities;
|
||||
if (!(entities = clipboard.getEntities()).isEmpty()) {
|
||||
schematic.writeNamedTagName("Entities", NBTConstants.TYPE_LIST);
|
||||
schematic.write(NBTConstants.TYPE_COMPOUND);
|
||||
schematic.writeInt(entities.size());
|
||||
for (final Entity entity : entities) {
|
||||
this.writeEntity(schematic, clipboard, entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeBlocks(NBTOutputStream blocks, Clipboard clipboard) throws IOException {
|
||||
final int[] tiles = new int[]{0};
|
||||
final ByteArrayOutputStream tileBytes = new ByteArrayOutputStream();
|
||||
try (LZ4BlockOutputStream lz4Stream = new LZ4BlockOutputStream(tileBytes);
|
||||
NBTOutputStream tileOut = new NBTOutputStream(lz4Stream)) {
|
||||
this.writePalette(
|
||||
blocks,
|
||||
BlockTypesCache.states.length,
|
||||
pos -> {
|
||||
BaseBlock block = pos.getFullBlock(clipboard);
|
||||
LinCompoundTag tag;
|
||||
if ((tag = block.getNbt()) != null) {
|
||||
tiles[0]++;
|
||||
try {
|
||||
tileOut.writeNamedTag("Id", block.getNbtId());
|
||||
tileOut.writeNamedTag("Pos", new int[]{
|
||||
pos.x() - clipboard.getMinimumPoint().x(),
|
||||
pos.y() - clipboard.getMinimumPoint().y(),
|
||||
pos.z() - clipboard.getMinimumPoint().z()
|
||||
});
|
||||
//noinspection deprecation
|
||||
tileOut.writeNamedTag("Data", new CompoundTag(tag));
|
||||
tileOut.write(NBTConstants.TYPE_END);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to write tile data", e);
|
||||
}
|
||||
}
|
||||
return block;
|
||||
},
|
||||
block -> {
|
||||
char ordinal = block.getOrdinalChar();
|
||||
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||
ordinal = BlockTypesCache.ReservedIDs.AIR;
|
||||
}
|
||||
return ordinal;
|
||||
},
|
||||
BlockStateHolder::getAsString,
|
||||
clipboard
|
||||
);
|
||||
lz4Stream.finish();
|
||||
} finally {
|
||||
// Write Tiles
|
||||
if (tiles[0] > 0) {
|
||||
blocks.writeNamedTagName("BlockEntities", NBTConstants.TYPE_LIST);
|
||||
blocks.write(NBTConstants.TYPE_COMPOUND);
|
||||
blocks.writeInt(tiles[0]);
|
||||
// Decompress cached data again
|
||||
try (LZ4BlockInputStream reader = new LZ4BlockInputStream(new ByteArrayInputStream(tileBytes.toByteArray()))) {
|
||||
IOUtil.copy(reader, blocks.getOutputStream());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeBiomes(NBTOutputStream biomes, Clipboard clipboard) throws IOException {
|
||||
this.writePalette(
|
||||
biomes, BiomeType.REGISTRY.size(),
|
||||
pos -> pos.getBiome(clipboard),
|
||||
biome -> (char) biome.getInternalId(),
|
||||
BiomeType::id,
|
||||
clipboard
|
||||
);
|
||||
}
|
||||
|
||||
private void writeEntity(NBTOutputStream out, Clipboard clipboard, Entity entity) throws IOException {
|
||||
final BaseEntity state = entity.getState();
|
||||
if (state == null) {
|
||||
throw new IOException("Entity has no state");
|
||||
}
|
||||
out.writeNamedTag("Id", state.getType().id());
|
||||
|
||||
out.writeNamedTagName("Pos", NBTConstants.TYPE_LIST);
|
||||
out.write(NBTConstants.TYPE_DOUBLE);
|
||||
out.writeInt(3);
|
||||
out.writeDouble(entity.getLocation().x() - clipboard.getMinimumPoint().x());
|
||||
out.writeDouble(entity.getLocation().y() - clipboard.getMinimumPoint().y());
|
||||
out.writeDouble(entity.getLocation().z() - clipboard.getMinimumPoint().z());
|
||||
|
||||
out.writeLazyCompoundTag("Data", data -> {
|
||||
//noinspection deprecation
|
||||
CompoundTag nbt = state.getNbtData();
|
||||
if (nbt != null) {
|
||||
nbt.getValue().forEach((s, tag) -> {
|
||||
if (s.equals("id") || s.equals("Rotation")) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
data.writeNamedTag(s, tag);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("failed to write entity data", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Write rotation list
|
||||
data.writeNamedTagName("Rotation", NBTConstants.TYPE_LIST);
|
||||
data.write(NBTConstants.TYPE_FLOAT);
|
||||
data.writeInt(2);
|
||||
data.writeFloat(entity.getLocation().getYaw());
|
||||
data.writeFloat(entity.getLocation().getPitch());
|
||||
});
|
||||
|
||||
out.write(NBTConstants.TYPE_END); // End the compound
|
||||
}
|
||||
|
||||
private <T> void writePalette(
|
||||
NBTOutputStream out, int capacity,
|
||||
Function<BlockVector3, T> objectResolver,
|
||||
Function<T, Character> ordinalResolver,
|
||||
Function<T, String> paletteEntryResolver,
|
||||
Clipboard clipboard
|
||||
) throws IOException {
|
||||
int dataBytesUsed = 0;
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
try (LZ4BlockOutputStream dataOut = new LZ4BlockOutputStream(bytes)) {
|
||||
int index = 0;
|
||||
char[] palette = new char[capacity];
|
||||
Arrays.fill(palette, Character.MAX_VALUE);
|
||||
final Iterator<BlockVector3> iterator = clipboard.iterator(Order.YZX);
|
||||
// Start Palette tag
|
||||
out.writeNamedTagName("Palette", NBTConstants.TYPE_COMPOUND);
|
||||
while (iterator.hasNext()) {
|
||||
BlockVector3 pos = iterator.next();
|
||||
T obj = objectResolver.apply(pos);
|
||||
char ordinal = ordinalResolver.apply(obj);
|
||||
char value = palette[ordinal];
|
||||
if (value == Character.MAX_VALUE) {
|
||||
palette[ordinal] = value = (char) index++;
|
||||
if (index >= palette.length) {
|
||||
throw new IOException("insufficient palette capacity: " + palette.length + ", index: " + index);
|
||||
}
|
||||
out.writeNamedTag(paletteEntryResolver.apply(obj), value);
|
||||
}
|
||||
if ((value & -128) != 0) {
|
||||
dataBytesUsed++;
|
||||
dataOut.write(value & 127 | 128);
|
||||
value >>>= 7;
|
||||
}
|
||||
dataOut.write(value);
|
||||
dataBytesUsed++;
|
||||
}
|
||||
// End Palette tag
|
||||
out.write(NBTConstants.TYPE_END);
|
||||
dataOut.finish();
|
||||
} finally {
|
||||
// Write Data tag
|
||||
if (dataBytesUsed > 0) {
|
||||
try (LZ4BlockInputStream reader = new LZ4BlockInputStream(new ByteArrayInputStream(bytes.toByteArray()))) {
|
||||
out.writeNamedTagName("Data", NBTConstants.TYPE_BYTE_ARRAY);
|
||||
out.writeInt(dataBytesUsed);
|
||||
IOUtil.copy(reader, (DataOutput) out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeMetadata(NBTOutputStream metadata, Clipboard clipboard) throws IOException {
|
||||
metadata.writeNamedTag("Date", System.currentTimeMillis());
|
||||
metadata.writeLazyCompoundTag("WorldEdit", out -> {
|
||||
out.writeNamedTag("Version", WorldEdit.getVersion());
|
||||
out.writeNamedTag(
|
||||
"EditingPlatform",
|
||||
WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getId()
|
||||
);
|
||||
out.writeNamedTag("Origin", new int[]{
|
||||
clipboard.getOrigin().x(), clipboard.getOrigin().y(), clipboard.getOrigin().z()
|
||||
});
|
||||
out.writeLazyCompoundTag("Platforms", platforms -> {
|
||||
for (final Platform platform : WorldEdit.getInstance().getPlatformManager().getPlatforms()) {
|
||||
platforms.writeLazyCompoundTag(platform.getId(), p -> {
|
||||
p.writeNamedTag("Name", platform.getPlatformName());
|
||||
p.writeNamedTag("Version", platform.getPlatformVersion());
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
this.outputStream.close();
|
||||
}
|
||||
|
||||
}
|
@ -70,7 +70,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
throw new IOException("Root tag has name - are you sure this is a structure?");
|
||||
}
|
||||
|
||||
Map<String, Tag> tags = ((CompoundTag) rootTag.getTag()).getValue();
|
||||
Map<String, Tag<?, ?>> tags = ((CompoundTag) rootTag.getTag()).getValue();
|
||||
|
||||
ListTag size = (ListTag) tags.get("size");
|
||||
int width = size.getInt(0);
|
||||
@ -89,13 +89,13 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
BlockState[] combinedArray = new BlockState[palette.size()];
|
||||
for (int i = 0; i < palette.size(); i++) {
|
||||
CompoundTag compound = palette.get(i);
|
||||
Map<String, Tag> map = compound.getValue();
|
||||
Map<String, Tag<?, ?>> map = compound.getValue();
|
||||
String name = ((StringTag) map.get("Name")).getValue();
|
||||
BlockType type = BlockTypes.get(name);
|
||||
BlockState state = type.getDefaultState();
|
||||
CompoundTag properties = (CompoundTag) map.get("Properties");
|
||||
if (properties != null) {
|
||||
for (Map.Entry<String, Tag> entry : properties.getValue().entrySet()) {
|
||||
for (Map.Entry<String, Tag<?, ?>> entry : properties.getValue().entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = ((StringTag) entry.getValue()).getValue();
|
||||
Property<Object> property = type.getProperty(key);
|
||||
@ -108,7 +108,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
List<CompoundTag> blocksList = (List<CompoundTag>) tags.get("blocks").getValue();
|
||||
try {
|
||||
for (CompoundTag compound : blocksList) {
|
||||
Map<String, Tag> blockMap = compound.getValue();
|
||||
Map<String, Tag<?, ?>> blockMap = compound.getValue();
|
||||
IntTag stateTag = (IntTag) blockMap.get("state");
|
||||
ListTag posTag = (ListTag) blockMap.get("pos");
|
||||
BlockState state = combinedArray[stateTag.getValue()];
|
||||
@ -136,7 +136,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
if (entities != null) {
|
||||
List<CompoundTag> entityList = (List<CompoundTag>) (List<?>) entities.getValue();
|
||||
for (CompoundTag entityEntry : entityList) {
|
||||
Map<String, Tag> entityEntryMap = entityEntry.getValue();
|
||||
Map<String, Tag<?, ?>> entityEntryMap = entityEntry.getValue();
|
||||
ListTag posTag = (ListTag) entityEntryMap.get("pos");
|
||||
CompoundTag nbtTag = (CompoundTag) entityEntryMap.get("nbt");
|
||||
String id = nbtTag.getString("Id");
|
||||
@ -216,7 +216,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
if (!block.hasNbtData()) {
|
||||
blocks.add(FaweCache.INSTANCE.asMap("state", index, "pos", pos));
|
||||
} else {
|
||||
Map<String, Tag> tag = new HashMap<>(block.getNbtData().getValue());
|
||||
Map<String, Tag<?, ?>> tag = new HashMap<>(block.getNbtData().getValue());
|
||||
tag.remove("x");
|
||||
tag.remove("y");
|
||||
tag.remove("z");
|
||||
@ -246,7 +246,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
BaseEntity state = entity.getState();
|
||||
if (state != null) {
|
||||
CompoundTag nbt = state.getNbtData();
|
||||
Map<String, Tag> nbtMap = new HashMap<>(nbt.getValue());
|
||||
Map<String, Tag<?, ?>> nbtMap = new HashMap<>(nbt.getValue());
|
||||
// Replace rotation data
|
||||
nbtMap.put("Rotation", writeRotation(entity.getLocation()));
|
||||
nbtMap.put("id", new StringTag(state.getType().id()));
|
||||
|
@ -17,19 +17,19 @@ public enum HeightMapType {
|
||||
MOTION_BLOCKING {
|
||||
@Override
|
||||
public boolean includes(BlockState state) {
|
||||
return state.getMaterial().isSolid() || HeightMapType.hasFluid(state);
|
||||
return state.getMaterial().isMovementBlocker() || HeightMapType.hasFluid(state);
|
||||
}
|
||||
},
|
||||
MOTION_BLOCKING_NO_LEAVES {
|
||||
@Override
|
||||
public boolean includes(BlockState state) {
|
||||
return (state.getMaterial().isSolid() || HeightMapType.hasFluid(state)) && !HeightMapType.isLeaf(state);
|
||||
return (state.getMaterial().isMovementBlocker() || HeightMapType.hasFluid(state)) && !HeightMapType.isLeaf(state);
|
||||
}
|
||||
},
|
||||
OCEAN_FLOOR {
|
||||
@Override
|
||||
public boolean includes(BlockState state) {
|
||||
return state.getMaterial().isSolid();
|
||||
return state.getMaterial().isMovementBlocker();
|
||||
}
|
||||
},
|
||||
WORLD_SURFACE {
|
||||
|
@ -7,6 +7,7 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
|
||||
import java.util.List;
|
||||
@ -19,29 +20,60 @@ public class SchemGen implements Resource {
|
||||
private final List<ClipboardHolder> clipboards;
|
||||
private final boolean randomRotate;
|
||||
private final Mask mask;
|
||||
private final Region region;
|
||||
|
||||
private final MutableBlockVector3 mutable = new MutableBlockVector3();
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link SchemGen#SchemGen(Mask, Extent, List, boolean, Region)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2.11.1")
|
||||
public SchemGen(Mask mask, Extent extent, List<ClipboardHolder> clipboards, boolean randomRotate) {
|
||||
this.mask = mask;
|
||||
this.extent = extent;
|
||||
this.clipboards = clipboards;
|
||||
this.randomRotate = randomRotate;
|
||||
this.region = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* New instance. Places a schematic on terrain at a given x,z when appropriate
|
||||
*
|
||||
* @since 2.11.1
|
||||
*/
|
||||
public SchemGen(Mask mask, Extent extent, List<ClipboardHolder> clipboards, boolean randomRotate, Region region) {
|
||||
this.mask = mask;
|
||||
this.extent = extent;
|
||||
this.clipboards = clipboards;
|
||||
this.randomRotate = randomRotate;
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
private int getY(int x, int z) {
|
||||
if (region == null) {
|
||||
return extent.getNearestSurfaceTerrainBlock(
|
||||
x,
|
||||
z,
|
||||
mutable.y(),
|
||||
this.extent.getMinY(),
|
||||
this.extent.getMaxY(),
|
||||
Integer.MIN_VALUE,
|
||||
Integer.MAX_VALUE
|
||||
);
|
||||
} else {
|
||||
int y = extent.getHighestTerrainBlock(x, z, region.getMinimumY(), region.getMaximumY(), mask);
|
||||
if (y == region.getMinimumY() && !extent.getBlock(x, y, z).getMaterial().isMovementBlocker()) {
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean spawn(Random random, int x, int z) throws WorldEditException {
|
||||
mutable.mutX(x);
|
||||
mutable.mutZ(z);
|
||||
int y = extent.getNearestSurfaceTerrainBlock(
|
||||
x,
|
||||
z,
|
||||
mutable.y(),
|
||||
this.extent.getMinY(),
|
||||
this.extent.getMaxY(),
|
||||
Integer.MIN_VALUE,
|
||||
Integer.MAX_VALUE
|
||||
);
|
||||
int y = getY(x, z);
|
||||
if (y == Integer.MIN_VALUE || y == Integer.MAX_VALUE) {
|
||||
return false;
|
||||
}
|
||||
@ -54,7 +86,8 @@ public class SchemGen implements Resource {
|
||||
if (randomRotate) {
|
||||
holder.setTransform(new AffineTransform().rotateY(ThreadLocalRandom.current().nextInt(4) * 90));
|
||||
}
|
||||
Clipboard clipboard = holder.getClipboard();
|
||||
Clipboard clipboard = holder.getClipboards().size() == 1 ? holder.getClipboard() :
|
||||
holder.getClipboards().get(ThreadLocalRandom.current().nextInt(clipboards.size()));
|
||||
Transform transform = holder.getTransform();
|
||||
if (transform.isIdentity()) {
|
||||
clipboard.paste(extent, mutable, false);
|
||||
|
@ -9,6 +9,7 @@ import com.fastasyncworldedit.core.util.MutableCharSequence;
|
||||
import com.fastasyncworldedit.core.util.StringMan;
|
||||
import com.fastasyncworldedit.core.world.block.BlanketBaseBlock;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.mask.BlockMask;
|
||||
import com.sk89q.worldedit.registry.state.AbstractProperty;
|
||||
@ -53,6 +54,7 @@ public class BlockMaskBuilder {
|
||||
|
||||
private static final long[] ALL = new long[0];
|
||||
private final long[][] bitSets;
|
||||
private final ParserContext context;
|
||||
private boolean[] ordinals;
|
||||
private boolean optimizedStates = true;
|
||||
|
||||
@ -60,8 +62,28 @@ public class BlockMaskBuilder {
|
||||
this(new long[BlockTypes.size()][]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance with a given {@link ParserContext} to use if parsing regex
|
||||
*
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public BlockMaskBuilder(ParserContext context) {
|
||||
this(new long[BlockTypes.size()][], context);
|
||||
}
|
||||
|
||||
protected BlockMaskBuilder(long[][] bitSets) {
|
||||
this.bitSets = bitSets;
|
||||
this.context = new ParserContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance with a given {@link ParserContext} to use if parsing regex
|
||||
*
|
||||
* @since 2.11.0
|
||||
*/
|
||||
protected BlockMaskBuilder(long[][] bitSets, ParserContext context) {
|
||||
this.bitSets = bitSets;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
private boolean handleRegex(BlockType blockType, PropertyKey key, String regex, FuzzyStateAllowingBuilder builder) {
|
||||
@ -173,7 +195,7 @@ public class BlockMaskBuilder {
|
||||
List<BlockType> blockTypeList;
|
||||
List<FuzzyStateAllowingBuilder> builders;
|
||||
if (StringMan.isAlphanumericUnd(charSequence)) {
|
||||
BlockType type = BlockTypes.parse(charSequence.toString());
|
||||
BlockType type = BlockTypes.parse(charSequence.toString(), context);
|
||||
blockTypeList = Collections.singletonList(type);
|
||||
builders = Collections.singletonList(new FuzzyStateAllowingBuilder(type));
|
||||
add(type);
|
||||
@ -280,7 +302,7 @@ public class BlockMaskBuilder {
|
||||
}
|
||||
} else {
|
||||
if (StringMan.isAlphanumericUnd(input)) {
|
||||
add(BlockTypes.parse(input));
|
||||
add(BlockTypes.parse(input, context));
|
||||
} else {
|
||||
boolean success = false;
|
||||
for (BlockType myType : BlockTypesCache.values) {
|
||||
|
@ -3,7 +3,6 @@ package com.fastasyncworldedit.core.history.change;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.DoubleTag;
|
||||
import com.sk89q.jnbt.LongTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
@ -52,7 +51,7 @@ public class MutableEntityChange implements Change {
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public void delete(UndoContext context) {
|
||||
Map<String, Tag> map = tag.getValue();
|
||||
Map<String, Tag<?, ?>> map = tag.getValue();
|
||||
UUID uuid = tag.getUUID();
|
||||
if (uuid == null) {
|
||||
LOGGER.info("Skipping entity without uuid.");
|
||||
@ -66,7 +65,7 @@ public class MutableEntityChange implements Change {
|
||||
}
|
||||
|
||||
public void create(UndoContext context) {
|
||||
Map<String, Tag> map = tag.getValue();
|
||||
Map<String, Tag<?, ?>> map = tag.getValue();
|
||||
Tag posTag = map.get("Pos");
|
||||
if (posTag == null) {
|
||||
LOGGER.warn("Missing pos tag: {}", tag);
|
||||
|
@ -306,7 +306,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return queue.isEmpty() && workerSemaphore.availablePermits() == 1 && size() == 0;
|
||||
return queue.isEmpty() && workerSemaphore.availablePermits() == 1 && longSize() == 0;
|
||||
}
|
||||
|
||||
public void add(BlockVector3 loc, BaseBlock from, BaseBlock to) {
|
||||
|
@ -176,6 +176,11 @@ public class AbstractDelegateChangeSet extends AbstractChangeSet {
|
||||
return parent.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long longSize() {
|
||||
return parent.longSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
parent.delete();
|
||||
|
@ -112,7 +112,7 @@ public class BlockBagChangeSet extends AbstractDelegateChangeSet {
|
||||
@Override
|
||||
public void addTileCreate(CompoundTag nbt) {
|
||||
if (nbt.containsKey("items")) {
|
||||
Map<String, Tag> map = new HashMap<>(nbt.getValue());
|
||||
Map<String, Tag<?, ?>> map = new HashMap<>(nbt.getValue());
|
||||
map.remove("items");
|
||||
}
|
||||
super.addTileCreate(nbt);
|
||||
|
@ -25,6 +25,7 @@ import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
@ -35,11 +36,18 @@ import java.util.NoSuchElementException;
|
||||
public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
|
||||
public static final int HEADER_SIZE = 9;
|
||||
private static final int version = 1;
|
||||
private static final int VERSION = 2;
|
||||
// equivalent to Short#MIN_VALUE three times stored with [(x) & 0xff, ((rx) >> 8) & 0xff]
|
||||
private static final byte[] MAGIC_NEW_RELATIVE = new byte[]{0, (byte) 128, 0, (byte) 128, 0, (byte) 128};
|
||||
private int mode;
|
||||
private final int compression;
|
||||
private final int minY;
|
||||
|
||||
protected long blockSize;
|
||||
private int originX;
|
||||
private int originZ;
|
||||
private int version;
|
||||
|
||||
protected FaweStreamIdDelegate idDel;
|
||||
protected FaweStreamPositionDelegate posDel;
|
||||
|
||||
@ -192,6 +200,20 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
int rx = -lx + (lx = x);
|
||||
int ry = -ly + (ly = y);
|
||||
int rz = -lz + (lz = z);
|
||||
// Use LE/GE to ensure we don't accidentally write MAGIC_NEW_RELATIVE
|
||||
if (rx >= Short.MAX_VALUE || rz >= Short.MAX_VALUE || rx <= Short.MIN_VALUE || rz <= Short.MIN_VALUE) {
|
||||
stream.write(MAGIC_NEW_RELATIVE);
|
||||
stream.write((byte) (x >> 24));
|
||||
stream.write((byte) (x >> 16));
|
||||
stream.write((byte) (x >> 8));
|
||||
stream.write((byte) (x));
|
||||
stream.write((byte) (z >> 24));
|
||||
stream.write((byte) (z >> 16));
|
||||
stream.write((byte) (z >> 8));
|
||||
stream.write((byte) (z));
|
||||
rx = 0;
|
||||
rz = 0;
|
||||
}
|
||||
stream.write((rx) & 0xff);
|
||||
stream.write(((rx) >> 8) & 0xff);
|
||||
stream.write((rz) & 0xff);
|
||||
@ -203,6 +225,12 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
@Override
|
||||
public int readX(FaweInputStream is) throws IOException {
|
||||
is.readFully(buffer);
|
||||
// Don't break reading version 1 history (just in case)
|
||||
if (version == 2 && Arrays.equals(buffer, MAGIC_NEW_RELATIVE)) {
|
||||
lx = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + is.read());
|
||||
lz = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + is.read());
|
||||
is.readFully(buffer);
|
||||
}
|
||||
return lx = lx + ((buffer[0] & 0xFF) | (buffer[1] << 8));
|
||||
}
|
||||
|
||||
@ -222,7 +250,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
public void writeHeader(OutputStream os, int x, int y, int z) throws IOException {
|
||||
os.write(mode);
|
||||
// Allows for version detection of history in case of changes to format.
|
||||
os.write(version);
|
||||
os.write(VERSION);
|
||||
setOrigin(x, z);
|
||||
os.write((byte) (x >> 24));
|
||||
os.write((byte) (x >> 16));
|
||||
@ -238,8 +266,8 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
public void readHeader(InputStream is) throws IOException {
|
||||
// skip mode
|
||||
int mode = is.read();
|
||||
int version = is.read();
|
||||
if (version != FaweStreamChangeSet.version) {
|
||||
version = is.read();
|
||||
if (version != 1 && version != VERSION) { // version 1 is fine
|
||||
throw new UnsupportedOperationException(String.format("Version %s history not supported!", version));
|
||||
}
|
||||
// origin
|
||||
@ -266,12 +294,17 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
public long longSize() {
|
||||
// Flush so we can accurately get the size
|
||||
flush();
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return (int) longSize();
|
||||
}
|
||||
|
||||
public abstract int getCompressedSize();
|
||||
|
||||
public abstract long getSizeInMemory();
|
||||
@ -304,11 +337,6 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
|
||||
public abstract NBTInputStream getTileRemoveIS() throws IOException;
|
||||
|
||||
protected int blockSize;
|
||||
|
||||
private int originX;
|
||||
private int originZ;
|
||||
|
||||
public void setOrigin(int x, int z) {
|
||||
originX = x;
|
||||
originZ = z;
|
||||
|
@ -0,0 +1,70 @@
|
||||
package com.fastasyncworldedit.core.internal.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.PrimitiveIterator;
|
||||
|
||||
/**
|
||||
* Basically {@link com.sk89q.worldedit.internal.util.VarIntIterator} but backed by {@link java.io.InputStream}
|
||||
*/
|
||||
public class VarIntStreamIterator implements PrimitiveIterator.OfInt {
|
||||
|
||||
private final InputStream parent;
|
||||
private final int limit;
|
||||
private int index;
|
||||
private boolean hasNextInt;
|
||||
private int nextInt;
|
||||
|
||||
public VarIntStreamIterator(final InputStream parent, int limit) {
|
||||
this.parent = parent;
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (hasNextInt) {
|
||||
return true;
|
||||
}
|
||||
if (index >= limit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
nextInt = readNextInt();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return hasNextInt = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextInt() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
hasNextInt = false;
|
||||
return nextInt;
|
||||
}
|
||||
|
||||
|
||||
private int readNextInt() throws IOException {
|
||||
int value = 0;
|
||||
for (int bitsRead = 0; ; bitsRead += 7) {
|
||||
if (index >= limit) {
|
||||
throw new IllegalStateException("Ran out of bytes while reading VarInt (probably corrupted data)");
|
||||
}
|
||||
byte next = (byte) this.parent.read();
|
||||
index++;
|
||||
value |= (next & 0x7F) << bitsRead;
|
||||
if (bitsRead > 7 * 5) {
|
||||
throw new IllegalStateException("VarInt too big (probably corrupted data)");
|
||||
}
|
||||
if ((next & 0x80) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
@ -19,7 +19,7 @@ public abstract class CompressedCompoundTag<T> extends CompoundTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Tag> getValue() {
|
||||
public Map<String, Tag<?, ?>> getValue() {
|
||||
if (in != null) {
|
||||
decompress();
|
||||
}
|
||||
@ -36,8 +36,8 @@ public abstract class CompressedCompoundTag<T> extends CompoundTag {
|
||||
try (NBTInputStream nbtIn = new NBTInputStream(adapt(in))) {
|
||||
in = null;
|
||||
CompoundTag tag = (CompoundTag) nbtIn.readTag();
|
||||
Map<String, Tag> value = tag.getValue();
|
||||
Map<String, Tag> raw = super.getValue();
|
||||
Map<String, Tag<?, ?>> value = tag.getValue();
|
||||
Map<String, Tag<?, ?>> raw = super.getValue();
|
||||
raw.putAll(value);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.fastasyncworldedit.core.jnbt;
|
||||
|
||||
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriter;
|
||||
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriterV2;
|
||||
import com.fastasyncworldedit.core.internal.io.FastByteArrayOutputStream;
|
||||
import com.fastasyncworldedit.core.internal.io.FastByteArraysInputStream;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
@ -21,7 +21,7 @@ public class CompressedSchematicTag extends CompressedCompoundTag<Clipboard> {
|
||||
FastByteArrayOutputStream blocksOut = new FastByteArrayOutputStream();
|
||||
try (LZ4BlockOutputStream lz4out = new LZ4BlockOutputStream(blocksOut)) {
|
||||
NBTOutputStream nbtOut = new NBTOutputStream(lz4out);
|
||||
new FastSchematicWriter(nbtOut).write(getSource());
|
||||
new FastSchematicWriterV2(nbtOut).write(getSource());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ import com.sk89q.jnbt.Tag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Stack;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -409,7 +408,7 @@ public class JSON2NBT {
|
||||
}
|
||||
|
||||
public Tag parse() throws NBTException {
|
||||
HashMap<String, Tag> map = new HashMap<>();
|
||||
HashMap<String, Tag<?, ?>> map = new HashMap<>();
|
||||
|
||||
for (Any JSON2NBT$any : this.tagList) {
|
||||
map.put(JSON2NBT$any.json, JSON2NBT$any.parse());
|
||||
|
@ -1,11 +1,16 @@
|
||||
package com.fastasyncworldedit.core.jnbt;
|
||||
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import org.enginehub.linbus.tree.LinTag;
|
||||
|
||||
/**
|
||||
* A numerical {@link Tag}
|
||||
*/
|
||||
public abstract class NumberTag extends Tag {
|
||||
public abstract class NumberTag<LT extends LinTag<? extends Number>> extends Tag<Number, LT> {
|
||||
|
||||
protected NumberTag(LT linTag) {
|
||||
super(linTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Number getValue();
|
||||
|
@ -28,6 +28,7 @@ public class FaweLimit {
|
||||
public boolean FAST_PLACEMENT = false;
|
||||
public boolean CONFIRM_LARGE = true;
|
||||
public boolean RESTRICT_HISTORY_TO_REGIONS = true;
|
||||
public boolean ALLOW_LEGACY = true;
|
||||
public Set<String> STRIP_NBT = null;
|
||||
public boolean UNIVERSAL_DISALLOWED_BLOCKS = true;
|
||||
public Set<String> DISALLOWED_BLOCKS = null;
|
||||
@ -127,6 +128,7 @@ public class FaweLimit {
|
||||
MAX.RESTRICT_HISTORY_TO_REGIONS = false;
|
||||
MAX.STRIP_NBT = Collections.emptySet();
|
||||
MAX.UNIVERSAL_DISALLOWED_BLOCKS = false;
|
||||
MAX.ALLOW_LEGACY = true;
|
||||
MAX.DISALLOWED_BLOCKS = Collections.emptySet();
|
||||
MAX.REMAP_PROPERTIES = Collections.emptySet();
|
||||
MAX.MAX_RADIUS = Integer.MAX_VALUE;
|
||||
@ -259,13 +261,13 @@ public class FaweLimit {
|
||||
&& !RESTRICT_HISTORY_TO_REGIONS
|
||||
&& (STRIP_NBT == null || STRIP_NBT.isEmpty())
|
||||
// && !UNIVERSAL_DISALLOWED_BLOCKS --> do not include this, it effectively has no relevance
|
||||
&& ALLOW_LEGACY
|
||||
&& (DISALLOWED_BLOCKS == null || DISALLOWED_BLOCKS.isEmpty())
|
||||
&& (REMAP_PROPERTIES == null || REMAP_PROPERTIES.isEmpty())
|
||||
&& MAX_RADIUS == Integer.MAX_VALUE
|
||||
&& MAX_SUPER_PICKAXE_SIZE == Integer.MAX_VALUE
|
||||
&& MAX_BRUSH_RADIUS == Integer.MAX_VALUE
|
||||
&& MAX_BUTCHER_RADIUS == Integer.MAX_VALUE;
|
||||
|
||||
}
|
||||
|
||||
public void set(FaweLimit limit) {
|
||||
@ -286,6 +288,7 @@ public class FaweLimit {
|
||||
RESTRICT_HISTORY_TO_REGIONS = limit.RESTRICT_HISTORY_TO_REGIONS;
|
||||
STRIP_NBT = limit.STRIP_NBT;
|
||||
UNIVERSAL_DISALLOWED_BLOCKS = limit.UNIVERSAL_DISALLOWED_BLOCKS;
|
||||
ALLOW_LEGACY = limit.ALLOW_LEGACY;
|
||||
DISALLOWED_BLOCKS = limit.DISALLOWED_BLOCKS;
|
||||
REMAP_PROPERTIES = limit.REMAP_PROPERTIES;
|
||||
MAX_RADIUS = limit.MAX_RADIUS;
|
||||
@ -313,6 +316,7 @@ public class FaweLimit {
|
||||
limit.RESTRICT_HISTORY_TO_REGIONS = RESTRICT_HISTORY_TO_REGIONS;
|
||||
limit.STRIP_NBT = STRIP_NBT;
|
||||
limit.UNIVERSAL_DISALLOWED_BLOCKS = UNIVERSAL_DISALLOWED_BLOCKS;
|
||||
limit.ALLOW_LEGACY = ALLOW_LEGACY;
|
||||
limit.DISALLOWED_BLOCKS = DISALLOWED_BLOCKS;
|
||||
limit.REMAP_PROPERTIES = REMAP_PROPERTIES;
|
||||
limit.MAX_RADIUS = MAX_RADIUS;
|
||||
|
@ -192,12 +192,13 @@ public class BlockVectorSet extends AbstractCollection<BlockVector3> implements
|
||||
}
|
||||
|
||||
public boolean remove(int x, int y, int z) {
|
||||
int pair = MathMan.pair((short) (x >> 11), (short) (z >> 11));
|
||||
LocalBlockVectorSet localMap = localSets.get(pair);
|
||||
int indexedY = (y + 128) >> 9;
|
||||
long triple = MathMan.tripleWorldCoord((x >> 11), indexedY, (z >> 11));
|
||||
LocalBlockVectorSet localMap = localSets.get(triple);
|
||||
if (localMap != null) {
|
||||
if (localMap.remove(x & 2047, y, z & 2047)) {
|
||||
if (localMap.remove(x & 2047, ((y + 128) & 511) - 128, z & 2047)) {
|
||||
if (localMap.isEmpty()) {
|
||||
localSets.remove(pair);
|
||||
localSets.remove(triple);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ public interface IChunkExtent<T extends IChunk> extends Extent {
|
||||
@Override
|
||||
default Entity createEntity(Location location, BaseEntity entity, UUID uuid) {
|
||||
final IChunk chunk = getOrCreateChunk(location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
Map<String, Tag> map = new HashMap<>(entity.getNbtData().getValue()); //do not modify original entity data
|
||||
Map<String, Tag<?, ?>> map = new HashMap<>(entity.getNbtData().getValue()); //do not modify original entity data
|
||||
map.put("Id", new StringTag(entity.getType().getName()));
|
||||
|
||||
//Set pos
|
||||
|
@ -31,7 +31,9 @@ public abstract class CharBlocks implements IBlocks {
|
||||
char[] arr = blocks.blocks[layer];
|
||||
if (arr == null) {
|
||||
// Chunk probably trimmed mid-operations, but do nothing about it to avoid other issues
|
||||
return EMPTY.get(blocks, layer, false);
|
||||
synchronized (blocks.sectionLocks[layer]) {
|
||||
return getSkipFull(blocks, layer, aggressive);
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
@ -54,22 +56,7 @@ public abstract class CharBlocks implements IBlocks {
|
||||
if (blocks.sections[layer] == FULL) {
|
||||
return FULL.get(blocks, layer);
|
||||
}
|
||||
char[] arr = blocks.blocks[layer];
|
||||
if (arr == null) {
|
||||
arr = blocks.blocks[layer] = blocks.update(layer, null, aggressive);
|
||||
if (arr == null) {
|
||||
throw new IllegalStateException("Array cannot be null: " + blocks.getClass());
|
||||
}
|
||||
} else {
|
||||
blocks.blocks[layer] = blocks.update(layer, arr, aggressive);
|
||||
if (blocks.blocks[layer] == null) {
|
||||
throw new IllegalStateException("Array cannot be null (update): " + blocks.getClass());
|
||||
}
|
||||
}
|
||||
if (blocks.blocks[layer] != null) {
|
||||
blocks.sections[layer] = FULL;
|
||||
}
|
||||
return arr;
|
||||
return getSkipFull(blocks, layer, aggressive);
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,6 +249,25 @@ public abstract class CharBlocks implements IBlocks {
|
||||
get(blocks, layer)[index] = value;
|
||||
}
|
||||
|
||||
static char[] getSkipFull(CharBlocks blocks, int layer, boolean aggressive) {
|
||||
char[] arr = blocks.blocks[layer];
|
||||
if (arr == null) {
|
||||
arr = blocks.blocks[layer] = blocks.update(layer, null, aggressive);
|
||||
if (arr == null) {
|
||||
throw new IllegalStateException("Array cannot be null: " + blocks.getClass());
|
||||
}
|
||||
} else {
|
||||
blocks.blocks[layer] = blocks.update(layer, arr, aggressive);
|
||||
if (blocks.blocks[layer] == null) {
|
||||
throw new IllegalStateException("Array cannot be null (update): " + blocks.getClass());
|
||||
}
|
||||
}
|
||||
if (blocks.blocks[layer] != null) {
|
||||
blocks.sections[layer] = FULL;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ public class PolyhedralRegion extends AbstractRegion {
|
||||
minimumPoint = region.minimumPoint;
|
||||
maximumPoint = region.maximumPoint;
|
||||
centerAccum = region.centerAccum;
|
||||
lastTriangle = region.lastTriangle;
|
||||
lastTriangle = lastTriangle == null ? null : region.lastTriangle.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,7 +82,7 @@ public final class BrushCache {
|
||||
}
|
||||
|
||||
CompoundTag nbt = item.getNbtData();
|
||||
Map<String, Tag> map;
|
||||
Map<String, Tag<?, ?>> map;
|
||||
if (nbt == null) {
|
||||
if (tool == null) {
|
||||
item.setNbtData(null);
|
||||
@ -92,9 +92,10 @@ public final class BrushCache {
|
||||
} else {
|
||||
map = nbt.getValue();
|
||||
}
|
||||
item.setNbtData(nbt);
|
||||
brushCache.remove(getKey(item));
|
||||
CompoundTag display = (CompoundTag) map.get("display");
|
||||
Map<String, Tag> displayMap;
|
||||
Map<String, Tag<?, ?>> displayMap;
|
||||
return tool;
|
||||
}
|
||||
|
||||
|
@ -217,7 +217,7 @@ public class MainUtil {
|
||||
// } else if (changeSet instanceof CPUOptimizedChangeSet) {
|
||||
// return changeSet.size() + 32;
|
||||
} else if (changeSet != null) {
|
||||
return changeSet.size() * 128L;
|
||||
return changeSet.longSize() * 128; // Approx
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@ -427,7 +427,7 @@ public class MainUtil {
|
||||
*/
|
||||
@Nonnull
|
||||
public static CompoundTag setPosition(@Nonnull CompoundTag tag, int x, int y, int z) {
|
||||
Map<String, Tag> value = new HashMap<>(tag.getValue());
|
||||
Map<String, Tag<?, ?>> value = new HashMap<>(tag.getValue());
|
||||
value.put("x", new IntTag(x));
|
||||
value.put("y", new IntTag(y));
|
||||
value.put("z", new IntTag(z));
|
||||
@ -443,7 +443,7 @@ public class MainUtil {
|
||||
*/
|
||||
@Nonnull
|
||||
public static CompoundTag setEntityInfo(@Nonnull CompoundTag tag, @Nonnull Entity entity) {
|
||||
Map<String, Tag> map = new HashMap<>(tag.getValue());
|
||||
Map<String, Tag<?, ?>> map = new HashMap<>(tag.getValue());
|
||||
map.put("Id", new StringTag(entity.getState().getType().id()));
|
||||
ListTag pos = (ListTag) map.get("Pos");
|
||||
if (pos != null) {
|
||||
@ -712,6 +712,12 @@ public class MainUtil {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
if (filename.matches(".*\\.[\\w].*")) {
|
||||
File file = MainUtil.resolveRelative(new File(dir, filename));
|
||||
if (file.exists()) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
for (ClipboardFormat f : ClipboardFormats.getAll()) {
|
||||
File file = MainUtil.resolveRelative(new File(dir, filename + "." + f.getPrimaryFileExtension()));
|
||||
if (file.exists()) {
|
||||
|
@ -1,13 +1,12 @@
|
||||
package com.fastasyncworldedit.core.util;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTagType;
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTagTypes;
|
||||
import com.sk89q.worldedit.util.nbt.ByteBinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.IntBinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.ShortBinaryTag;
|
||||
import com.sk89q.worldedit.world.storage.InvalidFormatException;
|
||||
import org.enginehub.linbus.tree.LinByteTag;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
import org.enginehub.linbus.tree.LinIntTag;
|
||||
import org.enginehub.linbus.tree.LinShortTag;
|
||||
import org.enginehub.linbus.tree.LinTag;
|
||||
import org.enginehub.linbus.tree.LinTagType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -23,9 +22,9 @@ public class NbtUtils {
|
||||
* @return child tag
|
||||
* @throws InvalidFormatException if the format of the items is invalid
|
||||
*/
|
||||
public static <T extends BinaryTag> T getChildTag(CompoundBinaryTag tag, String key, BinaryTagType<T> expected) throws
|
||||
public static <T extends LinTag> T getChildTag(LinCompoundTag tag, String key, LinTagType expected) throws
|
||||
InvalidFormatException {
|
||||
BinaryTag childTag = tag.get(key);
|
||||
LinTag childTag = tag.value().get(key);
|
||||
if (childTag == null) {
|
||||
throw new InvalidFormatException("Missing a \"" + key + "\" tag");
|
||||
}
|
||||
@ -48,35 +47,35 @@ public class NbtUtils {
|
||||
* @throws InvalidFormatException if the format of the items is invalid
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public static int getInt(CompoundBinaryTag tag, String key) throws InvalidFormatException {
|
||||
BinaryTag childTag = tag.get(key);
|
||||
public static int getInt(LinCompoundTag tag, String key) throws InvalidFormatException {
|
||||
LinTag childTag = tag.value().get(key);
|
||||
if (childTag == null) {
|
||||
throw new InvalidFormatException("Missing a \"" + key + "\" tag");
|
||||
}
|
||||
|
||||
BinaryTagType<?> type = childTag.type();
|
||||
if (type == BinaryTagTypes.INT) {
|
||||
return ((IntBinaryTag) childTag).intValue();
|
||||
LinTagType<?> type = childTag.type();
|
||||
if (type == LinTagType.intTag()) {
|
||||
return ((LinIntTag) childTag).value();
|
||||
}
|
||||
if (type == BinaryTagTypes.BYTE) {
|
||||
return ((ByteBinaryTag) childTag).intValue();
|
||||
if (type == LinTagType.byteTag()) {
|
||||
return ((LinByteTag) childTag).value();
|
||||
}
|
||||
if (type == BinaryTagTypes.SHORT) {
|
||||
return ((ShortBinaryTag) childTag).intValue();
|
||||
if (type == LinTagType.shortTag()) {
|
||||
return ((LinShortTag) childTag).value();
|
||||
}
|
||||
throw new InvalidFormatException(key + " tag is not of int, short or byte tag type.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a mutable map of the values stored inside a {@link CompoundBinaryTag}
|
||||
* Get a mutable map of the values stored inside a {@link LinCompoundTag}
|
||||
*
|
||||
* @param tag {@link CompoundBinaryTag} to get values for
|
||||
* @param tag {@link LinCompoundTag} to get values for
|
||||
* @return Mutable map of values
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public static Map<String, BinaryTag> getCompoundBinaryTagValues(CompoundBinaryTag tag) {
|
||||
Map<String, BinaryTag> value = new HashMap<>();
|
||||
tag.forEach((e) -> value.put(e.getKey(), e.getValue()));
|
||||
public static Map<String, LinTag<?>> getLinCompoundTagValues(LinCompoundTag tag) {
|
||||
Map<String, LinTag<?>> value = new HashMap<>();
|
||||
value.putAll(tag.value());
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -10,9 +10,10 @@ import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.sk89q.worldedit.blocks.BaseItem;
|
||||
import com.sk89q.worldedit.util.concurrency.LazyReference;
|
||||
import com.sk89q.worldedit.util.nbt.TagStringIO;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.item.ItemTypes;
|
||||
import org.enginehub.linbus.format.snbt.LinStringIO;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
@ -36,7 +37,10 @@ public final class BaseItemAdapter implements JsonDeserializer<BaseItem>, JsonSe
|
||||
return new BaseItem(itemType);
|
||||
}
|
||||
try {
|
||||
return new BaseItem(itemType, LazyReference.computed(TagStringIO.get().asCompound(nbt.getAsString())));
|
||||
return new BaseItem(
|
||||
itemType,
|
||||
LazyReference.computed(LinCompoundTag.readFrom(LinStringIO.readFromString(nbt.getAsString())))
|
||||
);
|
||||
} catch (IOException e) {
|
||||
throw new JsonParseException("Could not deserialize BaseItem", e);
|
||||
}
|
||||
@ -50,12 +54,8 @@ public final class BaseItemAdapter implements JsonDeserializer<BaseItem>, JsonSe
|
||||
) {
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.add("itemType", jsonSerializationContext.serialize(baseItem.getType()));
|
||||
try {
|
||||
obj.add("nbt", baseItem.getNbt() == null ? null : new JsonPrimitive(TagStringIO.get().asString(baseItem.getNbt())));
|
||||
return obj;
|
||||
} catch (IOException e) {
|
||||
throw new JsonParseException("Could not deserialize BaseItem", e);
|
||||
}
|
||||
obj.add("nbt", baseItem.getNbt() == null ? null : new JsonPrimitive(LinStringIO.writeToString(baseItem.getNbt())));
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,110 +0,0 @@
|
||||
/*
|
||||
* 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 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTagType;
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTagTypes;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Converts between JNBT and Adventure-NBT classes.
|
||||
*
|
||||
* @deprecated JNBT is being removed in WE8.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public class AdventureNBTConverter {
|
||||
|
||||
private static final BiMap<Class<? extends Tag>, BinaryTagType<?>> TAG_TYPES =
|
||||
new ImmutableBiMap.Builder<Class<? extends Tag>, BinaryTagType<?>>()
|
||||
.put(ByteArrayTag.class, BinaryTagTypes.BYTE_ARRAY)
|
||||
.put(ByteTag.class, BinaryTagTypes.BYTE)
|
||||
.put(CompoundTag.class, BinaryTagTypes.COMPOUND)
|
||||
.put(DoubleTag.class, BinaryTagTypes.DOUBLE)
|
||||
.put(EndTag.class, BinaryTagTypes.END)
|
||||
.put(FloatTag.class, BinaryTagTypes.FLOAT)
|
||||
.put(IntArrayTag.class, BinaryTagTypes.INT_ARRAY)
|
||||
.put(IntTag.class, BinaryTagTypes.INT)
|
||||
.put(ListTag.class, BinaryTagTypes.LIST)
|
||||
.put(LongArrayTag.class, BinaryTagTypes.LONG_ARRAY)
|
||||
.put(LongTag.class, BinaryTagTypes.LONG)
|
||||
.put(ShortTag.class, BinaryTagTypes.SHORT)
|
||||
.put(StringTag.class, BinaryTagTypes.STRING)
|
||||
.build();
|
||||
|
||||
private static final Map<BinaryTagType<?>, Function<BinaryTag, Tag>> CONVERSION;
|
||||
|
||||
static {
|
||||
ImmutableMap.Builder<BinaryTagType<?>, Function<BinaryTag, Tag>> conversion =
|
||||
ImmutableMap.builder();
|
||||
|
||||
for (Map.Entry<Class<? extends Tag>, BinaryTagType<?>> tag : TAG_TYPES.entrySet()) {
|
||||
Constructor<?>[] constructors = tag.getKey().getConstructors();
|
||||
for (Constructor<?> c : constructors) {
|
||||
if (c.getParameterCount() == 1 && BinaryTag.class.isAssignableFrom(c.getParameterTypes()[0])) {
|
||||
conversion.put(tag.getValue(), binaryTag -> {
|
||||
try {
|
||||
return (Tag) c.newInstance(binaryTag);
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
// I assume this is always a RuntimeException since we control the ctor
|
||||
throw (RuntimeException) e.getCause();
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CONVERSION = conversion.build();
|
||||
}
|
||||
|
||||
public static BinaryTagType<?> getAdventureType(Class<? extends Tag> type) {
|
||||
return Objects.requireNonNull(TAG_TYPES.get(type), () -> "Missing entry for " + type);
|
||||
}
|
||||
|
||||
public static Class<? extends Tag> getJNBTType(BinaryTagType<?> type) {
|
||||
return Objects.requireNonNull(TAG_TYPES.inverse().get(type), () -> "Missing entry for " + type);
|
||||
}
|
||||
|
||||
private AdventureNBTConverter() {
|
||||
}
|
||||
|
||||
public static Tag fromAdventure(BinaryTag other) {
|
||||
if (other == null) {
|
||||
return null;
|
||||
}
|
||||
Function<BinaryTag, Tag> conversion = CONVERSION.get(other.type());
|
||||
if (conversion == null) {
|
||||
throw new IllegalArgumentException("Can't convert other of type " + other.getClass().getCanonicalName());
|
||||
}
|
||||
return conversion.apply(other);
|
||||
}
|
||||
|
||||
}
|
@ -19,41 +19,26 @@
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag;
|
||||
import org.enginehub.linbus.tree.LinByteArrayTag;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Byte_Array} tag.
|
||||
*
|
||||
* @deprecated Use {@link ByteArrayBinaryTag}.
|
||||
* @deprecated Use {@link LinByteArrayTag}.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class ByteArrayTag extends Tag {
|
||||
|
||||
private final ByteArrayBinaryTag innerTag;
|
||||
|
||||
public final class ByteArrayTag extends Tag<byte[], LinByteArrayTag> {
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
*
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public ByteArrayTag(byte[] value) {
|
||||
super();
|
||||
this.innerTag = ByteArrayBinaryTag.of(value);
|
||||
this(LinByteArrayTag.of(value));
|
||||
}
|
||||
|
||||
public ByteArrayTag(ByteArrayBinaryTag adventureTag) {
|
||||
super();
|
||||
this.innerTag = adventureTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getValue() {
|
||||
return innerTag.value();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteArrayBinaryTag asBinaryTag() {
|
||||
return innerTag;
|
||||
public ByteArrayTag(LinByteArrayTag tag) {
|
||||
super(tag);
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
@ -19,41 +19,32 @@
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.ByteBinaryTag;
|
||||
import com.fastasyncworldedit.core.jnbt.NumberTag;
|
||||
import org.enginehub.linbus.tree.LinByteTag;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Byte} tag.
|
||||
*
|
||||
* @deprecated Use {@link ByteBinaryTag}.
|
||||
* @deprecated Use {@link LinByteTag}.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class ByteTag extends Tag {
|
||||
|
||||
private final ByteBinaryTag innerTag;
|
||||
|
||||
public final class ByteTag extends NumberTag<LinByteTag> {
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
*
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public ByteTag(byte value) {
|
||||
super();
|
||||
this.innerTag = ByteBinaryTag.of(value);
|
||||
this(LinByteTag.of(value));
|
||||
}
|
||||
|
||||
public ByteTag(ByteBinaryTag adventureTag) {
|
||||
super();
|
||||
this.innerTag = adventureTag;
|
||||
public ByteTag(LinByteTag tag) {
|
||||
super(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte getValue() {
|
||||
return innerTag.value();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBinaryTag asBinaryTag() {
|
||||
return innerTag;
|
||||
return linTag.value();
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
@ -25,10 +25,11 @@ import com.google.common.collect.Maps;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTagLike;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.NumberBinaryTag;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
import org.enginehub.linbus.tree.LinListTag;
|
||||
import org.enginehub.linbus.tree.LinNumberTag;
|
||||
import org.enginehub.linbus.tree.LinTag;
|
||||
import org.enginehub.linbus.tree.LinTagType;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@ -39,26 +40,24 @@ import java.util.UUID;
|
||||
/**
|
||||
* The {@code TAG_Compound} tag.
|
||||
*
|
||||
* @deprecated Use {@link com.sk89q.worldedit.util.nbt.CompoundBinaryTag}.
|
||||
* @deprecated Use {@link LinCompoundTag}.
|
||||
*/
|
||||
@Deprecated
|
||||
public class CompoundTag extends Tag {
|
||||
|
||||
private final CompoundBinaryTag innerTag;
|
||||
//FAWE start - nonfinal
|
||||
public class CompoundTag extends Tag<Object, LinCompoundTag> {
|
||||
//FAWE end
|
||||
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
*
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public CompoundTag(Map<String, Tag> value) {
|
||||
this(CompoundBinaryTag.builder()
|
||||
.put(Maps.transformValues(value, BinaryTagLike::asBinaryTag))
|
||||
.build());
|
||||
public CompoundTag(Map<String, Tag<?, ?>> value) {
|
||||
this(LinCompoundTag.of(Maps.transformValues(value, Tag::toLinTag)));
|
||||
}
|
||||
|
||||
public CompoundTag(CompoundBinaryTag adventureTag) {
|
||||
this.innerTag = adventureTag;
|
||||
public CompoundTag(LinCompoundTag tag) {
|
||||
super(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,16 +67,16 @@ public class CompoundTag extends Tag {
|
||||
* @return true if the tag contains the given key
|
||||
*/
|
||||
public boolean containsKey(String key) {
|
||||
return innerTag.keySet().contains(key);
|
||||
return linTag.value().containsKey(key);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
public Map<String, Tag> getValue() {
|
||||
ImmutableMap.Builder<String, Tag> map = ImmutableMap.builder();
|
||||
for (String key : innerTag.keySet()) {
|
||||
map.put(key, AdventureNBTConverter.fromAdventure(innerTag.get(key)));
|
||||
}
|
||||
return map.build();
|
||||
public Map<String, Tag<?, ?>> getValue() {
|
||||
return ImmutableMap.copyOf(Maps.transformValues(
|
||||
linTag.value(),
|
||||
tag -> (Tag<?, ?>) LinBusConverter.toJnbtTag((LinTag) tag)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,7 +85,7 @@ public class CompoundTag extends Tag {
|
||||
* @param value the value
|
||||
* @return the new compound tag
|
||||
*/
|
||||
public CompoundTag setValue(Map<String, Tag> value) {
|
||||
public CompoundTag setValue(Map<String, Tag<?, ?>> value) {
|
||||
return new CompoundTag(value);
|
||||
}
|
||||
|
||||
@ -96,7 +95,7 @@ public class CompoundTag extends Tag {
|
||||
* @return the builder
|
||||
*/
|
||||
public CompoundTagBuilder createBuilder() {
|
||||
return new CompoundTagBuilder(innerTag);
|
||||
return new CompoundTagBuilder(linTag);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,7 +108,8 @@ public class CompoundTag extends Tag {
|
||||
* @return a byte array
|
||||
*/
|
||||
public byte[] getByteArray(String key) {
|
||||
return this.innerTag.getByteArray(key);
|
||||
var tag = linTag.findTag(key, LinTagType.byteArrayTag());
|
||||
return tag == null ? new byte[0] : tag.value();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,7 +122,8 @@ public class CompoundTag extends Tag {
|
||||
* @return a byte
|
||||
*/
|
||||
public byte getByte(String key) {
|
||||
return this.innerTag.getByte(key);
|
||||
var tag = linTag.findTag(key, LinTagType.byteTag());
|
||||
return tag == null ? 0 : tag.value();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,7 +136,8 @@ public class CompoundTag extends Tag {
|
||||
* @return a double
|
||||
*/
|
||||
public double getDouble(String key) {
|
||||
return this.innerTag.getDouble(key);
|
||||
var tag = linTag.findTag(key, LinTagType.doubleTag());
|
||||
return tag == null ? 0 : tag.value();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,9 +151,10 @@ public class CompoundTag extends Tag {
|
||||
* @return a double
|
||||
*/
|
||||
public double asDouble(String key) {
|
||||
BinaryTag tag = this.innerTag.get(key);
|
||||
if (tag instanceof NumberBinaryTag) {
|
||||
return ((NumberBinaryTag) tag).doubleValue();
|
||||
var tag = linTag.value().get(key);
|
||||
if (tag instanceof LinNumberTag<?> numberTag) {
|
||||
Number value = numberTag.value();
|
||||
return value.doubleValue();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -166,7 +169,8 @@ public class CompoundTag extends Tag {
|
||||
* @return a float
|
||||
*/
|
||||
public float getFloat(String key) {
|
||||
return this.innerTag.getFloat(key);
|
||||
var tag = linTag.findTag(key, LinTagType.floatTag());
|
||||
return tag == null ? 0 : tag.value();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -179,7 +183,8 @@ public class CompoundTag extends Tag {
|
||||
* @return an int array
|
||||
*/
|
||||
public int[] getIntArray(String key) {
|
||||
return this.innerTag.getIntArray(key);
|
||||
var tag = linTag.findTag(key, LinTagType.intArrayTag());
|
||||
return tag == null ? new int[0] : tag.value();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -192,7 +197,8 @@ public class CompoundTag extends Tag {
|
||||
* @return an int
|
||||
*/
|
||||
public int getInt(String key) {
|
||||
return this.innerTag.getInt(key);
|
||||
var tag = linTag.findTag(key, LinTagType.intTag());
|
||||
return tag == null ? 0 : tag.value();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -206,9 +212,10 @@ public class CompoundTag extends Tag {
|
||||
* @return an int
|
||||
*/
|
||||
public int asInt(String key) {
|
||||
BinaryTag tag = this.innerTag.get(key);
|
||||
if (tag instanceof NumberBinaryTag) {
|
||||
return ((NumberBinaryTag) tag).intValue();
|
||||
var tag = linTag.value().get(key);
|
||||
if (tag instanceof LinNumberTag<?> numberTag) {
|
||||
Number value = numberTag.value();
|
||||
return value.intValue();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -222,7 +229,7 @@ public class CompoundTag extends Tag {
|
||||
* @param key the key
|
||||
* @return a list of tags
|
||||
*/
|
||||
public List<Tag> getList(String key) {
|
||||
public List<? extends Tag<?, ?>> getList(String key) {
|
||||
return getListTag(key).getValue();
|
||||
}
|
||||
|
||||
@ -235,8 +242,15 @@ public class CompoundTag extends Tag {
|
||||
* @param key the key
|
||||
* @return a tag list instance
|
||||
*/
|
||||
public ListTag getListTag(String key) {
|
||||
return new ListTag(this.innerTag.getList(key));
|
||||
public <EV, E extends LinTag<EV>> ListTag<EV, E> getListTag(String key) {
|
||||
LinListTag<E> tag = linTag.findTag(key, LinTagType.listTag());
|
||||
if (tag == null) {
|
||||
// This is actually hella unsafe. But eh.
|
||||
@SuppressWarnings("unchecked")
|
||||
LinTagType<E> endGenerically = (LinTagType<E>) LinTagType.endTag();
|
||||
return new ListTag<>(LinListTag.empty(endGenerically));
|
||||
}
|
||||
return new ListTag<>(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -253,8 +267,8 @@ public class CompoundTag extends Tag {
|
||||
* @return a list of tags
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Tag> List<T> getList(String key, Class<T> listType) {
|
||||
ListTag listTag = getListTag(key);
|
||||
public <T extends Tag<?, ?>> List<T> getList(String key, Class<T> listType) {
|
||||
ListTag<?, ?> listTag = getListTag(key);
|
||||
if (listTag.getType().equals(listType)) {
|
||||
return (List<T>) listTag.getValue();
|
||||
} else {
|
||||
@ -272,7 +286,8 @@ public class CompoundTag extends Tag {
|
||||
* @return an int array
|
||||
*/
|
||||
public long[] getLongArray(String key) {
|
||||
return this.innerTag.getLongArray(key);
|
||||
var tag = linTag.findTag(key, LinTagType.longArrayTag());
|
||||
return tag == null ? new long[0] : tag.value();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -285,7 +300,8 @@ public class CompoundTag extends Tag {
|
||||
* @return a long
|
||||
*/
|
||||
public long getLong(String key) {
|
||||
return this.innerTag.getLong(key);
|
||||
var tag = linTag.findTag(key, LinTagType.longTag());
|
||||
return tag == null ? 0 : tag.value();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -299,9 +315,10 @@ public class CompoundTag extends Tag {
|
||||
* @return a long
|
||||
*/
|
||||
public long asLong(String key) {
|
||||
BinaryTag tag = this.innerTag.get(key);
|
||||
if (tag instanceof NumberBinaryTag) {
|
||||
return ((NumberBinaryTag) tag).longValue();
|
||||
var tag = linTag.value().get(key);
|
||||
if (tag instanceof LinNumberTag<?> numberTag) {
|
||||
Number value = numberTag.value();
|
||||
return value.longValue();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -316,7 +333,8 @@ public class CompoundTag extends Tag {
|
||||
* @return a short
|
||||
*/
|
||||
public short getShort(String key) {
|
||||
return this.innerTag.getShort(key);
|
||||
var tag = linTag.findTag(key, LinTagType.shortTag());
|
||||
return tag == null ? 0 : tag.value();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -329,12 +347,8 @@ public class CompoundTag extends Tag {
|
||||
* @return a string
|
||||
*/
|
||||
public String getString(String key) {
|
||||
return this.innerTag.getString(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundBinaryTag asBinaryTag() {
|
||||
return this.innerTag;
|
||||
var tag = linTag.findTag(key, LinTagType.stringTag());
|
||||
return tag == null ? "" : tag.value();
|
||||
}
|
||||
|
||||
|
||||
@ -357,7 +371,7 @@ public class CompoundTag extends Tag {
|
||||
}
|
||||
|
||||
public Vector3 getEntityPosition() {
|
||||
List<Tag> posTags = getList("Pos");
|
||||
List<? extends Tag<?, ?>> posTags = getList("Pos");
|
||||
double x = ((NumberTag) posTags.get(0)).getValue().doubleValue();
|
||||
double y = ((NumberTag) posTags.get(1)).getValue().doubleValue();
|
||||
double z = ((NumberTag) posTags.get(2)).getValue().doubleValue();
|
||||
@ -365,7 +379,7 @@ public class CompoundTag extends Tag {
|
||||
}
|
||||
|
||||
public Location getEntityLocation(Extent extent) {
|
||||
List<Tag> rotTag = getList("Rotation");
|
||||
List<? extends Tag<?, ?>> rotTag = getList("Rotation");
|
||||
float yaw = ((NumberTag) rotTag.get(0)).getValue().floatValue();
|
||||
float pitch = ((NumberTag) rotTag.get(1)).getValue().floatValue();
|
||||
return new Location(extent, getEntityPosition(), yaw, pitch);
|
||||
@ -382,7 +396,7 @@ public class CompoundTag extends Tag {
|
||||
if (this.getValue().isEmpty()) {
|
||||
return raw;
|
||||
}
|
||||
for (Map.Entry<String, Tag> entry : getValue().entrySet()) {
|
||||
for (Map.Entry<String, Tag<?, ?>> entry : getValue().entrySet()) {
|
||||
raw.put(entry.getKey(), entry.getValue().toRaw());
|
||||
}
|
||||
return raw;
|
||||
|
@ -19,27 +19,27 @@
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Helps create compound tags.
|
||||
*
|
||||
* @deprecated Use {@link com.sk89q.worldedit.util.nbt.CompoundBinaryTag.Builder}.
|
||||
* @deprecated Use {@link LinCompoundTag.Builder}.
|
||||
*/
|
||||
@Deprecated
|
||||
public class CompoundTagBuilder {
|
||||
|
||||
private final CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
|
||||
private final LinCompoundTag.Builder builder;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*/
|
||||
CompoundTagBuilder() {
|
||||
this.builder = LinCompoundTag.builder();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,11 +47,9 @@ public class CompoundTagBuilder {
|
||||
*
|
||||
* @param source the value
|
||||
*/
|
||||
CompoundTagBuilder(CompoundBinaryTag source) {
|
||||
CompoundTagBuilder(LinCompoundTag source) {
|
||||
checkNotNull(source);
|
||||
for (String key : source.keySet()) {
|
||||
this.builder.put(key, Objects.requireNonNull(source.get(key)));
|
||||
}
|
||||
this.builder = source.toBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,10 +59,10 @@ public class CompoundTagBuilder {
|
||||
* @param value the value
|
||||
* @return this object
|
||||
*/
|
||||
public CompoundTagBuilder put(String key, Tag value) {
|
||||
public CompoundTagBuilder put(String key, Tag<?, ?> value) {
|
||||
checkNotNull(key);
|
||||
checkNotNull(value);
|
||||
this.builder.put(key, value.asBinaryTag());
|
||||
this.builder.put(key, value.toLinTag());
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -215,9 +213,9 @@ public class CompoundTagBuilder {
|
||||
* @param value the map of tags
|
||||
* @return this object
|
||||
*/
|
||||
public CompoundTagBuilder putAll(Map<String, ? extends Tag> value) {
|
||||
public CompoundTagBuilder putAll(Map<String, ? extends Tag<?, ?>> value) {
|
||||
checkNotNull(value);
|
||||
for (Map.Entry<String, ? extends Tag> entry : value.entrySet()) {
|
||||
for (Map.Entry<String, ? extends Tag<?, ?>> entry : value.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return this;
|
||||
|
@ -20,17 +20,15 @@
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.fastasyncworldedit.core.jnbt.NumberTag;
|
||||
import com.sk89q.worldedit.util.nbt.DoubleBinaryTag;
|
||||
import org.enginehub.linbus.tree.LinDoubleTag;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Double} tag.
|
||||
*
|
||||
* @deprecated Use {@link DoubleBinaryTag}.
|
||||
* @deprecated Use {@link LinDoubleTag}.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class DoubleTag extends NumberTag {
|
||||
|
||||
private final DoubleBinaryTag innerTag;
|
||||
public final class DoubleTag extends NumberTag<LinDoubleTag> {
|
||||
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
@ -38,23 +36,16 @@ public final class DoubleTag extends NumberTag {
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public DoubleTag(double value) {
|
||||
super();
|
||||
this.innerTag = DoubleBinaryTag.of(value);
|
||||
this(LinDoubleTag.of(value));
|
||||
}
|
||||
|
||||
public DoubleTag(DoubleBinaryTag adventureTag) {
|
||||
super();
|
||||
this.innerTag = adventureTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DoubleBinaryTag asBinaryTag() {
|
||||
return this.innerTag;
|
||||
public DoubleTag(LinDoubleTag tag) {
|
||||
super(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getValue() {
|
||||
return innerTag.value();
|
||||
return linTag.value();
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
@ -19,24 +19,17 @@
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.EndBinaryTag;
|
||||
import org.enginehub.linbus.tree.LinEndTag;
|
||||
|
||||
/**
|
||||
* The {@code TAG_End} tag.
|
||||
*
|
||||
* @deprecated Use {@link com.sk89q.worldedit.util.nbt.EndBinaryTag}.
|
||||
* @deprecated Use {@link LinEndTag}.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class EndTag extends Tag {
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EndBinaryTag asBinaryTag() {
|
||||
return EndBinaryTag.get();
|
||||
public final class EndTag extends Tag<Object, LinEndTag> {
|
||||
public EndTag() {
|
||||
super(LinEndTag.instance());
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
@ -20,17 +20,14 @@
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.fastasyncworldedit.core.jnbt.NumberTag;
|
||||
import com.sk89q.worldedit.util.nbt.FloatBinaryTag;
|
||||
import org.enginehub.linbus.tree.LinFloatTag;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Float} tag.
|
||||
*
|
||||
* @deprecated Use {@link FloatBinaryTag}.
|
||||
* @deprecated Use {@link LinFloatTag}.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class FloatTag extends NumberTag {
|
||||
|
||||
private final FloatBinaryTag innerTag;
|
||||
public final class FloatTag extends NumberTag<LinFloatTag> {
|
||||
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
@ -38,23 +35,16 @@ public final class FloatTag extends NumberTag {
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public FloatTag(float value) {
|
||||
super();
|
||||
this.innerTag = FloatBinaryTag.of(value);
|
||||
this(LinFloatTag.of(value));
|
||||
}
|
||||
|
||||
public FloatTag(FloatBinaryTag adventureTag) {
|
||||
super();
|
||||
this.innerTag = adventureTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatBinaryTag asBinaryTag() {
|
||||
return this.innerTag;
|
||||
public FloatTag(LinFloatTag tag) {
|
||||
super(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getValue() {
|
||||
return innerTag.value();
|
||||
return linTag.value();
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
@ -19,44 +19,33 @@
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag;
|
||||
import org.enginehub.linbus.tree.LinIntArrayTag;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Int_Array} tag.
|
||||
*
|
||||
* @deprecated Use {@link IntArrayBinaryTag}.
|
||||
* @deprecated Use {@link LinIntArrayTag}.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class IntArrayTag extends Tag {
|
||||
|
||||
private final IntArrayBinaryTag innerTag;
|
||||
|
||||
public final class IntArrayTag extends Tag<int[], LinIntArrayTag> {
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
*
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public IntArrayTag(int[] value) {
|
||||
super();
|
||||
checkNotNull(value);
|
||||
this.innerTag = IntArrayBinaryTag.of(value);
|
||||
this(LinIntArrayTag.of(checkNotNull(value)));
|
||||
}
|
||||
|
||||
public IntArrayTag(IntArrayBinaryTag adventureTag) {
|
||||
super();
|
||||
this.innerTag = adventureTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntArrayBinaryTag asBinaryTag() {
|
||||
return this.innerTag;
|
||||
public IntArrayTag(LinIntArrayTag tag) {
|
||||
super(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getValue() {
|
||||
return innerTag.value();
|
||||
return linTag.value();
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
@ -19,17 +19,16 @@
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.IntBinaryTag;
|
||||
import com.fastasyncworldedit.core.jnbt.NumberTag;
|
||||
import org.enginehub.linbus.tree.LinIntTag;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Int} tag.
|
||||
*
|
||||
* @deprecated Use {@link IntBinaryTag}.
|
||||
* @deprecated Use {@link LinIntTag}.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class IntTag extends Tag {
|
||||
|
||||
private final IntBinaryTag innerTag;
|
||||
public final class IntTag extends NumberTag<LinIntTag> {
|
||||
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
@ -37,23 +36,16 @@ public final class IntTag extends Tag {
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public IntTag(int value) {
|
||||
super();
|
||||
this.innerTag = IntBinaryTag.of(value);
|
||||
this(LinIntTag.of(value));
|
||||
}
|
||||
|
||||
public IntTag(IntBinaryTag adventureTag) {
|
||||
super();
|
||||
this.innerTag = adventureTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntBinaryTag asBinaryTag() {
|
||||
return this.innerTag;
|
||||
public IntTag(LinIntTag tag) {
|
||||
super(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return innerTag.value();
|
||||
return linTag.value();
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
@ -20,27 +20,27 @@
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Allows detection of the version-specific LazyCompoundTag classes.
|
||||
*
|
||||
* @deprecated Use {@link CompoundBinaryTag}.
|
||||
* @deprecated Use {@link LinCompoundTag}.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class LazyCompoundTag extends CompoundTag {
|
||||
|
||||
public LazyCompoundTag(Map<String, Tag> value) {
|
||||
public LazyCompoundTag(Map<String, Tag<?, ?>> value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
public LazyCompoundTag(CompoundBinaryTag adventureTag) {
|
||||
public LazyCompoundTag(LinCompoundTag adventureTag) {
|
||||
super(adventureTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract CompoundBinaryTag asBinaryTag();
|
||||
public abstract LinCompoundTag toLinTag();
|
||||
|
||||
}
|
||||
|
140
worldedit-core/src/main/java/com/sk89q/jnbt/LinBusConverter.java
Normal file
140
worldedit-core/src/main/java/com/sk89q/jnbt/LinBusConverter.java
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.enginehub.linbus.tree.LinByteArrayTag;
|
||||
import org.enginehub.linbus.tree.LinByteTag;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
import org.enginehub.linbus.tree.LinDoubleTag;
|
||||
import org.enginehub.linbus.tree.LinFloatTag;
|
||||
import org.enginehub.linbus.tree.LinIntArrayTag;
|
||||
import org.enginehub.linbus.tree.LinIntTag;
|
||||
import org.enginehub.linbus.tree.LinListTag;
|
||||
import org.enginehub.linbus.tree.LinLongArrayTag;
|
||||
import org.enginehub.linbus.tree.LinLongTag;
|
||||
import org.enginehub.linbus.tree.LinShortTag;
|
||||
import org.enginehub.linbus.tree.LinStringTag;
|
||||
import org.enginehub.linbus.tree.LinTag;
|
||||
import org.enginehub.linbus.tree.LinTagType;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Converts between JNBT and Adventure-NBT classes.
|
||||
*
|
||||
* @deprecated JNBT is being removed in WE8.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public class LinBusConverter {
|
||||
|
||||
private static final BiMap<Class<? extends Tag>, LinTagType<?>> TAG_TYPES =
|
||||
new ImmutableBiMap.Builder<Class<? extends Tag>, LinTagType<?>>()
|
||||
.put(ByteArrayTag.class, LinTagType.byteArrayTag())
|
||||
.put(ByteTag.class, LinTagType.byteTag())
|
||||
.put(CompoundTag.class, LinTagType.compoundTag())
|
||||
.put(DoubleTag.class, LinTagType.doubleTag())
|
||||
.put(EndTag.class, LinTagType.endTag())
|
||||
.put(FloatTag.class, LinTagType.floatTag())
|
||||
.put(IntArrayTag.class, LinTagType.intArrayTag())
|
||||
.put(IntTag.class, LinTagType.intTag())
|
||||
.put(ListTag.class, LinTagType.listTag())
|
||||
.put(LongArrayTag.class, LinTagType.longArrayTag())
|
||||
.put(LongTag.class, LinTagType.longTag())
|
||||
.put(ShortTag.class, LinTagType.shortTag())
|
||||
.put(StringTag.class, LinTagType.stringTag())
|
||||
.build();
|
||||
|
||||
private static final Map<LinTagType<?>, Function<LinTag, Tag>> CONVERSION;
|
||||
|
||||
static {
|
||||
ImmutableMap.Builder<LinTagType<?>, Function<LinTag, Tag>> conversion =
|
||||
ImmutableMap.builder();
|
||||
|
||||
for (Map.Entry<Class<? extends Tag>, LinTagType<?>> tag : TAG_TYPES.entrySet()) {
|
||||
Constructor<?>[] constructors = tag.getKey().getConstructors();
|
||||
for (Constructor<?> c : constructors) {
|
||||
if (c.getParameterCount() == 1 && LinTag.class.isAssignableFrom(c.getParameterTypes()[0])) {
|
||||
conversion.put(tag.getValue(), linTag -> {
|
||||
try {
|
||||
return (Tag) c.newInstance(linTag);
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
// I assume this is always a RuntimeException since we control the ctor
|
||||
throw (RuntimeException) e.getCause();
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CONVERSION = conversion.build();
|
||||
}
|
||||
|
||||
public static LinTagType<?> getAdventureType(Class<? extends Tag> type) {
|
||||
return Objects.requireNonNull(TAG_TYPES.get(type), () -> "Missing entry for " + type);
|
||||
}
|
||||
|
||||
public static Class<? extends Tag> getJNBTType(LinTagType<?> type) {
|
||||
return Objects.requireNonNull(TAG_TYPES.inverse().get(type), () -> "Missing entry for " + type);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public static <V, LT extends LinTag<? extends V>> Tag<V, LT> toJnbtTag(LT tag) {
|
||||
return (Tag<V, LT>) switch (tag.type().id()) {
|
||||
case BYTE_ARRAY -> new ByteArrayTag((LinByteArrayTag) tag);
|
||||
case BYTE -> new ByteTag((LinByteTag) tag);
|
||||
case COMPOUND -> new CompoundTag((LinCompoundTag) tag);
|
||||
case DOUBLE -> new DoubleTag((LinDoubleTag) tag);
|
||||
case END -> new EndTag();
|
||||
case FLOAT -> new FloatTag((LinFloatTag) tag);
|
||||
case INT_ARRAY -> new IntArrayTag((LinIntArrayTag) tag);
|
||||
case INT -> new IntTag((LinIntTag) tag);
|
||||
case LIST -> new ListTag((LinListTag<?>) tag);
|
||||
case LONG_ARRAY -> new LongArrayTag((LinLongArrayTag) tag);
|
||||
case LONG -> new LongTag((LinLongTag) tag);
|
||||
case SHORT -> new ShortTag((LinShortTag) tag);
|
||||
case STRING -> new StringTag((LinStringTag) tag);
|
||||
};
|
||||
}
|
||||
|
||||
private LinBusConverter() {
|
||||
}
|
||||
|
||||
public static Tag fromLinBus(LinTag other) {
|
||||
if (other == null) {
|
||||
return null;
|
||||
}
|
||||
Function<LinTag, Tag> conversion = CONVERSION.get(other.type());
|
||||
if (conversion == null) {
|
||||
throw new IllegalArgumentException("Can't convert other of type " + other.getClass().getCanonicalName());
|
||||
}
|
||||
return conversion.apply(other);
|
||||
}
|
||||
|
||||
}
|
@ -19,10 +19,20 @@
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTagLike;
|
||||
import com.sk89q.worldedit.util.nbt.ListBinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.NumberBinaryTag;
|
||||
import org.enginehub.linbus.common.LinTagId;
|
||||
import org.enginehub.linbus.tree.LinByteArrayTag;
|
||||
import org.enginehub.linbus.tree.LinByteTag;
|
||||
import org.enginehub.linbus.tree.LinDoubleTag;
|
||||
import org.enginehub.linbus.tree.LinFloatTag;
|
||||
import org.enginehub.linbus.tree.LinIntArrayTag;
|
||||
import org.enginehub.linbus.tree.LinIntTag;
|
||||
import org.enginehub.linbus.tree.LinListTag;
|
||||
import org.enginehub.linbus.tree.LinLongTag;
|
||||
import org.enginehub.linbus.tree.LinNumberTag;
|
||||
import org.enginehub.linbus.tree.LinShortTag;
|
||||
import org.enginehub.linbus.tree.LinStringTag;
|
||||
import org.enginehub.linbus.tree.LinTag;
|
||||
import org.enginehub.linbus.tree.LinTagType;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collections;
|
||||
@ -34,12 +44,10 @@ import java.util.stream.Collectors;
|
||||
/**
|
||||
* The {@code TAG_List} tag.
|
||||
*
|
||||
* @deprecated Use {@link com.sk89q.worldedit.util.nbt.ListBinaryTag}.
|
||||
* @deprecated Use {@link LinListTag}.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class ListTag extends Tag {
|
||||
|
||||
private final ListBinaryTag innerTag;
|
||||
public final class ListTag<EV, E extends LinTag<EV>> extends Tag<Object, LinListTag<E>> {
|
||||
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
@ -47,20 +55,15 @@ public final class ListTag extends Tag {
|
||||
* @param type the type of tag
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public ListTag(Class<? extends Tag> type, List<? extends Tag> value) {
|
||||
this(ListBinaryTag.of(
|
||||
AdventureNBTConverter.getAdventureType(type),
|
||||
value.stream().map(BinaryTagLike::asBinaryTag).collect(Collectors.toList())
|
||||
public ListTag(Class<? extends Tag<EV, E>> type, List<? extends Tag<EV, E>> value) {
|
||||
this(LinListTag.of(
|
||||
LinTagType.fromId(LinTagId.fromId(NBTUtils.getTypeCode(type))),
|
||||
value.stream().map(Tag::toLinTag).collect(Collectors.toList())
|
||||
));
|
||||
}
|
||||
|
||||
public ListTag(ListBinaryTag adventureTag) {
|
||||
this.innerTag = adventureTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListBinaryTag asBinaryTag() {
|
||||
return this.innerTag;
|
||||
public ListTag(LinListTag<E> tag) {
|
||||
super(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,15 +71,14 @@ public final class ListTag extends Tag {
|
||||
*
|
||||
* @return The type of item in this list.
|
||||
*/
|
||||
public Class<? extends Tag> getType() {
|
||||
return AdventureNBTConverter.getJNBTType(this.innerTag.elementType());
|
||||
@SuppressWarnings("unchecked")
|
||||
public Class<? extends Tag<EV, E>> getType() {
|
||||
return (Class<? extends Tag<EV, E>>) NBTUtils.getTypeClass(linTag.elementType().id().id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tag> getValue() {
|
||||
return this.innerTag.stream()
|
||||
.map(AdventureNBTConverter::fromAdventure)
|
||||
.collect(Collectors.toList());
|
||||
public List<? extends Tag<EV, E>> getValue() {
|
||||
return linTag.value().stream().map(LinBusConverter::toJnbtTag).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,17 +87,31 @@ public final class ListTag extends Tag {
|
||||
* @param list the new list
|
||||
* @return a new list tag
|
||||
*/
|
||||
public ListTag setValue(List<Tag> list) {
|
||||
return new ListTag(getType(), list);
|
||||
public ListTag<EV, E> setValue(List<? extends Tag<EV, E>> list) {
|
||||
return new ListTag<>(getType(), list);
|
||||
}
|
||||
|
||||
private <T> T accessIfExists(int index, Supplier<T> defaultValue, IntFunction<T> accessor) {
|
||||
if (index >= this.innerTag.size()) {
|
||||
if (index >= this.linTag.value().size()) {
|
||||
return defaultValue.get();
|
||||
}
|
||||
return accessor.apply(index);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T, LT extends LinTag<T>> T extractViaValue(
|
||||
int index, Class<LT> requiredType, Supplier<T> defaultValue
|
||||
) {
|
||||
if (index >= this.linTag.value().size()) {
|
||||
return defaultValue.get();
|
||||
}
|
||||
E value = this.linTag.get(index);
|
||||
if (!requiredType.isInstance(value)) {
|
||||
return defaultValue.get();
|
||||
}
|
||||
return (T) value.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tag if it exists at the given index.
|
||||
*
|
||||
@ -103,11 +119,11 @@ public final class ListTag extends Tag {
|
||||
* @return the tag or null
|
||||
*/
|
||||
@Nullable
|
||||
public Tag getIfExists(int index) {
|
||||
public Tag<EV, E> getIfExists(int index) {
|
||||
return accessIfExists(
|
||||
index,
|
||||
() -> null,
|
||||
i -> AdventureNBTConverter.fromAdventure(this.innerTag.get(i))
|
||||
index,
|
||||
() -> null,
|
||||
i -> LinBusConverter.toJnbtTag(this.linTag.get(i))
|
||||
);
|
||||
}
|
||||
|
||||
@ -121,11 +137,7 @@ public final class ListTag extends Tag {
|
||||
* @return a byte array
|
||||
*/
|
||||
public byte[] getByteArray(int index) {
|
||||
return accessIfExists(
|
||||
index,
|
||||
() -> new byte[0],
|
||||
this.innerTag::getByteArray
|
||||
);
|
||||
return extractViaValue(index, LinByteArrayTag.class, () -> new byte[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,11 +150,7 @@ public final class ListTag extends Tag {
|
||||
* @return a byte
|
||||
*/
|
||||
public byte getByte(int index) {
|
||||
return accessIfExists(
|
||||
index,
|
||||
() -> (byte) 0,
|
||||
this.innerTag::getByte
|
||||
);
|
||||
return extractViaValue(index, LinByteTag.class, () -> (byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,11 +163,7 @@ public final class ListTag extends Tag {
|
||||
* @return a double
|
||||
*/
|
||||
public double getDouble(int index) {
|
||||
return accessIfExists(
|
||||
index,
|
||||
() -> 0.0,
|
||||
this.innerTag::getDouble
|
||||
);
|
||||
return extractViaValue(index, LinDoubleTag.class, () -> 0.0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -174,15 +178,11 @@ public final class ListTag extends Tag {
|
||||
*/
|
||||
public double asDouble(int index) {
|
||||
return accessIfExists(
|
||||
index,
|
||||
() -> 0.0,
|
||||
i -> {
|
||||
BinaryTag tag = this.innerTag.get(i);
|
||||
if (tag instanceof NumberBinaryTag) {
|
||||
return ((NumberBinaryTag) tag).doubleValue();
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
index,
|
||||
() -> 0.0,
|
||||
i -> this.linTag.get(i) instanceof LinNumberTag<?> tag
|
||||
? tag.value().doubleValue()
|
||||
: 0.0
|
||||
);
|
||||
}
|
||||
|
||||
@ -196,11 +196,7 @@ public final class ListTag extends Tag {
|
||||
* @return a float
|
||||
*/
|
||||
public float getFloat(int index) {
|
||||
return accessIfExists(
|
||||
index,
|
||||
() -> 0.0f,
|
||||
this.innerTag::getFloat
|
||||
);
|
||||
return extractViaValue(index, LinFloatTag.class, () -> 0f);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -213,11 +209,7 @@ public final class ListTag extends Tag {
|
||||
* @return an int array
|
||||
*/
|
||||
public int[] getIntArray(int index) {
|
||||
return accessIfExists(
|
||||
index,
|
||||
() -> new int[0],
|
||||
this.innerTag::getIntArray
|
||||
);
|
||||
return extractViaValue(index, LinIntArrayTag.class, () -> new int[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -230,11 +222,7 @@ public final class ListTag extends Tag {
|
||||
* @return an int
|
||||
*/
|
||||
public int getInt(int index) {
|
||||
return accessIfExists(
|
||||
index,
|
||||
() -> 0,
|
||||
this.innerTag::getInt
|
||||
);
|
||||
return extractViaValue(index, LinIntTag.class, () -> 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -249,15 +237,11 @@ public final class ListTag extends Tag {
|
||||
*/
|
||||
public int asInt(int index) {
|
||||
return accessIfExists(
|
||||
index,
|
||||
() -> 0,
|
||||
i -> {
|
||||
BinaryTag tag = this.innerTag.get(i);
|
||||
if (tag instanceof NumberBinaryTag) {
|
||||
return ((NumberBinaryTag) tag).intValue();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
index,
|
||||
() -> 0,
|
||||
i -> this.linTag.get(i) instanceof LinNumberTag<?> tag
|
||||
? tag.value().intValue()
|
||||
: 0
|
||||
);
|
||||
}
|
||||
|
||||
@ -270,7 +254,7 @@ public final class ListTag extends Tag {
|
||||
* @param index the index
|
||||
* @return a list of tags
|
||||
*/
|
||||
public List<Tag> getList(int index) {
|
||||
public List<? extends Tag<?, ?>> getList(int index) {
|
||||
return getListTag(index).getValue();
|
||||
}
|
||||
|
||||
@ -283,11 +267,12 @@ public final class ListTag extends Tag {
|
||||
* @param index the index
|
||||
* @return a tag list instance
|
||||
*/
|
||||
public ListTag getListTag(int index) {
|
||||
return new ListTag(accessIfExists(
|
||||
index,
|
||||
ListBinaryTag::empty,
|
||||
this.innerTag::getList
|
||||
@SuppressWarnings("unchecked")
|
||||
public ListTag<?, ?> getListTag(int index) {
|
||||
return new ListTag<>(extractViaValue(
|
||||
index,
|
||||
LinListTag.class,
|
||||
() -> LinListTag.empty(LinTagType.endTag())
|
||||
));
|
||||
}
|
||||
|
||||
@ -305,8 +290,8 @@ public final class ListTag extends Tag {
|
||||
* @return a list of tags
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Tag> List<T> getList(int index, Class<T> listType) {
|
||||
ListTag listTag = getListTag(index);
|
||||
public <T extends Tag<?, ?>> List<T> getList(int index, Class<T> listType) {
|
||||
ListTag<?, ?> listTag = getListTag(index);
|
||||
if (listTag.getType().equals(listType)) {
|
||||
return (List<T>) listTag.getValue();
|
||||
} else {
|
||||
@ -324,11 +309,7 @@ public final class ListTag extends Tag {
|
||||
* @return a long
|
||||
*/
|
||||
public long getLong(int index) {
|
||||
return accessIfExists(
|
||||
index,
|
||||
() -> 0L,
|
||||
this.innerTag::getLong
|
||||
);
|
||||
return extractViaValue(index, LinLongTag.class, () -> 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -343,15 +324,11 @@ public final class ListTag extends Tag {
|
||||
*/
|
||||
public long asLong(int index) {
|
||||
return accessIfExists(
|
||||
index,
|
||||
() -> 0L,
|
||||
i -> {
|
||||
BinaryTag tag = this.innerTag.get(i);
|
||||
if (tag instanceof NumberBinaryTag) {
|
||||
return ((NumberBinaryTag) tag).longValue();
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
index,
|
||||
() -> 0L,
|
||||
i -> this.linTag.get(i) instanceof LinNumberTag<?> tag
|
||||
? tag.value().longValue()
|
||||
: 0L
|
||||
);
|
||||
}
|
||||
|
||||
@ -365,11 +342,7 @@ public final class ListTag extends Tag {
|
||||
* @return a short
|
||||
*/
|
||||
public short getShort(int index) {
|
||||
return accessIfExists(
|
||||
index,
|
||||
() -> (short) 0,
|
||||
this.innerTag::getShort
|
||||
);
|
||||
return extractViaValue(index, LinShortTag.class, () -> (short) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -382,11 +355,7 @@ public final class ListTag extends Tag {
|
||||
* @return a string
|
||||
*/
|
||||
public String getString(int index) {
|
||||
return accessIfExists(
|
||||
index,
|
||||
() -> "",
|
||||
this.innerTag::getString
|
||||
);
|
||||
return extractViaValue(index, LinStringTag.class, () -> "");
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
@ -19,11 +19,11 @@
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTagType;
|
||||
import com.sk89q.worldedit.util.nbt.ListBinaryTag;
|
||||
import org.enginehub.linbus.common.LinTagId;
|
||||
import org.enginehub.linbus.tree.LinListTag;
|
||||
import org.enginehub.linbus.tree.LinTag;
|
||||
import org.enginehub.linbus.tree.LinTagType;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
@ -31,12 +31,12 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
/**
|
||||
* Helps create list tags.
|
||||
*
|
||||
* @deprecated Use {@link com.sk89q.worldedit.util.nbt.ListBinaryTag.Builder}.
|
||||
* @deprecated Use {@link LinListTag.Builder}.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ListTagBuilder {
|
||||
public class ListTagBuilder<V, LT extends LinTag<V>> {
|
||||
|
||||
private final ListBinaryTag.Builder<BinaryTag> builder;
|
||||
private final LinListTag.Builder<LT> builder;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
@ -44,11 +44,11 @@ public class ListTagBuilder {
|
||||
* @param type of tag contained in this list
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
ListTagBuilder(Class<? extends Tag> type) {
|
||||
ListTagBuilder(Class<? extends Tag<V, LT>> type) {
|
||||
checkNotNull(type);
|
||||
this.builder = type != EndTag.class
|
||||
? ListBinaryTag.builder((BinaryTagType<BinaryTag>) AdventureNBTConverter.getAdventureType(type))
|
||||
: ListBinaryTag.builder();
|
||||
this.builder = (LinListTag.Builder<LT>) LinListTag.builder(LinTagType.fromId(LinTagId.fromId(
|
||||
NBTUtils.getTypeCode(type)
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,9 +57,9 @@ public class ListTagBuilder {
|
||||
* @param value the tag
|
||||
* @return this object
|
||||
*/
|
||||
public ListTagBuilder add(Tag value) {
|
||||
public ListTagBuilder<V, LT> add(Tag<V, LT> value) {
|
||||
checkNotNull(value);
|
||||
builder.add(value.asBinaryTag());
|
||||
builder.add(value.toLinTag());
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -69,9 +69,9 @@ public class ListTagBuilder {
|
||||
* @param value a list of tags
|
||||
* @return this object
|
||||
*/
|
||||
public ListTagBuilder addAll(Collection<? extends Tag> value) {
|
||||
public ListTagBuilder<V, LT> addAll(Collection<? extends Tag<V, LT>> value) {
|
||||
checkNotNull(value);
|
||||
for (Tag v : value) {
|
||||
for (Tag<V, LT> v : value) {
|
||||
add(v);
|
||||
}
|
||||
return this;
|
||||
@ -82,8 +82,8 @@ public class ListTagBuilder {
|
||||
*
|
||||
* @return the new list tag
|
||||
*/
|
||||
public ListTag build() {
|
||||
return new ListTag(this.builder.build());
|
||||
public ListTag<V, LT> build() {
|
||||
return new ListTag<>(this.builder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,8 +91,8 @@ public class ListTagBuilder {
|
||||
*
|
||||
* @return a new builder
|
||||
*/
|
||||
public static ListTagBuilder create(Class<? extends Tag> type) {
|
||||
return new ListTagBuilder(type);
|
||||
public static <V, LT extends LinTag<V>> ListTagBuilder<V, LT> create(Class<? extends Tag<V, LT>> type) {
|
||||
return new ListTagBuilder<>(type);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -100,22 +100,24 @@ public class ListTagBuilder {
|
||||
*
|
||||
* @return a new builder
|
||||
*/
|
||||
public static ListTagBuilder createWith(Tag... entries) {
|
||||
@SafeVarargs
|
||||
public static <V, LT extends LinTag<V>> ListTagBuilder<V, LT> createWith(Tag<V, LT>... entries) {
|
||||
checkNotNull(entries);
|
||||
|
||||
if (entries.length == 0) {
|
||||
throw new IllegalArgumentException("This method needs an array of at least one entry");
|
||||
}
|
||||
|
||||
Class<? extends Tag> type = entries[0].getClass();
|
||||
for (int i = 1; i < entries.length; i++) {
|
||||
if (!type.isInstance(entries[i])) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Tag<V, LT>> type = (Class<? extends Tag<V, LT>>) entries[0].getClass();
|
||||
ListTagBuilder<V, LT> builder = new ListTagBuilder<>(type);
|
||||
for (Tag<V, LT> entry : entries) {
|
||||
if (!type.isInstance(entry)) {
|
||||
throw new IllegalArgumentException("An array of different tag types was provided");
|
||||
}
|
||||
builder.add(entry);
|
||||
}
|
||||
|
||||
ListTagBuilder builder = new ListTagBuilder(type);
|
||||
builder.addAll(Arrays.asList(entries));
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
@ -19,44 +19,33 @@
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag;
|
||||
import org.enginehub.linbus.tree.LinLongArrayTag;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Long_Array} tag.
|
||||
*
|
||||
* @deprecated Use {@link LongArrayBinaryTag}.
|
||||
* @deprecated Use {@link LinLongArrayTag}.
|
||||
*/
|
||||
@Deprecated
|
||||
public class LongArrayTag extends Tag {
|
||||
|
||||
private final LongArrayBinaryTag innerTag;
|
||||
|
||||
public class LongArrayTag extends Tag<long[], LinLongArrayTag> {
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
*
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public LongArrayTag(long[] value) {
|
||||
super();
|
||||
checkNotNull(value);
|
||||
this.innerTag = LongArrayBinaryTag.of(value);
|
||||
this(LinLongArrayTag.of(checkNotNull(value)));
|
||||
}
|
||||
|
||||
public LongArrayTag(LongArrayBinaryTag adventureTag) {
|
||||
super();
|
||||
this.innerTag = adventureTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongArrayBinaryTag asBinaryTag() {
|
||||
return this.innerTag;
|
||||
public LongArrayTag(LinLongArrayTag tag) {
|
||||
super(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getValue() {
|
||||
return innerTag.value();
|
||||
return linTag.value();
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
@ -19,41 +19,32 @@
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.LongBinaryTag;
|
||||
import com.fastasyncworldedit.core.jnbt.NumberTag;
|
||||
import org.enginehub.linbus.tree.LinLongTag;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Long} tag.
|
||||
*
|
||||
* @deprecated Use {@link LongBinaryTag}.
|
||||
* @deprecated Use {@link LinLongTag}.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class LongTag extends Tag {
|
||||
|
||||
private final LongBinaryTag innerTag;
|
||||
|
||||
public final class LongTag extends NumberTag<LinLongTag> {
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
*
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public LongTag(long value) {
|
||||
super();
|
||||
this.innerTag = LongBinaryTag.of(value);
|
||||
this(LinLongTag.of(value));
|
||||
}
|
||||
|
||||
public LongTag(LongBinaryTag adventureTag) {
|
||||
super();
|
||||
this.innerTag = adventureTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongBinaryTag asBinaryTag() {
|
||||
return this.innerTag;
|
||||
public LongTag(LinLongTag tag) {
|
||||
super(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getValue() {
|
||||
return innerTag.value();
|
||||
return linTag.value();
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
@ -50,7 +50,6 @@ public final class NBTConstants {
|
||||
* Default private constructor.
|
||||
*/
|
||||
private NBTConstants() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,37 +59,27 @@ public final class NBTConstants {
|
||||
* @return tag class
|
||||
* @throws IllegalArgumentException thrown if the tag ID is not valid
|
||||
*/
|
||||
public static Class<? extends Tag> getClassFromType(int id) {
|
||||
switch (id) {
|
||||
case TYPE_END:
|
||||
return EndTag.class;
|
||||
case TYPE_BYTE:
|
||||
return ByteTag.class;
|
||||
case TYPE_SHORT:
|
||||
return ShortTag.class;
|
||||
case TYPE_INT:
|
||||
return IntTag.class;
|
||||
case TYPE_LONG:
|
||||
return LongTag.class;
|
||||
case TYPE_FLOAT:
|
||||
return FloatTag.class;
|
||||
case TYPE_DOUBLE:
|
||||
return DoubleTag.class;
|
||||
case TYPE_BYTE_ARRAY:
|
||||
return ByteArrayTag.class;
|
||||
case TYPE_STRING:
|
||||
return StringTag.class;
|
||||
case TYPE_LIST:
|
||||
return ListTag.class;
|
||||
case TYPE_COMPOUND:
|
||||
return CompoundTag.class;
|
||||
case TYPE_INT_ARRAY:
|
||||
return IntArrayTag.class;
|
||||
case TYPE_LONG_ARRAY:
|
||||
return LongArrayTag.class;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown tag type ID of " + id);
|
||||
}
|
||||
public static Class<? extends Tag<?, ?>> getClassFromType(int id) {
|
||||
return switch (id) {
|
||||
case TYPE_END -> EndTag.class;
|
||||
case TYPE_BYTE -> ByteTag.class;
|
||||
case TYPE_SHORT -> ShortTag.class;
|
||||
case TYPE_INT -> IntTag.class;
|
||||
case TYPE_LONG -> LongTag.class;
|
||||
case TYPE_FLOAT -> FloatTag.class;
|
||||
case TYPE_DOUBLE -> DoubleTag.class;
|
||||
case TYPE_BYTE_ARRAY -> ByteArrayTag.class;
|
||||
case TYPE_STRING -> StringTag.class;
|
||||
case TYPE_LIST -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
var aClass = (Class<? extends Tag<?, ?>>) (Class<?>) ListTag.class;
|
||||
yield aClass;
|
||||
}
|
||||
case TYPE_COMPOUND -> CompoundTag.class;
|
||||
case TYPE_INT_ARRAY -> IntArrayTag.class;
|
||||
case TYPE_LONG_ARRAY -> LongArrayTag.class;
|
||||
default -> throw new IllegalArgumentException("Unknown tag type ID of " + id);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ package com.sk89q.jnbt;
|
||||
|
||||
import com.fastasyncworldedit.core.jnbt.streamer.StreamDelegate;
|
||||
import com.fastasyncworldedit.core.jnbt.streamer.ValueReader;
|
||||
import org.enginehub.linbus.stream.LinBinaryIO;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.DataInputStream;
|
||||
@ -44,8 +45,9 @@ import java.util.Map;
|
||||
* https://minecraft.gamepedia.com/NBT_format</a>.
|
||||
* </p>
|
||||
*
|
||||
* @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8.
|
||||
* @deprecated JNBT is being removed for lin-bus in WorldEdit 8, use {@link LinBinaryIO} instead
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
@Deprecated(forRemoval = true)
|
||||
public final class NBTInputStream implements Closeable {
|
||||
|
||||
@ -77,7 +79,6 @@ public final class NBTInputStream implements Closeable {
|
||||
* Reads an NBT tag from the stream.
|
||||
*
|
||||
* @return The tag that was read.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public NamedTag readNamedTag() throws IOException {
|
||||
return readNamedTag(0);
|
||||
@ -571,7 +572,7 @@ public final class NBTInputStream implements Closeable {
|
||||
* @return the tag
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
private Tag readTagPayload(int type, int depth) throws IOException {
|
||||
public Tag readTagPayload(int type, int depth) throws IOException { //FAWE - public
|
||||
switch (type) {
|
||||
case NBTConstants.TYPE_END:
|
||||
if (depth == 0) {
|
||||
@ -617,7 +618,7 @@ public final class NBTInputStream implements Closeable {
|
||||
|
||||
return new ListTag(NBTUtils.getTypeClass(childType), tagList);
|
||||
case NBTConstants.TYPE_COMPOUND:
|
||||
Map<String, Tag> tagMap = new HashMap<>();
|
||||
Map<String, Tag<?, ?>> tagMap = new HashMap<>();
|
||||
while (true) {
|
||||
NamedTag namedTag = readNamedTag(depth + 1);
|
||||
Tag tag = namedTag.getTag();
|
||||
|
@ -20,6 +20,7 @@
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.fastasyncworldedit.core.internal.io.LittleEndianOutputStream;
|
||||
import org.enginehub.linbus.stream.LinBinaryIO;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.DataOutput;
|
||||
@ -44,8 +45,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
* https://minecraft.gamepedia.com/NBT_format</a>.
|
||||
* </p>
|
||||
*
|
||||
* @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8.
|
||||
* @deprecated JNBT is being removed for lin-bus in WorldEdit 8, use {@link LinBinaryIO} instead
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
@Deprecated(forRemoval = true)
|
||||
public final class NBTOutputStream extends OutputStream implements Closeable, DataOutput {
|
||||
|
||||
@ -61,7 +63,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da
|
||||
* @param os The output stream.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public NBTOutputStream(OutputStream os) throws IOException {
|
||||
public NBTOutputStream(OutputStream os) {
|
||||
this(os instanceof DataOutput ? (DataOutput) os : new DataOutputStream(os));
|
||||
}
|
||||
|
||||
@ -91,11 +93,11 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da
|
||||
* @param tag The tag to write.
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public void writeNamedTag(String name, Tag tag) throws IOException {
|
||||
public void writeNamedTag(String name, Tag<?, ?> tag) throws IOException {
|
||||
checkNotNull(name);
|
||||
checkNotNull(tag);
|
||||
|
||||
int type = NBTUtils.getTypeCode(tag.getClass());
|
||||
int type = tag.getTypeCode();
|
||||
writeNamedTagName(name, type);
|
||||
|
||||
if (type == NBTConstants.TYPE_END) {
|
||||
@ -196,7 +198,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da
|
||||
}
|
||||
|
||||
public void writeTag(Tag tag) throws IOException {
|
||||
int type = NBTUtils.getTypeCode(tag.getClass());
|
||||
int type = tag.getTypeCode();
|
||||
os.writeByte(type);
|
||||
writeTagPayload(tag);
|
||||
}
|
||||
@ -212,7 +214,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
public void writeTagPayload(Tag tag) throws IOException {
|
||||
int type = NBTUtils.getTypeCode(tag.getClass());
|
||||
int type = tag.getTypeCode();
|
||||
switch (type) {
|
||||
case NBTConstants.TYPE_END:
|
||||
writeEndTagPayload((EndTag) tag);
|
||||
@ -287,7 +289,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
private void writeCompoundTagPayload(CompoundTag tag) throws IOException {
|
||||
for (Map.Entry<String, Tag> entry : tag.getValue().entrySet()) {
|
||||
for (Map.Entry<String, Tag<?, ?>> entry : tag.getValue().entrySet()) {
|
||||
writeNamedTag(entry.getKey(), entry.getValue());
|
||||
}
|
||||
os.writeByte((byte) 0); // end tag - better way?
|
||||
@ -300,7 +302,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*/
|
||||
private void writeListTagPayload(ListTag tag) throws IOException {
|
||||
Class<? extends Tag> clazz = tag.getType();
|
||||
Class<? extends Tag<?, ?>> clazz = tag.getType();
|
||||
if (clazz == null) {
|
||||
clazz = CompoundTag.class;
|
||||
}
|
||||
|
@ -20,7 +20,6 @@
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTagTypes;
|
||||
import com.sk89q.worldedit.world.storage.InvalidFormatException;
|
||||
|
||||
import java.util.Map;
|
||||
@ -33,6 +32,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
*
|
||||
* @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8.
|
||||
*/
|
||||
@SuppressWarnings("ALL")
|
||||
@Deprecated
|
||||
public final class NBTUtils {
|
||||
|
||||
@ -48,7 +48,7 @@ public final class NBTUtils {
|
||||
* @param clazz the tag class
|
||||
* @return The type name.
|
||||
*/
|
||||
public static String getTypeName(Class<? extends Tag> clazz) {
|
||||
public static String getTypeName(Class<? extends Tag<?, ?>> clazz) {
|
||||
if (clazz.equals(ByteArrayTag.class)) {
|
||||
return "TAG_Byte_Array";
|
||||
} else if (clazz.equals(ByteTag.class)) {
|
||||
@ -77,7 +77,7 @@ public final class NBTUtils {
|
||||
return "TAG_Long_Array";
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid tag class ("
|
||||
+ clazz.getName() + ").");
|
||||
+ clazz.getName() + ").");
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,11 +88,35 @@ public final class NBTUtils {
|
||||
* @return The type code.
|
||||
* @throws IllegalArgumentException if the tag class is invalid.
|
||||
*/
|
||||
public static int getTypeCode(Class<? extends Tag> clazz) {
|
||||
if (LazyCompoundTag.class.isAssignableFrom(clazz)) {
|
||||
return BinaryTagTypes.COMPOUND.id();
|
||||
public static int getTypeCode(Class<? extends Tag<?, ?>> clazz) {
|
||||
if (clazz == ByteArrayTag.class) {
|
||||
return NBTConstants.TYPE_BYTE_ARRAY;
|
||||
} else if (clazz == ByteTag.class) {
|
||||
return NBTConstants.TYPE_BYTE;
|
||||
} else if (clazz == CompoundTag.class) {
|
||||
return NBTConstants.TYPE_COMPOUND;
|
||||
} else if (clazz == DoubleTag.class) {
|
||||
return NBTConstants.TYPE_DOUBLE;
|
||||
} else if (clazz == EndTag.class) {
|
||||
return NBTConstants.TYPE_END;
|
||||
} else if (clazz == FloatTag.class) {
|
||||
return NBTConstants.TYPE_FLOAT;
|
||||
} else if (clazz == IntArrayTag.class) {
|
||||
return NBTConstants.TYPE_INT_ARRAY;
|
||||
} else if (clazz == IntTag.class) {
|
||||
return NBTConstants.TYPE_INT;
|
||||
} else if (clazz.equals(ListTag.class) /* I hate this, it wouldn't do == b/c generics */) {
|
||||
return NBTConstants.TYPE_LIST;
|
||||
} else if (clazz == LongArrayTag.class) {
|
||||
return NBTConstants.TYPE_LONG_ARRAY;
|
||||
} else if (clazz == LongTag.class) {
|
||||
return NBTConstants.TYPE_LONG;
|
||||
} else if (clazz == ShortTag.class) {
|
||||
return NBTConstants.TYPE_SHORT;
|
||||
} else if (clazz == StringTag.class) {
|
||||
return NBTConstants.TYPE_STRING;
|
||||
}
|
||||
return AdventureNBTConverter.getAdventureType(clazz).id();
|
||||
throw new IllegalArgumentException("Invalid tag class (" + clazz.getName() + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,38 +126,8 @@ public final class NBTUtils {
|
||||
* @return The class.
|
||||
* @throws IllegalArgumentException if the tag type is invalid.
|
||||
*/
|
||||
public static Class<? extends Tag> getTypeClass(int type) {
|
||||
switch (type) {
|
||||
case NBTConstants.TYPE_END:
|
||||
return EndTag.class;
|
||||
case NBTConstants.TYPE_BYTE:
|
||||
return ByteTag.class;
|
||||
case NBTConstants.TYPE_SHORT:
|
||||
return ShortTag.class;
|
||||
case NBTConstants.TYPE_INT:
|
||||
return IntTag.class;
|
||||
case NBTConstants.TYPE_LONG:
|
||||
return LongTag.class;
|
||||
case NBTConstants.TYPE_FLOAT:
|
||||
return FloatTag.class;
|
||||
case NBTConstants.TYPE_DOUBLE:
|
||||
return DoubleTag.class;
|
||||
case NBTConstants.TYPE_BYTE_ARRAY:
|
||||
return ByteArrayTag.class;
|
||||
case NBTConstants.TYPE_STRING:
|
||||
return StringTag.class;
|
||||
case NBTConstants.TYPE_LIST:
|
||||
return ListTag.class;
|
||||
case NBTConstants.TYPE_COMPOUND:
|
||||
return CompoundTag.class;
|
||||
case NBTConstants.TYPE_INT_ARRAY:
|
||||
return IntArrayTag.class;
|
||||
case NBTConstants.TYPE_LONG_ARRAY:
|
||||
return LongArrayTag.class;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid tag type : " + type
|
||||
+ ".");
|
||||
}
|
||||
public static Class<? extends Tag<?, ?>> getTypeClass(int type) {
|
||||
return NBTConstants.getClassFromType(type);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,7 +139,7 @@ public final class NBTUtils {
|
||||
* @param listTag the list tag
|
||||
* @return a vector
|
||||
*/
|
||||
public static Vector3 toVector(ListTag listTag) {
|
||||
public static Vector3 toVector(ListTag<?, ?> listTag) {
|
||||
checkNotNull(listTag);
|
||||
return Vector3.at(listTag.asDouble(0), listTag.asDouble(1), listTag.asDouble(2));
|
||||
}
|
||||
@ -159,12 +153,12 @@ public final class NBTUtils {
|
||||
* @return child tag
|
||||
* @throws InvalidFormatException if the format of the items is invalid
|
||||
*/
|
||||
public static <T extends Tag> T getChildTag(Map<String, Tag> items, String key, Class<T> expected) throws
|
||||
public static <T extends Tag<?, ?>> T getChildTag(Map<String, Tag<?, ?>> items, String key, Class<T> expected) throws
|
||||
InvalidFormatException {
|
||||
if (!items.containsKey(key)) {
|
||||
throw new InvalidFormatException("Missing a \"" + key + "\" tag");
|
||||
}
|
||||
Tag tag = items.get(key);
|
||||
Tag<?, ?> tag = items.get(key);
|
||||
if (!expected.isInstance(tag)) {
|
||||
throw new InvalidFormatException(key + " tag is not of tag type " + expected.getName());
|
||||
}
|
||||
@ -179,7 +173,7 @@ public final class NBTUtils {
|
||||
* @param uuid {@link UUID} to add
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public static void addUUIDToMap(Map<String, Tag> map, UUID uuid) {
|
||||
public static void addUUIDToMap(Map<String, Tag<?, ?>> map, UUID uuid) {
|
||||
int[] uuidArray = new int[4];
|
||||
uuidArray[0] = (int) (uuid.getMostSignificantBits() >> 32);
|
||||
uuidArray[1] = (int) uuid.getMostSignificantBits();
|
||||
|
@ -30,7 +30,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
public class NamedTag {
|
||||
|
||||
private final String name;
|
||||
private final Tag tag;
|
||||
private final Tag<?, ?> tag;
|
||||
|
||||
/**
|
||||
* Create a new named tag.
|
||||
@ -38,7 +38,7 @@ public class NamedTag {
|
||||
* @param name the name
|
||||
* @param tag the tag
|
||||
*/
|
||||
public NamedTag(String name, Tag tag) {
|
||||
public NamedTag(String name, Tag<?, ?> tag) {
|
||||
checkNotNull(name);
|
||||
checkNotNull(tag);
|
||||
this.name = name;
|
||||
@ -59,7 +59,7 @@ public class NamedTag {
|
||||
*
|
||||
* @return the tag
|
||||
*/
|
||||
public Tag getTag() {
|
||||
public Tag<?, ?> getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
|
@ -19,41 +19,32 @@
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.ShortBinaryTag;
|
||||
import com.fastasyncworldedit.core.jnbt.NumberTag;
|
||||
import org.enginehub.linbus.tree.LinShortTag;
|
||||
|
||||
/**
|
||||
* The {@code TAG_Short} tag.
|
||||
*
|
||||
* @deprecated Use {@link ShortBinaryTag}.
|
||||
* @deprecated Use {@link LinShortTag}.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class ShortTag extends Tag {
|
||||
|
||||
private final ShortBinaryTag innerTag;
|
||||
|
||||
public final class ShortTag extends NumberTag<LinShortTag> {
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
*
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public ShortTag(short value) {
|
||||
super();
|
||||
this.innerTag = ShortBinaryTag.of(value);
|
||||
super(LinShortTag.of(value));
|
||||
}
|
||||
|
||||
public ShortTag(ShortBinaryTag adventureTag) {
|
||||
super();
|
||||
this.innerTag = adventureTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShortBinaryTag asBinaryTag() {
|
||||
return this.innerTag;
|
||||
public ShortTag(LinShortTag tag) {
|
||||
super(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Short getValue() {
|
||||
return innerTag.value();
|
||||
return linTag.value();
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
@ -19,44 +19,33 @@
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.StringBinaryTag;
|
||||
import org.enginehub.linbus.tree.LinStringTag;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* The {@code TAG_String} tag.
|
||||
*
|
||||
* @deprecated Use {@link StringBinaryTag}.
|
||||
* @deprecated Use {@link LinStringTag}.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class StringTag extends Tag {
|
||||
|
||||
private final StringBinaryTag innerTag;
|
||||
|
||||
public final class StringTag extends Tag<String, LinStringTag> {
|
||||
/**
|
||||
* Creates the tag with an empty name.
|
||||
*
|
||||
* @param value the value of the tag
|
||||
*/
|
||||
public StringTag(String value) {
|
||||
super();
|
||||
checkNotNull(value);
|
||||
this.innerTag = StringBinaryTag.of(value);
|
||||
super(LinStringTag.of(checkNotNull(value)));
|
||||
}
|
||||
|
||||
public StringTag(StringBinaryTag adventureTag) {
|
||||
super();
|
||||
this.innerTag = adventureTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBinaryTag asBinaryTag() {
|
||||
return this.innerTag;
|
||||
public StringTag(LinStringTag tag) {
|
||||
super(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return innerTag.value();
|
||||
return linTag.value();
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
@ -19,26 +19,43 @@
|
||||
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTagLike;
|
||||
import org.enginehub.linbus.tree.LinTag;
|
||||
import org.enginehub.linbus.tree.ToLinTag;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Represents a NBT tag.
|
||||
*
|
||||
* @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8.
|
||||
* @deprecated JNBT is being removed for lin-bus in WorldEdit 8, use {@link LinTag} instead
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public abstract class Tag implements BinaryTagLike {
|
||||
@Deprecated
|
||||
public abstract class Tag<V, LT extends LinTag<? extends V>> implements ToLinTag<LT> {
|
||||
|
||||
protected final LT linTag;
|
||||
|
||||
protected Tag(LT linTag) {
|
||||
this.linTag = linTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of this tag.
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
public abstract Object getValue();
|
||||
public V getValue() {
|
||||
return linTag.value();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return asBinaryTag().toString();
|
||||
return toLinTag().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public LT toLinTag() {
|
||||
return linTag;
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
@ -3881,7 +3881,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
@Override
|
||||
public void addSchems(Region region, Mask mask, List<ClipboardHolder> clipboards, int rarity, boolean rotate) throws
|
||||
WorldEditException {
|
||||
spawnResource(region, new SchemGen(mask, this, clipboards, rotate), rarity, 1);
|
||||
spawnResource(region, new SchemGen(mask, this, clipboards, rotate, region), rarity, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -76,7 +76,6 @@ import com.sk89q.worldedit.util.Countable;
|
||||
import com.sk89q.worldedit.util.HandSide;
|
||||
import com.sk89q.worldedit.util.Identifiable;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
@ -84,6 +83,8 @@ import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.snapshot.experimental.Snapshot;
|
||||
import com.zaxxer.sparsebits.SparseBitSet;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
import org.enginehub.linbus.tree.LinTagType;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
@ -499,7 +500,7 @@ public class LocalSession implements TextureHolder {
|
||||
if (Settings.settings().HISTORY.USE_DISK) {
|
||||
LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE;
|
||||
}
|
||||
if (changeSet.size() == 0) {
|
||||
if (changeSet.longSize() == 0) {
|
||||
return;
|
||||
}
|
||||
loadSessionHistoryFromDisk(player.getUniqueId(), world);
|
||||
@ -1351,7 +1352,7 @@ public class LocalSession implements TextureHolder {
|
||||
* @param item the item type
|
||||
* @param tool the tool to set, which can be {@code null}
|
||||
* @throws InvalidToolBindException if the item can't be bound to that item
|
||||
* @since TODO
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public void setTool(BaseItem item, @Nullable Tool tool) throws InvalidToolBindException {
|
||||
if (item.getType().hasBlockType()) {
|
||||
@ -1513,13 +1514,13 @@ public class LocalSession implements TextureHolder {
|
||||
|
||||
BaseBlock block = ServerCUIHandler.createStructureBlock(player);
|
||||
if (block != null) {
|
||||
CompoundBinaryTag tags = Objects.requireNonNull(
|
||||
block.getNbt(), "createStructureBlock should return nbt"
|
||||
LinCompoundTag tags = Objects.requireNonNull(
|
||||
block.getNbt(), "createStructureBlock should return nbt"
|
||||
);
|
||||
BlockVector3 tempCuiTemporaryBlock = BlockVector3.at(
|
||||
tags.getInt("x"),
|
||||
tags.getInt("y"),
|
||||
tags.getInt("z")
|
||||
tags.getTag("x", LinTagType.intTag()).valueAsInt(),
|
||||
tags.getTag("y", LinTagType.intTag()).valueAsInt(),
|
||||
tags.getTag("z", LinTagType.intTag()).valueAsInt()
|
||||
);
|
||||
// If it's null, we don't need to do anything. The old was already removed.
|
||||
if (cuiTemporaryBlock != null && !tempCuiTemporaryBlock.equals(cuiTemporaryBlock)) {
|
||||
@ -1918,7 +1919,7 @@ public class LocalSession implements TextureHolder {
|
||||
* Get the preferred wand item for this user, or {@code null} to use the default
|
||||
*
|
||||
* @return item id of wand item, or {@code null}
|
||||
* @since TODO
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public BaseItem getWandBaseItem() {
|
||||
return wandItem == null ? null : new BaseItem(wandItem.getType(), wandItem.getNbtReference());
|
||||
@ -1928,7 +1929,7 @@ public class LocalSession implements TextureHolder {
|
||||
* Get the preferred navigation wand item for this user, or {@code null} to use the default
|
||||
*
|
||||
* @return item id of nav wand item, or {@code null}
|
||||
* @since TODO
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public BaseItem getNavWandBaseItem() {
|
||||
return navWandItem == null ? null : new BaseItem(navWandItem.getType(), navWandItem.getNbtReference());
|
||||
|
@ -21,6 +21,7 @@ package com.sk89q.worldedit;
|
||||
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.fastasyncworldedit.core.exception.BrushRadiusLimitException;
|
||||
import com.fastasyncworldedit.core.exception.OutsideWorldBoundsException;
|
||||
import com.fastasyncworldedit.core.exception.RadiusLimitException;
|
||||
import com.fastasyncworldedit.core.extension.factory.TransformFactory;
|
||||
import com.fastasyncworldedit.core.extent.ResettableExtent;
|
||||
@ -46,6 +47,7 @@ import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.Locatable;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.extension.platform.PlatformManager;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
@ -463,7 +465,7 @@ public final class WorldEdit {
|
||||
/**
|
||||
* @deprecated Use {@link WorldEdit#checkMaxBrushRadius(Expression, Actor)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "TODO")
|
||||
@Deprecated(forRemoval = true, since = "2.11.0")
|
||||
public void checkMaxBrushRadius(Expression radius) throws MaxBrushRadiusException {
|
||||
double val = radius.evaluate();
|
||||
checkArgument(val >= 0, "Radius must be a positive number.");
|
||||
@ -480,7 +482,7 @@ public final class WorldEdit {
|
||||
* @param radius Radius to check
|
||||
* @param actor Actor to check for
|
||||
* @throws MaxRadiusException If given radius larger than allowed
|
||||
* @since TODO
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public void checkMaxRadius(double radius, Actor actor) {
|
||||
int max = actor.getLimit().MAX_RADIUS;
|
||||
@ -495,7 +497,7 @@ public final class WorldEdit {
|
||||
* @param radius Radius to check
|
||||
* @param actor Actor to check for
|
||||
* @throws MaxRadiusException If given radius larger than allowed
|
||||
* @since TODO
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public void checkMaxBrushRadius(double radius, Actor actor) {
|
||||
int max = actor.getLimit().MAX_BRUSH_RADIUS;
|
||||
@ -510,7 +512,7 @@ public final class WorldEdit {
|
||||
* @param expression Radius to check
|
||||
* @param actor Actor to check for
|
||||
* @throws BrushRadiusLimitException If given radius larger than allowed
|
||||
* @since TODO
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public void checkMaxBrushRadius(Expression expression, Actor actor) {
|
||||
double radius = expression.evaluate();
|
||||
@ -520,6 +522,20 @@ public final class WorldEdit {
|
||||
throw new BrushRadiusLimitException(max);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given position is contained by the extent's min/max height
|
||||
*
|
||||
* @param position Position to check
|
||||
* @param extent Extent to check in
|
||||
* @throws OutsideWorldBoundsException If the position is outside the world height limits
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public void checkExtentHeightBounds(BlockVector3 position, Extent extent) {
|
||||
if (position.y() < extent.getMinY() || position.y() > extent.getMaxY()) {
|
||||
throw new OutsideWorldBoundsException(position.y());
|
||||
}
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
/**
|
||||
|
@ -20,15 +20,13 @@
|
||||
package com.sk89q.worldedit.blocks;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.util.concurrency.LazyReference;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.TagStringIO;
|
||||
import com.sk89q.worldedit.world.NbtValued;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import org.enginehub.linbus.format.snbt.LinStringIO;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -42,9 +40,7 @@ public class BaseItem implements NbtValued {
|
||||
|
||||
private ItemType itemType;
|
||||
@Nullable
|
||||
//FAWE start - Use LR & CBT over CompoundTag
|
||||
private LazyReference<CompoundBinaryTag> nbtData;
|
||||
//FAWE end
|
||||
private LazyReference<LinCompoundTag> nbtData;
|
||||
|
||||
/**
|
||||
* Construct the object.
|
||||
@ -56,6 +52,29 @@ public class BaseItem implements NbtValued {
|
||||
this.itemType = itemType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the object.
|
||||
*
|
||||
* @param itemType Type of the item
|
||||
* @param nbtData NBT Compound tag
|
||||
*/
|
||||
@Deprecated
|
||||
public BaseItem(ItemType itemType, @Nullable CompoundTag nbtData) {
|
||||
this(itemType, nbtData == null ? null : LazyReference.from(nbtData::toLinTag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the object.
|
||||
*
|
||||
* @param itemType Type of the item
|
||||
* @param tag NBT Compound tag
|
||||
*/
|
||||
public BaseItem(ItemType itemType, @Nullable LazyReference<LinCompoundTag> tag) {
|
||||
checkNotNull(itemType);
|
||||
this.itemType = itemType;
|
||||
this.nbtData = tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of item.
|
||||
*
|
||||
@ -77,29 +96,6 @@ public class BaseItem implements NbtValued {
|
||||
|
||||
//FAWE start
|
||||
|
||||
/**
|
||||
* Construct the object.
|
||||
*
|
||||
* @param itemType Type of the item
|
||||
* @param nbtData NBT Compound tag
|
||||
*/
|
||||
@Deprecated
|
||||
public BaseItem(ItemType itemType, @Nullable CompoundTag nbtData) {
|
||||
this(itemType, nbtData == null ? null : LazyReference.from(nbtData::asBinaryTag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the object.
|
||||
*
|
||||
* @param itemType Type of the item
|
||||
* @param tag NBT Compound tag
|
||||
*/
|
||||
public BaseItem(ItemType itemType, @Nullable LazyReference<CompoundBinaryTag> tag) {
|
||||
checkNotNull(itemType);
|
||||
this.itemType = itemType;
|
||||
this.nbtData = tag;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Nullable
|
||||
public Object getNativeItem() {
|
||||
@ -108,25 +104,20 @@ public class BaseItem implements NbtValued {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public LazyReference<CompoundBinaryTag> getNbtReference() {
|
||||
public LazyReference<LinCompoundTag> getNbtReference() {
|
||||
return this.nbtData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNbtReference(@Nullable LazyReference<CompoundBinaryTag> nbtData) {
|
||||
public void setNbtReference(@Nullable LazyReference<LinCompoundTag> nbtData) {
|
||||
this.nbtData = nbtData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String nbtString = "";
|
||||
LazyReference<CompoundBinaryTag> nbtData = this.nbtData;
|
||||
if (nbtData != null) {
|
||||
try {
|
||||
nbtString = TagStringIO.get().asString(nbtData.getValue());
|
||||
} catch (IOException e) {
|
||||
WorldEdit.logger.error("Failed to serialize NBT of Item", e);
|
||||
}
|
||||
nbtString = LinStringIO.writeToString(nbtData.getValue());
|
||||
}
|
||||
|
||||
return getType().id() + nbtString;
|
||||
|
@ -24,8 +24,8 @@ import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.util.concurrency.LazyReference;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
|
||||
/**
|
||||
* Represents a stack of BaseItems.
|
||||
@ -70,6 +70,18 @@ public class BaseItemStack extends BaseItem {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the object.
|
||||
*
|
||||
* @param id The item type
|
||||
* @param tag Tag value
|
||||
* @param amount amount in the stack
|
||||
*/
|
||||
public BaseItemStack(ItemType id, LazyReference<LinCompoundTag> tag, int amount) {
|
||||
super(id, tag);
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of items in the stack.
|
||||
*
|
||||
@ -93,18 +105,4 @@ public class BaseItemStack extends BaseItem {
|
||||
.getRegistries().getItemRegistry().getRichName(this);
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
||||
/**
|
||||
* Construct the object.
|
||||
*
|
||||
* @param id The item type
|
||||
* @param tag Tag value
|
||||
* @param amount amount in the stack
|
||||
*/
|
||||
public BaseItemStack(ItemType id, LazyReference<CompoundBinaryTag> tag, int amount) {
|
||||
super(id, tag);
|
||||
this.amount = amount;
|
||||
}
|
||||
//FAWE end
|
||||
}
|
||||
|
@ -645,10 +645,10 @@ public class BrushCommands {
|
||||
@CommandPermissions("worldedit.brush.populateschematic")
|
||||
public void scatterSchemBrush(
|
||||
Player player, InjectedValueAccess context,
|
||||
@Arg(desc = "Mask")
|
||||
Mask mask,
|
||||
@Arg(name = "clipboard", desc = "Clipboard uri")
|
||||
String clipboardStr,
|
||||
@Arg(desc = "Mask of block to place on. Defaults to solid blocks.", def = "")
|
||||
Mask mask,
|
||||
@Arg(desc = "Expression", def = "30")
|
||||
Expression radius,
|
||||
@Arg(desc = "double", def = "50")
|
||||
|
@ -510,6 +510,7 @@ public class GeneralCommands {
|
||||
parserContext.setWorld(worldArg);
|
||||
parserContext.setSession(session);
|
||||
parserContext.setExtent(editSession);
|
||||
parserContext.setTryLegacy(actor.getLimit().ALLOW_LEGACY);
|
||||
Mask mask = worldEdit.getMaskFactory().parseFromInput(arg, parserContext);
|
||||
util = TextureUtil.fromMask(mask);
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ public class HistorySubCommands {
|
||||
long seconds = (System.currentTimeMillis() - edit.getBDFile().lastModified()) / 1000;
|
||||
String timeStr = MainUtil.secToTime(seconds);
|
||||
|
||||
int size = edit.size();
|
||||
long size = edit.longSize();
|
||||
boolean biomes = edit.getBioFile().exists();
|
||||
boolean createdEnts = edit.getEnttFile().exists();
|
||||
boolean removedEnts = edit.getEntfFile().exists();
|
||||
@ -335,7 +335,7 @@ public class HistorySubCommands {
|
||||
long seconds = (System.currentTimeMillis() - rollback.getBDFile().lastModified()) / 1000;
|
||||
String timeStr = MainUtil.secToTime(seconds);
|
||||
|
||||
int size = edit.size();
|
||||
long size = edit.longSize();
|
||||
|
||||
TranslatableComponent elem = Caption.of(
|
||||
"fawe.worldedit.history.find.element",
|
||||
|
@ -345,7 +345,7 @@ public class SchematicCommands {
|
||||
: saveDir;
|
||||
File file;
|
||||
if (filename.startsWith("#")) {
|
||||
format = ClipboardFormats.findByAlias(formatName);
|
||||
format = noExplicitFormat ? null :ClipboardFormats.findByAlias(formatName);
|
||||
String[] extensions;
|
||||
if (format != null) {
|
||||
extensions = format.getFileExtensions().toArray(new String[0]);
|
||||
@ -365,11 +365,13 @@ public class SchematicCommands {
|
||||
actor.print(Caption.of("fawe.error.no-perm", "worldedit.schematic.load.other"));
|
||||
return;
|
||||
}
|
||||
if (noExplicitFormat && filename.matches(".*\\.[\\w].*")) {
|
||||
if (!noExplicitFormat) {
|
||||
format = ClipboardFormats.findByAlias(formatName);
|
||||
} else if ( filename.matches(".*\\.[\\w].*")) {
|
||||
format = ClipboardFormats
|
||||
.findByExtension(filename.substring(filename.lastIndexOf('.') + 1));
|
||||
.findByExplicitExtension(filename.substring(filename.lastIndexOf('.') + 1));
|
||||
} else {
|
||||
format = ClipboardFormats.findByAlias(formatName);
|
||||
format = null;
|
||||
}
|
||||
file = MainUtil.resolve(dir, filename, format, false);
|
||||
}
|
||||
@ -387,8 +389,10 @@ public class SchematicCommands {
|
||||
}
|
||||
if (format == null) {
|
||||
format = ClipboardFormats.findByFile(file);
|
||||
if (format == null) {
|
||||
actor.print(Caption.of("worldedit.schematic.unknown-format", TextComponent.of(formatName)));
|
||||
if (format == null) {if (noExplicitFormat) {
|
||||
actor.print(Caption.of("fawe.worldedit.schematic.schematic.load-failure", TextComponent.of(file.getName())));
|
||||
} else {
|
||||
actor.print(Caption.of("worldedit.schematic.unknown-format", TextComponent.of(formatName)));}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -408,6 +412,9 @@ public class SchematicCommands {
|
||||
} catch (IOException e) {
|
||||
actor.print(Caption.of("worldedit.schematic.file-not-exist", TextComponent.of(Objects.toString(e.getMessage()))));
|
||||
LOGGER.warn("Failed to load a saved clipboard", e);
|
||||
} catch (Exception e) {
|
||||
actor.print(Caption.of("fawe.worldedit.schematic.schematic.load-failure", TextComponent.of(e.getMessage())));
|
||||
LOGGER.error("Error loading a schematic", e);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
|
@ -242,6 +242,7 @@ public class UtilityCommands {
|
||||
we.checkMaxRadius(depth, actor);
|
||||
|
||||
BlockVector3 pos = session.getPlacementPosition(actor);
|
||||
we.checkExtentHeightBounds(pos, editSession);
|
||||
int affected = editSession.fillDirection(pos, pattern, radius, depth, direction);
|
||||
actor.print(Caption.of("worldedit.fill.created", TextComponent.of(affected)));
|
||||
return affected;
|
||||
@ -330,6 +331,7 @@ public class UtilityCommands {
|
||||
we.checkMaxRadius(radius, actor);
|
||||
|
||||
BlockVector3 pos = session.getPlacementPosition(actor);
|
||||
we.checkExtentHeightBounds(pos, editSession);
|
||||
int affected = editSession.fillXZ(pos, pattern, radius, depth, true);
|
||||
actor.print(Caption.of("worldedit.fillr.created", TextComponent.of(affected)));
|
||||
return affected;
|
||||
@ -357,7 +359,9 @@ public class UtilityCommands {
|
||||
double radius = radiusExp.evaluate();
|
||||
radius = Math.max(0, radius);
|
||||
we.checkMaxRadius(radius, actor);
|
||||
int affected = editSession.drainArea(session.getPlacementPosition(actor), radius, waterlogged, plants);
|
||||
BlockVector3 pos = session.getPlacementPosition(actor);
|
||||
we.checkExtentHeightBounds(pos, editSession);
|
||||
int affected = editSession.drainArea(pos, radius, waterlogged, plants);
|
||||
actor.print(Caption.of("worldedit.drain.drained", TextComponent.of(affected)));
|
||||
return affected;
|
||||
}
|
||||
@ -376,7 +380,9 @@ public class UtilityCommands {
|
||||
) throws WorldEditException {
|
||||
radius = Math.max(0, radius);
|
||||
we.checkMaxRadius(radius, actor);
|
||||
int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.LAVA);
|
||||
BlockVector3 pos = session.getPlacementPosition(actor);
|
||||
we.checkExtentHeightBounds(pos, editSession);
|
||||
int affected = editSession.fixLiquid(pos, radius, BlockTypes.LAVA);
|
||||
actor.print(Caption.of("worldedit.fixlava.fixed", TextComponent.of(affected)));
|
||||
return affected;
|
||||
}
|
||||
@ -395,7 +401,9 @@ public class UtilityCommands {
|
||||
) throws WorldEditException {
|
||||
radius = Math.max(0, radius);
|
||||
we.checkMaxRadius(radius, actor);
|
||||
int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.WATER);
|
||||
BlockVector3 pos = session.getPlacementPosition(actor);
|
||||
we.checkExtentHeightBounds(pos, editSession);
|
||||
int affected = editSession.fixLiquid(pos, radius, BlockTypes.WATER);
|
||||
actor.print(Caption.of("worldedit.fixwater.fixed", TextComponent.of(affected)));
|
||||
return affected;
|
||||
}
|
||||
|
@ -133,6 +133,7 @@ public class FactoryConverter<T> implements ArgumentConverter<T> {
|
||||
parserContext.setSession(session);
|
||||
parserContext.setRestricted(true);
|
||||
parserContext.setInjected(context);
|
||||
parserContext.setTryLegacy(actor.getLimit().ALLOW_LEGACY);
|
||||
|
||||
if (contextTweaker != null) {
|
||||
contextTweaker.accept(parserContext);
|
||||
|
@ -21,10 +21,10 @@ package com.sk89q.worldedit.entity;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.util.concurrency.LazyReference;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.world.NbtValued;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.entity.EntityTypes;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ -47,7 +47,7 @@ public class BaseEntity implements NbtValued {
|
||||
|
||||
private final EntityType type;
|
||||
@Nullable
|
||||
private LazyReference<CompoundBinaryTag> nbtData;
|
||||
private LazyReference<LinCompoundTag> nbtData;
|
||||
|
||||
/**
|
||||
* Create a new base entity.
|
||||
@ -69,7 +69,7 @@ public class BaseEntity implements NbtValued {
|
||||
* @param type the entity type
|
||||
* @param nbtData NBT data
|
||||
*/
|
||||
public BaseEntity(EntityType type, LazyReference<CompoundBinaryTag> nbtData) {
|
||||
public BaseEntity(EntityType type, LazyReference<LinCompoundTag> nbtData) {
|
||||
this(type);
|
||||
setNbtReference(nbtData);
|
||||
}
|
||||
@ -97,12 +97,12 @@ public class BaseEntity implements NbtValued {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public LazyReference<CompoundBinaryTag> getNbtReference() {
|
||||
public LazyReference<LinCompoundTag> getNbtReference() {
|
||||
return nbtData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNbtReference(@Nullable LazyReference<CompoundBinaryTag> nbtData) {
|
||||
public void setNbtReference(@Nullable LazyReference<LinCompoundTag> nbtData) {
|
||||
this.nbtData = nbtData;
|
||||
}
|
||||
|
||||
|
@ -22,19 +22,15 @@ package com.sk89q.worldedit.entity;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.extent.clipboard.DiskOptimizedClipboard;
|
||||
import com.fastasyncworldedit.core.internal.exception.FaweClipboardVersionMismatchException;
|
||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||
import com.fastasyncworldedit.core.util.MainUtil;
|
||||
import com.sk89q.worldedit.EmptyClipboardException;
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
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.extent.inventory.BlockBag;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.internal.util.DeprecationUtil;
|
||||
@ -43,7 +39,6 @@ import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.regions.RegionSelector;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.util.HandSide;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
@ -432,7 +427,8 @@ public interface Player extends Entity, Actor {
|
||||
} else if (Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT) {
|
||||
session.setClipboard(null);
|
||||
}
|
||||
if (Settings.settings().HISTORY.DELETE_ON_LOGOUT) {
|
||||
if (!Settings.settings().HISTORY.USE_DISK && Settings.settings().HISTORY.DELETE_ON_LOGOUT
|
||||
|| Settings.settings().HISTORY.USE_DISK && Settings.settings().HISTORY.DELETE_DISK_ON_LOGOUT) {
|
||||
session.clearHistory();
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ import com.sk89q.worldedit.extension.factory.parser.mask.NoiseMaskParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.mask.OffsetMaskParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.mask.RegionMaskParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.mask.SolidMaskParser;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.NoMatchException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
@ -132,6 +133,11 @@ public final class MaskFactory extends AbstractFactory<Mask> {
|
||||
|
||||
//FAWE start - rich mask parsing
|
||||
|
||||
@Override
|
||||
public Mask parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
return super.parseFromInput(input, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Mask getParsed(final String input, final List<Mask> masks) {
|
||||
return switch (masks.size()) {
|
||||
|
@ -60,7 +60,9 @@ import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.pattern.RandomStatePatternParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.pattern.SingleBlockPatternParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.pattern.TypeOrStateApplyingPatternParser;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.NoMatchException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.function.pattern.RandomPattern;
|
||||
import com.sk89q.worldedit.internal.registry.AbstractFactory;
|
||||
@ -130,6 +132,13 @@ public final class PatternFactory extends AbstractFactory<Pattern> {
|
||||
register(new VoronoiPatternParser(worldEdit));
|
||||
}
|
||||
|
||||
//FAWE start - rich pattern parsing
|
||||
|
||||
@Override
|
||||
public Pattern parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
return super.parseFromInput(input, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pattern getParsed(final String input, final List<Pattern> patterns) {
|
||||
switch (patterns.size()) {
|
||||
|
@ -20,7 +20,6 @@
|
||||
package com.sk89q.worldedit.extension.factory.parser;
|
||||
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.blocks.BaseItem;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
@ -35,13 +34,13 @@ import com.sk89q.worldedit.util.HandSide;
|
||||
import com.sk89q.worldedit.util.concurrency.LazyReference;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.TagStringIO;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.item.ItemTypes;
|
||||
import com.sk89q.worldedit.world.registry.LegacyMapper;
|
||||
import org.enginehub.linbus.format.snbt.LinStringIO;
|
||||
import org.enginehub.linbus.stream.exception.NbtParseException;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -59,7 +58,7 @@ public class DefaultItemParser extends InputParser<BaseItem> {
|
||||
@Override
|
||||
public BaseItem parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
ItemType itemType;
|
||||
CompoundBinaryTag itemNbtData = null;
|
||||
LinCompoundTag itemNbtData = null;
|
||||
|
||||
BaseItem item = null;
|
||||
|
||||
@ -128,20 +127,21 @@ public class DefaultItemParser extends InputParser<BaseItem> {
|
||||
}
|
||||
|
||||
if (nbtString != null) {
|
||||
LinCompoundTag otherTag;
|
||||
try {
|
||||
CompoundBinaryTag otherTag = TagStringIO.get().asCompound(nbtString);
|
||||
if (itemNbtData == null) {
|
||||
itemNbtData = otherTag;
|
||||
} else {
|
||||
itemNbtData.put(NbtUtils.getCompoundBinaryTagValues(otherTag));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
otherTag = LinStringIO.readFromStringUsing(nbtString, LinCompoundTag::readFrom);
|
||||
} catch (NbtParseException e) {
|
||||
throw new NoMatchException(TranslatableComponent.of(
|
||||
"worldedit.error.invalid-nbt",
|
||||
TextComponent.of(input),
|
||||
TextComponent.of(e.getMessage())
|
||||
));
|
||||
}
|
||||
if (itemNbtData == null) {
|
||||
itemNbtData = otherTag;
|
||||
} else {
|
||||
itemNbtData = itemNbtData.toBuilder().putAll(otherTag.value()).build();
|
||||
}
|
||||
}
|
||||
|
||||
item = new BaseItem(itemType, itemNbtData == null ? null : LazyReference.computed(itemNbtData));
|
||||
|
@ -49,6 +49,7 @@ public class BlocksMaskParser extends InputParser<Mask> {
|
||||
ParserContext tempContext = new ParserContext(context);
|
||||
tempContext.setRestricted(false);
|
||||
tempContext.setPreferringWildcard(true);
|
||||
tempContext.setTryLegacy(context.isTryingLegacy());
|
||||
try {
|
||||
Set<BaseBlock> holders = worldEdit.getBlockFactory().parseFromListInput(component, tempContext);
|
||||
if (holders.isEmpty()) {
|
||||
|
@ -216,7 +216,7 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the highest solid 'terrain' block.
|
||||
* Returns the highest solid 'terrain' (movement-blocking) block.
|
||||
*
|
||||
* @param x the X coordinate
|
||||
* @param z the Z coordinate
|
||||
@ -225,6 +225,9 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
* @return height of highest block found or 'minY'
|
||||
*/
|
||||
default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY) {
|
||||
maxY = Math.min(maxY, getMaxY());
|
||||
minY = Math.max(getMinY(), minY);
|
||||
|
||||
for (int y = maxY; y >= minY; --y) {
|
||||
BlockState block = getBlock(x, y, z);
|
||||
if (block.getBlockType().getMaterial().isMovementBlocker()) {
|
||||
@ -235,7 +238,7 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the highest solid 'terrain' block.
|
||||
* Returns the highest block matching the given mask.
|
||||
*
|
||||
* @param x the X coordinate
|
||||
* @param z the Z coordinate
|
||||
@ -245,6 +248,9 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
* @return height of highest block found or 'minY'
|
||||
*/
|
||||
default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY, Mask filter) {
|
||||
if (filter == null) {
|
||||
return getHighestTerrainBlock(x, z, minY, maxY);
|
||||
}
|
||||
maxY = Math.min(maxY, getMaxY());
|
||||
minY = Math.max(getMinY(), minY);
|
||||
|
||||
@ -259,9 +265,7 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nearest surface layer (up/down from start)
|
||||
* <p>
|
||||
* TODO: Someone understand this..?
|
||||
* Returns the nearest surface layer (up/down from start), where a layer is 1/16th of a block to allow for snow, liquid, etc.
|
||||
*
|
||||
* @param x x to search from
|
||||
* @param z y to search from
|
||||
@ -271,6 +275,9 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
* @return nearest surface layer
|
||||
*/
|
||||
default int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
|
||||
maxY = Math.min(maxY, getMaxY());
|
||||
minY = Math.max(getMinY(), minY);
|
||||
|
||||
int clearanceAbove = maxY - y;
|
||||
int clearanceBelow = y - minY;
|
||||
int clearance = Math.min(clearanceAbove, clearanceBelow);
|
||||
@ -331,6 +338,9 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
* @return The y value of the nearest terrain block
|
||||
*/
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) {
|
||||
maxY = Math.min(maxY, getMaxY());
|
||||
minY = Math.max(getMinY(), minY);
|
||||
|
||||
y = Math.max(minY, Math.min(maxY, y));
|
||||
int clearanceAbove = maxY - y;
|
||||
int clearanceBelow = y - minY;
|
||||
@ -438,6 +448,9 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
int failedMax,
|
||||
boolean ignoreAir
|
||||
) {
|
||||
maxY = Math.min(maxY, getMaxY());
|
||||
minY = Math.max(getMinY(), minY);
|
||||
|
||||
y = Math.max(minY, Math.min(maxY, y));
|
||||
int clearanceAbove = maxY - y;
|
||||
int clearanceBelow = y - minY;
|
||||
@ -494,7 +507,7 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
|
||||
default void addSchems(Region region, Mask mask, List<ClipboardHolder> clipboards, int rarity, boolean rotate) throws
|
||||
WorldEditException {
|
||||
spawnResource(region, new SchemGen(mask, this, clipboards, rotate), rarity, 1);
|
||||
spawnResource(region, new SchemGen(mask, this, clipboards, rotate, region), rarity, 1);
|
||||
}
|
||||
|
||||
default void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException {
|
||||
|
@ -186,7 +186,7 @@ public class BlockArrayClipboard implements Clipboard {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block) throws WorldEditException {
|
||||
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block) {
|
||||
if (region.contains(position)) {
|
||||
//FAWE - get points
|
||||
final int x = position.x();
|
||||
|
@ -19,28 +19,39 @@
|
||||
|
||||
package com.sk89q.worldedit.extent.clipboard.io;
|
||||
|
||||
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReader;
|
||||
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriter;
|
||||
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV2;
|
||||
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV3;
|
||||
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriterV2;
|
||||
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriterV3;
|
||||
import com.fastasyncworldedit.core.extent.clipboard.io.schematic.MinecraftStructure;
|
||||
import com.fastasyncworldedit.core.extent.clipboard.io.schematic.PNGWriter;
|
||||
import com.fastasyncworldedit.core.internal.io.ResettableFileInputStream;
|
||||
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;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV1Reader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV2Reader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV2Writer;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Writer;
|
||||
import it.unimi.dsi.fastutil.io.FastBufferedInputStream;
|
||||
import org.anarres.parallelgzip.ParallelGZIPOutputStream;
|
||||
import org.enginehub.linbus.stream.LinBinaryIO;
|
||||
import org.enginehub.linbus.tree.LinRootEntry;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
@ -48,23 +59,14 @@ import java.util.zip.GZIPOutputStream;
|
||||
/**
|
||||
* A collection of supported clipboard formats.
|
||||
*/
|
||||
@SuppressWarnings("removal") //FAWE: suppress JNBT deprecations
|
||||
public enum BuiltInClipboardFormat implements ClipboardFormat {
|
||||
|
||||
//FAWE start - register fast clipboard io
|
||||
FAST("fast", "fawe", "sponge", "schem") {
|
||||
@Override
|
||||
public String getPrimaryFileExtension() {
|
||||
return "schem";
|
||||
}
|
||||
|
||||
FAST_V3("fast", "fawe", "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)));
|
||||
return new FastSchematicReader(nbtStream);
|
||||
return new FastSchematicReaderV3(inputStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -77,15 +79,106 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
|
||||
gzip = new ParallelGZIPOutputStream(outputStream);
|
||||
}
|
||||
NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip));
|
||||
return new FastSchematicWriter(nbtStream);
|
||||
return new FastSchematicWriterV3(nbtStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(final InputStream inputStream) {
|
||||
try (final DataInputStream stream = new DataInputStream(new FastBufferedInputStream(new GZIPInputStream(inputStream)));
|
||||
final NBTInputStream nbt = new NBTInputStream(stream)) {
|
||||
if (stream.readByte() != NBTConstants.TYPE_COMPOUND) {
|
||||
return false;
|
||||
}
|
||||
stream.skipNBytes(2); // TAG name length ("" = 0), no need to read name as no bytes are written for root tag
|
||||
if (stream.readByte() != NBTConstants.TYPE_COMPOUND) {
|
||||
return false;
|
||||
}
|
||||
stream.skipNBytes(2); // TAG name length ("Schematic" = 9)
|
||||
stream.skipNBytes(9); // "Schematic"
|
||||
|
||||
// We can't guarantee the specific order of nbt data, so scan and skip, if required
|
||||
do {
|
||||
byte type = stream.readByte();
|
||||
String name = stream.readUTF();
|
||||
if (type == NBTConstants.TYPE_END) {
|
||||
return false;
|
||||
}
|
||||
if (type == NBTConstants.TYPE_INT && name.equals("Version")) {
|
||||
return stream.readInt() == FastSchematicWriterV3.CURRENT_VERSION;
|
||||
}
|
||||
nbt.readTagPayloadLazy(type, 0);
|
||||
} while (true);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
String name = file.getName().toLowerCase(Locale.ROOT);
|
||||
return name.endsWith(".schem") || name.endsWith(".sponge");
|
||||
if (name.endsWith(".schematic") || name.endsWith(".mcedit") || name.endsWith(".mce")) {
|
||||
return false;
|
||||
}
|
||||
return super.isFormat(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrimaryFileExtension() {
|
||||
return "schem";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getExplicitFileExtensions() {
|
||||
return Set.of("schem3", "sponge3", "fast3");
|
||||
}
|
||||
},
|
||||
FAST_V2("fast.2", "fawe.2", "schem.2") {
|
||||
@Override
|
||||
public String getPrimaryFileExtension() {
|
||||
return "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)));
|
||||
return new FastSchematicReaderV2(nbtStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
|
||||
OutputStream gzip;
|
||||
if (outputStream instanceof ParallelGZIPOutputStream || outputStream instanceof GZIPOutputStream) {
|
||||
gzip = outputStream;
|
||||
} else {
|
||||
outputStream = new BufferedOutputStream(outputStream);
|
||||
gzip = new ParallelGZIPOutputStream(outputStream);
|
||||
}
|
||||
NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip));
|
||||
return new FastSchematicWriterV2(nbtStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(InputStream inputStream) {
|
||||
return detectOldSpongeSchematic(inputStream, FastSchematicWriterV2.CURRENT_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
String name = file.getName().toLowerCase(Locale.ROOT);
|
||||
if (name.endsWith(".schematic") || name.endsWith(".mcedit") || name.endsWith(".mce")) {
|
||||
return false;
|
||||
}
|
||||
return super.isFormat(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getExplicitFileExtensions() {
|
||||
return Set.of("schem2", "sponge2", "fast2");
|
||||
}
|
||||
},
|
||||
//FAWE end
|
||||
|
||||
@ -115,7 +208,61 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
String name = file.getName().toLowerCase(Locale.ROOT);
|
||||
return name.endsWith(".schematic") || name.endsWith(".mcedit") || name.endsWith(".mce");
|
||||
if (!name.endsWith(".schematic") && !name.endsWith(".mcedit") && !name.endsWith(".mce")) {
|
||||
return false;
|
||||
}
|
||||
return super.isFormat(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(InputStream inputStream) {
|
||||
LinRootEntry rootEntry;
|
||||
try {
|
||||
DataInputStream stream = new DataInputStream(new GZIPInputStream(inputStream));
|
||||
rootEntry = LinBinaryIO.readUsing(stream, LinRootEntry::readFrom);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
if (!rootEntry.name().equals("Schematic")) {
|
||||
return false;
|
||||
}
|
||||
return rootEntry.value().value().containsKey("Materials");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getExplicitFileExtensions() {
|
||||
return Set.of("mcedit", "schem1", "sponge1", "fast1");
|
||||
}
|
||||
},
|
||||
SPONGE_V1_SCHEMATIC("sponge.1") {
|
||||
@Override
|
||||
public String getPrimaryFileExtension() {
|
||||
return "schem";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
return new SpongeSchematicV1Reader(LinBinaryIO.read(new DataInputStream(new GZIPInputStream(inputStream))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
|
||||
throw new IOException("This format does not support saving");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(InputStream inputStream) {
|
||||
return detectOldSpongeSchematic(inputStream, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
return MCEDIT_SCHEMATIC.isFormat(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getExplicitFileExtensions() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
},
|
||||
|
||||
@ -125,7 +272,8 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
|
||||
* Avoid using with any large schematics/clipboards for reading/writing.
|
||||
*/
|
||||
@Deprecated
|
||||
SPONGE_SCHEMATIC("slow", "safe") {
|
||||
SPONGE_V2_SCHEMATIC("slow.2", "safe.2", "sponge.2") { // FAWE - edit aliases for fast
|
||||
|
||||
@Override
|
||||
public String getPrimaryFileExtension() {
|
||||
return "schem";
|
||||
@ -133,38 +281,58 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
|
||||
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(inputStream));
|
||||
return new SpongeSchematicReader(nbtStream);
|
||||
return new SpongeSchematicV2Reader(LinBinaryIO.read(new DataInputStream(new GZIPInputStream(inputStream))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
|
||||
NBTOutputStream nbtStream = new NBTOutputStream(new GZIPOutputStream(outputStream));
|
||||
return new SpongeSchematicWriter(nbtStream);
|
||||
return new SpongeSchematicV2Writer(new DataOutputStream(new GZIPOutputStream(outputStream)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(InputStream inputStream) {
|
||||
return detectOldSpongeSchematic(inputStream, 2);
|
||||
}
|
||||
|
||||
@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();
|
||||
return FAST_V2.isFormat(file);
|
||||
}
|
||||
|
||||
// Check
|
||||
Map<String, Tag> schematic = schematicTag.getValue();
|
||||
if (!schematic.containsKey("Version")) {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@Override
|
||||
public Set<String> getExplicitFileExtensions() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
},
|
||||
SPONGE_V3_SCHEMATIC("sponge.3", "slow", "safe") { // FAWE - edit aliases for fast
|
||||
|
||||
@Override
|
||||
public String getPrimaryFileExtension() {
|
||||
return "schem";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
return new SpongeSchematicV3Reader(LinBinaryIO.read(new DataInputStream(new GZIPInputStream(inputStream))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
|
||||
return new SpongeSchematicV3Writer(new DataOutputStream(new GZIPOutputStream(outputStream)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
//FAWE start - delegate to stream-based isFormat approach of fast impl
|
||||
return FAST_V3.isFormat(file);
|
||||
//FAWE end
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getExplicitFileExtensions() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
},
|
||||
//FAWE start - recover schematics with bad entity data & register other clipboard formats
|
||||
BROKENENTITY("brokenentity", "legacyentity", "le", "be", "brokenentities", "legacyentities") {
|
||||
@Override
|
||||
@ -179,7 +347,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
|
||||
}
|
||||
BufferedInputStream buffered = new BufferedInputStream(inputStream);
|
||||
NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered)));
|
||||
FastSchematicReader reader = new FastSchematicReader(nbtStream);
|
||||
FastSchematicReaderV2 reader = new FastSchematicReaderV2(nbtStream);
|
||||
reader.setBrokenEntities(true);
|
||||
return reader;
|
||||
}
|
||||
@ -194,7 +362,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
|
||||
gzip = new ParallelGZIPOutputStream(outputStream);
|
||||
}
|
||||
NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip));
|
||||
FastSchematicWriter writer = new FastSchematicWriter(nbtStream);
|
||||
FastSchematicWriterV2 writer = new FastSchematicWriterV2(nbtStream);
|
||||
writer.setBrokenEntities(true);
|
||||
return writer;
|
||||
}
|
||||
@ -204,6 +372,10 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getExplicitFileExtensions() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -232,9 +404,42 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(File file) {
|
||||
String name = file.getName().toLowerCase(Locale.ROOT);
|
||||
return name.endsWith(".nbt");
|
||||
public boolean isFormat(InputStream inputStream) {
|
||||
try (final DataInputStream stream = new DataInputStream(new FastBufferedInputStream(new GZIPInputStream(inputStream)));
|
||||
final NBTInputStream nbt = new NBTInputStream(stream)) {
|
||||
if (stream.readByte() != NBTConstants.TYPE_COMPOUND) {
|
||||
return false;
|
||||
}
|
||||
NamedTag namedTag = nbt.readNamedTag();
|
||||
if (!namedTag.getName().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can't guarantee the specific order of nbt data, so scan and skip, if required
|
||||
do {
|
||||
byte type = stream.readByte();
|
||||
String name = stream.readUTF();
|
||||
if (type == NBTConstants.TYPE_END) {
|
||||
return false;
|
||||
}
|
||||
if (type == NBTConstants.TYPE_LIST && name.equals("size")) {
|
||||
return true;
|
||||
}
|
||||
nbt.readTagPayloadLazy(type, 0);
|
||||
} while (true);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormat(final File file) {
|
||||
return file.getName().toLowerCase(Locale.ROOT).endsWith(".nbt") && super.isFormat(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getExplicitFileExtensions() {
|
||||
return Set.of("nbt");
|
||||
}
|
||||
},
|
||||
|
||||
@ -262,9 +467,61 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
|
||||
public String getPrimaryFileExtension() {
|
||||
return "png";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getExplicitFileExtensions() {
|
||||
return Set.of("png");
|
||||
}
|
||||
};
|
||||
//FAWE end
|
||||
|
||||
private static boolean detectOldSpongeSchematic(InputStream inputStream, int version) {
|
||||
//FAWE start - dont utilize linbus - WorldEdit approach is not really streamed
|
||||
try (final DataInputStream stream = new DataInputStream(new FastBufferedInputStream(new GZIPInputStream(inputStream)));
|
||||
final NBTInputStream nbt = new NBTInputStream(stream)) {
|
||||
if (stream.readByte() != NBTConstants.TYPE_COMPOUND) {
|
||||
return false;
|
||||
}
|
||||
stream.skipNBytes(2); // TAG name length ("Schematic" = 9)
|
||||
stream.skipNBytes(9); // "Schematic"
|
||||
|
||||
// We can't guarantee the specific order of nbt data, so scan and skip, if required
|
||||
do {
|
||||
byte type = stream.readByte();
|
||||
String name = stream.readUTF();
|
||||
if (type == NBTConstants.TYPE_END) {
|
||||
return false;
|
||||
}
|
||||
if (type == NBTConstants.TYPE_INT && name.equals("Version")) {
|
||||
return stream.readInt() == version;
|
||||
}
|
||||
nbt.readTagPayloadLazy(type, 0);
|
||||
} while (true);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* For backwards compatibility, this points to the Sponge Schematic Specification (Version 2)
|
||||
* format. This should not be used going forwards.
|
||||
*
|
||||
* @deprecated Use {@link #SPONGE_V2_SCHEMATIC} or {@link #SPONGE_V3_SCHEMATIC}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final BuiltInClipboardFormat SPONGE_SCHEMATIC = SPONGE_V2_SCHEMATIC;
|
||||
|
||||
//FAWE start
|
||||
/**
|
||||
* For backwards compatibility, this points to the fast implementation of the Sponge Schematic Specification (Version 2)
|
||||
* format. This should not be used going forwards.
|
||||
*
|
||||
* @deprecated Use {@link #FAST_V2} or {@link #FAST_V3}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final BuiltInClipboardFormat FAST = FAST_V2;
|
||||
//FAWE end
|
||||
|
||||
private final ImmutableSet<String> aliases;
|
||||
|
||||
BuiltInClipboardFormat(String... aliases) {
|
||||
|
@ -35,6 +35,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
@ -82,7 +83,29 @@ public interface ClipboardFormat {
|
||||
* @param file the file
|
||||
* @return true if the given file is of this format
|
||||
*/
|
||||
boolean isFormat(File file);
|
||||
default boolean isFormat(File file) {
|
||||
try (InputStream stream = Files.newInputStream(file.toPath())) {
|
||||
return isFormat(stream);
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given stream is of this format.
|
||||
*
|
||||
* @apiNote The caller is responsible for the following:
|
||||
* <ul>
|
||||
* <li>Closing the input stream</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param inputStream The stream
|
||||
* @return true if the given stream is of this format
|
||||
* @since 2.11.1
|
||||
*/
|
||||
default boolean isFormat(InputStream inputStream) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file extension this format primarily uses.
|
||||
@ -101,6 +124,13 @@ public interface ClipboardFormat {
|
||||
|
||||
//FAWE start
|
||||
|
||||
/**
|
||||
* Get the explicit file extensions (e.g. .schem2) this format is commonly known to use.
|
||||
*
|
||||
* @return The explicit file extensions this format might be known by
|
||||
*/
|
||||
Set<String> getExplicitFileExtensions();
|
||||
|
||||
/**
|
||||
* Sets the actor's clipboard.
|
||||
*
|
||||
|
@ -66,6 +66,7 @@ public class ClipboardFormats {
|
||||
private static final Map<String, ClipboardFormat> aliasMap = new HashMap<>();
|
||||
// FAWE start - keep order of ClipboardFormat entries -> prefer FAST over SPONGE_SCHEMATIC
|
||||
private static final Multimap<String, ClipboardFormat> fileExtensionMap = Multimaps.newMultimap(new HashMap<>(), LinkedHashSet::new);
|
||||
private static final Multimap<String, ClipboardFormat> explicitFileExtensionMap = Multimaps.newMultimap(new HashMap<>(), LinkedHashSet::new);
|
||||
// FAWE end
|
||||
private static final List<ClipboardFormat> registeredFormats = new ArrayList<>();
|
||||
|
||||
@ -86,6 +87,10 @@ public class ClipboardFormats {
|
||||
String lowExt = ext.toLowerCase(Locale.ROOT);
|
||||
fileExtensionMap.put(lowExt, format);
|
||||
}
|
||||
for (String ext : format.getExplicitFileExtensions()) {
|
||||
String lowExt = ext.toLowerCase(Locale.ROOT);
|
||||
explicitFileExtensionMap.put(lowExt, format);
|
||||
}
|
||||
registeredFormats.add(format);
|
||||
}
|
||||
|
||||
@ -147,6 +152,18 @@ public class ClipboardFormats {
|
||||
return fileExtensionMap.keySet().toArray(new String[fileExtensionMap.keySet().size()]);
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
||||
/**
|
||||
* A mapping from explicit extensions (e.g. .schem2) to formats.
|
||||
*
|
||||
* @return a multimap from a file extension to the potential matching formats.
|
||||
*/
|
||||
public static Multimap<String, ClipboardFormat> getExplicitFileExtensionMap() {
|
||||
return Multimaps.unmodifiableMultimap(explicitFileExtensionMap);
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
private ClipboardFormats() {
|
||||
}
|
||||
|
||||
@ -157,8 +174,10 @@ public class ClipboardFormats {
|
||||
*
|
||||
* @param extension the extension
|
||||
* @return the format, otherwise null if one cannot be detected
|
||||
* @deprecated DO NOT USE. Sponge formats 2 and 3 both use .schem by default.
|
||||
*/
|
||||
@Nullable
|
||||
@Deprecated(forRemoval = true, since = "2.11.1")
|
||||
public static ClipboardFormat findByExtension(String extension) {
|
||||
checkNotNull(extension);
|
||||
|
||||
@ -172,6 +191,25 @@ public class ClipboardFormats {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the format given an explicit extension, e.g. ".schem2"
|
||||
*
|
||||
* @param extension the extension
|
||||
* @return the format, otherwise null if one cannot be detected
|
||||
*/
|
||||
@Nullable
|
||||
public static ClipboardFormat findByExplicitExtension(String extension) {
|
||||
checkNotNull(extension);
|
||||
|
||||
Collection<Entry<String, ClipboardFormat>> entries = getExplicitFileExtensionMap().entries();
|
||||
for (Map.Entry<String, ClipboardFormat> entry : entries) {
|
||||
if (entry.getKey().equalsIgnoreCase(extension)) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MultiClipboardHolder loadAllFromInput(
|
||||
Actor player,
|
||||
String input,
|
||||
@ -231,7 +269,7 @@ public class ClipboardFormats {
|
||||
}
|
||||
if (format == null && input.matches(".*\\.[\\w].*")) {
|
||||
String extension = input.substring(input.lastIndexOf('.') + 1);
|
||||
format = findByExtension(extension);
|
||||
format = findByExplicitExtension(extension);
|
||||
}
|
||||
f = MainUtil.resolve(dir, input, format, true);
|
||||
}
|
||||
@ -302,7 +340,7 @@ public class ClipboardFormats {
|
||||
byte[] buffer = new byte[8192];
|
||||
while ((entry = zip.getNextEntry()) != null) {
|
||||
String filename = entry.getName();
|
||||
ClipboardFormat format = findByExtension(filename);
|
||||
ClipboardFormat format = findByExtension(filename); // FIXME
|
||||
if (format != null) {
|
||||
FastByteArrayOutputStream out = new FastByteArrayOutputStream();
|
||||
int len;
|
||||
|
@ -20,17 +20,7 @@
|
||||
package com.sk89q.worldedit.extent.clipboard.io;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.sk89q.jnbt.AdventureNBTConverter;
|
||||
import com.sk89q.jnbt.ByteArrayTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NamedTag;
|
||||
import com.sk89q.jnbt.ShortTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
@ -49,7 +39,7 @@ import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.util.collection.BlockMap;
|
||||
import com.sk89q.worldedit.world.DataFixer;
|
||||
import com.sk89q.worldedit.util.concurrency.LazyReference;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
@ -57,27 +47,25 @@ import com.sk89q.worldedit.world.entity.EntityTypes;
|
||||
import com.sk89q.worldedit.world.registry.LegacyMapper;
|
||||
import com.sk89q.worldedit.world.storage.NBTConversions;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.enginehub.linbus.tree.LinByteArrayTag;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
import org.enginehub.linbus.tree.LinRootEntry;
|
||||
import org.enginehub.linbus.tree.LinTagType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Reads schematic files that are compatible with MCEdit and other editors.
|
||||
*/
|
||||
public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
private final NBTInputStream inputStream;
|
||||
private final DataFixer fixer;
|
||||
private final LinRootEntry root;
|
||||
private static final ImmutableList<NBTCompatibilityHandler> COMPATIBILITY_HANDLERS
|
||||
= ImmutableList.of(
|
||||
new SignCompatibilityHandler(),
|
||||
@ -98,30 +86,30 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
* @param inputStream the input stream to read from
|
||||
*/
|
||||
public MCEditSchematicReader(NBTInputStream inputStream) {
|
||||
checkNotNull(inputStream);
|
||||
this.inputStream = inputStream;
|
||||
this.fixer = null;
|
||||
//com.sk89q.worldedit.WorldEdit.getInstance().getPlatformManager().queryCapability(
|
||||
//com.sk89q.worldedit.extension.platform.Capability.WORLD_EDITING).getDataFixer();
|
||||
try {
|
||||
var tag = inputStream.readNamedTag();
|
||||
this.root = new LinRootEntry(tag.getName(), (LinCompoundTag) tag.getTag().toLinTag());
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
MCEditSchematicReader(LinRootEntry root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clipboard read() throws IOException {
|
||||
// Schematic tag
|
||||
NamedTag rootTag = inputStream.readNamedTag();
|
||||
if (!rootTag.getName().equals("Schematic")) {
|
||||
if (!root.name().equals("Schematic")) {
|
||||
throw new IOException("Tag 'Schematic' does not exist or is not first");
|
||||
}
|
||||
CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
|
||||
var schematicTag = root.value();
|
||||
|
||||
// Check
|
||||
Map<String, Tag> schematic = schematicTag.getValue();
|
||||
if (!schematic.containsKey("Blocks")) {
|
||||
if (!schematicTag.value().containsKey("Blocks")) {
|
||||
throw new IOException("Schematic file is missing a 'Blocks' tag");
|
||||
}
|
||||
|
||||
// Check type of Schematic
|
||||
String materials = requireTag(schematic, "Materials", StringTag.class).getValue();
|
||||
String materials = schematicTag.getTag("Materials", LinTagType.stringTag()).value();
|
||||
if (!materials.equals("Alpha")) {
|
||||
throw new IOException("Schematic file is not an Alpha schematic");
|
||||
}
|
||||
@ -134,42 +122,38 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
Region region;
|
||||
|
||||
// Get information
|
||||
short width = requireTag(schematic, "Width", ShortTag.class).getValue();
|
||||
short height = requireTag(schematic, "Height", ShortTag.class).getValue();
|
||||
short length = requireTag(schematic, "Length", ShortTag.class).getValue();
|
||||
short width = schematicTag.getTag("Width", LinTagType.shortTag()).valueAsShort();
|
||||
short height = schematicTag.getTag("Height", LinTagType.shortTag()).valueAsShort();
|
||||
short length = schematicTag.getTag("Length", LinTagType.shortTag()).valueAsShort();
|
||||
|
||||
try {
|
||||
int originX = requireTag(schematic, "WEOriginX", IntTag.class).getValue();
|
||||
int originY = requireTag(schematic, "WEOriginY", IntTag.class).getValue();
|
||||
int originZ = requireTag(schematic, "WEOriginZ", IntTag.class).getValue();
|
||||
BlockVector3 min = BlockVector3.at(originX, originY, originZ);
|
||||
int originX = schematicTag.getTag("WEOriginX", LinTagType.intTag()).valueAsInt();
|
||||
int originY = schematicTag.getTag("WEOriginY", LinTagType.intTag()).valueAsInt();
|
||||
int originZ = schematicTag.getTag("WEOriginZ", LinTagType.intTag()).valueAsInt();
|
||||
BlockVector3 min = BlockVector3.at(originX, originY, originZ);
|
||||
|
||||
int offsetX = requireTag(schematic, "WEOffsetX", IntTag.class).getValue();
|
||||
int offsetY = requireTag(schematic, "WEOffsetY", IntTag.class).getValue();
|
||||
int offsetZ = requireTag(schematic, "WEOffsetZ", IntTag.class).getValue();
|
||||
BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ);
|
||||
int offsetX = schematicTag.getTag("WEOffsetX", LinTagType.intTag()).valueAsInt();
|
||||
int offsetY = schematicTag.getTag("WEOffsetY", LinTagType.intTag()).valueAsInt();
|
||||
int offsetZ = schematicTag.getTag("WEOffsetZ", LinTagType.intTag()).valueAsInt();
|
||||
BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ);
|
||||
|
||||
origin = min.subtract(offset);
|
||||
region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE));
|
||||
} catch (IOException ignored) {
|
||||
origin = BlockVector3.ZERO;
|
||||
region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE));
|
||||
}
|
||||
origin = min.subtract(offset);
|
||||
region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE));
|
||||
|
||||
// ====================================================================
|
||||
// Blocks
|
||||
// ====================================================================
|
||||
|
||||
// Get blocks
|
||||
byte[] blockId = requireTag(schematic, "Blocks", ByteArrayTag.class).getValue();
|
||||
byte[] blockData = requireTag(schematic, "Data", ByteArrayTag.class).getValue();
|
||||
byte[] blockId = schematicTag.getTag("Blocks", LinTagType.byteArrayTag()).value();
|
||||
byte[] blockData = schematicTag.getTag("Data", LinTagType.byteArrayTag()).value();
|
||||
byte[] addId = new byte[0];
|
||||
short[] blocks = new short[blockId.length]; // Have to later combine IDs
|
||||
|
||||
// We support 4096 block IDs using the same method as vanilla Minecraft, where
|
||||
// the highest 4 bits are stored in a separate byte array.
|
||||
if (schematic.containsKey("AddBlocks")) {
|
||||
addId = requireTag(schematic, "AddBlocks", ByteArrayTag.class).getValue();
|
||||
LinByteArrayTag addBlocks = schematicTag.findTag("AddBlocks", LinTagType.byteArrayTag());
|
||||
if (addBlocks != null) {
|
||||
addId = addBlocks.value();
|
||||
}
|
||||
|
||||
// Combine the AddBlocks data with the first 8-bit block ID
|
||||
@ -186,21 +170,17 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
}
|
||||
|
||||
// Need to pull out tile entities
|
||||
final ListTag tileEntityTag = getTag(schematic, "TileEntities", ListTag.class);
|
||||
List<Tag> tileEntities = tileEntityTag == null ? new ArrayList<>() : tileEntityTag.getValue();
|
||||
var tileEntityTag = schematicTag.findListTag("TileEntities", LinTagType.compoundTag());
|
||||
List<LinCompoundTag> tileEntities = tileEntityTag == null ? List.of() : tileEntityTag.value();
|
||||
BlockMap<BaseBlock> tileEntityBlocks = BlockMap.createForBaseBlock();
|
||||
|
||||
for (Tag tag : tileEntities) {
|
||||
if (!(tag instanceof CompoundTag)) {
|
||||
continue;
|
||||
}
|
||||
CompoundTag t = (CompoundTag) tag;
|
||||
Map<String, Tag> values = new HashMap<>(t.getValue());
|
||||
String id = t.getString("id");
|
||||
values.put("id", new StringTag(convertBlockEntityId(id)));
|
||||
int x = t.getInt("x");
|
||||
int y = t.getInt("y");
|
||||
int z = t.getInt("z");
|
||||
for (LinCompoundTag tag : tileEntities) {
|
||||
var newTag = tag.toBuilder();
|
||||
String id = tag.getTag("id", LinTagType.stringTag()).value();
|
||||
newTag.putString("id", convertBlockEntityId(id));
|
||||
int x = tag.getTag("x", LinTagType.intTag()).valueAsInt();
|
||||
int y = tag.getTag("y", LinTagType.intTag()).valueAsInt();
|
||||
int z = tag.getTag("z", LinTagType.intTag()).valueAsInt();
|
||||
int index = y * width * length + z * width + x;
|
||||
|
||||
//FAWE start - tile entity safety - perhaps caused by the old issue with tile entities created in the wrong
|
||||
@ -211,44 +191,17 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
}
|
||||
|
||||
BlockState block = getBlockState(blocks[index], blockData[index]);
|
||||
BlockState newBlock = block;
|
||||
if (newBlock != null) {
|
||||
for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) {
|
||||
if (handler.isAffectedBlock(newBlock)) {
|
||||
newBlock = handler.updateNBT(block, values).toImmutableState();
|
||||
if (newBlock == null || values.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (block == null) {
|
||||
continue;
|
||||
}
|
||||
var updatedBlock = block.toBaseBlock(LazyReference.from(newTag::build));
|
||||
for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) {
|
||||
updatedBlock = handler.updateNbt(updatedBlock);
|
||||
if (updatedBlock.getNbtReference() == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (values.isEmpty()) {
|
||||
t = null;
|
||||
} else {
|
||||
t = new CompoundTag(values);
|
||||
}
|
||||
|
||||
if (fixer != null && t != null) {
|
||||
//FAWE start - BinaryTag
|
||||
t = (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp(
|
||||
DataFixer.FixTypes.BLOCK_ENTITY,
|
||||
t.asBinaryTag(),
|
||||
-1
|
||||
));
|
||||
//FAWE end
|
||||
}
|
||||
|
||||
BlockVector3 vec = BlockVector3.at(x, y, z);
|
||||
// Insert into the map if we have changed the block or have a tag
|
||||
BlockState blockToInsert = newBlock != null
|
||||
? newBlock
|
||||
: (t != null ? block : null);
|
||||
if (blockToInsert != null) {
|
||||
BaseBlock baseBlock = t != null
|
||||
? blockToInsert.toBaseBlock(new CompoundTag(t.getValue()))
|
||||
: blockToInsert.toBaseBlock();
|
||||
tileEntityBlocks.put(vec, baseBlock);
|
||||
}
|
||||
tileEntityBlocks.put(BlockVector3.at(x, y, z), updatedBlock);
|
||||
}
|
||||
|
||||
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
|
||||
@ -261,16 +214,10 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
for (int z = 0; z < length; ++z) {
|
||||
int index = y * width * length + z * width + x;
|
||||
BlockVector3 pt = BlockVector3.at(x, y, z);
|
||||
BaseBlock state = Optional.ofNullable(tileEntityBlocks.get(pt))
|
||||
.orElseGet(() -> {
|
||||
BlockState blockState = getBlockState(blocks[index], blockData[index]);
|
||||
return blockState == null ? null : blockState.toBaseBlock();
|
||||
});
|
||||
|
||||
try {
|
||||
if (state != null) {
|
||||
clipboard.setBlock(region.getMinimumPoint().add(pt), state);
|
||||
} else {
|
||||
BaseBlock state = tileEntityBlocks.get(pt);
|
||||
if (state == null) {
|
||||
BlockState blockState = getBlockState(blocks[index], blockData[index]);
|
||||
if (blockState == null) {
|
||||
short block = blocks[index];
|
||||
byte data = blockData[index];
|
||||
int combined = block << 8 | data;
|
||||
@ -278,9 +225,12 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
LOGGER.warn("Unknown block when loading schematic: {} {}. This is most likely a" +
|
||||
"bad schematic.", block, data);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} catch (WorldEditException ignored) { // BlockArrayClipboard won't throw this
|
||||
state = blockState.toBaseBlock();
|
||||
}
|
||||
|
||||
clipboard.setBlock(region.getMinimumPoint().add(pt), state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -289,40 +239,25 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
// Entities
|
||||
// ====================================================================
|
||||
|
||||
ListTag entityList = getTag(schematic, "Entities", ListTag.class);
|
||||
var entityList = schematicTag.findListTag("Entities", LinTagType.compoundTag());
|
||||
if (entityList != null) {
|
||||
List<Tag> entityTags = entityList.getValue();
|
||||
for (Tag tag : entityTags) {
|
||||
if (tag instanceof CompoundTag) {
|
||||
CompoundTag compound = (CompoundTag) tag;
|
||||
if (fixer != null) {
|
||||
//FAWE start - BinaryTag
|
||||
compound = (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp(
|
||||
DataFixer.FixTypes.ENTITY,
|
||||
compound.asBinaryTag(),
|
||||
-1
|
||||
));
|
||||
//FAWE end
|
||||
}
|
||||
String id = convertEntityId(compound.getString("id"));
|
||||
Location location = NBTConversions.toLocation(
|
||||
clipboard,
|
||||
compound.getListTag("Pos"),
|
||||
compound.getListTag("Rotation")
|
||||
);
|
||||
if (!id.isEmpty()) {
|
||||
EntityType entityType = EntityTypes.get(id.toLowerCase(Locale.ROOT));
|
||||
if (entityType != null) {
|
||||
for (EntityNBTCompatibilityHandler compatibilityHandler : ENTITY_COMPATIBILITY_HANDLERS) {
|
||||
if (compatibilityHandler.isAffectedEntity(entityType, compound)) {
|
||||
compound = compatibilityHandler.updateNBT(entityType, compound);
|
||||
}
|
||||
}
|
||||
BaseEntity state = new BaseEntity(entityType, compound);
|
||||
clipboard.createEntity(location, state);
|
||||
} else {
|
||||
LOGGER.warn("Unknown entity when pasting schematic: " + id.toLowerCase(Locale.ROOT));
|
||||
for (LinCompoundTag tag : entityList.value()) {
|
||||
String id = convertEntityId(tag.getTag("id", LinTagType.stringTag()).value());
|
||||
Location location = NBTConversions.toLocation(
|
||||
clipboard,
|
||||
tag.getListTag("Pos", LinTagType.doubleTag()),
|
||||
tag.getListTag("Rotation", LinTagType.floatTag())
|
||||
);
|
||||
if (!id.isEmpty()) {
|
||||
EntityType entityType = EntityTypes.get(id.toLowerCase(Locale.ROOT));
|
||||
if (entityType != null) {
|
||||
for (EntityNBTCompatibilityHandler compatibilityHandler : ENTITY_COMPATIBILITY_HANDLERS) {
|
||||
tag = compatibilityHandler.updateNbt(entityType, tag);
|
||||
}
|
||||
BaseEntity state = new BaseEntity(entityType, LazyReference.computed(tag));
|
||||
clipboard.createEntity(location, state);
|
||||
} else {
|
||||
LOGGER.warn("Unknown entity when pasting schematic: " + id.toLowerCase(Locale.ROOT));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -494,7 +429,6 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
inputStream.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
package com.sk89q.worldedit.extent.clipboard.io;
|
||||
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
@ -27,16 +28,19 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base class for NBT schematic readers.
|
||||
*
|
||||
* @deprecated These utility methods are provided by {@link LinCompoundTag} now.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class NBTSchematicReader implements ClipboardReader {
|
||||
|
||||
protected static <T extends Tag> T requireTag(Map<String, Tag> items, String key, Class<T> expected) throws IOException {
|
||||
protected static <T extends Tag<?, ?>> T requireTag(Map<String, Tag<?, ?>> items, String key, Class<T> expected) throws IOException {
|
||||
if (!items.containsKey(key)) {
|
||||
throw new IOException("Schematic file is missing a \"" + key + "\" tag of type "
|
||||
+ expected.getName());
|
||||
}
|
||||
|
||||
Tag tag = items.get(key);
|
||||
Tag<?, ?> tag = items.get(key);
|
||||
if (!expected.isInstance(tag)) {
|
||||
throw new IOException(key + " tag is not of tag type " + expected.getName() + ", got "
|
||||
+ tag.getClass().getName() + " instead");
|
||||
@ -46,12 +50,12 @@ public abstract class NBTSchematicReader implements ClipboardReader {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected static <T extends Tag> T getTag(Map<String, Tag> items, String key, Class<T> expected) {
|
||||
protected static <T extends Tag<?, ?>> T getTag(Map<String, Tag<?, ?>> items, String key, Class<T> expected) {
|
||||
if (!items.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Tag test = items.get(key);
|
||||
Tag<?, ?> test = items.get(key);
|
||||
if (!expected.isInstance(test)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.extent.clipboard.io;
|
||||
|
||||
import com.sk89q.jnbt.Tag;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
// note, when clearing deprecations these methods don't need to remain -- they're introduced in 7.3.0
|
||||
public class SchematicNbtUtil {
|
||||
public static <T extends Tag> T requireTag(Map<String, Tag> items, String key, Class<T> expected) throws IOException {
|
||||
if (!items.containsKey(key)) {
|
||||
throw new IOException("Schematic file is missing a \"" + key + "\" tag of type "
|
||||
+ expected.getName());
|
||||
}
|
||||
|
||||
Tag tag = items.get(key);
|
||||
if (!expected.isInstance(tag)) {
|
||||
throw new IOException(key + " tag is not of tag type " + expected.getName() + ", got "
|
||||
+ tag.getClass().getName() + " instead");
|
||||
}
|
||||
|
||||
return expected.cast(tag);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static <T extends Tag> T getTag(Map<String, Tag> items, String key, Class<T> expected) {
|
||||
if (!items.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Tag test = items.get(key);
|
||||
if (!expected.isInstance(test)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return expected.cast(test);
|
||||
}
|
||||
|
||||
private SchematicNbtUtil() {
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user