Use DFUs for some additional data fixing.

Legacy mapper now uses the data fixers to upgrade blocks and item types
(e.g. signs, dyes that changed names in 1.14).
The sponge schematic reader can now attempt to use the data fixers to
upgrade blocks, block entities, biomes and entities. This has been
tested with the 1.13 -> 1.14 changes. It is yet to be seen if it will
continue to work because...
The mc edit schematic reader has code for using data fixers, but it is
currently disabled as there seem to be some issues with fixing up older
block entities.
This commit is contained in:
wizjany
2019-05-16 00:00:31 -04:00
parent 8ee484fca8
commit b0777f6b06
12 changed files with 220 additions and 142 deletions

View File

@ -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<T> {
private FixType() {
}
}
final class FixTypes {
private FixTypes() {
}
public static FixType<CompoundTag> CHUNK = new FixType<>();
public static FixType<CompoundTag> BLOCK_ENTITY = new FixType<>();
public static FixType<CompoundTag> ENTITY = new FixType<>();
public static FixType<String> BLOCK_STATE = new FixType<>();
public static FixType<String> BIOME = new FixType<>();
public static FixType<String> ITEM_TYPE = new FixType<>();
}
default <T> T fixUp(FixType<T> type, T original) {
return fixUp(type, original, -1);
}
<T> T fixUp(FixType<T> type, T original, int srcVer);
}

View File

@ -173,33 +173,10 @@ public class AnvilChunk13 implements Chunk {
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());
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);

View File

@ -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<String, BlockState> stringToBlockMap = HashMultimap.create();
private Map<String, String> blockEntries = new HashMap<>();
private Map<String, BlockState> stringToBlockMap = new HashMap<>();
private Multimap<BlockState, String> blockToStringMap = HashMultimap.create();
private Multimap<String, ItemType> stringToItemMap = HashMultimap.create();
private Map<String, ItemType> stringToItemMap = new HashMap<>();
private Multimap<ItemType, String> itemToStringMap = HashMultimap.create();
/**
@ -82,31 +85,50 @@ public class LegacyMapper {
String data = Resources.toString(url, Charset.defaultCharset());
LegacyDataFile dataFile = gson.fromJson(data, new TypeToken<LegacyDataFile>() {}.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<String, String> 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<String, String> 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;
}
}

View File

@ -160,7 +160,7 @@ public class PassthroughBlockMaterial implements BlockMaterial {
if (blockMaterial == null) {
return true;
} else {
return blockMaterial.isOpaque();
return blockMaterial.isBurnable();
}
}

View File

@ -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) {