mirror of
https://github.com/ViaVersion/ViaBackwards.git
synced 2024-11-24 12:35:43 +01:00
Backup inconvertible item component data for creative clients in 1.21+ (#907)
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
This commit is contained in:
parent
1dfef5b97e
commit
276953f6cb
@ -18,13 +18,17 @@
|
|||||||
package com.viaversion.viabackwards.api.rewriters;
|
package com.viaversion.viabackwards.api.rewriters;
|
||||||
|
|
||||||
import com.viaversion.nbt.tag.CompoundTag;
|
import com.viaversion.nbt.tag.CompoundTag;
|
||||||
|
import com.viaversion.nbt.tag.IntArrayTag;
|
||||||
import com.viaversion.nbt.tag.IntTag;
|
import com.viaversion.nbt.tag.IntTag;
|
||||||
import com.viaversion.nbt.tag.ListTag;
|
import com.viaversion.nbt.tag.ListTag;
|
||||||
|
import com.viaversion.nbt.tag.StringTag;
|
||||||
import com.viaversion.nbt.tag.Tag;
|
import com.viaversion.nbt.tag.Tag;
|
||||||
import com.viaversion.viabackwards.api.BackwardsProtocol;
|
import com.viaversion.viabackwards.api.BackwardsProtocol;
|
||||||
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
|
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
|
||||||
import com.viaversion.viabackwards.api.data.MappedItem;
|
import com.viaversion.viabackwards.api.data.MappedItem;
|
||||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
import com.viaversion.viaversion.api.minecraft.Holder;
|
||||||
|
import com.viaversion.viaversion.api.minecraft.HolderSet;
|
||||||
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;
|
||||||
import com.viaversion.viaversion.api.minecraft.item.Item;
|
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||||
@ -34,6 +38,8 @@ import com.viaversion.viaversion.api.type.Type;
|
|||||||
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
|
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Function;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
public class BackwardsStructuredItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
|
public class BackwardsStructuredItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
|
||||||
@ -165,6 +171,54 @@ public class BackwardsStructuredItemRewriter<C extends ClientboundPacketType, S
|
|||||||
return new ArrayList<>(data.values());
|
return new ArrayList<>(data.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Tag holderSetToTag(final HolderSet set) {
|
||||||
|
if (set.hasIds()) {
|
||||||
|
return new IntArrayTag(set.ids());
|
||||||
|
} else {
|
||||||
|
return new StringTag(set.tagKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HolderSet restoreHolderSet(final CompoundTag tag, final String key) {
|
||||||
|
final Tag savedTag = tag.get(key);
|
||||||
|
if (savedTag == null) {
|
||||||
|
return HolderSet.of(new int[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (savedTag instanceof StringTag tagKey) {
|
||||||
|
return HolderSet.of(tagKey.getValue());
|
||||||
|
} else if (savedTag instanceof IntArrayTag idsTag) {
|
||||||
|
return HolderSet.of(idsTag.getValue());
|
||||||
|
} else {
|
||||||
|
return HolderSet.of(new int[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <V> Tag holderToTag(final Holder<V> holder, final BiConsumer<V, CompoundTag> valueSaveFunction) {
|
||||||
|
if (holder.hasId()) {
|
||||||
|
return new IntTag(holder.id());
|
||||||
|
} else {
|
||||||
|
final CompoundTag savedTag = new CompoundTag();
|
||||||
|
valueSaveFunction.accept(holder.value(), savedTag);
|
||||||
|
return savedTag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <V> Holder<V> restoreHolder(final CompoundTag tag, final String key, final Function<CompoundTag, V> valueRestoreFunction) {
|
||||||
|
final Tag savedTag = tag.get(key);
|
||||||
|
if (savedTag == null) {
|
||||||
|
return Holder.of(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (savedTag instanceof IntTag idTag) {
|
||||||
|
return Holder.of(idTag.asInt());
|
||||||
|
} else if (savedTag instanceof CompoundTag compoundTag) {
|
||||||
|
return Holder.of(valueRestoreFunction.apply(compoundTag));
|
||||||
|
} else {
|
||||||
|
return Holder.of(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String nbtTagName() {
|
public String nbtTagName() {
|
||||||
return "VB|" + protocol.getClass().getSimpleName();
|
return "VB|" + protocol.getClass().getSimpleName();
|
||||||
|
@ -17,14 +17,32 @@
|
|||||||
*/
|
*/
|
||||||
package com.viaversion.viabackwards.protocol.v1_21_2to1_21.rewriter;
|
package com.viaversion.viabackwards.protocol.v1_21_2to1_21.rewriter;
|
||||||
|
|
||||||
|
import com.viaversion.nbt.tag.ByteTag;
|
||||||
|
import com.viaversion.nbt.tag.CompoundTag;
|
||||||
|
import com.viaversion.nbt.tag.FloatTag;
|
||||||
|
import com.viaversion.nbt.tag.IntTag;
|
||||||
|
import com.viaversion.nbt.tag.ListTag;
|
||||||
|
import com.viaversion.nbt.tag.Tag;
|
||||||
import com.viaversion.viabackwards.api.rewriters.BackwardsStructuredItemRewriter;
|
import com.viaversion.viabackwards.api.rewriters.BackwardsStructuredItemRewriter;
|
||||||
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.Protocol1_21_2To1_21;
|
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.Protocol1_21_2To1_21;
|
||||||
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.InventoryStateIdStorage;
|
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.InventoryStateIdStorage;
|
||||||
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.RecipeStorage;
|
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.RecipeStorage;
|
||||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
import com.viaversion.viaversion.api.data.MappingData;
|
import com.viaversion.viaversion.api.data.MappingData;
|
||||||
|
import com.viaversion.viaversion.api.minecraft.Holder;
|
||||||
|
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.StructuredDataContainer;
|
||||||
|
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
|
||||||
import com.viaversion.viaversion.api.minecraft.item.Item;
|
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||||
|
import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2;
|
||||||
|
import com.viaversion.viaversion.api.minecraft.item.data.DeathProtection;
|
||||||
|
import com.viaversion.viaversion.api.minecraft.item.data.Equippable;
|
||||||
|
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_21_2;
|
||||||
|
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.UseCooldown;
|
||||||
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||||
import com.viaversion.viaversion.api.type.Types;
|
import com.viaversion.viaversion.api.type.Types;
|
||||||
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
|
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
|
||||||
@ -39,6 +57,7 @@ import com.viaversion.viaversion.rewriter.BlockRewriter;
|
|||||||
import com.viaversion.viaversion.rewriter.SoundRewriter;
|
import com.viaversion.viaversion.rewriter.SoundRewriter;
|
||||||
import com.viaversion.viaversion.util.Key;
|
import com.viaversion.viaversion.util.Key;
|
||||||
import com.viaversion.viaversion.util.Limit;
|
import com.viaversion.viaversion.util.Limit;
|
||||||
|
import com.viaversion.viaversion.util.Unit;
|
||||||
|
|
||||||
import static com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.BlockItemPacketRewriter1_21_2.downgradeItemData;
|
import static com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.BlockItemPacketRewriter1_21_2.downgradeItemData;
|
||||||
import static com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.BlockItemPacketRewriter1_21_2.updateItemData;
|
import static com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.BlockItemPacketRewriter1_21_2.updateItemData;
|
||||||
@ -276,6 +295,7 @@ public final class BlockItemPacketRewriter1_21_2 extends BackwardsStructuredItem
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Item handleItemToClient(final UserConnection connection, final Item item) {
|
public Item handleItemToClient(final UserConnection connection, final Item item) {
|
||||||
|
backupInconvertibleData(item);
|
||||||
super.handleItemToClient(connection, item);
|
super.handleItemToClient(connection, item);
|
||||||
downgradeItemData(item);
|
downgradeItemData(item);
|
||||||
return item;
|
return item;
|
||||||
@ -285,6 +305,266 @@ public final class BlockItemPacketRewriter1_21_2 extends BackwardsStructuredItem
|
|||||||
public Item handleItemToServer(final UserConnection connection, final Item item) {
|
public Item handleItemToServer(final UserConnection connection, final Item item) {
|
||||||
super.handleItemToServer(connection, item);
|
super.handleItemToServer(connection, item);
|
||||||
updateItemData(item);
|
updateItemData(item);
|
||||||
|
restoreInconvertibleData(item);
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Backup inconvertible data and later restore to prevent data loss for creative mode clients
|
||||||
|
private void backupInconvertibleData(final Item item) {
|
||||||
|
final StructuredDataContainer data = item.dataContainer();
|
||||||
|
data.setIdLookup(protocol, true);
|
||||||
|
|
||||||
|
final CompoundTag backupTag = new CompoundTag();
|
||||||
|
|
||||||
|
final Holder<Instrument1_21_2> instrument = data.get(StructuredDataKey.INSTRUMENT1_21_2);
|
||||||
|
if (instrument != null && instrument.isDirect()) {
|
||||||
|
backupTag.put("instrument_description", instrument.value().description());
|
||||||
|
}
|
||||||
|
|
||||||
|
final HolderSet repairable = data.get(StructuredDataKey.REPAIRABLE);
|
||||||
|
if (repairable != null) {
|
||||||
|
backupTag.put("repairable", holderSetToTag(repairable));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Integer enchantable = data.get(StructuredDataKey.ENCHANTABLE);
|
||||||
|
if (enchantable != null) {
|
||||||
|
backupTag.putInt("enchantable", enchantable);
|
||||||
|
}
|
||||||
|
|
||||||
|
final UseCooldown useCooldown = data.get(StructuredDataKey.USE_COOLDOWN);
|
||||||
|
if (useCooldown != null) {
|
||||||
|
final CompoundTag tag = new CompoundTag();
|
||||||
|
tag.putFloat("seconds", useCooldown.seconds());
|
||||||
|
if (useCooldown.cooldownGroup() != null) {
|
||||||
|
tag.putString("cooldown_group", useCooldown.cooldownGroup());
|
||||||
|
}
|
||||||
|
backupTag.put("use_cooldown", tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String itemModel = data.get(StructuredDataKey.ITEM_MODEL);
|
||||||
|
if (itemModel != null) {
|
||||||
|
backupTag.putString("item_model", itemModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Equippable equippable = data.get(StructuredDataKey.EQUIPPABLE);
|
||||||
|
if (equippable != null) {
|
||||||
|
final CompoundTag tag = new CompoundTag();
|
||||||
|
|
||||||
|
tag.putInt("equipment_slot", equippable.equipmentSlot());
|
||||||
|
convertSoundEventHolder(tag, equippable.soundEvent());
|
||||||
|
final String model = equippable.model();
|
||||||
|
if (model != null) {
|
||||||
|
tag.putString("model", model);
|
||||||
|
}
|
||||||
|
final String cameraOverlay = equippable.cameraOverlay();
|
||||||
|
if (cameraOverlay != null) {
|
||||||
|
tag.putString("camera_overlay", cameraOverlay);
|
||||||
|
}
|
||||||
|
if (equippable.allowedEntities() != null) {
|
||||||
|
tag.put("allowed_entities", holderSetToTag(equippable.allowedEntities()));
|
||||||
|
}
|
||||||
|
tag.putBoolean("dispensable", equippable.dispensable());
|
||||||
|
tag.putBoolean("swappable", equippable.swappable());
|
||||||
|
tag.putBoolean("damage_on_hurt", equippable.damageOnHurt());
|
||||||
|
|
||||||
|
backupTag.put("equippable", tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Unit glider = data.get(StructuredDataKey.GLIDER);
|
||||||
|
if (glider != null) {
|
||||||
|
backupTag.putBoolean("glider", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String tooltipStyle = data.get(StructuredDataKey.TOOLTIP_STYLE);
|
||||||
|
if (tooltipStyle != null) {
|
||||||
|
backupTag.putString("tooltip_style", tooltipStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
final DeathProtection deathProtection = data.get(StructuredDataKey.DEATH_PROTECTION);
|
||||||
|
if (deathProtection != null) {
|
||||||
|
final ListTag<CompoundTag> tag = new ListTag<>(CompoundTag.class);
|
||||||
|
for (final Consumable1_21_2.ConsumeEffect<?> effect : deathProtection.deathEffects()) {
|
||||||
|
final CompoundTag effectTag = new CompoundTag();
|
||||||
|
convertConsumableEffect(effectTag, effect);
|
||||||
|
tag.add(effectTag);
|
||||||
|
}
|
||||||
|
backupTag.put("death_protection", tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!backupTag.isEmpty()) {
|
||||||
|
saveTag(createCustomTag(item), backupTag, "inconvertible_data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void convertConsumableEffect(final CompoundTag tag, Consumable1_21_2.ConsumeEffect<?> effect) {
|
||||||
|
tag.putInt("id", effect.id());
|
||||||
|
if (effect.type() == Consumable1_21_2.ApplyStatusEffects.TYPE && effect.value() instanceof Consumable1_21_2.ApplyStatusEffects value) {
|
||||||
|
tag.putString("type", "apply_effects");
|
||||||
|
|
||||||
|
final ListTag<CompoundTag> effects = new ListTag<>(CompoundTag.class);
|
||||||
|
for (final PotionEffect potionEffect : value.effects()) {
|
||||||
|
final CompoundTag effectTag = new CompoundTag();
|
||||||
|
effectTag.putInt("effect", potionEffect.effect());
|
||||||
|
convertPotionEffectData(effectTag, potionEffect.effectData());
|
||||||
|
effects.add(effectTag);
|
||||||
|
}
|
||||||
|
tag.put("effects", effects);
|
||||||
|
tag.putFloat("probability", value.probability());
|
||||||
|
} else if (effect.type() == Types.HOLDER_SET && effect.value() instanceof HolderSet set) {
|
||||||
|
tag.putString("type", "remove_effects");
|
||||||
|
|
||||||
|
tag.put("remove_effects", holderSetToTag(set));
|
||||||
|
} else if (effect.type() == Types.EMPTY) {
|
||||||
|
tag.putString("type", "clear_all_effects");
|
||||||
|
} else if (effect.type() == Types.FLOAT) {
|
||||||
|
tag.putString("type", "teleport_randomly");
|
||||||
|
|
||||||
|
tag.putFloat("probability", (Float) effect.value());
|
||||||
|
} else if (effect.type() == Types.SOUND_EVENT && effect.value() instanceof Holder sound) {
|
||||||
|
tag.putString("type", "play_sound");
|
||||||
|
|
||||||
|
convertSoundEventHolder(tag, sound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void convertPotionEffectData(final CompoundTag tag, final PotionEffectData data) {
|
||||||
|
tag.putInt("amplifier", data.amplifier());
|
||||||
|
tag.putInt("duration", data.duration());
|
||||||
|
tag.putBoolean("ambient", data.ambient());
|
||||||
|
tag.putBoolean("show_particles", data.showParticles());
|
||||||
|
tag.putBoolean("show_icon", data.showIcon());
|
||||||
|
if (data.hiddenEffect() != null) {
|
||||||
|
final CompoundTag hiddenEffect = new CompoundTag();
|
||||||
|
convertPotionEffectData(hiddenEffect, data.hiddenEffect());
|
||||||
|
tag.put("hidden_effect", hiddenEffect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void convertSoundEventHolder(final CompoundTag tag, final Holder<SoundEvent> holder) {
|
||||||
|
tag.put("sound_event", holderToTag(holder, (event, soundEventTag) -> {
|
||||||
|
soundEventTag.putString("identifier", event.identifier());
|
||||||
|
if (event.fixedRange() != null) {
|
||||||
|
soundEventTag.putFloat("fixed_range", event.fixedRange());
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Consumable1_21_2.ConsumeEffect<?> convertConsumableEffect(final CompoundTag tag) {
|
||||||
|
final int id = tag.getInt("id");
|
||||||
|
final String type = tag.getString("type");
|
||||||
|
if ("apply_effects".equals(type)) {
|
||||||
|
final ListTag<CompoundTag> effects = tag.getListTag("effects", CompoundTag.class);
|
||||||
|
final PotionEffect[] potionEffects = new PotionEffect[effects.size()];
|
||||||
|
for (int i = 0; i < effects.size(); i++) {
|
||||||
|
final CompoundTag effectTag = effects.get(i);
|
||||||
|
final int effect = effectTag.getInt("effect");
|
||||||
|
final PotionEffectData data = convertPotionEffectData(effectTag.getCompoundTag("data"));
|
||||||
|
potionEffects[i] = new PotionEffect(effect, data);
|
||||||
|
}
|
||||||
|
final float probability = tag.getFloat("probability");
|
||||||
|
return new Consumable1_21_2.ConsumeEffect<>(id, Consumable1_21_2.ApplyStatusEffects.TYPE, new Consumable1_21_2.ApplyStatusEffects(potionEffects, probability));
|
||||||
|
} else if ("remove_effects".equals(type)) {
|
||||||
|
final HolderSet set = restoreHolderSet(tag, "remove_effects");
|
||||||
|
return new Consumable1_21_2.ConsumeEffect<>(id, Types.HOLDER_SET, set);
|
||||||
|
} else if ("clear_all_effects".equals(type)) {
|
||||||
|
return new Consumable1_21_2.ConsumeEffect<>(id, Types.EMPTY, Unit.INSTANCE);
|
||||||
|
} else if ("teleport_randomly".equals(type)) {
|
||||||
|
final float probability = tag.getFloat("probability");
|
||||||
|
return new Consumable1_21_2.ConsumeEffect<>(id, Types.FLOAT, probability);
|
||||||
|
} else if ("play_sound".equals(type)) {
|
||||||
|
final Holder<SoundEvent> sound = convertSoundEventHolder(tag);
|
||||||
|
return new Consumable1_21_2.ConsumeEffect<>(id, Types.SOUND_EVENT, sound);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PotionEffectData convertPotionEffectData(final CompoundTag tag) {
|
||||||
|
final int amplifier = tag.getInt("amplifier");
|
||||||
|
final int duration = tag.getInt("duration");
|
||||||
|
final boolean ambient = tag.getBoolean("ambient");
|
||||||
|
final boolean showParticles = tag.getBoolean("show_particles");
|
||||||
|
final boolean showIcon = tag.getBoolean("show_icon");
|
||||||
|
final CompoundTag hiddenEffect = tag.getCompoundTag("hidden_effect");
|
||||||
|
return new PotionEffectData(amplifier, duration, ambient, showParticles, showIcon, hiddenEffect != null ? convertPotionEffectData(hiddenEffect) : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Holder<SoundEvent> convertSoundEventHolder(final CompoundTag tag) {
|
||||||
|
return restoreHolder(tag, "sound_event", soundEventTag -> {
|
||||||
|
final String identifier = soundEventTag.getString("identifier");
|
||||||
|
final FloatTag fixedRange = soundEventTag.getFloatTag("fixed_range");
|
||||||
|
return new SoundEvent(identifier, fixedRange != null ? fixedRange.asFloat() : null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restoreInconvertibleData(final Item item) {
|
||||||
|
final StructuredDataContainer data = item.dataContainer();
|
||||||
|
final CompoundTag customData = data.get(StructuredDataKey.CUSTOM_DATA);
|
||||||
|
if (customData == null || !(customData.remove(nbtTagName("inconvertible_data")) instanceof CompoundTag backupTag)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Holder<Instrument1_21_2> instrument = data.get(StructuredDataKey.INSTRUMENT1_21_2);
|
||||||
|
if (instrument != null && instrument.isDirect()) {
|
||||||
|
final Tag description = backupTag.get("instrument_description");
|
||||||
|
if (description != null) {
|
||||||
|
final Instrument1_21_2 delegate = instrument.value();
|
||||||
|
data.set(StructuredDataKey.INSTRUMENT1_21_2, Holder.of(new Instrument1_21_2(delegate.soundEvent(), delegate.useDuration(), delegate.range(), description)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backupTag.contains("repairable")) {
|
||||||
|
data.set(StructuredDataKey.REPAIRABLE, restoreHolderSet(backupTag, "repairable"));
|
||||||
|
}
|
||||||
|
|
||||||
|
final IntTag enchantable = backupTag.getIntTag("enchantable");
|
||||||
|
if (enchantable != null) {
|
||||||
|
data.set(StructuredDataKey.ENCHANTABLE, enchantable.asInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
final CompoundTag useCooldown = backupTag.getCompoundTag("use_cooldown");
|
||||||
|
if (useCooldown != null) {
|
||||||
|
final float seconds = useCooldown.getFloat("seconds");
|
||||||
|
final String cooldownGroup = useCooldown.getString("cooldown_group");
|
||||||
|
data.set(StructuredDataKey.USE_COOLDOWN, new UseCooldown(seconds, cooldownGroup));
|
||||||
|
}
|
||||||
|
|
||||||
|
final String itemModel = backupTag.getString("item_model");
|
||||||
|
if (itemModel != null) {
|
||||||
|
data.set(StructuredDataKey.ITEM_MODEL, itemModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
final CompoundTag equippable = backupTag.getCompoundTag("equippable");
|
||||||
|
if (equippable != null) {
|
||||||
|
final int equipmentSlot = equippable.getInt("equipment_slot");
|
||||||
|
final Holder<SoundEvent> soundEvent = convertSoundEventHolder(equippable);
|
||||||
|
final String model = equippable.getString("model");
|
||||||
|
final String cameraOverlay = equippable.getString("camera_overlay");
|
||||||
|
final HolderSet allowedEntities = equippable.contains("allowed_entities") ? restoreHolderSet(equippable, "allowed_entities") : null;
|
||||||
|
final boolean dispensable = equippable.getBoolean("dispensable");
|
||||||
|
final boolean swappable = equippable.getBoolean("swappable");
|
||||||
|
final boolean damageOnHurt = equippable.getBoolean("damage_on_hurt");
|
||||||
|
data.set(StructuredDataKey.EQUIPPABLE, new Equippable(equipmentSlot, soundEvent, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt));
|
||||||
|
}
|
||||||
|
|
||||||
|
final ByteTag glider = backupTag.getByteTag("glider");
|
||||||
|
if (glider != null) {
|
||||||
|
data.set(StructuredDataKey.GLIDER, Unit.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String tooltipStyle = backupTag.getString("tooltip_style");
|
||||||
|
if (tooltipStyle != null) {
|
||||||
|
data.set(StructuredDataKey.TOOLTIP_STYLE, tooltipStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ListTag<CompoundTag> deathProtection = backupTag.getListTag("death_protection", CompoundTag.class);
|
||||||
|
if (deathProtection != null) {
|
||||||
|
final Consumable1_21_2.ConsumeEffect<?>[] effects = new Consumable1_21_2.ConsumeEffect[deathProtection.size()];
|
||||||
|
for (int i = 0; i < deathProtection.size(); i++) {
|
||||||
|
effects[i] = convertConsumableEffect(deathProtection.get(i));
|
||||||
|
}
|
||||||
|
data.set(StructuredDataKey.DEATH_PROTECTION, new DeathProtection(effects));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeCustomTag(data, customData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,10 +29,13 @@ import com.viaversion.viabackwards.protocol.v1_21to1_20_5.storage.EnchantmentsPa
|
|||||||
import com.viaversion.viabackwards.protocol.v1_21to1_20_5.storage.OpenScreenStorage;
|
import com.viaversion.viabackwards.protocol.v1_21to1_20_5.storage.OpenScreenStorage;
|
||||||
import com.viaversion.viabackwards.protocol.v1_21to1_20_5.storage.PlayerRotationStorage;
|
import com.viaversion.viabackwards.protocol.v1_21to1_20_5.storage.PlayerRotationStorage;
|
||||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||||
|
import com.viaversion.viaversion.api.minecraft.Holder;
|
||||||
|
import com.viaversion.viaversion.api.minecraft.SoundEvent;
|
||||||
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;
|
||||||
import com.viaversion.viaversion.api.minecraft.item.Item;
|
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||||
import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
|
import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
|
||||||
|
import com.viaversion.viaversion.api.minecraft.item.data.JukeboxPlayable;
|
||||||
import com.viaversion.viaversion.api.type.Types;
|
import com.viaversion.viaversion.api.type.Types;
|
||||||
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_5;
|
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
|
||||||
@ -49,6 +52,7 @@ import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacke
|
|||||||
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21;
|
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21;
|
||||||
import com.viaversion.viaversion.rewriter.BlockRewriter;
|
import com.viaversion.viaversion.rewriter.BlockRewriter;
|
||||||
import com.viaversion.viaversion.rewriter.IdRewriteFunction;
|
import com.viaversion.viaversion.rewriter.IdRewriteFunction;
|
||||||
|
import com.viaversion.viaversion.util.Either;
|
||||||
import com.viaversion.viaversion.util.SerializerVersion;
|
import com.viaversion.viaversion.util.SerializerVersion;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -187,6 +191,7 @@ public final class BlockItemPacketRewriter1_21 extends BackwardsStructuredItemRe
|
|||||||
final int identifier = item.identifier();
|
final int identifier = item.identifier();
|
||||||
|
|
||||||
// Order is important
|
// Order is important
|
||||||
|
backupInconvertibleData(item);
|
||||||
super.handleItemToClient(connection, item);
|
super.handleItemToClient(connection, item);
|
||||||
downgradeItemData(item);
|
downgradeItemData(item);
|
||||||
|
|
||||||
@ -222,6 +227,7 @@ public final class BlockItemPacketRewriter1_21 extends BackwardsStructuredItemRe
|
|||||||
// Order is important
|
// Order is important
|
||||||
super.handleItemToServer(connection, item);
|
super.handleItemToServer(connection, item);
|
||||||
updateItemData(item);
|
updateItemData(item);
|
||||||
|
restoreInconvertibleData(item);
|
||||||
|
|
||||||
final CompoundTag customData = data.get(StructuredDataKey.CUSTOM_DATA);
|
final CompoundTag customData = data.get(StructuredDataKey.CUSTOM_DATA);
|
||||||
if (customData == null) {
|
if (customData == null) {
|
||||||
@ -264,6 +270,67 @@ public final class BlockItemPacketRewriter1_21 extends BackwardsStructuredItemRe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void backupInconvertibleData(final Item item) {
|
||||||
|
final StructuredDataContainer data = item.dataContainer();
|
||||||
|
data.setIdLookup(protocol, true);
|
||||||
|
|
||||||
|
final JukeboxPlayable jukeboxPlayable = data.get(StructuredDataKey.JUKEBOX_PLAYABLE);
|
||||||
|
if (jukeboxPlayable == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final CompoundTag tag = new CompoundTag();
|
||||||
|
if (jukeboxPlayable.song().isLeft()) {
|
||||||
|
final Holder<JukeboxPlayable.JukeboxSong> songHolder = jukeboxPlayable.song().left();
|
||||||
|
tag.put("song", holderToTag(songHolder, (song, songTag) -> {
|
||||||
|
songTag.put("sound_event", holderToTag(song.soundEvent(), (soundEvent, soundEventTag) -> {
|
||||||
|
soundEventTag.putString("identifier", soundEvent.identifier());
|
||||||
|
if (soundEvent.fixedRange() != null) {
|
||||||
|
soundEventTag.putFloat("fixed_range", soundEvent.fixedRange());
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
songTag.put("description", song.description());
|
||||||
|
songTag.putFloat("length_in_seconds", song.lengthInSeconds());
|
||||||
|
songTag.putInt("comparator_output", song.comparatorOutput());
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
tag.putString("song_identifier", jukeboxPlayable.song().right());
|
||||||
|
}
|
||||||
|
tag.putBoolean("show_in_tooltip", jukeboxPlayable.showInTooltip());
|
||||||
|
|
||||||
|
saveTag(createCustomTag(item), tag, "jukebox_playable");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restoreInconvertibleData(final Item item) {
|
||||||
|
final StructuredDataContainer data = item.dataContainer();
|
||||||
|
final CompoundTag customData = data.get(StructuredDataKey.CUSTOM_DATA);
|
||||||
|
if (customData == null || !(customData.remove(nbtTagName("jukebox_playable")) instanceof CompoundTag tag)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Either<Holder<JukeboxPlayable.JukeboxSong>, String> song;
|
||||||
|
final String songIdentifier = tag.getString("song_identifier");
|
||||||
|
if (songIdentifier != null) {
|
||||||
|
song = Either.right(tag.getString(songIdentifier));
|
||||||
|
} else {
|
||||||
|
song = Either.left(restoreHolder(tag, "song", songTag -> {
|
||||||
|
final Holder<SoundEvent> soundEvent = restoreHolder(songTag, "sound_event", soundTag -> {
|
||||||
|
final String identifier = soundTag.getString("identifier");
|
||||||
|
final Float fixedRange = soundTag.contains("fixed_range") ? soundTag.getFloat("fixed_range") : null;
|
||||||
|
return new SoundEvent(identifier, fixedRange);
|
||||||
|
});
|
||||||
|
final Tag description = songTag.get("description");
|
||||||
|
final float lengthInSeconds = songTag.getFloat("length_in_seconds");
|
||||||
|
final int comparatorOutput = songTag.getInt("comparator_output");
|
||||||
|
return new JukeboxPlayable.JukeboxSong(soundEvent, description, lengthInSeconds, comparatorOutput);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
final JukeboxPlayable jukeboxPlayable = new JukeboxPlayable(song, tag.getBoolean("show_in_tooltip"));
|
||||||
|
data.set(StructuredDataKey.JUKEBOX_PLAYABLE, jukeboxPlayable);
|
||||||
|
removeCustomTag(data, customData);
|
||||||
|
}
|
||||||
|
|
||||||
private record PendingIdChange(int id, int mappedId, int level) {
|
private record PendingIdChange(int id, int mappedId, int level) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user