Major command changes that don't work yet.

This commit is contained in:
MattBDev
2019-07-05 20:46:48 -04:00
parent ffc2092d93
commit 8108d0a936
399 changed files with 13558 additions and 7985 deletions

View File

@ -37,7 +37,6 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;

View File

@ -20,6 +20,7 @@
package com.sk89q.worldedit.extent.clipboard;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;

View File

@ -33,7 +33,6 @@ import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.session.ClipboardHolder;
import java.io.File;
import java.io.FileInputStream;

View File

@ -19,8 +19,6 @@
package com.sk89q.worldedit.extent.clipboard.io;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.clipboard.LazyClipboardHolder;
@ -28,6 +26,8 @@ import com.boydti.fawe.object.clipboard.MultiClipboardHolder;
import com.boydti.fawe.object.clipboard.URIClipboardHolder;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.util.MainUtil;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
@ -60,8 +60,6 @@ import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import static com.google.common.base.Preconditions.checkNotNull;
public class ClipboardFormats {
private static final Map<String, ClipboardFormat> aliasMap = new HashMap<>();
@ -160,7 +158,7 @@ public class ClipboardFormats {
* It is not in SchematicCommands because it may rely on internal register calls.
*/
public static String[] getFileExtensionArray() {
return fileExtensionMap.keySet().toArray(new String[fileExtensionMap.keySet().size()]);
return fileExtensionMap.keySet().toArray(new String[0]);
}
private ClipboardFormats() {
@ -190,8 +188,7 @@ public class ClipboardFormats {
if (message) BBC.WEB_UNAUTHORIZED.send(player, url);
return null;
}
MultiClipboardHolder clipboards = loadAllFromUrl(url);
return clipboards;
return loadAllFromUrl(url);
} else {
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}").matcher(input).find() && !player.hasPermission("worldedit.schematic.load.other")) {
BBC.NO_PERM.send(player, "worldedit.schematic.load.other");
@ -218,7 +215,7 @@ public class ClipboardFormats {
return null;
}
if (format == null && input.matches(".*\\.[\\w].*")) {
String extension = input.substring(input.lastIndexOf('.') + 1, input.length());
String extension = input.substring(input.lastIndexOf('.') + 1);
format = findByExtension(extension);
}
f = MainUtil.resolve(dir, input, format, true);
@ -230,7 +227,7 @@ public class ClipboardFormats {
}
}
if (f == null || !f.exists() || !MainUtil.isInSubDirectory(working, f)) {
if (message) player.printError("Schematic " + input + " does not exist! (" + ((f == null) ? false : f.exists()) + "|" + f + "|" + (f == null ? false : !MainUtil.isInSubDirectory(working, f)) + ")");
if (message) player.printError("Schematic " + input + " does not exist! (" + ((f != null) && f.exists()) + "|" + f + "|" + (f != null && !MainUtil.isInSubDirectory(working, f)) + ")");
return null;
}
if (format == null && f.isFile()) {
@ -262,7 +259,7 @@ public class ClipboardFormats {
HashSet<String> extensions = new HashSet<>(Arrays.asList(ClipboardFormats.getFileExtensionArray()));
File[] files = dir.listFiles(pathname -> {
String input = pathname.getName();
String extension = input.substring(input.lastIndexOf('.') + 1, input.length());
String extension = input.substring(input.lastIndexOf('.') + 1);
return (extensions.contains(extension.toLowerCase()));
});
LazyClipboardHolder[] clipboards = new LazyClipboardHolder[files.length];
@ -287,7 +284,7 @@ public class ClipboardFormats {
ClipboardFormat format = findByExtension(filename);
if (format != null) {
FastByteArrayOutputStream out = new FastByteArrayOutputStream();
int len = 0;
int len;
while ((len = zip.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
@ -302,7 +299,7 @@ public class ClipboardFormats {
}
}
}
LazyClipboardHolder[] arr = clipboards.toArray(new LazyClipboardHolder[clipboards.size()]);
LazyClipboardHolder[] arr = clipboards.toArray(new LazyClipboardHolder[0]);
try {
MultiClipboardHolder multi = new MultiClipboardHolder(url.toURI());
for (LazyClipboardHolder h : arr) multi.add(h);

View File

@ -19,6 +19,8 @@
package com.sk89q.worldedit.extent.clipboard.io;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableList;
import com.sk89q.jnbt.ByteArrayTag;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag;
@ -32,12 +34,18 @@ 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;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.EntityNBTCompatibilityHandler;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.FlowerPotCompatibilityHandler;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NBTCompatibilityHandler;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NoteBlockCompatibilityHandler;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.Pre13HangingCompatibilityHandler;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.SignCompatibilityHandler;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.SkullBlockCompatibilityHandler;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.entity.EntityTypes;
@ -47,27 +55,30 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
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 List<NBTCompatibilityHandler> COMPATIBILITY_HANDLERS = new ArrayList<>();
static {
COMPATIBILITY_HANDLERS.add(new SignCompatibilityHandler());
// TODO Add a handler for skulls, flower pots, note blocks, etc.
}
private static final Logger log = LoggerFactory.getLogger(MCEditSchematicReader.class);
private final NBTInputStream inputStream;
private final DataFixer fixer;
private static final ImmutableList<NBTCompatibilityHandler> COMPATIBILITY_HANDLERS
= ImmutableList.of(
new SignCompatibilityHandler(),
new FlowerPotCompatibilityHandler(),
new NoteBlockCompatibilityHandler(),
new SkullBlockCompatibilityHandler()
);
private static final ImmutableList<EntityNBTCompatibilityHandler> ENTITY_COMPATIBILITY_HANDLERS
= ImmutableList.of(
new Pre13HangingCompatibilityHandler()
);
/**
* Create a new instance.
@ -77,6 +88,9 @@ public class MCEditSchematicReader extends NBTSchematicReader {
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();
}
@Override
@ -162,51 +176,44 @@ public class MCEditSchematicReader extends NBTSchematicReader {
// Need to pull out tile entities
List<Tag> tileEntities = requireTag(schematic, "TileEntities", ListTag.class).getValue();
Map<BlockVector3, Map<String, Tag>> tileEntitiesMap = new HashMap<>();
Map<BlockVector3, BlockState> blockStates = new HashMap<>();
for (Tag tag : tileEntities) {
if (!(tag instanceof CompoundTag)) continue;
CompoundTag t = (CompoundTag) tag;
int x = 0;
int y = 0;
int z = 0;
Map<String, Tag> values = new HashMap<>();
for (Map.Entry<String, Tag> entry : t.getValue().entrySet()) {
switch (entry.getKey()) {
case "x":
if (entry.getValue() instanceof IntTag) {
x = ((IntTag) entry.getValue()).getValue();
}
break;
case "y":
if (entry.getValue() instanceof IntTag) {
y = ((IntTag) entry.getValue()).getValue();
}
break;
case "z":
if (entry.getValue() instanceof IntTag) {
z = ((IntTag) entry.getValue()).getValue();
}
break;
}
values.put(entry.getKey(), entry.getValue());
}
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");
int index = y * width * length + z * width + x;
BlockState block = LegacyMapper.getInstance().getBlockFromLegacy(blocks[index], blockData[index]);
if (block != null) {
BlockState block = getBlockState(blocks[index], blockData[index]);
BlockState newBlock = block;
if (newBlock != null) {
for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) {
if (handler.isAffectedBlock(block)) {
handler.updateNBT(block, values);
if (handler.isAffectedBlock(newBlock)) {
newBlock = handler.updateNBT(block, values);
if (newBlock == null || values.isEmpty()) {
break;
}
}
}
}
if (values.isEmpty()) {
t = null;
}
if (fixer != null && t != null) {
t = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, t, -1);
}
BlockVector3 vec = BlockVector3.at(x, y, z);
tileEntitiesMap.put(vec, values);
if (t != null) {
tileEntitiesMap.put(vec, t.getValue());
}
blockStates.put(vec, newBlock);
}
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
@ -220,7 +227,7 @@ 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);
BlockState state = LegacyMapper.getInstance().getBlockFromLegacy(blocks[index], blockData[index]);
BlockState state = blockStates.computeIfAbsent(pt, p -> getBlockState(blocks[index], blockData[index]));
try {
if (state != null) {
@ -230,7 +237,8 @@ public class MCEditSchematicReader extends NBTSchematicReader {
clipboard.setBlock(region.getMinimumPoint().add(pt), state);
}
} else {
log.warn("Unknown block when pasting schematic: " + blocks[index] + ":" + blockData[index] + ". Please report this issue.");
log.warn("Unknown block when pasting schematic: "
+ blocks[index] + ":" + blockData[index] + ". Please report this issue.");
}
} catch (WorldEditException e) {
switch (failedBlockSets) {
@ -253,21 +261,29 @@ public class MCEditSchematicReader extends NBTSchematicReader {
// Entities
// ====================================================================
List<Tag> entityTags = getTag(schematic, "Entities", ListTag.class).getValue();
if (entityTags != null) {
ListTag entityList = getTag(schematic, "Entities", ListTag.class);
if (entityList != null) {
List<Tag> entityTags = entityList.getValue();
for (Tag tag : entityTags) {
if (tag instanceof CompoundTag) {
CompoundTag compound = (CompoundTag) tag;
if (fixer != null) {
compound = fixer.fixUp(DataFixer.FixTypes.ENTITY, compound, -1);
}
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());
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 {
log.warn("Unknown entity when pasting schematic: " + id.toLowerCase());
log.warn("Unknown entity when pasting schematic: " + id.toLowerCase(Locale.ROOT));
}
}
}
@ -279,32 +295,100 @@ public class MCEditSchematicReader extends NBTSchematicReader {
private String convertEntityId(String id) {
switch(id) {
case "AreaEffectCloud": return "area_effect_cloud";
case "ArmorStand": return "armor_stand";
case "CaveSpider": return "cave_spider";
case "MinecartChest": return "chest_minecart";
case "DragonFireball": return "dragon_fireball";
case "ThrownEgg": return "egg";
case "EnderDragon": return "ender_dragon";
case "ThrownEnderpearl": return "ender_pearl";
case "FallingSand": return "falling_block";
case "FireworksRocketEntity": return "fireworks_rocket";
case "MinecartFurnace": return "furnace_minecart";
case "MinecartHopper": return "hopper_minecart";
case "EntityHorse": return "horse";
case "ItemFrame": return "item_frame";
case "LeashKnot": return "leash_knot";
case "LightningBolt": return "lightning_bolt";
case "LavaSlime": return "magma_cube";
case "MinecartRideable": return "minecart";
case "MushroomCow": return "mooshroom";
case "Ozelot": return "ocelot";
case "PolarBear": return "polar_bear";
case "ThrownPotion": return "potion";
case "ShulkerBullet": return "shulker_bullet";
case "SmallFireball": return "small_fireball";
case "MinecartSpawner": return "spawner_minecart";
case "SpectralArrow": return "spectral_arrow";
case "PrimedTnt": return "tnt";
case "MinecartTNT": return "tnt_minecart";
case "VillagerGolem": return "villager_golem";
case "WitherBoss": return "wither";
case "WitherSkull": return "wither_skull";
case "PigZombie": return "zombie_pigman";
case "XPOrb":
case "xp_orb":
return "experience_orb";
case "ThrownExpBottle":
case "xp_bottle":
return "experience_bottle";
case "EyeOfEnderSignal":
case "eye_of_ender_signal":
return "eye_of_ender";
case "EnderCrystal":
case "ender_crystal":
return "end_crystal";
case "fireworks_rocket":
return "firework_rocket";
case "fireworks_rocket": return "firework_rocket";
case "MinecartCommandBlock":
case "commandblock_minecart":
return "command_block_minecart";
case "snowman":
return "snow_golem";
case "villager_golem":
return "iron_golem";
case "evocation_fangs":
return "evoker_fangs";
case "evocation_illager":
return "evoker";
case "vindication_illager":
return "vindicator";
case "illusion_illager":
return "illusioner";
case "snowman": return "snow_golem";
case "villager_golem": return "iron_golem";
case "evocation_fangs": return "evoker_fangs";
case "evocation_illager": return "evoker";
case "vindication_illager": return "vindicator";
case "illusion_illager": return "illusioner";
default: return id;
}
return id;
}
private String convertBlockEntityId(String id) {
switch (id) {
case "Cauldron":
return "brewing_stand";
case "Control":
return "command_block";
case "DLDetector":
return "daylight_detector";
case "Trap":
return "dispenser";
case "EnchantTable":
return "enchanting_table";
case "EndGateway":
return "end_gateway";
case "AirPortal":
return "end_portal";
case "EnderChest":
return "ender_chest";
case "FlowerPot":
return "flower_pot";
case "RecordPlayer":
return "jukebox";
case "MobSpawner":
return "mob_spawner";
case "Music":
case "noteblock":
return "note_block";
case "Structure":
return "structure_block";
default:
return id;
}
}
private BlockState getBlockState(int id, int data) {
return LegacyMapper.getInstance().getBlockFromLegacy(id, data);
}
@Override

View File

@ -19,14 +19,12 @@
package com.sk89q.worldedit.extent.clipboard.io;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.Tag;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Map;
import javax.annotation.Nullable;
/**
* Base class for NBT schematic readers
*/

View File

@ -31,34 +31,35 @@ import com.boydti.fawe.object.clipboard.MemoryOptimizedClipboard;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.object.io.FastByteArraysInputStream;
import com.boydti.fawe.util.IOUtil;
import com.google.common.collect.Maps;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.jnbt.ByteArrayTag;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntArrayTag;
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.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
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.legacycompat.NBTCompatibilityHandler;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
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.entity.EntityType;
import com.sk89q.worldedit.world.entity.EntityTypes;
import com.sk89q.worldedit.world.storage.NBTConversions;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import org.slf4j.Logger;
@ -66,30 +67,21 @@ import org.slf4j.LoggerFactory;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Reads schematic files using the Sponge Schematic Specification.
*/
public class SpongeSchematicReader extends NBTSchematicReader {
private static final List<NBTCompatibilityHandler> COMPATIBILITY_HANDLERS = new ArrayList<>();
static {
// If NBT Compat handlers are needed - add them here.
}
private static final Logger log = LoggerFactory.getLogger(SpongeSchematicReader.class);
private final NBTInputStream inputStream;
private DataFixer fixer = null;
private int dataVersion = -1;
/**
* Create a new instance.
@ -108,7 +100,7 @@ public class SpongeSchematicReader extends NBTSchematicReader {
@Override
public Clipboard read(UUID uuid) throws IOException {
return readVersion1(uuid);
return reader(uuid);
}
private int width, height, length;
@ -133,13 +125,56 @@ public class SpongeSchematicReader extends NBTSchematicReader {
}
}
private Clipboard readVersion1(UUID uuid) throws IOException {
private Clipboard reader(UUID uuid) throws IOException {
NamedTag rootTag = inputStream.readNamedTag();
if (!rootTag.getName().equals("Schematic")) {
throw new IOException("Tag 'Schematic' does not exist or is not first");
}
CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
// Check
Map<String, Tag> schematic = schematicTag.getValue();
int version = requireTag(schematic, "Version", IntTag.class).getValue();
final Platform platform = WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.WORLD_EDITING);
int liveDataVersion = platform.getDataVersion();
if (version == 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(uuid);
} else if (version == 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.info("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(uuid);
return readVersion2(clip, schematicTag);
}
throw new IOException("This schematic version is currently not supported");
}
private BlockArrayClipboard readVersion1(UUID uuid) throws IOException {
width = height = length = offsetX = offsetY = offsetZ = Integer.MIN_VALUE;
final BlockArrayClipboard clipboard = new BlockArrayClipboard(new CuboidRegion(BlockVector3.at(0, 0, 0), BlockVector3.at(0, 0, 0)), fc);
FastByteArrayOutputStream blocksOut = new FastByteArrayOutputStream();
FastByteArrayOutputStream biomesOut = new FastByteArrayOutputStream();
NBTStreamer streamer = new NBTStreamer(inputStream);
streamer.addReader("Schematic.Width", (BiConsumer<Integer, Short>) (i, v) -> width = v);
streamer.addReader("Schematic.Height", (BiConsumer<Integer, Short>) (i, v) -> height = v);
@ -151,7 +186,12 @@ public class SpongeSchematicReader extends NBTSchematicReader {
streamer.addReader("Schematic.Palette", (BiConsumer<Integer, HashMap<String, Tag>>) (i, v) -> {
palette = new char[v.size()];
for (Map.Entry<String, Tag> entry : v.entrySet()) {
BlockState state = BlockState.get(entry.getKey());
BlockState state = null;
try {
state = BlockState.get(entry.getKey());
} catch (InputParseException e) {
e.printStackTrace();
}
int index = ((IntTag) entry.getValue()).getValue();
palette[index] = (char) state.getOrdinal();
}
@ -176,39 +216,33 @@ public class SpongeSchematicReader extends NBTSchematicReader {
}
}
});
streamer.addReader("Schematic.TileEntities.#", new BiConsumer<Integer, CompoundTag>() {
@Override
public void accept(Integer index, CompoundTag value) {
if (fc == null) {
setupClipboard(0, uuid);
}
int[] pos = value.getIntArray("Pos");
int x = pos[0];
int y = pos[1];
int z = pos[2];
fc.setTile(x, y, z, value);
streamer.addReader("Schematic.TileEntities.#", (BiConsumer<Integer, CompoundTag>) (index, value) -> {
if (fc == null) {
setupClipboard(0, uuid);
}
int[] pos = value.getIntArray("Pos");
int x = pos[0];
int y = pos[1];
int z = pos[2];
fc.setTile(x, y, z, value);
});
streamer.addReader("Schematic.Entities.#", new BiConsumer<Integer, CompoundTag>() {
@Override
public void accept(Integer index, CompoundTag compound) {
if (fc == null) {
setupClipboard(0, uuid);
}
String id = compound.getString("id");
if (id.isEmpty()) {
return;
}
ListTag positionTag = compound.getListTag("Pos");
ListTag directionTag = compound.getListTag("Rotation");
EntityType type = EntityTypes.parse(id);
if (type != null) {
compound.getValue().put("Id", new StringTag(type.getId()));
BaseEntity state = new BaseEntity(type, compound);
fc.createEntity(clipboard, positionTag.asDouble(0), positionTag.asDouble(1), positionTag.asDouble(2), (float) directionTag.asDouble(0), (float) directionTag.asDouble(1), state);
} else {
Fawe.debug("Invalid entity: " + id);
}
streamer.addReader("Schematic.Entities.#", (BiConsumer<Integer, CompoundTag>) (index, compound) -> {
if (fc == null) {
setupClipboard(0, uuid);
}
String id = compound.getString("id");
if (id.isEmpty()) {
return;
}
ListTag positionTag = compound.getListTag("Pos");
ListTag directionTag = compound.getListTag("Rotation");
EntityType type = EntityTypes.parse(id);
if (type != null) {
compound.getValue().put("Id", new StringTag(type.getId()));
BaseEntity state = new BaseEntity(type, compound);
fc.createEntity(clipboard, positionTag.asDouble(0), positionTag.asDouble(1), positionTag.asDouble(2), (float) directionTag.asDouble(0), (float) directionTag.asDouble(1), state);
} else {
Fawe.debug("Invalid entity: " + id);
}
});
streamer.readFully();
@ -240,7 +274,7 @@ public class SpongeSchematicReader extends NBTSchematicReader {
try (FaweInputStream fis = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(biomesOut.toByteArrays())))) {
int volume = width * length;
for (int index = 0; index < volume; index++) {
fc.setBiome(index, BiomeTypes.get(fis.read()));
fc.setBiome(index, BiomeTypes.register(fis.read()));
}
}
}
@ -249,6 +283,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 (Map.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.register(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();

View File

@ -23,23 +23,18 @@ import com.boydti.fawe.object.clipboard.FaweClipboard;
import com.boydti.fawe.util.IOUtil;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.DoubleTag;
import com.sk89q.jnbt.FloatTag;
import com.sk89q.jnbt.IntArrayTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.NBTConstants;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.google.common.collect.Maps;
import com.sk89q.jnbt.*;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
@ -57,12 +52,16 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* Writes schematic files using the Sponge schematic format.
*/
public class SpongeSchematicWriter implements ClipboardWriter {
private static final int CURRENT_VERSION = 2;
private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE;
private final NBTOutputStream outputStream;
@ -78,16 +77,16 @@ public class SpongeSchematicWriter implements ClipboardWriter {
@Override
public void write(Clipboard clipboard) throws IOException {
write1(clipboard);
// For now always write the latest version. Maybe provide support for earlier if more appear.
write2(clipboard);
}
/**
* Writes a version 1 schematic file.
* Writes a version 2 schematic file.
*
* @param clipboard The clipboard
* @throws IOException If an error occurs
*/
private void write1(Clipboard clipboard) throws IOException {
private void write2(Clipboard clipboard) throws IOException {
Region region = clipboard.getRegion();
BlockVector3 origin = clipboard.getOrigin();
BlockVector3 min = region.getMinimumPoint();
@ -109,7 +108,7 @@ public class SpongeSchematicWriter implements ClipboardWriter {
final DataOutput rawStream = outputStream.getOutputStream();
outputStream.writeLazyCompoundTag("Schematic", out -> {
out.writeNamedTag("Version", 1);
out.writeNamedTag("Width", (short) width);
out.writeNamedTag("Width", (short) width);
out.writeNamedTag("Height", (short) height);
out.writeNamedTag("Length", (short) length);
@ -240,8 +239,8 @@ public class SpongeSchematicWriter implements ClipboardWriter {
// Store our location data, overwriting any
values.put("id", new StringTag(state.getType().getId()));
values.put("Pos", writeVector(entity.getLocation(), "Pos"));
values.put("Rotation", writeRotation(entity.getLocation(), "Rotation"));
values.put("Pos", writeVector(entity.getLocation()));
values.put("Rotation", writeRotation(entity.getLocation()));
CompoundTag entityTag = new CompoundTag(values);
entities.add(entityTag);
@ -252,10 +251,88 @@ public class SpongeSchematicWriter implements ClipboardWriter {
} else {
out.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
}
// version 2 stuff
if (clipboard.hasBiomes()) {
writeBiomes(clipboard, out);
}
if (!clipboard.getEntities().isEmpty()) {
writeEntities(clipboard, out);
}
});
}
private static Tag writeVector(Vector3 vector, String name) {
private void writeBiomes(Clipboard clipboard, NBTOutputStream schematic) throws IOException {
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.writeNamedTag("BiomePaletteMax", new IntTag(paletteMax));
Map<String, Tag> paletteTag = new HashMap<>();
palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value)));
schematic.writeNamedTag("BiomePalette", new CompoundTag(paletteTag));
schematic.writeNamedTag("BiomeData", new ByteArrayTag(buffer.toByteArray()));
}
private void writeEntities(Clipboard clipboard, NBTOutputStream schematic) throws IOException {
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()));
values.put("Pos", writeVector(e.getLocation().toVector()));
values.put("Rotation", writeRotation(e.getLocation()));
return new CompoundTag(values);
}).filter(Objects::nonNull).collect(Collectors.toList());
if (entities.isEmpty()) {
return;
}
schematic.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
}
private static Tag writeVector(Vector3 vector) {
List<DoubleTag> list = new ArrayList<>();
list.add(new DoubleTag(vector.getX()));
list.add(new DoubleTag(vector.getY()));
@ -263,7 +340,7 @@ public class SpongeSchematicWriter implements ClipboardWriter {
return new ListTag(DoubleTag.class, list);
}
private static Tag writeRotation(Location location, String name) {
private static Tag writeRotation(Location location) {
List<FloatTag> list = new ArrayList<>();
list.add(new FloatTag(location.getYaw()));
list.add(new FloatTag(location.getPitch()));

View File

@ -0,0 +1,28 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extent.clipboard.io.legacycompat;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.entity.EntityType;
public interface EntityNBTCompatibilityHandler {
boolean isAffectedEntity(EntityType type, CompoundTag entityTag);
CompoundTag updateNBT(EntityType type, CompoundTag entityTag);
}

View File

@ -0,0 +1,97 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extent.clipboard.io.legacycompat;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import java.util.Map;
public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler {
@Override
public <B extends BlockStateHolder<B>> boolean isAffectedBlock(B block) {
return block.getBlockType() == BlockTypes.FLOWER_POT;
}
@Override
public <B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values) {
Tag item = values.get("Item");
if (item instanceof StringTag) {
String id = ((StringTag) item).getValue();
if (id.isEmpty()) {
return (B) BlockTypes.FLOWER_POT.getDefaultState();
}
int data = 0;
Tag dataTag = values.get("Data");
if (dataTag instanceof IntTag) {
data = ((IntTag) dataTag).getValue();
}
BlockState newState = convertLegacyBlockType(id, data);
if (newState != null) {
values.clear();
return (B) newState; // generics pls :\
}
}
return block;
}
private BlockState convertLegacyBlockType(String id, int data) {
int newId = 0;
switch (id) {
case "minecraft:red_flower":
newId = 38; // now poppy
break;
case "minecraft:yellow_flower":
newId = 37; // now dandelion
break;
case "minecraft:sapling":
newId = 6; // oak_sapling
break;
case "minecraft:deadbush":
case "minecraft:tallgrass":
newId = 31; // dead_bush with fern and grass (not 32!)
break;
default:
break;
}
String plantedName = null;
if (newId == 0 && id.startsWith("minecraft:")) {
plantedName = id.substring(10);
} else {
BlockState plantedWithData = LegacyMapper.getInstance().getBlockFromLegacy(newId, data);
if (plantedWithData != null) {
plantedName = plantedWithData.getBlockType().getId().substring(10); // remove "minecraft:"
}
}
if (plantedName != null) {
BlockType potAndPlanted = BlockTypes.get("minecraft:potted_" + plantedName);
if (potAndPlanted != null) {
return potAndPlanted.getDefaultState();
}
}
return null;
}
}

View File

@ -26,5 +26,5 @@ import java.util.Map;
public interface NBTCompatibilityHandler {
<B extends BlockStateHolder<B>> boolean isAffectedBlock(B block);
<B extends BlockStateHolder<B>> void updateNBT(B block, Map<String, Tag> values);
<B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values);
}

View File

@ -0,0 +1,63 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extent.clipboard.io.legacycompat;
import com.sk89q.jnbt.ByteTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.registry.state.IntegerProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Map;
public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler {
private static final IntegerProperty NoteProperty;
static {
IntegerProperty temp;
try {
temp = (IntegerProperty) (Property<?>) BlockTypes.NOTE_BLOCK.getProperty("note");
} catch (NullPointerException | IllegalArgumentException | ClassCastException e) {
temp = null;
}
NoteProperty = temp;
}
@Override
public <B extends BlockStateHolder<B>> boolean isAffectedBlock(B block) {
return NoteProperty != null && block.getBlockType() == BlockTypes.NOTE_BLOCK;
}
@Override
public <B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values) {
// note that instrument was not stored (in state or nbt) previously.
// it will be updated to the block below when it gets set into the world for the first time
Tag noteTag = values.get("note");
if (noteTag instanceof ByteTag) {
Byte note = ((ByteTag) noteTag).getValue();
if (note != null) {
values.clear();
return (B) block.with(NoteProperty, (int) note).toImmutableState();
}
}
return block;
}
}

View File

@ -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 Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extent.clipboard.io.legacycompat;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.CompoundTagBuilder;
import com.sk89q.worldedit.internal.helper.MCDirections;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.entity.EntityType;
public class Pre13HangingCompatibilityHandler implements EntityNBTCompatibilityHandler {
@Override
public boolean isAffectedEntity(EntityType type, CompoundTag tag) {
if (!type.getId().startsWith("minecraft:")) {
return false;
}
boolean hasLegacyDirection = tag.containsKey("Dir") || tag.containsKey("Direction");
boolean hasFacing = tag.containsKey("Facing");
return hasLegacyDirection || hasFacing;
}
@Override
public CompoundTag updateNBT(EntityType type, CompoundTag tag) {
boolean hasLegacyDir = tag.containsKey("Dir");
boolean hasLegacyDirection = tag.containsKey("Direction");
boolean hasPre113Facing = tag.containsKey("Facing");
Direction newDirection;
if (hasLegacyDir) {
newDirection = MCDirections.fromPre13Hanging(MCDirections.fromLegacyHanging((byte) tag.asInt("Dir")));
} else if (hasLegacyDirection) {
newDirection = MCDirections.fromPre13Hanging(tag.asInt("Direction"));
} else if (hasPre113Facing) {
newDirection = MCDirections.fromPre13Hanging(tag.asInt("Facing"));
} else {
return tag;
}
byte hangingByte = (byte) MCDirections.toHanging(newDirection);
CompoundTagBuilder builder = tag.createBuilder();
builder.putByte("Facing", hangingByte);
return builder.build();
}
}

View File

@ -26,7 +26,6 @@ import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.world.block.BlockID;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
@ -40,7 +39,7 @@ public class SignCompatibilityHandler implements NBTCompatibilityHandler {
}
@Override
public <B extends BlockStateHolder<B>> void updateNBT(B block, Map<String, Tag> values) {
public <B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values) {
for (int i = 0; i < 4; ++i) {
String key = "Text" + (i + 1);
Tag value = values.get(key);
@ -70,5 +69,6 @@ public class SignCompatibilityHandler implements NBTCompatibilityHandler {
values.put("Text" + (i + 1), new StringTag(jsonTextObject.toString()));
}
}
return block;
}
}

View File

@ -0,0 +1,100 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extent.clipboard.io.legacycompat;
import com.sk89q.jnbt.ByteTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.registry.state.DirectionalProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Map;
public class SkullBlockCompatibilityHandler implements NBTCompatibilityHandler {
private static final DirectionalProperty FacingProperty;
static {
DirectionalProperty tempFacing;
try {
tempFacing = (DirectionalProperty) (Property<?>) BlockTypes.SKELETON_WALL_SKULL.getProperty("facing");
} catch (NullPointerException | IllegalArgumentException | ClassCastException e) {
tempFacing = null;
}
FacingProperty = tempFacing;
}
@Override
public <B extends BlockStateHolder<B>> boolean isAffectedBlock(B block) {
return block.getBlockType() == BlockTypes.SKELETON_SKULL
|| block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL;
}
@Override
public <B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values) {
boolean isWall = block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL;
Tag typeTag = values.get("SkullType");
if (typeTag instanceof ByteTag) {
String skullType = convertSkullType(((ByteTag) typeTag).getValue(), isWall);
if (skullType != null) {
BlockType type = BlockTypes.get("minecraft:" + skullType);
if (type != null) {
BlockState state = type.getDefaultState();
if (isWall) {
Property newProp = type.getProperty("facing");
state = state.with(newProp, block.getState(FacingProperty));
} else {
Tag rotTag = values.get("Rot");
if (rotTag instanceof ByteTag) {
Property newProp = type.getProperty("rotation");
state = state.with(newProp, (int) ((ByteTag) rotTag).getValue());
}
}
values.remove("SkullType");
values.remove("Rot");
return (B) state;
}
}
}
return block;
}
private String convertSkullType(Byte oldType, boolean isWall) {
switch (oldType) {
case 0:
return isWall ? "skeleton_wall_skull" : "skeleton_skull";
case 1:
return isWall ? "wither_skeleton_wall_skull" : "wither_skeleton_skull";
case 2:
return isWall ? "zombie_wall_head" : "zombie_head";
case 3:
return isWall ? "player_wall_head" : "player_head";
case 4:
return isWall ? "creeper_wall_head" : "creeper_head";
case 5:
return isWall ? "dragon_wall_head" : "dragon_head";
default:
return null;
}
}
}