mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-01 02:46:41 +00:00
Merge remote-tracking branch 'upstream/master' into merge
This commit is contained in:
@ -24,6 +24,7 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
@ -44,6 +45,15 @@ public interface ClipboardReader extends Closeable {
|
||||
return read(UUID.randomUUID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DataVersion from a file (if possible).
|
||||
*
|
||||
* @return The data version, or empty
|
||||
*/
|
||||
default OptionalInt getDataVersion() {
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
|
||||
default Clipboard read(UUID uuid) throws IOException {
|
||||
return read(uuid, DiskOptimizedClipboard::new);
|
||||
}
|
||||
|
@ -19,8 +19,9 @@
|
||||
|
||||
package com.sk89q.worldedit.extent.clipboard.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import com.sk89q.jnbt.ByteArrayTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
@ -59,6 +60,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Reads schematic files that are compatible with MCEdit and other editors.
|
||||
@ -176,7 +179,8 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
}
|
||||
|
||||
// Need to pull out tile entities
|
||||
List<Tag> tileEntities = requireTag(schematic, "TileEntities", ListTag.class).getValue();
|
||||
final ListTag tileEntityTag = getTag(schematic, "TileEntities", ListTag.class);
|
||||
List<Tag> tileEntities = tileEntityTag == null ? new ArrayList<>() : tileEntityTag.getValue();
|
||||
Map<BlockVector3, Map<String, Tag>> tileEntitiesMap = new HashMap<>();
|
||||
Map<BlockVector3, BlockState> blockStates = new HashMap<>();
|
||||
|
||||
@ -206,6 +210,11 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
if (values.isEmpty()) {
|
||||
t = null;
|
||||
}
|
||||
if (values.isEmpty()) {
|
||||
t = null;
|
||||
} else {
|
||||
t = new CompoundTag(values);
|
||||
}
|
||||
|
||||
if (fixer != null && t != null) {
|
||||
t = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, t, -1);
|
||||
@ -221,9 +230,8 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
|
||||
clipboard.setOrigin(origin);
|
||||
|
||||
// Don't log a torrent of errors
|
||||
int failedBlockSets = 0;
|
||||
|
||||
Set<Integer> unknownBlocks = new HashSet<>();
|
||||
for (int x = 0; x < width; ++x) {
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int z = 0; z < length; ++z) {
|
||||
@ -242,18 +250,7 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
log.warn("Unknown block when pasting schematic: "
|
||||
+ blocks[index] + ":" + blockData[index] + ". Please report this issue.");
|
||||
}
|
||||
} catch (WorldEditException e) {
|
||||
switch (failedBlockSets) {
|
||||
case 0:
|
||||
log.warn("Failed to set block on a Clipboard", e);
|
||||
break;
|
||||
case 1:
|
||||
log.warn("Failed to set block on a Clipboard (again) -- no more messages will be logged", e);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
failedBlockSets++;
|
||||
} catch (WorldEditException ignored) { // BlockArrayClipboard won't throw this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +56,8 @@ import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.entity.EntityTypes;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||
import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||
import org.slf4j.Logger;
|
||||
@ -63,7 +65,6 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -72,6 +73,8 @@ import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import com.sk89q.worldedit.world.storage.NBTConversions;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
/**
|
||||
* Reads schematic files using the Sponge Schematic Specification.
|
||||
@ -96,6 +99,7 @@ public class SpongeSchematicReader extends NBTSchematicReader {
|
||||
private int offsetX, offsetY, offsetZ;
|
||||
private char[] palette, biomePalette;
|
||||
private BlockVector3 min = BlockVector3.ZERO;
|
||||
private int schematicVersion = -1;
|
||||
|
||||
|
||||
/**
|
||||
@ -210,7 +214,58 @@ public class SpongeSchematicReader extends NBTSchematicReader {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clipboard read(UUID uuid, Function<BlockVector3, Clipboard> createOutput) throws IOException {
|
||||
public Clipboard read() throws IOException {
|
||||
CompoundTag schematicTag = getBaseTag();
|
||||
Map<String, Tag> schematic = schematicTag.getValue();
|
||||
|
||||
final Platform platform = WorldEdit.getInstance().getPlatformManager()
|
||||
.queryCapability(Capability.WORLD_EDITING);
|
||||
int liveDataVersion = platform.getDataVersion();
|
||||
|
||||
if (schematicVersion == 1) {
|
||||
dataVersion = 1631; // this is a relatively safe assumption unless someone imports a schematic from 1.12, e.g. sponge 7.1-
|
||||
fixer = platform.getDataFixer();
|
||||
return readVersion1(schematicTag);
|
||||
} else if (schematicVersion == 2) {
|
||||
dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue();
|
||||
if (dataVersion > liveDataVersion) {
|
||||
log.warn("Schematic was made in a newer Minecraft version ({} > {}). Data may be incompatible.",
|
||||
dataVersion, liveDataVersion);
|
||||
} else if (dataVersion < liveDataVersion) {
|
||||
fixer = platform.getDataFixer();
|
||||
if (fixer != null) {
|
||||
log.debug("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.",
|
||||
dataVersion, liveDataVersion);
|
||||
} else {
|
||||
log.info("Schematic was made in an older Minecraft version ({} < {}), but DFU is not available. Data may be incompatible.",
|
||||
dataVersion, liveDataVersion);
|
||||
}
|
||||
}
|
||||
|
||||
BlockArrayClipboard clip = readVersion1(schematicTag);
|
||||
return readVersion2(clip, schematicTag);
|
||||
}
|
||||
throw new IOException("This schematic version is currently not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getDataVersion() {
|
||||
try {
|
||||
CompoundTag schematicTag = getBaseTag();
|
||||
Map<String, Tag> schematic = schematicTag.getValue();
|
||||
if (schematicVersion == 1) {
|
||||
return OptionalInt.of(1631);
|
||||
} else if (schematicVersion == 2) {
|
||||
return OptionalInt.of(requireTag(schematic, "DataVersion", IntTag.class).getValue());
|
||||
}
|
||||
return OptionalInt.empty();
|
||||
} catch (IOException e) {
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clipboard getBaseTag(UUID uuid, Function<BlockVector3, Clipboard> createOutput) throws IOException {
|
||||
StreamDelegate root = createDelegate();
|
||||
inputStream.readNamedTagLazy(root);
|
||||
if (blocks != null) blocks.close();
|
||||
@ -349,6 +404,106 @@ public class SpongeSchematicReader extends NBTSchematicReader {
|
||||
return clipboard;
|
||||
}
|
||||
|
||||
private Clipboard readVersion2(BlockArrayClipboard version1, CompoundTag schematicTag) throws IOException {
|
||||
Map<String, Tag> schematic = schematicTag.getValue();
|
||||
if (schematic.containsKey("BiomeData")) {
|
||||
readBiomes(version1, schematic);
|
||||
}
|
||||
if (schematic.containsKey("Entities")) {
|
||||
readEntities(version1, schematic);
|
||||
}
|
||||
return version1;
|
||||
}
|
||||
|
||||
private void readBiomes(BlockArrayClipboard clipboard, Map<String, Tag> schematic) throws IOException {
|
||||
ByteArrayTag dataTag = requireTag(schematic, "BiomeData", ByteArrayTag.class);
|
||||
IntTag maxTag = requireTag(schematic, "BiomePaletteMax", IntTag.class);
|
||||
CompoundTag paletteTag = requireTag(schematic, "BiomePalette", CompoundTag.class);
|
||||
|
||||
Map<Integer, BiomeType> palette = new HashMap<>();
|
||||
if (maxTag.getValue() != paletteTag.getValue().size()) {
|
||||
throw new IOException("Biome palette size does not match expected size.");
|
||||
}
|
||||
|
||||
for (Entry<String, Tag> palettePart : paletteTag.getValue().entrySet()) {
|
||||
String key = palettePart.getKey();
|
||||
if (fixer != null) {
|
||||
key = fixer.fixUp(DataFixer.FixTypes.BIOME, key, dataVersion);
|
||||
}
|
||||
BiomeType biome = BiomeTypes.get(key);
|
||||
if (biome == null) {
|
||||
log.warn("Unknown biome type :" + key +
|
||||
" in palette. Are you missing a mod or using a schematic made in a newer version of Minecraft?");
|
||||
}
|
||||
Tag idTag = palettePart.getValue();
|
||||
if (!(idTag instanceof IntTag)) {
|
||||
throw new IOException("Biome mapped to non-Int tag.");
|
||||
}
|
||||
palette.put(((IntTag) idTag).getValue(), biome);
|
||||
}
|
||||
|
||||
int width = clipboard.getDimensions().getX();
|
||||
|
||||
byte[] biomes = dataTag.getValue();
|
||||
int biomeIndex = 0;
|
||||
int biomeJ = 0;
|
||||
int bVal;
|
||||
int varIntLength;
|
||||
BlockVector2 min = clipboard.getMinimumPoint().toBlockVector2();
|
||||
while (biomeJ < biomes.length) {
|
||||
bVal = 0;
|
||||
varIntLength = 0;
|
||||
|
||||
while (true) {
|
||||
bVal |= (biomes[biomeJ] & 127) << (varIntLength++ * 7);
|
||||
if (varIntLength > 5) {
|
||||
throw new IOException("VarInt too big (probably corrupted data)");
|
||||
}
|
||||
if (((biomes[biomeJ] & 128) != 128)) {
|
||||
biomeJ++;
|
||||
break;
|
||||
}
|
||||
biomeJ++;
|
||||
}
|
||||
int z = biomeIndex / width;
|
||||
int x = biomeIndex % width;
|
||||
BiomeType type = palette.get(bVal);
|
||||
clipboard.setBiome(min.add(x, z), type);
|
||||
biomeIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
private void readEntities(BlockArrayClipboard clipboard, Map<String, Tag> schematic) throws IOException {
|
||||
List<Tag> entList = requireTag(schematic, "Entities", ListTag.class).getValue();
|
||||
if (entList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (Tag et : entList) {
|
||||
if (!(et instanceof CompoundTag)) {
|
||||
continue;
|
||||
}
|
||||
CompoundTag entityTag = (CompoundTag) et;
|
||||
Map<String, Tag> tags = entityTag.getValue();
|
||||
String id = requireTag(tags, "Id", StringTag.class).getValue();
|
||||
entityTag = entityTag.createBuilder().putString("id", id).remove("Id").build();
|
||||
|
||||
if (fixer != null) {
|
||||
entityTag = fixer.fixUp(DataFixer.FixTypes.ENTITY, entityTag, dataVersion);
|
||||
}
|
||||
|
||||
EntityType entityType = EntityTypes.get(id);
|
||||
if (entityType != null) {
|
||||
Location location = NBTConversions.toLocation(clipboard,
|
||||
requireTag(tags, "Pos", ListTag.class),
|
||||
requireTag(tags, "Rotation", ListTag.class));
|
||||
BaseEntity state = new BaseEntity(entityType, entityTag);
|
||||
clipboard.createEntity(location, state);
|
||||
} else {
|
||||
log.warn("Unknown entity when pasting schematic: " + id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
inputStream.close();
|
||||
|
@ -20,13 +20,16 @@
|
||||
package com.sk89q.worldedit.extent.clipboard.io;
|
||||
|
||||
import com.boydti.fawe.jnbt.streamer.IntValueReader;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.object.clipboard.LinearClipboard;
|
||||
import com.boydti.fawe.util.IOUtil;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.IntArrayTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.FloatTag;
|
||||
import com.sk89q.jnbt.DoubleTag;
|
||||
import com.sk89q.jnbt.NBTConstants;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
@ -61,7 +64,9 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import java.util.Objects;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
@ -334,6 +339,90 @@ public class SpongeSchematicWriter implements ClipboardWriter {
|
||||
schematic.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
|
||||
}
|
||||
|
||||
private void writeBiomes(Clipboard clipboard, Map<String, Tag> schematic) {
|
||||
BlockVector3 min = clipboard.getMinimumPoint();
|
||||
int width = clipboard.getRegion().getWidth();
|
||||
int length = clipboard.getRegion().getLength();
|
||||
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * length);
|
||||
|
||||
int paletteMax = 0;
|
||||
Map<String, Integer> palette = new HashMap<>();
|
||||
|
||||
for (int z = 0; z < length; z++) {
|
||||
int z0 = min.getBlockZ() + z;
|
||||
for (int x = 0; x < width; x++) {
|
||||
int x0 = min.getBlockX() + x;
|
||||
BlockVector2 pt = BlockVector2.at(x0, z0);
|
||||
BiomeType biome = clipboard.getBiome(pt);
|
||||
|
||||
String biomeKey = biome.getId();
|
||||
int biomeId;
|
||||
if (palette.containsKey(biomeKey)) {
|
||||
biomeId = palette.get(biomeKey);
|
||||
} else {
|
||||
biomeId = paletteMax;
|
||||
palette.put(biomeKey, biomeId);
|
||||
paletteMax++;
|
||||
}
|
||||
|
||||
while ((biomeId & -128) != 0) {
|
||||
buffer.write(biomeId & 127 | 128);
|
||||
biomeId >>>= 7;
|
||||
}
|
||||
buffer.write(biomeId);
|
||||
}
|
||||
}
|
||||
|
||||
schematic.put("BiomePaletteMax", new IntTag(paletteMax));
|
||||
|
||||
Map<String, Tag> paletteTag = new HashMap<>();
|
||||
palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value)));
|
||||
|
||||
schematic.put("BiomePalette", new CompoundTag(paletteTag));
|
||||
schematic.put("BiomeData", new ByteArrayTag(buffer.toByteArray()));
|
||||
}
|
||||
|
||||
private void writeEntities(Clipboard clipboard, Map<String, Tag> schematic) {
|
||||
List<CompoundTag> entities = clipboard.getEntities().stream().map(e -> {
|
||||
BaseEntity state = e.getState();
|
||||
if (state == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Tag> values = Maps.newHashMap();
|
||||
CompoundTag rawData = state.getNbtData();
|
||||
if (rawData != null) {
|
||||
values.putAll(rawData.getValue());
|
||||
}
|
||||
values.remove("id");
|
||||
values.put("Id", new StringTag(state.getType().getId()));
|
||||
final Location location = e.getLocation();
|
||||
values.put("Pos", writeVector(location.toVector()));
|
||||
values.put("Rotation", writeRotation(location));
|
||||
|
||||
return new CompoundTag(values);
|
||||
}).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (entities.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
schematic.put("Entities", new ListTag(CompoundTag.class, entities));
|
||||
}
|
||||
|
||||
private Tag writeVector(Vector3 vector) {
|
||||
List<DoubleTag> list = new ArrayList<>();
|
||||
list.add(new DoubleTag(vector.getX()));
|
||||
list.add(new DoubleTag(vector.getY()));
|
||||
list.add(new DoubleTag(vector.getZ()));
|
||||
return new ListTag(DoubleTag.class, list);
|
||||
}
|
||||
|
||||
private Tag writeRotation(Location location) {
|
||||
List<FloatTag> list = new ArrayList<>();
|
||||
list.add(new FloatTag(location.getYaw()));
|
||||
list.add(new FloatTag(location.getPitch()));
|
||||
return new ListTag(FloatTag.class, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
outputStream.close();
|
||||
|
Reference in New Issue
Block a user