Back up 1.20.5 data components in VB for creative clients

This commit is contained in:
Nassim Jahnke 2024-04-05 15:38:12 +02:00
parent c743c20334
commit c2489c7a4c
No known key found for this signature in database
GPG Key ID: EF6771C01F6EF02F
7 changed files with 298 additions and 81 deletions

View File

@ -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<Clientboun
final CompoundTag effectTag = (CompoundTag) tag;
final Tag idTag = effectTag.remove("Id");
if (idTag instanceof NumberTag) {
final String key = PotionEffects.idToKey(((NumberTag) idTag).asInt());
// Empty effect removed
final String key = PotionEffects1_20_2.idToKey(((NumberTag) idTag).asInt() - 1);
if (key != null) {
effectTag.put("id", new StringTag(key));
}
@ -414,8 +415,8 @@ public final class BlockItemPacketRewriter1_20_2 extends ItemRewriter<Clientboun
final CompoundTag effectTag = (CompoundTag) tag;
final Tag idTag = effectTag.remove("id");
if (idTag instanceof StringTag) {
final int id = PotionEffects.keyToId(((StringTag) idTag).getValue());
effectTag.put("Id", new IntTag(id));
final int id = PotionEffects1_20_2.keyToId(((StringTag) idTag).getValue());
effectTag.putInt("Id", id + 1); // Account for empty effect at id 0
}
renameTag(effectTag, "amplifier", "Amplifier");
@ -443,12 +444,12 @@ public final class BlockItemPacketRewriter1_20_2 extends ItemRewriter<Clientboun
final Tag primaryEffect = tag.remove("Primary");
if (primaryEffect instanceof NumberTag && ((NumberTag) primaryEffect).asInt() != 0) {
tag.put("primary_effect", new StringTag(PotionEffects.idToKeyOrLuck(((NumberTag) primaryEffect).asInt())));
tag.put("primary_effect", new StringTag(PotionEffects1_20_2.idToKeyOrLuck(((NumberTag) primaryEffect).asInt() - 1)));
}
final Tag secondaryEffect = tag.remove("Secondary");
if (secondaryEffect instanceof NumberTag && ((NumberTag) secondaryEffect).asInt() != 0) {
tag.put("secondary_effect", new StringTag(PotionEffects.idToKeyOrLuck(((NumberTag) secondaryEffect).asInt())));
tag.put("secondary_effect", new StringTag(PotionEffects1_20_2.idToKeyOrLuck(((NumberTag) secondaryEffect).asInt() - 1)));
}
return tag;
}

View File

@ -22,11 +22,10 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class PotionEffects {
public final class PotionEffects1_20_2 {
private static final Object2IntMap<String> 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) {

View File

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

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<String> 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));
}
}

View File

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

View File

