diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index 11fc7de09..3c147456c 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -58,6 +58,10 @@ import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.world.WorldInitEvent; import org.bukkit.plugin.java.JavaPlugin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -102,11 +106,6 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { // Setup platform server = new BukkitServerInterface(this, getServer()); worldEdit.getPlatformManager().register(server); - loadAdapter(); // Need an adapter to work with special blocks with NBT data - setupRegistries(); - worldEdit.loadMappings(); - - loadConfig(); // Load configuration } /** @@ -114,8 +113,6 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { */ @Override public void onEnable() { - setupTags(); // these have to be done post-world since they rely on MC registries. the other ones just use Bukkit enums - PermissionsResolverManager.initialize(this); // Setup permission resolver // Register CUI @@ -125,10 +122,8 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { // Now we can register events getServer().getPluginManager().registerEvents(new WorldEditListener(this), this); - // If we are on MCPC+/Cauldron, then Forge will have already loaded - // Forge WorldEdit and there's (probably) not going to be any other - // platforms to be worried about... at the current time of writing - WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); + // register this so we can load world-dependent data right as the first world is loading + getServer().getPluginManager().registerEvents(new WorldInitListener(), this); // Enable metrics new Metrics(this); @@ -433,4 +428,20 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { return bukkitAdapter; } + private class WorldInitListener implements Listener { + private boolean loaded = false; + @EventHandler(priority = EventPriority.LOWEST) + public void onWorldInit(@SuppressWarnings("unused") WorldInitEvent event) { + if (loaded) return; + loaded = true; + + loadAdapter(); // Need an adapter to work with special blocks with NBT data + setupRegistries(); + WorldEdit.getInstance().loadMappings(); + loadConfig(); // Load configuration + setupTags(); + + WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); + } + } } diff --git a/worldedit-bukkit/src/main/resources/plugin.yml b/worldedit-bukkit/src/main/resources/plugin.yml index e64d26bdc..27808257f 100644 --- a/worldedit-bukkit/src/main/resources/plugin.yml +++ b/worldedit-bukkit/src/main/resources/plugin.yml @@ -1,6 +1,7 @@ name: WorldEdit main: com.sk89q.worldedit.bukkit.WorldEditPlugin version: "${internalVersion}" +load: STARTUP api-version: 1.13 # Permissions aren't here. Read http://wiki.sk89q.com/wiki/WEPIF/DinnerPerms diff --git a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar index 4c6d73bec..74ff20abd 100644 Binary files a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar and b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar differ diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java index dc99d66dc..bcba783a4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java @@ -44,6 +44,7 @@ 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; @@ -67,21 +68,20 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class MCEditSchematicReader extends NBTSchematicReader { - private static final ImmutableList COMPATIBILITY_HANDLERS - = ImmutableList.of( - new SignCompatibilityHandler(), - new FlowerPotCompatibilityHandler(), - new NoteBlockCompatibilityHandler(), - new SkullBlockCompatibilityHandler() - // TODO - item tags for inventories...? DFUs :> - ); - private static final ImmutableList ENTITY_COMPATIBILITY_HANDLERS - = ImmutableList.of( - new Pre13HangingCompatibilityHandler() - ); - private static final Logger log = LoggerFactory.getLogger(MCEditSchematicReader.class); private final NBTInputStream inputStream; + private final DataFixer fixer; + private static final ImmutableList COMPATIBILITY_HANDLERS + = ImmutableList.of( + new SignCompatibilityHandler(), + new FlowerPotCompatibilityHandler(), + new NoteBlockCompatibilityHandler(), + new SkullBlockCompatibilityHandler() + ); + private static final ImmutableList ENTITY_COMPATIBILITY_HANDLERS + = ImmutableList.of( + new Pre13HangingCompatibilityHandler() + ); /** * Create a new instance. @@ -91,6 +91,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 @@ -176,39 +179,44 @@ public class MCEditSchematicReader extends NBTSchematicReader { // Need to pull out tile entities List tileEntities = requireTag(schematic, "TileEntities", ListTag.class).getValue(); Map> tileEntitiesMap = new HashMap<>(); - Map blockOverrides = new HashMap<>(); + Map blockStates = new HashMap<>(); for (Tag tag : tileEntities) { if (!(tag instanceof CompoundTag)) continue; CompoundTag t = (CompoundTag) tag; - + Map 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"); - String id = t.getString("id"); - - Map values = new HashMap<>(t.getValue()); - values.put("id", new StringTag(convertBlockEntityId(id))); - int index = y * width * length + z * width + x; - BlockState block = LegacyMapper.getInstance().getBlockFromLegacy(blocks[index], blockData[index]); + + 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); - if (newBlock == null) { + 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 (newBlock != block) { - blockOverrides.put(vec, newBlock); + if (t != null) { + tileEntitiesMap.put(vec, t.getValue()); } + blockStates.put(vec, newBlock); } BlockArrayClipboard clipboard = new BlockArrayClipboard(region); @@ -221,10 +229,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); - boolean useOverride = blockOverrides.containsKey(pt); - BlockState state = useOverride - ? blockOverrides.get(pt) - : LegacyMapper.getInstance().getBlockFromLegacy(blocks[index], blockData[index]); + BlockState state = blockStates.computeIfAbsent(pt, p -> getBlockState(blocks[index], blockData[index])); try { if (state != null) { @@ -233,7 +238,7 @@ public class MCEditSchematicReader extends NBTSchematicReader { } else { clipboard.setBlock(region.getMinimumPoint().add(pt), state); } - } else if (!useOverride) { + } else { short block = blocks[index]; byte data = blockData[index]; int combined = block << 8 | data; @@ -258,9 +263,11 @@ public class MCEditSchematicReader extends NBTSchematicReader { 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(Locale.ROOT)); if (entityType != null) { @@ -343,26 +350,43 @@ public class MCEditSchematicReader extends NBTSchematicReader { } 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"; + 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; + case "Structure": + return "structure_block"; + default: + return id; } } + private BlockState getBlockState(int id, int data) { + return LegacyMapper.getInstance().getBlockFromLegacy(id, data); + } + @Override public void close() throws IOException { inputStream.close(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java index d42d76afd..4a9362b6e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java @@ -36,14 +36,15 @@ import com.sk89q.worldedit.entity.BaseEntity; 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; @@ -54,7 +55,6 @@ 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.Map; @@ -68,14 +68,10 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class SpongeSchematicReader extends NBTSchematicReader { - private static final List 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. @@ -97,17 +93,32 @@ public class SpongeSchematicReader extends NBTSchematicReader { // Check Map 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(schematicTag); } else if (version == 2) { - int dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue(); - int liveDataVersion = WorldEdit.getInstance().getPlatformManager() - .queryCapability(Capability.WORLD_EDITING).getDataVersion(); + 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(schematicTag); return readVersion2(clip, schematicTag); } @@ -159,6 +170,9 @@ public class SpongeSchematicReader extends NBTSchematicReader { for (String palettePart : paletteObject.keySet()) { int id = requireTag(paletteObject, palettePart, IntTag.class).getValue(); + if (fixer != null) { + palettePart = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, palettePart, dataVersion); + } BlockState state; try { state = WorldEdit.getInstance().getBlockFactory().parseFromInput(palettePart, parserContext).toImmutableState(); @@ -184,7 +198,18 @@ public class SpongeSchematicReader extends NBTSchematicReader { for (Map tileEntity : tileEntityTags) { int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue(); - tileEntitiesMap.put(BlockVector3.at(pos[0], pos[1], pos[2]), tileEntity); + final BlockVector3 pt = BlockVector3.at(pos[0], pos[1], pos[2]); + if (fixer != null) { + Map values = Maps.newHashMap(tileEntity); + values.put("x", new IntTag(pt.getBlockX())); + values.put("y", new IntTag(pt.getBlockY())); + values.put("z", new IntTag(pt.getBlockZ())); + values.put("id", values.get("Id")); + values.remove("Id"); + values.remove("Pos"); + tileEntity = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, new CompoundTag(values), dataVersion).getValue(); + } + tileEntitiesMap.put(pt, tileEntity); } } @@ -218,19 +243,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { BlockVector3 pt = BlockVector3.at(x, y, z); try { if (tileEntitiesMap.containsKey(pt)) { - Map values = Maps.newHashMap(tileEntitiesMap.get(pt)); - for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) { - if (handler.isAffectedBlock(state)) { - handler.updateNBT(state, values); - } - } - values.put("x", new IntTag(pt.getBlockX())); - values.put("y", new IntTag(pt.getBlockY())); - values.put("z", new IntTag(pt.getBlockZ())); - values.put("id", values.get("Id")); - values.remove("Id"); - values.remove("Pos"); - clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state.toBaseBlock(new CompoundTag(values))); + clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state.toBaseBlock(new CompoundTag(tileEntitiesMap.get(pt)))); } else { clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state); } @@ -267,9 +280,13 @@ public class SpongeSchematicReader extends NBTSchematicReader { Map paletteEntries = paletteTag.getValue(); for (Entry palettePart : paletteEntries.entrySet()) { - BiomeType biome = BiomeTypes.get(palettePart.getKey()); + 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 :" + palettePart.getKey() + + 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(); @@ -322,14 +339,18 @@ public class SpongeSchematicReader extends NBTSchematicReader { CompoundTag entityTag = (CompoundTag) et; Map 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.createBuilder().putString("id", id).remove("Id").build()); + BaseEntity state = new BaseEntity(entityType, entityTag); clipboard.createEntity(location, state); } else { log.warn("Unknown entity when pasting schematic: " + id); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java index 225a9555e..df18a95da 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java @@ -48,6 +48,7 @@ public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler { } BlockState newState = convertLegacyBlockType(id, data); if (newState != null) { + values.clear(); return (B) newState; // generics pls :\ } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java index 940086b8f..a839efe29 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java @@ -54,7 +54,8 @@ public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler { if (noteTag instanceof ByteTag) { Byte note = ((ByteTag) noteTag).getValue(); if (note != null) { - return block.with(NoteProperty, (int) note); + values.clear(); + return (B) block.with(NoteProperty, (int) note).toImmutableState(); } } return block; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java index 1318cf9c5..70182550d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java @@ -22,13 +22,32 @@ package com.sk89q.worldedit.world; import com.google.common.annotations.Beta; import com.sk89q.jnbt.CompoundTag; +/** + * This entire class is subject to heavy changes. Do not use this as API. + */ @Beta public interface DataFixer { - /** - * API SUBJECT TO CHANGE. DON'T USE THIS. - */ - @Beta - CompoundTag fixChunk(CompoundTag originalChunk); + final class FixType { + private FixType() { + } + } + final class FixTypes { + private FixTypes() { + } + + public static FixType CHUNK = new FixType<>(); + public static FixType BLOCK_ENTITY = new FixType<>(); + public static FixType ENTITY = new FixType<>(); + public static FixType BLOCK_STATE = new FixType<>(); + public static FixType BIOME = new FixType<>(); + public static FixType ITEM_TYPE = new FixType<>(); + } + + default T fixUp(FixType type, T original) { + return fixUp(type, original, -1); + } + + T fixUp(FixType type, T original, int srcVer); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java index b9434ff0d..832fbf020 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java @@ -173,33 +173,10 @@ public class AnvilChunk13 implements Chunk { CompoundTag t = (CompoundTag) tag; - int x = 0; - int y = 0; - int z = 0; - - Map values = new HashMap<>(); - - for (Map.Entry 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 values = new HashMap<>(t.getValue()); + int x = ((IntTag) values.get("x")).getValue(); + int y = ((IntTag) values.get("y")).getValue(); + int z = ((IntTag) values.get("z")).getValue(); BlockVector3 vec = BlockVector3.at(x, y, z); tileEntities.put(vec, values); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java index 05acbeb1d..d12503f19 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java @@ -26,10 +26,13 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import com.sk89q.worldedit.WorldEdit; +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.math.Vector3; import com.sk89q.worldedit.util.gson.VectorAdapter; import com.sk89q.worldedit.util.io.ResourceLoader; +import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; @@ -41,18 +44,18 @@ import java.io.IOException; import java.net.URL; import java.nio.charset.Charset; import java.util.Arrays; +import java.util.HashMap; import java.util.Map; -import static com.google.common.base.Preconditions.checkNotNull; - -public class LegacyMapper { +public final class LegacyMapper { private static final Logger log = LoggerFactory.getLogger(LegacyMapper.class); private static LegacyMapper INSTANCE; - private Multimap stringToBlockMap = HashMultimap.create(); + private Map blockEntries = new HashMap<>(); + private Map stringToBlockMap = new HashMap<>(); private Multimap blockToStringMap = HashMultimap.create(); - private Multimap stringToItemMap = HashMultimap.create(); + private Map stringToItemMap = new HashMap<>(); private Multimap itemToStringMap = HashMultimap.create(); /** @@ -82,31 +85,50 @@ public class LegacyMapper { String data = Resources.toString(url, Charset.defaultCharset()); LegacyDataFile dataFile = gson.fromJson(data, new TypeToken() {}.getType()); + DataFixer fixer = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataFixer(); ParserContext parserContext = new ParserContext(); parserContext.setPreferringWildcard(false); parserContext.setRestricted(false); parserContext.setTryLegacy(false); // This is legacy. Don't match itself. for (Map.Entry blockEntry : dataFile.blocks.entrySet()) { + String id = blockEntry.getKey(); + blockEntries.put(id, blockEntry.getValue()); try { - String id = blockEntry.getKey(); BlockState state = WorldEdit.getInstance().getBlockFactory().parseFromInput(blockEntry.getValue(), parserContext).toImmutableState(); blockToStringMap.put(state, id); stringToBlockMap.put(id, state); - } catch (Exception e) { - log.warn("Unknown block: " + blockEntry.getValue()); + } catch (InputParseException e) { + boolean fixed = false; + if (fixer != null) { + String newEntry = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, blockEntry.getValue(), 1631); + try { + BlockState state = WorldEdit.getInstance().getBlockFactory().parseFromInput(newEntry, parserContext).toImmutableState(); + blockToStringMap.put(state, id); + stringToBlockMap.put(id, state); + fixed = true; + } catch (InputParseException ignored) { + } + } + if (!fixed) { + log.warn("Unknown block: " + blockEntry.getValue()); + } } } for (Map.Entry itemEntry : dataFile.items.entrySet()) { - try { - String id = itemEntry.getKey(); - ItemType type = ItemTypes.get(itemEntry.getValue()); - checkNotNull(type); + String id = itemEntry.getKey(); + String value = itemEntry.getValue(); + ItemType type = ItemTypes.get(value); + if (type == null && fixer != null) { + value = fixer.fixUp(DataFixer.FixTypes.ITEM_TYPE, value, 1631); + type = ItemTypes.get(value); + } + if (type == null) { + log.warn("Unknown item: " + value); + } else { itemToStringMap.put(type, id); stringToItemMap.put(id, type); - } catch (Exception e) { - log.warn("Unknown item: " + itemEntry.getValue()); } } } @@ -118,16 +140,16 @@ public class LegacyMapper { @Nullable public ItemType getItemFromLegacy(int legacyId, int data) { - return stringToItemMap.get(legacyId + ":" + data).stream().findFirst().orElse(null); + return stringToItemMap.get(legacyId + ":" + data); } @Nullable public int[] getLegacyFromItem(ItemType itemType) { - if (!itemToStringMap.containsKey(itemType)) { - return null; - } else { + if (itemToStringMap.containsKey(itemType)) { String value = itemToStringMap.get(itemType).stream().findFirst().get(); return Arrays.stream(value.split(":")).mapToInt(Integer::parseInt).toArray(); + } else { + return null; } } @@ -138,16 +160,16 @@ public class LegacyMapper { @Nullable public BlockState getBlockFromLegacy(int legacyId, int data) { - return stringToBlockMap.get(legacyId + ":" + data).stream().findFirst().orElse(null); + return stringToBlockMap.get(legacyId + ":" + data); } @Nullable public int[] getLegacyFromBlock(BlockState blockState) { - if (!blockToStringMap.containsKey(blockState)) { - return null; - } else { + if (blockToStringMap.containsKey(blockState)) { String value = blockToStringMap.get(blockState).stream().findFirst().get(); return Arrays.stream(value.split(":")).mapToInt(Integer::parseInt).toArray(); + } else { + return null; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java index fef791531..a965943cc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java @@ -160,7 +160,7 @@ public class PassthroughBlockMaterial implements BlockMaterial { if (blockMaterial == null) { return true; } else { - return blockMaterial.isOpaque(); + return blockMaterial.isBurnable(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java index 1243a25fb..edd0799b4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java @@ -106,12 +106,13 @@ public abstract class ChunkStore implements Closeable { } int dataVersion = rootTag.getInt("DataVersion"); + if (dataVersion == 0) dataVersion = -1; final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); final int currentDataVersion = platform.getDataVersion(); if (dataVersion < currentDataVersion) { final DataFixer dataFixer = platform.getDataFixer(); if (dataFixer != null) { - return new AnvilChunk13((CompoundTag) dataFixer.fixChunk(rootTag).getValue().get("Level")); + return new AnvilChunk13((CompoundTag) dataFixer.fixUp(DataFixer.FixTypes.CHUNK, rootTag, dataVersion).getValue().get("Level")); } } if (dataVersion >= DATA_VERSION_MC_1_13) {