Add remaining data backup handling

This commit is contained in:
FlorianMichael 2024-04-07 21:47:44 +02:00 committed by Nassim Jahnke
parent 510747a7cd
commit 7b28683b6a
No known key found for this signature in database
GPG Key ID: EF6771C01F6EF02F
3 changed files with 313 additions and 53 deletions

View File

@ -32,30 +32,30 @@ public final class BannerPattern {
@Override @Override
public BannerPattern readDirect(final ByteBuf buffer) throws Exception { public BannerPattern readDirect(final ByteBuf buffer) throws Exception {
final String assetId = Type.STRING.read(buffer); final String assetId = Type.STRING.read(buffer);
final String tanslationKey = Type.STRING.read(buffer); final String translationKey = Type.STRING.read(buffer);
return new BannerPattern(assetId, tanslationKey); return new BannerPattern(assetId, translationKey);
} }
@Override @Override
public void writeDirect(final ByteBuf buffer, final BannerPattern value) throws Exception { public void writeDirect(final ByteBuf buffer, final BannerPattern value) throws Exception {
Type.STRING.write(buffer, value.assetId); Type.STRING.write(buffer, value.assetId);
Type.STRING.write(buffer, value.tanslationKey); Type.STRING.write(buffer, value.translationKey);
} }
}; };
private final String assetId; private final String assetId;
private final String tanslationKey; private final String translationKey;
public BannerPattern(final String assetId, final String tanslationKey) { public BannerPattern(final String assetId, final String translationKey) {
this.assetId = assetId; this.assetId = assetId;
this.tanslationKey = tanslationKey; this.translationKey = translationKey;
} }
public String assetId() { public String assetId() {
return assetId; return assetId;
} }
public String tanslationKey() { public String translationKey() {
return tanslationKey; return translationKey;
} }
} }

View File