@ -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<ClientboundPacket1_20_3, ServerboundPacket1_20_5, Protocol1_20_5To1_20_3> {
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<Clientboun
if (item == null) return null;
super.handleItemToServer(item);
return toOldItem(item);
return toOldItem(item, DATA_CONVERTER);
}
public Item toOldItem(final Item item) {
public Item toOldItem(final Item item, final StructuredDataConverter dataConverter) {
// Start out with custom data and add the rest on top, or short-curcuit with the original item
final StructuredDataContainer data = item.structuredData();
data.setIdLookup(protocol, true);
@ -264,7 +266,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
}
for (final StructuredData<?> 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<Clientboun
final ListTag<CompoundTag> 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<Clientboun
}
}
final CompoundTag backupTag = StructuredDataConverter.removeBackupTag(tag);
if (backupTag != null) {
// Restore original data components
restoreFromBackupTag(backupTag, data);
}
data.set(StructuredDataKey.CUSTOM_DATA, tag);
return item;
}
private void restoreFromBackupTag(final CompoundTag backupTag, final StructuredDataContainer data) {
final ByteTag enchantmentGlintOverride = backupTag.getByteTag("enchantment_glint_override");
if (enchantmentGlintOverride != null) {
data.set(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, enchantmentGlintOverride.asBoolean());
}
if (backupTag.contains("hide_tooltip")) {
data.set(StructuredDataKey.HIDE_TOOLTIP);
}
final Tag intangibleProjectile = backupTag.get("intangible_projectile");
if (intangibleProjectile != null) {
data.set(StructuredDataKey.INTANGIBLE_PROJECTILE, intangibleProjectile);
}
final IntTag maxStackSize = backupTag.getIntTag("max_stack_size");
if (maxStackSize != null) {
data.set(StructuredDataKey.MAX_STACK_SIZE, maxStackSize.asInt());
}
final IntTag maxDamage = backupTag.getIntTag("max_damage");
if (maxDamage != null) {
data.set(StructuredDataKey.MAX_DAMAGE, maxDamage.asInt());
}
final IntTag rarity = backupTag.getIntTag("rarity");
if (rarity != null) {
data.set(StructuredDataKey.RARITY, rarity.asInt());
}
if (backupTag.contains("fire_resistant")) {
data.set(StructuredDataKey.FIRE_RESISTANT);
}
final IntTag ominousBottleAmplifier = backupTag.getIntTag("ominous_bottle_amplifier");
if (ominousBottleAmplifier != null) {
data.set(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER, ominousBottleAmplifier.asInt());
}
}
private int unmappedItemId(final String name) {
return protocol.getMappingData().itemId(name);
}
@ -512,28 +560,30 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
);
}
private void updateAttributes(final StructuredDataContainer data, final ListTag<CompoundTag> attributeModifiersTag, final boolean showInTooltip) {
final AttributeModifier[] modifiers = attributeModifiersTag.stream().map(modifierTag -> {
private void updateAttributes(final StructuredDataContainer data, final CompoundTag tag, final ListTag<CompoundTag> attributeModifiersTag, final boolean showInTooltip) {
final List<AttributeModifier> 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<Clientboun
operationId
),
slotType
);
}).filter(Objects::nonNull).toArray(AttributeModifier[]::new);
data.set(StructuredDataKey.ATTRIBUTE_MODIFIERS, new AttributeModifiers(modifiers, showInTooltip));
));
}
data.set(StructuredDataKey.ATTRIBUTE_MODIFIERS, new AttributeModifiers(modifiers.toArray(new AttributeModifier[0]), showInTooltip));
}
private PotionEffectData readPotionEffectData(final CompoundTag tag) {
@ -566,8 +616,10 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
final String potion = tag.getString("Potion");
Integer potionId = null;
if (potion != null) {
final int id = Potions1_20_3.keyToId(potion);
potionId = id > 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<Clientboun
return null;
}
final int id = PotionEffects.keyToId(identifier) - 1;
if (id < 0) {
final int id = PotionEffects1_20_5.keyToId(identifier);
if (id == -1) {
return null;
}
return new PotionEffect(id, readPotionEffectData(effectTag));
@ -723,14 +775,17 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
final SuspiciousStewEffect[] suspiciousStewEffects = new SuspiciousStewEffect[effects.size()];
for (int i = 0; i < effects.size(); i++) {
final CompoundTag effect = effects.get(i);
final String effectId = effect.getString("id", "luck");
final String effectIdString = effect.getString("id", "luck");
final int duration = effect.getInt("duration");
final int effectId = PotionEffects1_20_5.keyToId(effectIdString);
if (effectId != -1) {
final SuspiciousStewEffect stewEffect = new SuspiciousStewEffect(
PotionEffects.keyToId(effectId) - 1,
effectId,
duration
);
suspiciousStewEffects[i] = stewEffect;
}
}
data.set(StructuredDataKey.SUSPICIOUS_STEW_EFFECTS, suspiciousStewEffects);
}
@ -941,7 +996,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
final float rotation = decorationTag.getFloat("rot");
final CompoundTag updatedDecorationTag = new CompoundTag();
updatedDecorationTag.putString("type", MapDecorations1_20_3.idToKey(type));
updatedDecorationTag.putString("type", MapDecorations1_20_5.idToKey(type));
updatedDecorationTag.putDouble("x", x);
updatedDecorationTag.putDouble("z", z);
updatedDecorationTag.putFloat("rotation", rotation);

View File

@ -44,14 +44,14 @@ import com.viaversion.viaversion.api.minecraft.item.data.PotionEffect;
import com.viaversion.viaversion.api.minecraft.item.data.PotionEffectData;
import com.viaversion.viaversion.api.minecraft.item.data.StatePropertyMatcher;
import com.viaversion.viaversion.api.minecraft.item.data.SuspiciousStewEffect;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.util.PotionEffects;
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.Protocol1_20_5To1_20_3;
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.Attributes1_20_5;
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.BannerPatterns1_20_5;
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.util.ComponentUtil;
import com.viaversion.viaversion.util.UUIDUtil;
@ -59,8 +59,9 @@ import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
final class StructuredDataConverter {
public final class StructuredDataConverter {
static final int HIDE_ENCHANTMENTS = 1;
static final int HIDE_ATTRIBUTES = 1 << 1;
@ -71,9 +72,13 @@ final class StructuredDataConverter {
static final int HIDE_DYE_COLOR = 1 << 6;
static final int HIDE_ARMOR_TRIM = 1 << 7;
private static final Map<StructuredDataKey<?>, DataConverter<?>> REWRITERS = new Reference2ObjectOpenHashMap<>();
private static final String BACKUP_TAG_KEY = "VV|DataComponents";
static {
private final Map<StructuredDataKey<?>, 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<CompoundTag> 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<CompoundTag> decorations = new ListTag<>(CompoundTag.class);
for (final Map.Entry<String, Tag> 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<CompoundTag> 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<CompoundTag> 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<CompoundTag> 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<StringTag> 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<CompoundTag> 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<CompoundTag> 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 <T> void writeToTag(final StructuredData<T> data, final CompoundTag tag) {
public <T> void writeToTag(final StructuredData<T> data, final CompoundTag tag) {
if (data.isEmpty()) {
return;
}
//noinspection unchecked
final DataConverter<T> converter = (DataConverter<T>) REWRITERS.get(data.key());
final DataConverter<T> converter = (DataConverter<T>) rewriters.get(data.key());
Preconditions.checkNotNull(converter, "No converter for %s found", data.key());
converter.convert(data.value(), tag);
}
private static <T> void register(final StructuredDataKey<T> key, final DataConverter<T> converter) {
REWRITERS.put(key, converter);
private <T> void register(final StructuredDataKey<T> key, final DataConverter<T> converter) {
rewriters.put(key, converter);
}
private static <T> void noop(final StructuredDataKey<T> 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