mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-02-16 10:30:42 +00:00
feat: support 1.21.20 and newer versions
This commit is contained in:
@@ -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<String, Map<String, String>> JE_BLOCK_DEFAULT_PROPERTIES = new Object2ObjectOpenHashMap<>();
|
||||
private static final Map<BlockState, JeBlockState> BLOCK_STATE_BE_TO_JE = new Object2ObjectOpenHashMap<>();
|
||||
private static final Map<Integer, BlockState> BLOCK_STATE_JE_HASH_TO_BE = new Int2ObjectOpenHashMap<>();
|
||||
private static final Map<String, String> ITEM_ID_JE_TO_BE = new Object2ObjectOpenHashMap<>();
|
||||
private static final Map<String, Integer> JE_ITEM_ID_TO_BE_ITEM_META = new Object2IntOpenHashMap<>();
|
||||
private static final Map<String, Integer> 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<Map<String, Map<String, Integer>>>(){}).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<Map<String, Map<String, Object>>>(){}).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<Map<String, Map<String, Object>>>) JSONUtils.from(stream, new TypeToken<Map<String, Object>>(){}).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<String, Object> 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<String, Object> state = (Map<String, Object>) 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<String, Object> 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<String, Object> state = (Map<String, Object>) 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<String, Object> state = (Map<String, Object>) 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<String, Object> convertValueType(Map<String, Object> 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<String, Object>();
|
||||
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<String, Object> 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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user