@ -33,6 +33,7 @@ import com.viaversion.viaversion.api.minecraft.GlobalPosition;
import com.viaversion.viaversion.api.minecraft.Holder; import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet; import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.Particle; import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.data.StructuredData; import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer; import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey; import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
@ -45,6 +46,7 @@ import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrimMaterial;
import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrimPattern; import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrimPattern;
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifier; import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifier;
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers; import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers;
import com.viaversion.viaversion.api.minecraft.item.data.BannerPattern;
import com.viaversion.viaversion.api.minecraft.item.data.BannerPatternLayer; import com.viaversion.viaversion.api.minecraft.item.data.BannerPatternLayer;
import com.viaversion.viaversion.api.minecraft.item.data.Bee; import com.viaversion.viaversion.api.minecraft.item.data.Bee;
import com.viaversion.viaversion.api.minecraft.item.data.BlockPredicate; import com.viaversion.viaversion.api.minecraft.item.data.BlockPredicate;
@ -55,6 +57,9 @@ import com.viaversion.viaversion.api.minecraft.item.data.FilterableComponent;
import com.viaversion.viaversion.api.minecraft.item.data.FilterableString; import com.viaversion.viaversion.api.minecraft.item.data.FilterableString;
import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion; import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion;
import com.viaversion.viaversion.api.minecraft.item.data.Fireworks; import com.viaversion.viaversion.api.minecraft.item.data.Fireworks;
import com.viaversion.viaversion.api.minecraft.item.data.FoodEffect;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument;
import com.viaversion.viaversion.api.minecraft.item.data.LodestoneTracker; import com.viaversion.viaversion.api.minecraft.item.data.LodestoneTracker;
import com.viaversion.viaversion.api.minecraft.item.data.ModifierData; import com.viaversion.viaversion.api.minecraft.item.data.ModifierData;
import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations; import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations;
@ -63,6 +68,8 @@ 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.api.minecraft.item.data.ToolProperties;
import com.viaversion.viaversion.api.minecraft.item.data.ToolRule;
import com.viaversion.viaversion.api.minecraft.item.data.Unbreakable; import com.viaversion.viaversion.api.minecraft.item.data.Unbreakable;
import com.viaversion.viaversion.api.minecraft.item.data.WrittenBook; import com.viaversion.viaversion.api.minecraft.item.data.WrittenBook;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
@ -498,6 +505,16 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
} }
private void restoreFromBackupTag(final CompoundTag backupTag, final StructuredDataContainer data) { private void restoreFromBackupTag(final CompoundTag backupTag, final StructuredDataContainer data) {
final CompoundTag instrument = backupTag.getCompoundTag("instrument");
if (instrument != null) {
restoreInstrumentFromBackup(instrument, data);
}
final IntArrayTag potDecorationsTag = backupTag.getIntArrayTag("pot_decorations");
if (potDecorationsTag != null && potDecorationsTag.getValue().length == 4) {
data.set(StructuredDataKey.POT_DECORATIONS, new PotDecorations(potDecorationsTag.getValue()));
}
final ByteTag enchantmentGlintOverride = backupTag.getByteTag("enchantment_glint_override"); final ByteTag enchantmentGlintOverride = backupTag.getByteTag("enchantment_glint_override");
if (enchantmentGlintOverride != null) { if (enchantmentGlintOverride != null) {
data.set(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, enchantmentGlintOverride.asBoolean()); data.set(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, enchantmentGlintOverride.asBoolean());
@ -527,14 +544,128 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
data.set(StructuredDataKey.RARITY, rarity.asInt()); data.set(StructuredDataKey.RARITY, rarity.asInt());
} }
final CompoundTag food = backupTag.getCompoundTag("food");
if (food != null) {
restoreFoodFromBackup(food, data);
}
if (backupTag.contains("fire_resistant")) { if (backupTag.contains("fire_resistant")) {
data.set(StructuredDataKey.FIRE_RESISTANT); data.set(StructuredDataKey.FIRE_RESISTANT);
} }
final CompoundTag tool = backupTag.getCompoundTag("tool");
if (tool != null) {
restoreToolFromBackup(tool, data);
}
final IntTag ominousBottleAmplifier = backupTag.getIntTag("ominous_bottle_amplifier"); final IntTag ominousBottleAmplifier = backupTag.getIntTag("ominous_bottle_amplifier");
if (ominousBottleAmplifier != null) { if (ominousBottleAmplifier != null) {
data.set(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER, clamp(ominousBottleAmplifier.asInt(), 0, 4)); data.set(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER, clamp(ominousBottleAmplifier.asInt(), 0, 4));
} }
final ListTag<CompoundTag> bannerPatterns = backupTag.getListTag("banner_patterns", CompoundTag.class);
if (bannerPatterns != null) {
restoreBannerPatternsFromBackup(bannerPatterns, data);
}
}
private void restoreInstrumentFromBackup(final CompoundTag instrument, final StructuredDataContainer data) {
final int useDuration = instrument.getInt("use_duration");
final float range = instrument.getFloat("range");
Holder<SoundEvent> soundEvent;
final Tag soundEventTag = instrument.get("sound_event");
if (soundEventTag instanceof IntTag) {
soundEvent = Holder.of(((IntTag) soundEventTag).asInt());
} else if (soundEventTag instanceof CompoundTag) {
final CompoundTag soundEventCompound = (CompoundTag) soundEventTag;
final StringTag identifier = soundEventCompound.getStringTag("identifier");
if (identifier == null) {
return; // Nothing we can do about
}
soundEvent = Holder.of(new SoundEvent(
identifier.getValue(),
soundEventCompound.contains("fixed_range") ?
soundEventCompound.getFloat("fixed_range") : null
));
} else {
return; // Nothing we can do about
}
data.set(StructuredDataKey.INSTRUMENT, Holder.of(new Instrument(soundEvent, useDuration, range)));
}
private void restoreFoodFromBackup(final CompoundTag food, final StructuredDataContainer data) {
final int nutrition = food.getInt("nutrition");
final float saturation = food.getFloat("saturation");
final boolean canAlwaysEat = food.getBoolean("can_always_eat");
final float eatSeconds = food.getFloat("eat_seconds");
final ListTag<CompoundTag> possibleEffectsTag = food.getListTag("possible_effects", CompoundTag.class);
if (possibleEffectsTag == null) {
return;
}
final List<FoodEffect> possibleEffects = new ArrayList<>();
for (final CompoundTag effect : possibleEffectsTag) {
final CompoundTag potionEffectTag = effect.getCompoundTag("effect");
if (potionEffectTag == null) {
continue; // Nothing we can do about
}
possibleEffects.add(new FoodEffect(
new PotionEffect(
potionEffectTag.getInt("effect"),
readPotionEffectData(potionEffectTag)
),
effect.getFloat("probability")
));
}
data.set(StructuredDataKey.FOOD, new FoodProperties(nutrition, saturation, canAlwaysEat, eatSeconds, possibleEffects.toArray(new FoodEffect[0])));
}
private void restoreToolFromBackup(final CompoundTag tool, final StructuredDataContainer data) {
final ListTag<CompoundTag> rulesTag = tool.getListTag("rules", CompoundTag.class);
if (rulesTag == null) {
return;
}
final List<ToolRule> rules = new ArrayList<>();
for (final CompoundTag tag : rulesTag) {
HolderSet blocks = null;
if (tag.get("blocks") instanceof StringTag) {
blocks = HolderSet.of(tag.getString("blocks"));
} else {
final IntArrayTag blockIds = tag.getIntArrayTag("blocks");
if (blockIds != null) {
blocks = HolderSet.of(blockIds.getValue());
}
}
if (blocks == null) {
continue; // Nothing we can do about
}
rules.add(new ToolRule(
blocks,
tag.contains("speed") ? tag.getFloat("speed") : null,
tag.contains("correct_for_drops") ? tag.getBoolean("correct_for_drops") : null
));
}
data.set(StructuredDataKey.TOOL, new ToolProperties(
rules.toArray(new ToolRule[0]),
tool.getFloat("default_mining_speed"),
tool.getInt("damage_per_block")
));
}
private void restoreBannerPatternsFromBackup(final ListTag<CompoundTag> bannerPatterns, final StructuredDataContainer data) {
final List<BannerPatternLayer> patternLayer = new ArrayList<>();
for (final CompoundTag tag : bannerPatterns) {
final CompoundTag patternTag = tag.getCompoundTag("pattern");
if (patternTag == null) {
continue; // Nothing we can do about
}
final String assetId = patternTag.getString("asset_id");
final String translationKey = patternTag.getString("translation_key");
final int dyeColor = tag.getInt("dye_color");
patternLayer.add(new BannerPatternLayer(Holder.of(new BannerPattern(assetId, translationKey)), dyeColor));
}
data.set(StructuredDataKey.BANNER_PATTERNS, patternLayer.toArray(new BannerPatternLayer[0]));
} }
private int unmappedItemId(final String name) { private int unmappedItemId(final String name) {
@ -706,7 +837,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
final Tag materialTag = trimTag.get("material"); final Tag materialTag = trimTag.get("material");
final Holder<ArmorTrimMaterial> materialHolder; final Holder<ArmorTrimMaterial> materialHolder;
if (materialTag instanceof StringTag) { if (materialTag instanceof StringTag) {
// Would technically have to be stored and retreived from registry data, but that'd mean a lot of work // Would technically have to be stored and retrieved from registry data, but that'd mean a lot of work
final int id = TrimMaterials1_20_3.keyToId(((StringTag) materialTag).getValue()); final int id = TrimMaterials1_20_3.keyToId(((StringTag) materialTag).getValue());
if (id == -1) { if (id == -1) {
return; return;
@ -720,7 +851,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
return; return;
} }
final int ingredientId = toMappedItemId(ingredientTag.getValue()); final int ingredientId = StructuredDataConverter.getBackupItemId(materialCompoundTag, toMappedItemId(ingredientTag.getValue()));
if (ingredientId == -1) { if (ingredientId == -1) {
return; return;
} }
@ -755,7 +886,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
final Tag patternTag = trimTag.get("pattern"); final Tag patternTag = trimTag.get("pattern");
final Holder<ArmorTrimPattern> patternHolder; final Holder<ArmorTrimPattern> patternHolder;
if (patternTag instanceof StringTag) { if (patternTag instanceof StringTag) {
// Would technically have to be stored and retreived from registry data, but that'd mean a lot of work // Would technically have to be stored and retrieved from registry data, but that'd mean a lot of work
final int id = TrimPatterns1_20_3.keyToId(((StringTag) patternTag).getValue()); final int id = TrimPatterns1_20_3.keyToId(((StringTag) patternTag).getValue());
if (id == -1) { if (id == -1) {
return; return;
@ -769,7 +900,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
return; return;
} }
final int templateItemId = toMappedItemId(templateItem); final int templateItemId = StructuredDataConverter.getBackupItemId(patternCompoundTag, toMappedItemId(templateItem));
if (templateItemId == -1) { if (templateItemId == -1) {
return; return;
} }
@ -954,7 +1085,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
return null; return null;
} }
final int itemId = unmappedItemId(id); final int itemId = StructuredDataConverter.getBackupItemId(item, unmappedItemId(id));
if (itemId == -1) { if (itemId == -1) {
return null; return null;
} }

View File

@ -20,12 +20,14 @@ package com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.rewriter;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.FloatTag; import com.github.steveice10.opennbt.tag.builtin.FloatTag;
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.ListTag; import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag; import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.minecraft.GameProfile; import com.viaversion.viaversion.api.minecraft.GameProfile;
import com.viaversion.viaversion.api.minecraft.HolderSet; import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.data.StructuredData; import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey; import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.minecraft.item.Item;
@ -33,6 +35,7 @@ import com.viaversion.viaversion.api.minecraft.item.data.AdventureModePredicate;
import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrimMaterial; import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrimMaterial;
import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrimPattern; import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrimPattern;
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifier; import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifier;
import com.viaversion.viaversion.api.minecraft.item.data.BannerPattern;
import com.viaversion.viaversion.api.minecraft.item.data.BannerPatternLayer; import com.viaversion.viaversion.api.minecraft.item.data.BannerPatternLayer;
import com.viaversion.viaversion.api.minecraft.item.data.Bee; import com.viaversion.viaversion.api.minecraft.item.data.Bee;
import com.viaversion.viaversion.api.minecraft.item.data.BlockPredicate; import com.viaversion.viaversion.api.minecraft.item.data.BlockPredicate;
@ -40,10 +43,13 @@ import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
import com.viaversion.viaversion.api.minecraft.item.data.FilterableComponent; import com.viaversion.viaversion.api.minecraft.item.data.FilterableComponent;
import com.viaversion.viaversion.api.minecraft.item.data.FilterableString; import com.viaversion.viaversion.api.minecraft.item.data.FilterableString;
import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion; import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion;
import com.viaversion.viaversion.api.minecraft.item.data.FoodEffect;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument;
import com.viaversion.viaversion.api.minecraft.item.data.PotionEffect; 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.api.minecraft.item.data.ToolRule;
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;
@ -58,6 +64,7 @@ import com.viaversion.viaversion.util.UUIDUtil;
import it.unimi.dsi.fastutil.ints.Int2IntMap; 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.Arrays;
import java.util.Map; import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
@ -72,13 +79,13 @@ public 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;
// Can't do nicely
private static final String BACKUP_TAG_KEY = "VV|DataComponents"; private static final String BACKUP_TAG_KEY = "VV|DataComponents";
private static final String ITEM_TAG_KEY = "VV|id";
private final Map<StructuredDataKey<?>, DataConverter<?>> rewriters = new Reference2ObjectOpenHashMap<>(); private final Map<StructuredDataKey<?>, DataConverter<?>> rewriters = new Reference2ObjectOpenHashMap<>();
private final boolean backupInconvertibleData;
public StructuredDataConverter(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
}); });
@ -244,9 +251,26 @@ public final class StructuredDataConverter {
} }
}); });
register(StructuredDataKey.INSTRUMENT, (data, tag) -> { register(StructuredDataKey.INSTRUMENT, (data, tag) -> {
// Can't do anything with direct values
if (!data.hasId()) { if (!data.hasId()) {
// Can't do anything with direct values if (backupInconvertibleData) {
// TODO Backup final CompoundTag backupTag = new CompoundTag();
final Instrument instrument = data.value();
if (instrument.soundEvent().hasId()) {
backupTag.putInt("sound_event", instrument.soundEvent().id());
} else {
final CompoundTag soundEventTag = new CompoundTag();
final SoundEvent soundEvent = instrument.soundEvent().value();
soundEventTag.putString("identifier", soundEvent.identifier());
if (soundEvent.fixedRange() != null) {
soundEventTag.putFloat("fixed_range", soundEvent.fixedRange());
}
backupTag.put("sound_event", soundEventTag);
}
backupTag.putInt("use_duration", instrument.useDuration());
backupTag.putFloat("range", instrument.range());
getBackupTag(tag).put("instrument", backupTag);
}
return; return;
} }
@ -269,9 +293,23 @@ public final class StructuredDataConverter {
register(StructuredDataKey.LOCK, (data, tag) -> getBlockEntityTag(tag).put("Lock", data)); register(StructuredDataKey.LOCK, (data, tag) -> getBlockEntityTag(tag).put("Lock", data));
register(StructuredDataKey.NOTE_BLOCK_SOUND, (data, tag) -> getBlockEntityTag(tag).putString("note_block_sound", data)); register(StructuredDataKey.NOTE_BLOCK_SOUND, (data, tag) -> getBlockEntityTag(tag).putString("note_block_sound", data));
register(StructuredDataKey.POT_DECORATIONS, (data, tag) -> { register(StructuredDataKey.POT_DECORATIONS, (data, tag) -> {
IntArrayTag originalSherds = null;
final ListTag<StringTag> sherds = new ListTag<>(StringTag.class); final ListTag<StringTag> sherds = new ListTag<>(StringTag.class);
for (final int id : data.itemIds()) { for (final int id : data.itemIds()) {
sherds.add(new StringTag(toItemName(id))); final String name = toMappedItemName(id);
if (name.isEmpty()) {
// Backup whole data if one of the sherds is inconvertible
// Since we don't want to break the order of the sherds
if (backupInconvertibleData && originalSherds == null) {
originalSherds = new IntArrayTag(data.itemIds());
}
continue;
}
sherds.add(new StringTag(name));
}
if (originalSherds != null) {
getBackupTag(tag).put("pot_decorations", originalSherds);
} }
getBlockEntityTag(tag).put("sherds", sherds); getBlockEntityTag(tag).put("sherds", sherds);
}); });
@ -302,7 +340,7 @@ public final class StructuredDataConverter {
}); });
register(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, (data, tag) -> { register(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, (data, tag) -> {
if (backupInconvertibleData) { if (backupInconvertibleData) {
createBackupTag(tag).putBoolean("enchantment_glint_override", data); getBackupTag(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
@ -368,14 +406,32 @@ public final class StructuredDataConverter {
tag.put("effects", effectsTag); tag.put("effects", effectsTag);
}); });
register(StructuredDataKey.BANNER_PATTERNS, (data, tag) -> { register(StructuredDataKey.BANNER_PATTERNS, (data, tag) -> {
final ListTag<CompoundTag> originalPatterns = new ListTag<>(CompoundTag.class);
if (backupInconvertibleData) {
// Backup whole data if one of the patterns is inconvertible
// Since we don't want to break the order of the patterns
if (Arrays.stream(data).anyMatch(layer -> layer.pattern().isDirect())) {
for (final BannerPatternLayer layer : data) {
final CompoundTag layerTag = new CompoundTag();
final CompoundTag patternTag = new CompoundTag();
final BannerPattern pattern = layer.pattern().value();
patternTag.putString("asset_id", pattern.assetId());
patternTag.putString("translation_key", pattern.translationKey());
layerTag.put("pattern", patternTag);
layerTag.putInt("dye_color", layer.dyeColor());
originalPatterns.add(layerTag);
}
getBackupTag(tag).put("banner_patterns", originalPatterns);
return;
}
}
final ListTag<CompoundTag> patternsTag = new ListTag<>(CompoundTag.class); final ListTag<CompoundTag> patternsTag = new ListTag<>(CompoundTag.class);
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());
@ -403,9 +459,9 @@ public final class StructuredDataConverter {
final ArmorTrimMaterial material = data.material().value(); final ArmorTrimMaterial material = data.material().value();
materialTag.putString("asset_name", material.assetName()); materialTag.putString("asset_name", material.assetName());
final String ingredientName = toItemName(material.itemId()); final String ingredientName = toMappedItemName(material.itemId());
if (ingredientName.isEmpty()) { if (ingredientName.isEmpty()) {
return; getBackupTag(materialTag).putInt(ITEM_TAG_KEY, material.itemId());
} }
materialTag.putString("ingredient", ingredientName); materialTag.putString("ingredient", ingredientName);
materialTag.put("item_model_index", new FloatTag(material.itemModelIndex())); materialTag.put("item_model_index", new FloatTag(material.itemModelIndex()));
@ -429,9 +485,9 @@ public final class StructuredDataConverter {
final ArmorTrimPattern pattern = data.pattern().value(); final ArmorTrimPattern pattern = data.pattern().value();
patternTag.putString("assetId", pattern.assetName()); patternTag.putString("assetId", pattern.assetName());
final String itemName = toItemName(pattern.itemId()); final String itemName = toMappedItemName(pattern.itemId());
if (itemName.isEmpty()) { if (itemName.isEmpty()) {
return; getBackupTag(patternTag).putInt(ITEM_TAG_KEY, pattern.itemId());
} }
patternTag.putString("templateItem", itemName); patternTag.putString("templateItem", itemName);
patternTag.put("description", pattern.description()); patternTag.put("description", pattern.description());
@ -459,60 +515,102 @@ public final class StructuredDataConverter {
// Hide everything we can hide // Hide everything we can hide
putHideFlag(tag, 0xFF); putHideFlag(tag, 0xFF);
if (backupInconvertibleData) { if (backupInconvertibleData) {
createBackupTag(tag).putBoolean("hide_tooltip", true); getBackupTag(tag).putBoolean("hide_tooltip", true);
} }
}); });
// New in 1.20.5 // New in 1.20.5
register(StructuredDataKey.INTANGIBLE_PROJECTILE, (data, tag) -> { register(StructuredDataKey.INTANGIBLE_PROJECTILE, (data, tag) -> {
if (backupInconvertibleData) { if (backupInconvertibleData) {
createBackupTag(tag).put("intangible_projectile", data); getBackupTag(tag).put("intangible_projectile", data);
} }
}); });
register(StructuredDataKey.MAX_STACK_SIZE, (data, tag) -> { register(StructuredDataKey.MAX_STACK_SIZE, (data, tag) -> {
if (backupInconvertibleData) { if (backupInconvertibleData) {
createBackupTag(tag).putInt("max_stack_size", data); getBackupTag(tag).putInt("max_stack_size", data);
} }
}); });
register(StructuredDataKey.MAX_DAMAGE, (data, tag) -> { register(StructuredDataKey.MAX_DAMAGE, (data, tag) -> {
if (backupInconvertibleData) { if (backupInconvertibleData) {
createBackupTag(tag).putInt("max_damage", data); getBackupTag(tag).putInt("max_damage", data);
} }
}); });
register(StructuredDataKey.RARITY, (data, tag) -> { register(StructuredDataKey.RARITY, (data, tag) -> {
if (backupInconvertibleData) { if (backupInconvertibleData) {
createBackupTag(tag).putInt("rarity", data); getBackupTag(tag).putInt("rarity", data);
} }
}); });
register(StructuredDataKey.FOOD, (data, tag) -> { register(StructuredDataKey.FOOD, (data, tag) -> {
if (backupInconvertibleData) { if (backupInconvertibleData) {
//createBackupTag(tag).; // TODO Backup final CompoundTag backupTag = new CompoundTag();
backupTag.putInt("nutrition", data.nutrition());
backupTag.putFloat("saturation_modifier", data.saturationModifier());
backupTag.putBoolean("can_always_eat", data.canAlwaysEat());
backupTag.putFloat("eat_seconds", data.eatSeconds());
final ListTag<CompoundTag> possibleEffectsTag = new ListTag<>(CompoundTag.class);
for (final FoodEffect effect : data.possibleEffects()) {
final CompoundTag effectTag = new CompoundTag();
final PotionEffect potionEffect = effect.effect();
final CompoundTag potionEffectTag = new CompoundTag();
potionEffectTag.putInt("effect", potionEffect.effect());
potionEffectTag.put("effect_data", convertPotionEffectData(potionEffect.effectData()));
effectTag.putFloat("probability", effect.probability());
effectTag.put("effect", potionEffectTag);
possibleEffectsTag.add(effectTag);
}
backupTag.put("possible_effects", possibleEffectsTag);
getBackupTag(tag).put("food", backupTag);
} }
}); });
register(StructuredDataKey.FIRE_RESISTANT, (data, tag) -> { register(StructuredDataKey.FIRE_RESISTANT, (data, tag) -> {
if (backupInconvertibleData) { if (backupInconvertibleData) {
createBackupTag(tag).putBoolean("fire_resistant", true); getBackupTag(tag).putBoolean("fire_resistant", true);
} }
}); });
register(StructuredDataKey.TOOL, (data, tag) -> { register(StructuredDataKey.TOOL, (data, tag) -> {
if (backupInconvertibleData) { if (backupInconvertibleData) {
//createBackupTag(tag).; // TODO Backup final CompoundTag backupTag = new CompoundTag();
final ListTag<CompoundTag> rulesTag = new ListTag<>(CompoundTag.class);
for (final ToolRule rule : data.rules()) {
final CompoundTag ruleTag = new CompoundTag();
final HolderSet set = rule.blocks();
if (set.hasTagKey()) {
ruleTag.putString("blocks", set.tagKey());
} else {
ruleTag.put("blocks", new IntArrayTag(set.ids()));
}
if (rule.speed() != null) {
ruleTag.putFloat("speed", rule.speed());
}
if (rule.correctForDrops() != null) {
ruleTag.putBoolean("correct_for_drops", rule.correctForDrops());
}
rulesTag.add(ruleTag);
}
backupTag.put("rules", rulesTag);
backupTag.putFloat("default_mining_speed", data.defaultMiningSpeed());
backupTag.putInt("damage_per_block", data.damagePerBlock());
getBackupTag(tag).put("tool", backupTag);
} }
}); });
register(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER, (data, tag) -> { register(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER, (data, tag) -> {
if (backupInconvertibleData) { if (backupInconvertibleData) {
createBackupTag(tag).putInt("ominous_bottle_amplifier", data); getBackupTag(tag).putInt("ominous_bottle_amplifier", data);
} }
}); });
} }
private String toItemName(final int id) { private int unmappedItemId(final int id) {
final int mappedId = Protocol1_20_5To1_20_3.MAPPINGS.getOldItemId(id); return Protocol1_20_5To1_20_3.MAPPINGS.getOldItemId(id);
// TODO Backup
return mappedId != -1 ? Protocol1_20_5To1_20_3.MAPPINGS.itemName(mappedId) : "";
} }
// If multiple item components which previously were stored in BlockEntityTag are present, we need to merge them private String toMappedItemName(final int id) {
final int mappedId = unmappedItemId(id);
return mappedId != -1 ? Protocol1_20_5To1_20_3.MAPPINGS.itemName(mappedId) : "";
}
private static CompoundTag getBlockEntityTag(final CompoundTag tag) { private static CompoundTag getBlockEntityTag(final CompoundTag tag) {
return getOrCreate(tag, "BlockEntityTag"); return getOrCreate(tag, "BlockEntityTag");
@ -522,6 +620,11 @@ public final class StructuredDataConverter {
return getOrCreate(tag, "display"); return getOrCreate(tag, "display");
} }
private static CompoundTag getBackupTag(final CompoundTag tag) {
return getOrCreate(tag, BACKUP_TAG_KEY);
}
// If multiple item components which previously were stored in BlockEntityTag are present, we need to merge them
private static CompoundTag getOrCreate(final CompoundTag tag, final String key) { private static CompoundTag getOrCreate(final CompoundTag tag, final String key) {
CompoundTag subTag = tag.getCompoundTag(key); CompoundTag subTag = tag.getCompoundTag(key);
if (subTag == null) { if (subTag == null) {
@ -531,6 +634,22 @@ public final class StructuredDataConverter {
return subTag; return subTag;
} }
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;
}
static int getBackupItemId(final CompoundTag tag, final int unmappedId) {
if (unmappedId != -1) {
return unmappedId;
}
final IntTag itemIdTag = tag.getIntTag(ITEM_TAG_KEY);
return itemIdTag != null ? itemIdTag.getTagId() : -1;
}
private 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()) {
@ -545,7 +664,12 @@ public final class StructuredDataConverter {
predicatedListTag.add(serializeBlockPredicate(predicate, tagKey)); predicatedListTag.add(serializeBlockPredicate(predicate, tagKey));
} else { } else {
for (final int id : holders.ids()) { for (final int id : holders.ids()) {
predicatedListTag.add(serializeBlockPredicate(predicate, toItemName(id))); final String name = toMappedItemName(id);
if (name.isEmpty()) {
// TODO HANDLE
continue;
}
predicatedListTag.add(serializeBlockPredicate(predicate, name));
} }
} }
} }
@ -583,11 +707,28 @@ public final class StructuredDataConverter {
return explosionTag; return explosionTag;
} }
private CompoundTag convertPotionEffectData(final PotionEffectData data) {
final CompoundTag effectDataTag = new CompoundTag();
effectDataTag.putInt("amplifier", data.amplifier());
effectDataTag.putInt("duration", data.duration());
effectDataTag.putBoolean("ambient", data.ambient());
effectDataTag.putBoolean("show_particles", data.showParticles());
effectDataTag.putBoolean("show_icon", data.showIcon());
if (data.hiddenEffect() != null) {
effectDataTag.put("hidden_effect", convertPotionEffectData(data.hiddenEffect()));
}
return effectDataTag;
}
private 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();
savedItem.putString("id", toItemName(item.identifier())); final String name = toMappedItemName(item.identifier());
savedItem.putString("id", name);
if (name.isEmpty()) {
savedItem.putInt(ITEM_TAG_KEY, item.identifier());
}
savedItem.putByte("Count", (byte) item.amount()); savedItem.putByte("Count", (byte) item.amount());
final CompoundTag itemTag = new CompoundTag(); final CompoundTag itemTag = new CompoundTag();
@ -649,18 +790,6 @@ public final class StructuredDataConverter {
rewriters.put(key, converter); rewriters.put(key, converter);
} }
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 @FunctionalInterface
interface DataConverter<T> { interface DataConverter<T> {