From c2489c7a4c32f266657e5169331b4b295093c3b5 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Fri, 5 Apr 2024 15:38:12 +0200 Subject: [PATCH] Back up 1.20.5 data components in VB for creative clients --- .../BlockItemPacketRewriter1_20_2.java | 13 +- ...nEffects.java => PotionEffects1_20_2.java} | 10 +- ...s1_20_3.java => MapDecorations1_20_5.java} | 5 +- .../data/PotionEffects1_20_5.java | 89 +++++++++++ ...{Potions1_20_3.java => Potions1_20_5.java} | 9 +- .../BlockItemPacketRewriter1_20_5.java | 109 +++++++++---- .../rewriter/StructuredDataConverter.java | 144 +++++++++++++----- 7 files changed, 298 insertions(+), 81 deletions(-) rename common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_2to1_20/util/{PotionEffects.java => PotionEffects1_20_2.java} (90%) rename common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/{MapDecorations1_20_3.java => MapDecorations1_20_5.java} (95%) create mode 100644 common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/PotionEffects1_20_5.java rename common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/{Potions1_20_3.java => Potions1_20_5.java} (93%) diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_2to1_20/rewriter/BlockItemPacketRewriter1_20_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_2to1_20/rewriter/BlockItemPacketRewriter1_20_2.java index a60e652e3..f12b5e611 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_2to1_20/rewriter/BlockItemPacketRewriter1_20_2.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_2to1_20/rewriter/BlockItemPacketRewriter1_20_2.java @@ -41,7 +41,7 @@ import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPac import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.rewriter.RecipeRewriter1_19_4; import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.Protocol1_20_2To1_20; import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ServerboundPackets1_20_2; -import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.util.PotionEffects; +import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.util.PotionEffects1_20_2; import com.viaversion.viaversion.rewriter.BlockRewriter; import com.viaversion.viaversion.rewriter.ItemRewriter; import com.viaversion.viaversion.util.MathUtil; @@ -383,7 +383,8 @@ public final class BlockItemPacketRewriter1_20_2 extends ItemRewriter KEY_TO_ID = new Object2IntOpenHashMap<>(); private static final String[] POTION_EFFECTS = { - "", // No effect "speed", "slowness", "haste", @@ -63,18 +62,19 @@ public final class PotionEffects { }; static { - for (int i = 1; i < POTION_EFFECTS.length; i++) { + for (int i = 0; i < POTION_EFFECTS.length; i++) { final String effect = POTION_EFFECTS[i]; KEY_TO_ID.put(effect, i); } + KEY_TO_ID.defaultReturnValue(-1); } public static @Nullable String idToKey(final int id) { - return id >= 1 && id < POTION_EFFECTS.length ? Key.namespaced(POTION_EFFECTS[id]) : null; + return id >= 0 && id < POTION_EFFECTS.length ? Key.namespaced(POTION_EFFECTS[id]) : null; } public static String idToKeyOrLuck(final int id) { - return id >= 1 && id < POTION_EFFECTS.length ? Key.namespaced(POTION_EFFECTS[id]) : "minecraft:luck"; + return id >= 0 && id < POTION_EFFECTS.length ? Key.namespaced(POTION_EFFECTS[id]) : "minecraft:luck"; } public static int keyToId(final String key) { diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/MapDecorations1_20_3.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/MapDecorations1_20_5.java similarity index 95% rename from common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/MapDecorations1_20_3.java rename to common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/MapDecorations1_20_5.java index 37925b79f..08f07bd97 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/MapDecorations1_20_3.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/MapDecorations1_20_5.java @@ -19,7 +19,7 @@ package com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data; import com.viaversion.viaversion.util.KeyMappings; -public final class MapDecorations1_20_3 { +public final class MapDecorations1_20_5 { private static final KeyMappings MAP_DECORATIONS = new KeyMappings( "player", @@ -55,7 +55,8 @@ public final class MapDecorations1_20_3 { "village_snowy", "village_taiga", "jungle_temple", - "swamp_hut" + "swamp_hut", + "trial_chambers" ); public static String idToKey(final int index) { diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/PotionEffects1_20_5.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/PotionEffects1_20_5.java new file mode 100644 index 000000000..e9f59ef20 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/PotionEffects1_20_5.java @@ -0,0 +1,89 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data; + +import com.viaversion.viaversion.util.Key; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import org.checkerframework.checker.nullness.qual.Nullable; + +public final class PotionEffects1_20_5 { + + private static final Object2IntMap KEY_TO_ID = new Object2IntOpenHashMap<>(); + private static final String[] POTION_EFFECTS = { + "speed", + "slowness", + "haste", + "mining_fatigue", + "strength", + "instant_health", + "instant_damage", + "jump_boost", + "nausea", + "regeneration", + "resistance", + "fire_resistance", + "water_breathing", + "invisibility", + "blindness", + "night_vision", + "hunger", + "weakness", + "poison", + "wither", + "health_boost", + "absorption", + "saturation", + "glowing", + "levitation", + "luck", + "unluck", + "slow_falling", + "conduit_power", + "dolphins_grace", + "bad_omen", + "hero_of_the_village", + "darkness", + "trial_omen", + "raid_omen", + "wind_charged", + "weaving", + "oozing", + "infested" + }; + + static { + for (int i = 0; i < POTION_EFFECTS.length; i++) { + final String effect = POTION_EFFECTS[i]; + KEY_TO_ID.put(effect, i); + } + KEY_TO_ID.defaultReturnValue(-1); + } + + public static @Nullable String idToKey(final int id) { + return id >= 0 && id < POTION_EFFECTS.length ? Key.namespaced(POTION_EFFECTS[id]) : null; + } + + public static String idToKeyOrLuck(final int id) { + return id >= 0 && id < POTION_EFFECTS.length ? Key.namespaced(POTION_EFFECTS[id]) : "minecraft:luck"; + } + + public static int keyToId(final String key) { + return KEY_TO_ID.getInt(Key.stripMinecraftNamespace(key)); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/Potions1_20_3.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/Potions1_20_5.java similarity index 93% rename from common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/Potions1_20_3.java rename to common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/Potions1_20_5.java index 16375b90f..83213e846 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/Potions1_20_3.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/data/Potions1_20_5.java @@ -20,10 +20,9 @@ package com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data; import com.viaversion.viaversion.util.KeyMappings; import org.checkerframework.checker.nullness.qual.Nullable; -public final class Potions1_20_3 { +public final class Potions1_20_5 { private static final KeyMappings POTIONS = new KeyMappings( - "empty", "water", "mundane", "thick", @@ -65,7 +64,11 @@ public final class Potions1_20_3 { "long_weakness", "luck", "slow_falling", - "long_slow_falling" + "long_slow_falling", + "wind_charged", + "weaving", + "oozing", + "infested" ); public static @Nullable String idToKey(final int id) { diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/rewriter/BlockItemPacketRewriter1_20_5.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/rewriter/BlockItemPacketRewriter1_20_5.java index 9b0d88453..16d2d739d 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/rewriter/BlockItemPacketRewriter1_20_5.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_20_5to1_20_3/rewriter/BlockItemPacketRewriter1_20_5.java @@ -18,6 +18,7 @@ package com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.rewriter; import com.github.steveice10.opennbt.stringified.SNBT; +import com.github.steveice10.opennbt.tag.builtin.ByteTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; @@ -68,7 +69,6 @@ import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2; import com.viaversion.viaversion.api.type.types.version.Types1_20_3; import com.viaversion.viaversion.api.type.types.version.Types1_20_5; -import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.util.PotionEffects; import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ClientboundPacket1_20_3; import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.ClientboundPackets1_20_3; import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.rewriter.RecipeRewriter1_20_3; @@ -78,8 +78,9 @@ import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.BannerPat import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.DyeColors; import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.Enchantments1_20_3; import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.Instruments1_20_3; -import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.MapDecorations1_20_3; -import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.Potions1_20_3; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.MapDecorations1_20_5; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.PotionEffects1_20_5; +import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.Potions1_20_5; import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.TrimMaterials1_20_3; import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.TrimPatterns1_20_3; import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ServerboundPacket1_20_5; @@ -105,6 +106,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter { public static final String[] MOB_TAGS = {"NoAI", "Silent", "NoGravity", "Glowing", "Invulnerable", "Health", "Age", "Variant", "HuntingCooldown", "BucketVariantTag"}; + private static final StructuredDataConverter DATA_CONVERTER = new StructuredDataConverter(false); private static final GameProfile.Property[] EMPTY_PROPERTIES = new GameProfile.Property[0]; private static final StatePropertyMatcher[] EMPTY_PROPERTY_MATCHERS = new StatePropertyMatcher[0]; @@ -248,10 +250,10 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter structuredData : data.data().values()) { - StructuredDataConverter.writeToTag(structuredData, tag); + dataConverter.writeToTag(structuredData, tag); } return dataItem; @@ -366,7 +368,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter attributeModifiersTag = tag.getListTag("AttributeModifiers", CompoundTag.class); if (attributeModifiersTag != null) { - updateAttributes(data, attributeModifiersTag, (hideFlagsValue & StructuredDataConverter.HIDE_ATTRIBUTES) == 0); + updateAttributes(data, tag, attributeModifiersTag, (hideFlagsValue & StructuredDataConverter.HIDE_ATTRIBUTES) == 0); } final CompoundTag fireworksTag = tag.getCompoundTag("Fireworks"); @@ -432,10 +434,56 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter attributeModifiersTag, final boolean showInTooltip) { - final AttributeModifier[] modifiers = attributeModifiersTag.stream().map(modifierTag -> { + private void updateAttributes(final StructuredDataContainer data, final CompoundTag tag, final ListTag attributeModifiersTag, final boolean showInTooltip) { + final List modifiers = new ArrayList<>(); + for (int i = 0; i < attributeModifiersTag.size(); i++) { + final CompoundTag modifierTag = attributeModifiersTag.get(i); final String attributeName = modifierTag.getString("AttributeName"); final String name = modifierTag.getString("Name"); final NumberTag amountTag = modifierTag.getNumberTag("Amount"); final IntArrayTag uuidTag = modifierTag.getIntArrayTag("UUID"); final int slotType = modifierTag.getInt("Slot"); if (name == null || attributeName == null || amountTag == null || uuidTag == null) { - return null; + continue; } final int operationId = modifierTag.getInt("Operation"); if (operationId < 0 || operationId > 2) { - return null; + continue; } final int attributeId = Attributes1_20_5.keyToId(attributeName); if (attributeId == -1) { - return null; + continue; } - return new AttributeModifier( + modifiers.add(new AttributeModifier( attributeId, new ModifierData( UUIDUtil.fromIntArray(uuidTag.getValue()), @@ -542,9 +592,9 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter 0 ? id - 1 : null; // Empty potion type removed + final int id = Potions1_20_5.keyToId(potion); + if (id != -1) { + potionId = id; + } } final NumberTag customPotionColorTag = tag.getNumberTag("CustomPotionColor"); @@ -580,8 +632,8 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter, DataConverter> REWRITERS = new Reference2ObjectOpenHashMap<>(); + private static final String BACKUP_TAG_KEY = "VV|DataComponents"; - static { + private final Map, DataConverter> rewriters = new Reference2ObjectOpenHashMap<>(); + private final boolean backupInconvertibleData; + + public StructuredDataConverter(final boolean backupInconvertibleData) { + this.backupInconvertibleData = backupInconvertibleData; register(StructuredDataKey.CUSTOM_DATA, (data, tag) -> { // Handled manually }); @@ -102,7 +107,8 @@ final class StructuredDataConverter { register(StructuredDataKey.STORED_ENCHANTMENTS, (data, tag) -> convertEnchantments(data, tag, true)); register(StructuredDataKey.ATTRIBUTE_MODIFIERS, (data, tag) -> { final ListTag modifiers = new ListTag<>(CompoundTag.class); - for (final AttributeModifier modifier : data.modifiers()) { + for (int i = 0; i < data.modifiers().length; i++) { + final AttributeModifier modifier = data.modifiers()[i]; final String identifier = Attributes1_20_5.idToKey(modifier.attribute()); if (identifier == null) { continue; @@ -137,14 +143,14 @@ final class StructuredDataConverter { final ListTag decorations = new ListTag<>(CompoundTag.class); for (final Map.Entry entry : data.entrySet()) { final CompoundTag decorationTag = (CompoundTag) entry.getValue(); - final int id = MapDecorations1_20_3.keyToId(decorationTag.getString("type")); + final int id = MapDecorations1_20_5.keyToId(decorationTag.getString("type")); if (id == -1) { continue; } final CompoundTag convertedDecoration = new CompoundTag(); convertedDecoration.putString("id", entry.getKey()); - convertedDecoration.putInt("type", id); + convertedDecoration.putInt("type", id); // Write the id even if it is a new 1.20.5 one convertedDecoration.putDouble("x", decorationTag.getDouble("x")); convertedDecoration.putDouble("z", decorationTag.getDouble("z")); convertedDecoration.putFloat("rot", decorationTag.getFloat("rotation")); @@ -240,6 +246,7 @@ final class StructuredDataConverter { register(StructuredDataKey.INSTRUMENT, (data, tag) -> { if (!data.hasId()) { // Can't do anything with direct values + // TODO Backup return; } @@ -294,11 +301,15 @@ final class StructuredDataConverter { } }); register(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, (data, tag) -> { + if (backupInconvertibleData) { + createBackupTag(tag).putBoolean("enchantment_glint_override", data); + } if (!data) { // There is no way to remove the glint without removing the enchantments // which would lead to broken data, so we just don't do anything return; } + // If the glint is overridden, we just add an invalid enchantment to the existing list ListTag enchantmentsTag = tag.getListTag("Enchantments", CompoundTag.class); if (enchantmentsTag == null) { @@ -314,7 +325,7 @@ final class StructuredDataConverter { }); register(StructuredDataKey.POTION_CONTENTS, (data, tag) -> { if (data.potion() != null) { - final String potion = Potions1_20_3.idToKey(data.potion() + 1); // Empty potion type added + final String potion = Potions1_20_5.idToKey(data.potion()); // Include 1.20.5 names if (potion != null) { tag.putString("Potion", potion); } @@ -322,12 +333,13 @@ final class StructuredDataConverter { if (data.customColor() != null) { tag.putInt("CustomPotionColor", data.customColor()); } + final ListTag customPotionEffectsTag = new ListTag<>(CompoundTag.class); for (final PotionEffect effect : data.customEffects()) { final CompoundTag effectTag = new CompoundTag(); - final String id = PotionEffects.idToKey(effect.effect() + 1); // Empty potion type added + final String id = PotionEffects1_20_5.idToKey(effect.effect()); if (id != null) { - effectTag.putString("id", id); + effectTag.putString("id", id); // Include 1.20.5 ids } final PotionEffectData details = effect.effectData(); @@ -345,9 +357,9 @@ final class StructuredDataConverter { final ListTag effectsTag = new ListTag<>(CompoundTag.class); for (final SuspiciousStewEffect effect : data) { final CompoundTag effectTag = new CompoundTag(); - final String id = PotionEffects.idToKey(effect.mobEffect() + 1); + final String id = PotionEffects1_20_5.idToKey(effect.mobEffect()); if (id != null) { - effectTag.putString("id", id); + effectTag.putString("id", id); // Include 1.20.5 ids } effectTag.putInt("duration", effect.duration()); @@ -360,8 +372,10 @@ final class StructuredDataConverter { for (final BannerPatternLayer layer : data) { final String pattern = BannerPatterns1_20_5.fullIdToCompact(BannerPatterns1_20_5.idToKey(layer.pattern().id())); if (pattern == null) { + // TODO Backup continue; } + final CompoundTag patternTag = new CompoundTag(); patternTag.putString("Pattern", pattern); patternTag.putInt("Color", layer.dyeColor()); @@ -444,21 +458,57 @@ final class StructuredDataConverter { register(StructuredDataKey.HIDE_TOOLTIP, (data, tag) -> { // Hide everything we can hide putHideFlag(tag, 0xFF); + if (backupInconvertibleData) { + createBackupTag(tag).putBoolean("hide_tooltip", true); + } }); - // Nothing to do for these - noop(StructuredDataKey.INTANGIBLE_PROJECTILE); - noop(StructuredDataKey.MAX_STACK_SIZE); - noop(StructuredDataKey.MAX_DAMAGE); - noop(StructuredDataKey.RARITY); - noop(StructuredDataKey.FOOD); - noop(StructuredDataKey.FIRE_RESISTANT); - noop(StructuredDataKey.TOOL); - noop(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER); + // New in 1.20.5 + register(StructuredDataKey.INTANGIBLE_PROJECTILE, (data, tag) -> { + if (backupInconvertibleData) { + createBackupTag(tag).put("intangible_projectile", data); + } + }); + register(StructuredDataKey.MAX_STACK_SIZE, (data, tag) -> { + if (backupInconvertibleData) { + createBackupTag(tag).putInt("max_stack_size", data); + } + }); + register(StructuredDataKey.MAX_DAMAGE, (data, tag) -> { + if (backupInconvertibleData) { + createBackupTag(tag).putInt("max_damage", data); + } + }); + register(StructuredDataKey.RARITY, (data, tag) -> { + if (backupInconvertibleData) { + createBackupTag(tag).putInt("rarity", data); + } + }); + register(StructuredDataKey.FOOD, (data, tag) -> { + if (backupInconvertibleData) { + //createBackupTag(tag).; // TODO Backup + } + }); + register(StructuredDataKey.FIRE_RESISTANT, (data, tag) -> { + if (backupInconvertibleData) { + createBackupTag(tag).putBoolean("fire_resistant", true); + } + }); + register(StructuredDataKey.TOOL, (data, tag) -> { + if (backupInconvertibleData) { + //createBackupTag(tag).; // TODO Backup + } + }); + register(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER, (data, tag) -> { + if (backupInconvertibleData) { + createBackupTag(tag).putInt("ominous_bottle_amplifier", data); + } + }); } - private static String toItemName(final int id) { + private String toItemName(final int id) { final int mappedId = Protocol1_20_5To1_20_3.MAPPINGS.getOldItemId(id); + // TODO Backup return mappedId != -1 ? Protocol1_20_5To1_20_3.MAPPINGS.itemName(mappedId) : ""; } @@ -480,12 +530,13 @@ final class StructuredDataConverter { return subTag; } - private static void convertBlockPredicates(final CompoundTag tag, final AdventureModePredicate data, final String key, final int hideFlag) { + private void convertBlockPredicates(final CompoundTag tag, final AdventureModePredicate data, final String key, final int hideFlag) { final ListTag predicatedListTag = new ListTag<>(StringTag.class); for (final BlockPredicate predicate : data.predicates()) { final HolderSet holders = predicate.holderSet(); if (holders == null) { // Can't do (nicely) + // TODO Backup continue; } if (holders.hasTagKey()) { @@ -504,7 +555,7 @@ final class StructuredDataConverter { } } - private static StringTag serializeBlockPredicate(final BlockPredicate predicate, final String identifier) { + private StringTag serializeBlockPredicate(final BlockPredicate predicate, final String identifier) { final StringBuilder builder = new StringBuilder(identifier); if (predicate.propertyMatchers() != null) { for (final StatePropertyMatcher matcher : predicate.propertyMatchers()) { @@ -521,7 +572,7 @@ final class StructuredDataConverter { return new StringTag(builder.toString()); } - private static CompoundTag convertExplosion(final FireworkExplosion explosion) { + private CompoundTag convertExplosion(final FireworkExplosion explosion) { final CompoundTag explosionTag = new CompoundTag(); explosionTag.putInt("Type", explosion.shape()); explosionTag.put("Colors", new IntArrayTag(explosion.colors().clone())); @@ -531,7 +582,7 @@ final class StructuredDataConverter { return explosionTag; } - private static void convertItemList(final Item[] items, final CompoundTag tag, final String key) { + private void convertItemList(final Item[] items, final CompoundTag tag, final String key) { final ListTag itemsTag = new ListTag<>(CompoundTag.class); for (final Item item : items) { final CompoundTag savedItem = new CompoundTag(); @@ -548,10 +599,20 @@ final class StructuredDataConverter { tag.put(key, itemsTag); } - private static void convertEnchantments(final Enchantments data, final CompoundTag tag, final boolean storedEnchantments) { + private void convertEnchantments(final Enchantments data, final CompoundTag tag, final boolean storedEnchantments) { final ListTag enchantments = new ListTag<>(CompoundTag.class); + final int piercingId = Enchantments1_20_3.keyToId("piercing"); for (final Int2IntMap.Entry entry : data.enchantments().int2IntEntrySet()) { - final String identifier = Enchantments1_20_3.idToKey(entry.getIntKey()); + int id = entry.getIntKey(); + if (id > piercingId) { + if (id <= piercingId + 3) { + // Density, breach, wind burst - Already backed up by VB + continue; + } + id -= 3; + } + + final String identifier = Enchantments1_20_3.idToKey(id); if (identifier == null) { continue; } @@ -568,28 +629,35 @@ final class StructuredDataConverter { } } - private static void putHideFlag(final CompoundTag tag, final int value) { + private void putHideFlag(final CompoundTag tag, final int value) { tag.putInt("HideFlags", tag.getInt("HideFlags") | value); } - public static void writeToTag(final StructuredData data, final CompoundTag tag) { + public void writeToTag(final StructuredData data, final CompoundTag tag) { if (data.isEmpty()) { return; } //noinspection unchecked - final DataConverter converter = (DataConverter) REWRITERS.get(data.key()); + final DataConverter converter = (DataConverter) rewriters.get(data.key()); Preconditions.checkNotNull(converter, "No converter for %s found", data.key()); converter.convert(data.value(), tag); } - private static void register(final StructuredDataKey key, final DataConverter converter) { - REWRITERS.put(key, converter); + private void register(final StructuredDataKey key, final DataConverter converter) { + rewriters.put(key, converter); } - private static void noop(final StructuredDataKey key) { - register(key, (data, tag) -> { - }); + private static CompoundTag createBackupTag(final CompoundTag tag) { + return getOrCreate(tag, BACKUP_TAG_KEY); + } + + static @Nullable CompoundTag removeBackupTag(final CompoundTag tag) { + final CompoundTag backupTag = tag.getCompoundTag(BACKUP_TAG_KEY); + if (backupTag != null) { + tag.remove(BACKUP_TAG_KEY); + } + return backupTag; } @FunctionalInterface