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_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.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.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.BlockRewriter;
import com.viaversion.viaversion.rewriter.ItemRewriter; import com.viaversion.viaversion.rewriter.ItemRewriter;
import com.viaversion.viaversion.util.MathUtil; 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 CompoundTag effectTag = (CompoundTag) tag;
final Tag idTag = effectTag.remove("Id"); final Tag idTag = effectTag.remove("Id");
if (idTag instanceof NumberTag) { 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) { if (key != null) {
effectTag.put("id", new StringTag(key)); 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 CompoundTag effectTag = (CompoundTag) tag;
final Tag idTag = effectTag.remove("id"); final Tag idTag = effectTag.remove("id");
if (idTag instanceof StringTag) { if (idTag instanceof StringTag) {
final int id = PotionEffects.keyToId(((StringTag) idTag).getValue()); final int id = PotionEffects1_20_2.keyToId(((StringTag) idTag).getValue());
effectTag.put("Id", new IntTag(id)); effectTag.putInt("Id", id + 1); // Account for empty effect at id 0
} }
renameTag(effectTag, "amplifier", "Amplifier"); renameTag(effectTag, "amplifier", "Amplifier");
@ -443,12 +444,12 @@ public final class BlockItemPacketRewriter1_20_2 extends ItemRewriter<Clientboun
final Tag primaryEffect = tag.remove("Primary"); final Tag primaryEffect = tag.remove("Primary");
if (primaryEffect instanceof NumberTag && ((NumberTag) primaryEffect).asInt() != 0) { 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"); final Tag secondaryEffect = tag.remove("Secondary");
if (secondaryEffect instanceof NumberTag && ((NumberTag) secondaryEffect).asInt() != 0) { 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; return tag;
} }

View File

@ -22,11 +22,10 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import org.checkerframework.checker.nullness.qual.Nullable; 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 Object2IntMap<String> KEY_TO_ID = new Object2IntOpenHashMap<>();
private static final String[] POTION_EFFECTS = { private static final String[] POTION_EFFECTS = {
"", // No effect
"speed", "speed",
"slowness", "slowness",
"haste", "haste",
@ -63,18 +62,19 @@ public final class PotionEffects {
}; };
static { 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]; final String effect = POTION_EFFECTS[i];
KEY_TO_ID.put(effect, i); KEY_TO_ID.put(effect, i);
} }
KEY_TO_ID.defaultReturnValue(-1);
} }
public static @Nullable String idToKey(final int id) { 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) { 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) { 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; 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( private static final KeyMappings MAP_DECORATIONS = new KeyMappings(
"player", "player",
@ -55,7 +55,8 @@ public final class MapDecorations1_20_3 {
"village_snowy", "village_snowy",
"village_taiga", "village_taiga",
"jungle_temple", "jungle_temple",
"swamp_hut" "swamp_hut",
"trial_chambers"
); );
public static String idToKey(final int index) { 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 com.viaversion.viaversion.util.KeyMappings;
import org.checkerframework.checker.nullness.qual.Nullable; 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( private static final KeyMappings POTIONS = new KeyMappings(
"empty",
"water", "water",
"mundane", "mundane",
"thick", "thick",
@ -65,7 +64,11 @@ public final class Potions1_20_3 {
"long_weakness", "long_weakness",
"luck", "luck",
"slow_falling", "slow_falling",
"long_slow_falling" "long_slow_falling",
"wind_charged",
"weaving",
"oozing",
"infested"
); );
public static @Nullable String idToKey(final int id) { 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; package com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.rewriter;
import com.github.steveice10.opennbt.stringified.SNBT; 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.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag; 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.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_3;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5; 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.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.packet.ClientboundPackets1_20_3;
import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.rewriter.RecipeRewriter1_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.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.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.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.MapDecorations1_20_5;
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.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.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.data.TrimPatterns1_20_3;
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.ServerboundPacket1_20_5; 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 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"}; 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 GameProfile.Property[] EMPTY_PROPERTIES = new GameProfile.Property[0];
private static final StatePropertyMatcher[] EMPTY_PROPERTY_MATCHERS = new StatePropertyMatcher[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; if (item == null) return null;
super.handleItemToServer(item); 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 // Start out with custom data and add the rest on top, or short-curcuit with the original item
final StructuredDataContainer data = item.structuredData(); final StructuredDataContainer data = item.structuredData();
data.setIdLookup(protocol, true); data.setIdLookup(protocol, true);
@ -264,7 +266,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
} }
for (final StructuredData<?> structuredData : data.data().values()) { for (final StructuredData<?> structuredData : data.data().values()) {
StructuredDataConverter.writeToTag(structuredData, tag); dataConverter.writeToTag(structuredData, tag);
} }
return dataItem; return dataItem;
@ -366,7 +368,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
final ListTag<CompoundTag> attributeModifiersTag = tag.getListTag("AttributeModifiers", CompoundTag.class); final ListTag<CompoundTag> attributeModifiersTag = tag.getListTag("AttributeModifiers", CompoundTag.class);
if (attributeModifiersTag != null) { 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"); 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); data.set(StructuredDataKey.CUSTOM_DATA, tag);
return item; 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) { private int unmappedItemId(final String name) {
return protocol.getMappingData().itemId(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) { private void updateAttributes(final StructuredDataContainer data, final CompoundTag tag, final ListTag<CompoundTag> attributeModifiersTag, final boolean showInTooltip) {
final AttributeModifier[] modifiers = attributeModifiersTag.stream().map(modifierTag -> { 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 attributeName = modifierTag.getString("AttributeName");
final String name = modifierTag.getString("Name"); final String name = modifierTag.getString("Name");
final NumberTag amountTag = modifierTag.getNumberTag("Amount"); final NumberTag amountTag = modifierTag.getNumberTag("Amount");
final IntArrayTag uuidTag = modifierTag.getIntArrayTag("UUID"); final IntArrayTag uuidTag = modifierTag.getIntArrayTag("UUID");
final int slotType = modifierTag.getInt("Slot"); final int slotType = modifierTag.getInt("Slot");
if (name == null || attributeName == null || amountTag == null || uuidTag == null) { if (name == null || attributeName == null || amountTag == null || uuidTag == null) {
return null; continue;
} }
final int operationId = modifierTag.getInt("Operation"); final int operationId = modifierTag.getInt("Operation");
if (operationId < 0 || operationId > 2) { if (operationId < 0 || operationId > 2) {
return null; continue;
} }
final int attributeId = Attributes1_20_5.keyToId(attributeName); final int attributeId = Attributes1_20_5.keyToId(attributeName);
if (attributeId == -1) { if (attributeId == -1) {
return null; continue;
} }
return new AttributeModifier( modifiers.add(new AttributeModifier(
attributeId, attributeId,
new ModifierData( new ModifierData(
UUIDUtil.fromIntArray(uuidTag.getValue()), UUIDUtil.fromIntArray(uuidTag.getValue()),
@ -542,9 +592,9 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
operationId operationId
), ),
slotType 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) { 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"); final String potion = tag.getString("Potion");
Integer potionId = null; Integer potionId = null;
if (potion != null) { if (potion != null) {
final int id = Potions1_20_3.keyToId(potion); final int id = Potions1_20_5.keyToId(potion);
potionId = id > 0 ? id - 1 : null; // Empty potion type removed if (id != -1) {
potionId = id;
}
} }
final NumberTag customPotionColorTag = tag.getNumberTag("CustomPotionColor"); final NumberTag customPotionColorTag = tag.getNumberTag("CustomPotionColor");
@ -580,8 +632,8 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
return null; return null;
} }
final int id = PotionEffects.keyToId(identifier) - 1; final int id = PotionEffects1_20_5.keyToId(identifier);
if (id < 0) { if (id == -1) {
return null; return null;
} }
return new PotionEffect(id, readPotionEffectData(effectTag)); return new PotionEffect(id, readPotionEffectData(effectTag));
@ -723,13 +775,16 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
final SuspiciousStewEffect[] suspiciousStewEffects = new SuspiciousStewEffect[effects.size()]; final SuspiciousStewEffect[] suspiciousStewEffects = new SuspiciousStewEffect[effects.size()];
for (int i = 0; i < effects.size(); i++) { for (int i = 0; i < effects.size(); i++) {
final CompoundTag effect = effects.get(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 duration = effect.getInt("duration");
final SuspiciousStewEffect stewEffect = new SuspiciousStewEffect( final int effectId = PotionEffects1_20_5.keyToId(effectIdString);
PotionEffects.keyToId(effectId) - 1, if (effectId != -1) {
duration final SuspiciousStewEffect stewEffect = new SuspiciousStewEffect(
); effectId,
suspiciousStewEffects[i] = stewEffect; duration
);
suspiciousStewEffects[i] = stewEffect;
}
} }
data.set(StructuredDataKey.SUSPICIOUS_STEW_EFFECTS, suspiciousStewEffects); 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 float rotation = decorationTag.getFloat("rot");
final CompoundTag updatedDecorationTag = new CompoundTag(); 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("x", x);
updatedDecorationTag.putDouble("z", z); updatedDecorationTag.putDouble("z", z);
updatedDecorationTag.putFloat("rotation", rotation); 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.PotionEffectData;
import com.viaversion.viaversion.api.minecraft.item.data.StatePropertyMatcher; import com.viaversion.viaversion.api.minecraft.item.data.StatePropertyMatcher;
import com.viaversion.viaversion.api.minecraft.item.data.SuspiciousStewEffect; 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.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.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.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.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.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.MapDecorations1_20_5;
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.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.TrimMaterials1_20_3;
import com.viaversion.viaversion.util.ComponentUtil; import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.UUIDUtil; 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.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
import java.util.Map; 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_ENCHANTMENTS = 1;
static final int HIDE_ATTRIBUTES = 1 << 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_DYE_COLOR = 1 << 6;
static final int HIDE_ARMOR_TRIM = 1 << 7; 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) -> { register(StructuredDataKey.CUSTOM_DATA, (data, tag) -> {
// Handled manually // Handled manually
}); });
@ -102,7 +107,8 @@ final class StructuredDataConverter {
register(StructuredDataKey.STORED_ENCHANTMENTS, (data, tag) -> convertEnchantments(data, tag, true)); register(StructuredDataKey.STORED_ENCHANTMENTS, (data, tag) -> convertEnchantments(data, tag, true));
register(StructuredDataKey.ATTRIBUTE_MODIFIERS, (data, tag) -> { register(StructuredDataKey.ATTRIBUTE_MODIFIERS, (data, tag) -> {
final ListTag<CompoundTag> modifiers = new ListTag<>(CompoundTag.class); 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()); final String identifier = Attributes1_20_5.idToKey(modifier.attribute());
if (identifier == null) { if (identifier == null) {
continue; continue;
@ -137,14 +143,14 @@ final class StructuredDataConverter {
final ListTag<CompoundTag> decorations = new ListTag<>(CompoundTag.class); final ListTag<CompoundTag> decorations = new ListTag<>(CompoundTag.class);
for (final Map.Entry<String, Tag> entry : data.entrySet()) { for (final Map.Entry<String, Tag> entry : data.entrySet()) {
final CompoundTag decorationTag = (CompoundTag) entry.getValue(); 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) { if (id == -1) {
continue; continue;
} }
final CompoundTag convertedDecoration = new CompoundTag(); final CompoundTag convertedDecoration = new CompoundTag();
convertedDecoration.putString("id", entry.getKey()); 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("x", decorationTag.getDouble("x"));
convertedDecoration.putDouble("z", decorationTag.getDouble("z")); convertedDecoration.putDouble("z", decorationTag.getDouble("z"));
convertedDecoration.putFloat("rot", decorationTag.getFloat("rotation")); convertedDecoration.putFloat("rot", decorationTag.getFloat("rotation"));
@ -240,6 +246,7 @@ final class StructuredDataConverter {
register(StructuredDataKey.INSTRUMENT, (data, tag) -> { register(StructuredDataKey.INSTRUMENT, (data, tag) -> {
if (!data.hasId()) { if (!data.hasId()) {
// Can't do anything with direct values // Can't do anything with direct values
// TODO Backup
return; return;
} }
@ -294,11 +301,15 @@ final class StructuredDataConverter {
} }
}); });
register(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, (data, tag) -> { register(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, (data, tag) -> {
if (backupInconvertibleData) {
createBackupTag(tag).putBoolean("enchantment_glint_override", data);
}
if (!data) { if (!data) {
// There is no way to remove the glint without removing the enchantments // 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 // which would lead to broken data, so we just don't do anything
return; return;
} }
// If the glint is overridden, we just add an invalid enchantment to the existing list // If the glint is overridden, we just add an invalid enchantment to the existing list
ListTag<CompoundTag> enchantmentsTag = tag.getListTag("Enchantments", CompoundTag.class); ListTag<CompoundTag> enchantmentsTag = tag.getListTag("Enchantments", CompoundTag.class);
if (enchantmentsTag == null) { if (enchantmentsTag == null) {
@ -314,7 +325,7 @@ final class StructuredDataConverter {
}); });
register(StructuredDataKey.POTION_CONTENTS, (data, tag) -> { register(StructuredDataKey.POTION_CONTENTS, (data, tag) -> {
if (data.potion() != null) { 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) { if (potion != null) {
tag.putString("Potion", potion); tag.putString("Potion", potion);
} }
@ -322,12 +333,13 @@ final class StructuredDataConverter {
if (data.customColor() != null) { if (data.customColor() != null) {
tag.putInt("CustomPotionColor", data.customColor()); tag.putInt("CustomPotionColor", data.customColor());
} }
final ListTag<CompoundTag> customPotionEffectsTag = new ListTag<>(CompoundTag.class); final ListTag<CompoundTag> customPotionEffectsTag = new ListTag<>(CompoundTag.class);
for (final PotionEffect effect : data.customEffects()) { for (final PotionEffect effect : data.customEffects()) {
final CompoundTag effectTag = new CompoundTag(); 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) { if (id != null) {
effectTag.putString("id", id); effectTag.putString("id", id); // Include 1.20.5 ids
} }
final PotionEffectData details = effect.effectData(); final PotionEffectData details = effect.effectData();
@ -345,9 +357,9 @@ final class StructuredDataConverter {
final ListTag<CompoundTag> effectsTag = new ListTag<>(CompoundTag.class); final ListTag<CompoundTag> effectsTag = new ListTag<>(CompoundTag.class);
for (final SuspiciousStewEffect effect : data) { for (final SuspiciousStewEffect effect : data) {
final CompoundTag effectTag = new CompoundTag(); 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) { if (id != null) {
effectTag.putString("id", id); effectTag.putString("id", id); // Include 1.20.5 ids
} }
effectTag.putInt("duration", effect.duration()); effectTag.putInt("duration", effect.duration());
@ -360,8 +372,10 @@ final class StructuredDataConverter {
for (final BannerPatternLayer layer : data) { for (final BannerPatternLayer layer : data) {
final String pattern = BannerPatterns1_20_5.fullIdToCompact(BannerPatterns1_20_5.idToKey(layer.pattern().id())); final String pattern = BannerPatterns1_20_5.fullIdToCompact(BannerPatterns1_20_5.idToKey(layer.pattern().id()));
if (pattern == null) { if (pattern == null) {
// TODO Backup
continue; continue;
} }
final CompoundTag patternTag = new CompoundTag(); final CompoundTag patternTag = new CompoundTag();
patternTag.putString("Pattern", pattern); patternTag.putString("Pattern", pattern);
patternTag.putInt("Color", layer.dyeColor()); patternTag.putInt("Color", layer.dyeColor());
@ -444,21 +458,57 @@ final class StructuredDataConverter {
register(StructuredDataKey.HIDE_TOOLTIP, (data, tag) -> { register(StructuredDataKey.HIDE_TOOLTIP, (data, tag) -> {
// Hide everything we can hide // Hide everything we can hide
putHideFlag(tag, 0xFF); putHideFlag(tag, 0xFF);
if (backupInconvertibleData) {
createBackupTag(tag).putBoolean("hide_tooltip", true);
}
}); });
// Nothing to do for these // New in 1.20.5
noop(StructuredDataKey.INTANGIBLE_PROJECTILE); register(StructuredDataKey.INTANGIBLE_PROJECTILE, (data, tag) -> {
noop(StructuredDataKey.MAX_STACK_SIZE); if (backupInconvertibleData) {
noop(StructuredDataKey.MAX_DAMAGE); createBackupTag(tag).put("intangible_projectile", data);
noop(StructuredDataKey.RARITY); }
noop(StructuredDataKey.FOOD); });
noop(StructuredDataKey.FIRE_RESISTANT); register(StructuredDataKey.MAX_STACK_SIZE, (data, tag) -> {
noop(StructuredDataKey.TOOL); if (backupInconvertibleData) {
noop(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER); 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); final int mappedId = Protocol1_20_5To1_20_3.MAPPINGS.getOldItemId(id);
// TODO Backup
return mappedId != -1 ? Protocol1_20_5To1_20_3.MAPPINGS.itemName(mappedId) : ""; return mappedId != -1 ? Protocol1_20_5To1_20_3.MAPPINGS.itemName(mappedId) : "";
} }
@ -480,12 +530,13 @@ final class StructuredDataConverter {
return subTag; 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); final ListTag<StringTag> predicatedListTag = new ListTag<>(StringTag.class);
for (final BlockPredicate predicate : data.predicates()) { for (final BlockPredicate predicate : data.predicates()) {
final HolderSet holders = predicate.holderSet(); final HolderSet holders = predicate.holderSet();
if (holders == null) { if (holders == null) {
// Can't do (nicely) // Can't do (nicely)
// TODO Backup
continue; continue;
} }
if (holders.hasTagKey()) { 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); final StringBuilder builder = new StringBuilder(identifier);
if (predicate.propertyMatchers() != null) { if (predicate.propertyMatchers() != null) {
for (final StatePropertyMatcher matcher : predicate.propertyMatchers()) { for (final StatePropertyMatcher matcher : predicate.propertyMatchers()) {
@ -521,7 +572,7 @@ final class StructuredDataConverter {
return new StringTag(builder.toString()); return new StringTag(builder.toString());
} }
private static CompoundTag convertExplosion(final FireworkExplosion explosion) { private CompoundTag convertExplosion(final FireworkExplosion explosion) {
final CompoundTag explosionTag = new CompoundTag(); final CompoundTag explosionTag = new CompoundTag();
explosionTag.putInt("Type", explosion.shape()); explosionTag.putInt("Type", explosion.shape());
explosionTag.put("Colors", new IntArrayTag(explosion.colors().clone())); explosionTag.put("Colors", new IntArrayTag(explosion.colors().clone()));
@ -531,7 +582,7 @@ final class StructuredDataConverter {
return explosionTag; 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); final ListTag<CompoundTag> itemsTag = new ListTag<>(CompoundTag.class);
for (final Item item : items) { for (final Item item : items) {
final CompoundTag savedItem = new CompoundTag(); final CompoundTag savedItem = new CompoundTag();
@ -548,10 +599,20 @@ final class StructuredDataConverter {
tag.put(key, itemsTag); 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 ListTag<CompoundTag> enchantments = new ListTag<>(CompoundTag.class);
final int piercingId = Enchantments1_20_3.keyToId("piercing");
for (final Int2IntMap.Entry entry : data.enchantments().int2IntEntrySet()) { 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) { if (identifier == null) {
continue; 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); 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()) { if (data.isEmpty()) {
return; return;
} }
//noinspection unchecked //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()); Preconditions.checkNotNull(converter, "No converter for %s found", data.key());
converter.convert(data.value(), tag); converter.convert(data.value(), tag);
} }
private static <T> void register(final StructuredDataKey<T> key, final DataConverter<T> converter) { private <T> void register(final StructuredDataKey<T> key, final DataConverter<T> converter) {
REWRITERS.put(key, converter); rewriters.put(key, converter);
} }
private static <T> void noop(final StructuredDataKey<T> key) { private static CompoundTag createBackupTag(final CompoundTag tag) {
register(key, (data, 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 @FunctionalInterface