diff --git a/platforms/allay/src/main/java/org/allaymc/terra/allay/Mapping.java b/platforms/allay/src/main/java/org/allaymc/terra/allay/Mapping.java index f50545787..fc22750ea 100644 --- a/platforms/allay/src/main/java/org/allaymc/terra/allay/Mapping.java +++ b/platforms/allay/src/main/java/org/allaymc/terra/allay/Mapping.java @@ -5,12 +5,14 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.extern.slf4j.Slf4j; -import org.allaymc.api.block.property.type.BlockPropertyType.BlockPropertyValue; import org.allaymc.api.block.type.BlockState; import org.allaymc.api.block.type.BlockTypes; import org.allaymc.api.registry.Registries; -import org.allaymc.api.utils.Identifier; +import org.allaymc.api.utils.HashUtils; import org.allaymc.api.utils.JSONUtils; +import org.allaymc.updater.block.BlockStateUpdaters; +import org.allaymc.updater.item.ItemStateUpdaters; +import org.cloudburstmc.nbt.NbtMap; import java.io.IOException; import java.util.List; @@ -25,17 +27,17 @@ import java.util.TreeMap; */ @Slf4j public final class Mapping { - private static final Map> JE_BLOCK_DEFAULT_PROPERTIES = new Object2ObjectOpenHashMap<>(); private static final Map BLOCK_STATE_BE_TO_JE = new Object2ObjectOpenHashMap<>(); private static final Map BLOCK_STATE_JE_HASH_TO_BE = new Int2ObjectOpenHashMap<>(); private static final Map ITEM_ID_JE_TO_BE = new Object2ObjectOpenHashMap<>(); + private static final Map JE_ITEM_ID_TO_BE_ITEM_META = new Object2IntOpenHashMap<>(); private static final Map BIOME_ID_JE_TO_BE = new Object2IntOpenHashMap<>(); private static final BlockState BE_AIR_STATE = BlockTypes.AIR.getDefaultState(); public static void init() { if(!initBlockStateMapping()) error(); - if (!initJeBlockDefaultProperties()) error(); + if(!initJeBlockDefaultProperties()) error(); if(!initItemMapping()) error(); if(!initBiomeMapping()) error(); } @@ -45,9 +47,9 @@ public final class Mapping { } private static boolean initBiomeMapping() { - try (var stream = Mapping.class.getClassLoader().getResourceAsStream("mapping/biomes.json")) { + try (var stream = Mapping.class.getClassLoader().getResourceAsStream("mapping/biomes_JE_1_20_4_TO_BE_1_20_0.json")) { if (stream == null) { - log.error("biomes.json not found"); + log.error("biomes mapping not found"); return false; } var mappings = JSONUtils.from(stream, new TypeToken>>(){}).entrySet(); @@ -62,14 +64,22 @@ public final class Mapping { } private static boolean initItemMapping() { - try (var stream = Mapping.class.getClassLoader().getResourceAsStream("mapping/items.json")) { + try (var stream = Mapping.class.getClassLoader().getResourceAsStream("mapping/items_JE_1_20_4_TO_BE_1_20_0.json")) { if (stream == null) { - log.error("items.json not found"); + log.error("items mapping not found"); return false; } var mappings = JSONUtils.from(stream, new TypeToken>>(){}).entrySet(); for(var mapping : mappings) { - ITEM_ID_JE_TO_BE.put(mapping.getKey(), (String) mapping.getValue().get("bedrock_identifier")); + var updatedNBT = ItemStateUpdaters.updateItemState( + NbtMap.builder() + .putString("Name", (String) mapping.getValue().get("bedrock_identifier")) + .putInt("Damage", ((Double) mapping.getValue().get("bedrock_data")).intValue()) + .build(), + ItemStateUpdaters.LATEST_VERSION + ); + ITEM_ID_JE_TO_BE.put(mapping.getKey(), updatedNBT.getString("Name")); + JE_ITEM_ID_TO_BE_ITEM_META.put(mapping.getKey(), updatedNBT.getInt("Damage")); } } catch(IOException e) { log.error("Failed to load mapping", e); @@ -78,9 +88,9 @@ public final class Mapping { } private static boolean initBlockStateMapping() { - try (var stream = Mapping.class.getClassLoader().getResourceAsStream("mapping/blocks.json")) { + try (var stream = Mapping.class.getClassLoader().getResourceAsStream("mapping/blocks_JE_1_20_4_TO_BE_1_20_0.json")) { if (stream == null) { - log.error("blocks.json not found"); + log.error("blocks mapping not found"); return false; } var mappings = (List>>) JSONUtils.from(stream, new TypeToken>(){}).get("mappings"); @@ -97,7 +107,7 @@ public final class Mapping { } private static boolean initJeBlockDefaultProperties() { - try (var stream = Mapping.class.getClassLoader().getResourceAsStream("je_block_default_states.json")) { + try (var stream = Mapping.class.getClassLoader().getResourceAsStream("je_block_default_states_1_20_4.json")) { if (stream == null) { log.error("je_block_default_states.json not found"); return false; @@ -114,35 +124,82 @@ public final class Mapping { return true; } +// private static BlockState createBeBlockState(Map data) { +// var identifier = new Identifier((String) data.get("bedrock_identifier")); +// // 方块类型 +// var blockType = Registries.BLOCKS.get(identifier); +// if (blockType == null) { +// log.error("Cannot find bedrock block type: {}", identifier); +// return BE_AIR_STATE; +// } +// // 方块属性 +// Map state = (Map) data.get("state"); +// if (state == null) return blockType.getDefaultState(); +// var propertyValues = new BlockPropertyValue[state.size()]; +// int index = -1; +// for(var entry : state.entrySet()) { +// index++; +// var propertyName = entry.getKey(); +// var propertyType = blockType.getProperties().get(propertyName); +// if (propertyType == null) { +// log.warn("Unknown property type: {}", propertyName); +// return BlockTypes.AIR.getDefaultState(); +// } +// try { +// propertyValues[index] = propertyType.tryCreateValue(entry.getValue()); +// } catch (IllegalArgumentException e) { +// log.warn("Failed to create property value for {}: {}", propertyName, entry.getValue()); +// return BE_AIR_STATE; +// } +// } +// return blockType.ofState(propertyValues); +// } + private static BlockState createBeBlockState(Map data) { - var identifier = new Identifier((String) data.get("bedrock_identifier")); - // 方块类型 - var blockType = Registries.BLOCKS.get(identifier); - if (blockType == null) { - log.error("Cannot find bedrock block type: {}", identifier); + var builder = NbtMap.builder(); + builder.putString("name", "minecraft:" + data.get("bedrock_identifier")); + + Map state = (Map) data.get("state"); + builder.put("states", state != null ? NbtMap.fromMap(convertValueType(state)) : NbtMap.EMPTY); + + // The mapping file may not be the latest, so we use block state updater + // to update the old block state to the latest version + var updatedNBT = BlockStateUpdaters.updateBlockState(builder.build(), BlockStateUpdaters.LATEST_VERSION); + var blockStateTag = NbtMap.builder() + // To calculate the hash of the block state + // 'name' field must be in the first place + .putString("name", updatedNBT.getString("name")) + // map implementation inside updatedNBT.getCompound("states") should be TreeMap + // see convertValueType() method + .putCompound("states", updatedNBT.getCompound("states")) + .build(); + var blockStateHash = HashUtils.fnv1a_32_nbt(blockStateTag); + var blockState = Registries.BLOCK_STATE_PALETTE.get(blockStateHash); + if (blockState == null) { + log.error("Cannot find bedrock block state: {}", blockStateTag); return BE_AIR_STATE; } - // 方块属性 - Map state = (Map) data.get("state"); - if (state == null) return blockType.getDefaultState(); - var propertyValues = new BlockPropertyValue[state.size()]; - int index = -1; - for(var entry : state.entrySet()) { - index++; - var propertyName = entry.getKey(); - var propertyType = blockType.getProperties().get(propertyName); - if (propertyType == null) { - log.warn("Unknown property type: {}", propertyName); - return BlockTypes.AIR.getDefaultState(); - } - try { - propertyValues[index] = propertyType.tryCreateValue(entry.getValue()); - } catch (IllegalArgumentException e) { - log.warn("Failed to create property value for {}: {}", propertyName, entry.getValue()); - return BE_AIR_STATE; + return blockState; + } + + private static TreeMap convertValueType(Map data) { + // Use tree map to make sure that the order of property is correct + // Otherwise the block state hash calculated may not be correct! + var result = new TreeMap(); + for (var entry : data.entrySet()) { + var value = entry.getValue(); + if (value instanceof Boolean) { + // BooleanProperty + result.put(entry.getKey(), (Boolean) value ? (byte) 1 : (byte) 0); + } else if (value instanceof Number number) { + // IntProperty + result.put(entry.getKey(), number.intValue()); + } else { + // EnumProperty + result.put(entry.getKey(), value); } } - return blockType.ofState(propertyValues); + return result; } private static JeBlockState createJeBlockState(Map data) { @@ -168,6 +225,10 @@ public final class Mapping { return ITEM_ID_JE_TO_BE.get(jeItemId); } + public static int jeItemIdToBeItemMeta(String jeItemId) { + return JE_ITEM_ID_TO_BE_ITEM_META.get(jeItemId); + } + // Enchantment identifiers are same in both versions public static String enchantmentIdBeToJe(String beEnchantmentId) { diff --git a/platforms/allay/src/main/java/org/allaymc/terra/allay/delegate/AllayItemStack.java b/platforms/allay/src/main/java/org/allaymc/terra/allay/delegate/AllayItemStack.java index 9eb4484be..cbddcd96b 100644 --- a/platforms/allay/src/main/java/org/allaymc/terra/allay/delegate/AllayItemStack.java +++ b/platforms/allay/src/main/java/org/allaymc/terra/allay/delegate/AllayItemStack.java @@ -24,7 +24,7 @@ public record AllayItemStack(ItemStack allayItemStack) implements com.dfsek.terr @Override public Item getType() { - return new AllayItemType(allayItemStack.getItemType()); + return new AllayItemType(allayItemStack.getItemType(), allayItemStack.getMeta()); } @Override diff --git a/platforms/allay/src/main/java/org/allaymc/terra/allay/delegate/AllayItemType.java b/platforms/allay/src/main/java/org/allaymc/terra/allay/delegate/AllayItemType.java index d8685f8c2..0f379f8ea 100644 --- a/platforms/allay/src/main/java/org/allaymc/terra/allay/delegate/AllayItemType.java +++ b/platforms/allay/src/main/java/org/allaymc/terra/allay/delegate/AllayItemType.java @@ -12,17 +12,19 @@ import com.dfsek.terra.api.inventory.Item; */ public final class AllayItemType implements Item { private final ItemType allayItemType; + private final int beData; private final double maxDurability; - public AllayItemType(ItemType allayItemType) { + public AllayItemType(ItemType allayItemType, int beData) { this.allayItemType = allayItemType; - // TODO: 感觉不太优雅,应该有更好的办法 + this.beData = beData; + // TODO: Better way to get max damage this.maxDurability = allayItemType.createItemStack().getItemData().maxDamage(); } @Override public com.dfsek.terra.api.inventory.ItemStack newItemStack(int amount) { - return new AllayItemStack(allayItemType.createItemStack(amount)); + return new AllayItemStack(allayItemType.createItemStack(amount, beData)); } @Override diff --git a/platforms/allay/src/main/java/org/allaymc/terra/allay/handle/AllayItemHandle.java b/platforms/allay/src/main/java/org/allaymc/terra/allay/handle/AllayItemHandle.java index beb7d4e40..9101b1bc4 100644 --- a/platforms/allay/src/main/java/org/allaymc/terra/allay/handle/AllayItemHandle.java +++ b/platforms/allay/src/main/java/org/allaymc/terra/allay/handle/AllayItemHandle.java @@ -22,7 +22,7 @@ import com.dfsek.terra.api.inventory.item.Enchantment; public class AllayItemHandle implements ItemHandle { @Override public Item createItem(String data) { - return new AllayItemType(Registries.ITEMS.get(new Identifier(Mapping.itemIdJeToBe(data)))); + return new AllayItemType(Registries.ITEMS.get(new Identifier(Mapping.itemIdJeToBe(data))), Mapping.jeItemIdToBeItemMeta(data)); } @Override diff --git a/platforms/allay/src/main/resources/je_block_default_states.json b/platforms/allay/src/main/resources/je_block_default_states_1_20_4.json similarity index 100% rename from platforms/allay/src/main/resources/je_block_default_states.json rename to platforms/allay/src/main/resources/je_block_default_states_1_20_4.json diff --git a/platforms/allay/src/main/resources/mapping/biomes.json b/platforms/allay/src/main/resources/mapping/biomes_JE_1_20_4_TO_BE_1_20_0.json similarity index 100% rename from platforms/allay/src/main/resources/mapping/biomes.json rename to platforms/allay/src/main/resources/mapping/biomes_JE_1_20_4_TO_BE_1_20_0.json diff --git a/platforms/allay/src/main/resources/mapping/blocks.json b/platforms/allay/src/main/resources/mapping/blocks_JE_1_20_4_TO_BE_1_20_0.json similarity index 100% rename from platforms/allay/src/main/resources/mapping/blocks.json rename to platforms/allay/src/main/resources/mapping/blocks_JE_1_20_4_TO_BE_1_20_0.json diff --git a/platforms/allay/src/main/resources/mapping/items.json b/platforms/allay/src/main/resources/mapping/items_JE_1_20_4_TO_BE_1_20_0.json similarity index 100% rename from platforms/allay/src/main/resources/mapping/items.json rename to platforms/allay/src/main/resources/mapping/items_JE_1_20_4_TO_BE_1_20_0.json