Handle CanPlaceOn and CanDestroy tags

This commit is contained in:
Nassim Jahnke 2024-03-14 16:33:08 +01:00
parent 7a96498f6d
commit 3f82b150d2
No known key found for this signature in database
GPG Key ID: EF6771C01F6EF02F
7 changed files with 115 additions and 27 deletions

View File

@ -24,6 +24,9 @@ package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.util.EitherImpl; import com.viaversion.viaversion.util.EitherImpl;
/**
* Set of ids that either holds a string tag key or an array of ids.
*/
public final class HolderSet extends EitherImpl<String, int[]> { public final class HolderSet extends EitherImpl<String, int[]> {
public HolderSet(final String tagKey) { public HolderSet(final String tagKey) {

View File

@ -65,7 +65,7 @@ public final class StructuredDataKey<T> {
public static final StructuredDataKey<Unit> CREATIVE_SLOT_LOCK = new StructuredDataKey<>("creative_slot_lock", Type.EMPTY); public static final StructuredDataKey<Unit> CREATIVE_SLOT_LOCK = new StructuredDataKey<>("creative_slot_lock", Type.EMPTY);
public static final StructuredDataKey<Boolean> ENCHANTMENT_GLINT_OVERRIDE = new StructuredDataKey<>("enchantment_glint_override", Type.BOOLEAN); public static final StructuredDataKey<Boolean> ENCHANTMENT_GLINT_OVERRIDE = new StructuredDataKey<>("enchantment_glint_override", Type.BOOLEAN);
public static final StructuredDataKey<Unit> INTANGIBLE_PROJECTILE = new StructuredDataKey<>("intangible_projectile", Type.EMPTY); public static final StructuredDataKey<Unit> INTANGIBLE_PROJECTILE = new StructuredDataKey<>("intangible_projectile", Type.EMPTY);
public static final StructuredDataKey<Enchantments> STORED_ENCHANTMENTS = new StructuredDataKey<>("storded_enchantments", Enchantments.TYPE); public static final StructuredDataKey<Enchantments> STORED_ENCHANTMENTS = new StructuredDataKey<>("stored_enchantments", Enchantments.TYPE);
public static final StructuredDataKey<DyedColor> DYED_COLOR = new StructuredDataKey<>("dyed_color", DyedColor.TYPE); public static final StructuredDataKey<DyedColor> DYED_COLOR = new StructuredDataKey<>("dyed_color", DyedColor.TYPE);
public static final StructuredDataKey<Integer> MAP_COLOR = new StructuredDataKey<>("map_color", Type.INT); public static final StructuredDataKey<Integer> MAP_COLOR = new StructuredDataKey<>("map_color", Type.INT);
public static final StructuredDataKey<Integer> MAP_ID = new StructuredDataKey<>("map_id", Type.VAR_INT); public static final StructuredDataKey<Integer> MAP_ID = new StructuredDataKey<>("map_id", Type.VAR_INT);

View File

@ -18,19 +18,16 @@
package com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data; package com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
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.viaversion.viaversion.api.data.MappingDataBase; import com.viaversion.viaversion.api.data.MappingDataBase;
import com.viaversion.viaversion.api.data.MappingDataLoader; import com.viaversion.viaversion.api.data.MappingDataLoader;
import it.unimi.dsi.fastutil.objects.Object2IntMap; import com.viaversion.viaversion.util.KeyMappings;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList;
import java.util.List;
public class MappingData extends MappingDataBase { public class MappingData extends MappingDataBase {
private final Object2IntMap<String> byId = new Object2IntOpenHashMap<>(); private KeyMappings items;
private final List<String> itemIds = new ArrayList<>(); private KeyMappings blocks;
public MappingData() { public MappingData() {
super("1.20.3", "1.20.5"); super("1.20.3", "1.20.5");
@ -40,20 +37,24 @@ public class MappingData extends MappingDataBase {
protected void loadExtras(final CompoundTag data) { protected void loadExtras(final CompoundTag data) {
super.loadExtras(data); super.loadExtras(data);
final ListTag<StringTag> items = MappingDataLoader.loadNBT("itemIds-1.20.3.nbt").getListTag("items", StringTag.class); final CompoundTag extraMappings = MappingDataLoader.loadNBT("items-blocks-1.20.3.nbt");
for (int i = 0; i < items.size(); i++) { items = new KeyMappings(extraMappings.getListTag("items", StringTag.class));
final StringTag tag = items.get(i); blocks = new KeyMappings(extraMappings.getListTag("blocks", StringTag.class));
itemIds.add(tag.getValue());
byId.put(tag.getValue(), i);
}
byId.defaultReturnValue(-1);
} }
public int itemId(final String name) { public int itemId(final String name) {
return byId.getInt(name); return items.keyToId(name);
} }
public String itemName(final int id) { public @Nullable String itemName(final int id) {
return itemIds.get(id); return items.idToKey(id);
}
public int blockId(final String name) {
return blocks.keyToId(name);
}
public @Nullable String blockName(final int id) {
return blocks.idToKey(id);
} }
} }

View File

@ -17,16 +17,19 @@
*/ */
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.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.ListTag; import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.NumberTag; import com.github.steveice10.opennbt.tag.builtin.NumberTag;
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.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.data.ParticleMappings; import com.viaversion.viaversion.api.data.ParticleMappings;
import com.viaversion.viaversion.api.minecraft.GameProfile; import com.viaversion.viaversion.api.minecraft.GameProfile;
import com.viaversion.viaversion.api.minecraft.GlobalPosition; 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.Particle; import com.viaversion.viaversion.api.minecraft.Particle;
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;
@ -34,6 +37,7 @@ import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.DataItem; import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.StructuredItem; import com.viaversion.viaversion.api.minecraft.item.StructuredItem;
import com.viaversion.viaversion.api.minecraft.item.data.AdventureModePredicate;
import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrim; import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrim;
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;
@ -41,6 +45,7 @@ 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.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.BlockStateProperties; import com.viaversion.viaversion.api.minecraft.item.data.BlockStateProperties;
import com.viaversion.viaversion.api.minecraft.item.data.DyedColor; import com.viaversion.viaversion.api.minecraft.item.data.DyedColor;
import com.viaversion.viaversion.api.minecraft.item.data.Enchantments; import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
@ -53,6 +58,7 @@ import com.viaversion.viaversion.api.minecraft.item.data.ModifierData;
import com.viaversion.viaversion.api.minecraft.item.data.PotionContents; import com.viaversion.viaversion.api.minecraft.item.data.PotionContents;
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.SuspiciousStewEffect; import com.viaversion.viaversion.api.minecraft.item.data.SuspiciousStewEffect;
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;
@ -79,6 +85,7 @@ import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.packet.Serverb
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.ComponentUtil; import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.Either;
import com.viaversion.viaversion.util.Key; import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.UUIDUtil; import com.viaversion.viaversion.util.UUIDUtil;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
@ -88,12 +95,14 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level;
import org.checkerframework.checker.nullness.qual.Nullable; 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 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];
public BlockItemPacketRewriter1_20_5(final Protocol1_20_5To1_20_3 protocol) { public BlockItemPacketRewriter1_20_5(final Protocol1_20_5To1_20_3 protocol) {
super(protocol, Type.ITEM1_20_2, Type.ITEM1_20_2_ARRAY, Types1_20_5.ITEM, Types1_20_5.ITEM_ARRAY); super(protocol, Type.ITEM1_20_2, Type.ITEM1_20_2_ARRAY, Types1_20_5.ITEM, Types1_20_5.ITEM_ARRAY);
@ -392,8 +401,6 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
updateMapDecorations(data, decorationsTag); updateMapDecorations(data, decorationsTag);
} }
// MAP_POST_PROCESSING is only used internally
updateProfile(data, tag.get("SkullOwner")); updateProfile(data, tag.get("SkullOwner"));
final CompoundTag customCreativeLock = tag.getCompoundTag("CustomCreativeLock"); final CompoundTag customCreativeLock = tag.getCompoundTag("CustomCreativeLock");
@ -401,15 +408,82 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
data.set(StructuredDataKey.CREATIVE_SLOT_LOCK); data.set(StructuredDataKey.CREATIVE_SLOT_LOCK);
} }
// TODO final ListTag<StringTag> canPlaceOnTag = tag.getListTag("CanPlaceOn", StringTag.class);
// StructuredDataKey.CAN_PLACE_ON if (canPlaceOnTag != null) {
// StructuredDataKey.CAN_BREAK data.set(StructuredDataKey.CAN_PLACE_ON, updateBlockPredicates(canPlaceOnTag, (hideFlagsValue & StructuredDataConverter.HIDE_CAN_PLACE_ON) == 0));
// (remaining ones should only affect non-essential item tooltip, or not be shown/checked at all) }
final ListTag<StringTag> canDestroyTag = tag.getListTag("CanDestroy", StringTag.class);
if (canDestroyTag != null) {
data.set(StructuredDataKey.CAN_BREAK, updateBlockPredicates(canDestroyTag, (hideFlagsValue & StructuredDataConverter.HIDE_CAN_DESTROY) == 0));
}
// TODO MAP_POST_PROCESSING
data.set(StructuredDataKey.CUSTOM_DATA, tag); data.set(StructuredDataKey.CUSTOM_DATA, tag);
return item; return item;
} }
private AdventureModePredicate updateBlockPredicates(final ListTag<StringTag> tag, final boolean showInTooltip) {
final BlockPredicate[] predicates = tag.stream()
.map(StringTag::getValue)
.map(this::deserializeBlockPredicate)
.filter(Objects::nonNull)
.toArray(BlockPredicate[]::new);
return new AdventureModePredicate(predicates, showInTooltip);
}
private @Nullable BlockPredicate deserializeBlockPredicate(final String rawPredicate) {
final int propertiesStartIndex = rawPredicate.indexOf('[');
final int tagStartIndex = rawPredicate.indexOf('{');
int idLength = rawPredicate.length();
if (propertiesStartIndex != -1) {
idLength = propertiesStartIndex;
}
if (tagStartIndex != -1) {
idLength = Math.min(propertiesStartIndex, tagStartIndex);
}
final String identifier = rawPredicate.substring(0, idLength);
final int id = Protocol1_20_5To1_20_3.MAPPINGS.blockId(identifier);
if (id == -1) {
return null;
}
final int propertiesEndIndex = rawPredicate.indexOf(']');
final List<StatePropertyMatcher> propertyMatchers = new ArrayList<>();
if (propertiesStartIndex != -1 && propertiesEndIndex != -1) {
for (final String property : rawPredicate.substring(propertiesStartIndex + 1, propertiesEndIndex).split(",")) {
final int propertySplitIndex = property.indexOf('=');
if (propertySplitIndex == -1) {
continue;
}
final String propertyId = property.substring(0, propertySplitIndex).trim();
final String propertyValue = property.substring(propertySplitIndex + 1).trim();
propertyMatchers.add(new StatePropertyMatcher(propertyId, Either.left(propertyValue))); // TODO Also handle ranged matchers
}
}
final int tagEndIndex = rawPredicate.indexOf('}');
CompoundTag tag = null;
if (tagStartIndex != -1 && tagEndIndex != -1) {
try {
tag = SNBT.deserializeCompoundTag(rawPredicate.substring(tagStartIndex, tagEndIndex + 1));
} catch (final Exception e) {
if (Via.getManager().isDebug()) {
Via.getPlatform().getLogger().log(Level.SEVERE, "Failed to parse block predicate tag: " + rawPredicate.substring(tagStartIndex, tagEndIndex + 1), e);
}
}
}
return new BlockPredicate(
new HolderSet(new int[]{Protocol1_20_5To1_20_3.MAPPINGS.getNewBlockId(id)}),
propertyMatchers.isEmpty() ? null : propertyMatchers.toArray(EMPTY_PROPERTY_MATCHERS),
tag
);
}
private void updateAttributes(final StructuredDataContainer data, final ListTag<CompoundTag> attributeModifiersTag, final boolean showInTooltip) { private void updateAttributes(final StructuredDataContainer data, final ListTag<CompoundTag> attributeModifiersTag, final boolean showInTooltip) {
final AttributeModifier[] modifiers = attributeModifiersTag.stream().map(modifierTag -> { final AttributeModifier[] modifiers = attributeModifiersTag.stream().map(modifierTag -> {
final String attributeName = modifierTag.getString("AttributeName"); final String attributeName = modifierTag.getString("AttributeName");
@ -676,7 +750,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
} }
private int toItemId(final String id) { private int toItemId(final String id) {
final int unmappedId = protocol.getMappingData().itemId(Key.stripMinecraftNamespace(id)); final int unmappedId = protocol.getMappingData().itemId(id);
return unmappedId != -1 ? protocol.getMappingData().getNewItemId(unmappedId) : -1; return unmappedId != -1 ? protocol.getMappingData().getNewItemId(unmappedId) : -1;
} }

View File

@ -38,7 +38,6 @@ import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.Enchantme
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_3;
import com.viaversion.viaversion.util.ComponentUtil; import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.UUIDUtil; 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.objects.Reference2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
@ -49,7 +48,7 @@ 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;
static final int HIDE_UNBREAKABLE = 1 << 2; static final int HIDE_UNBREAKABLE = 1 << 2;
static final int HIDE_CAN_BREAK = 1 << 3; static final int HIDE_CAN_DESTROY = 1 << 3;
static final int HIDE_CAN_PLACE_ON = 1 << 4; static final int HIDE_CAN_PLACE_ON = 1 << 4;
static final int HIDE_ADDITIONAL = 1 << 5; static final int HIDE_ADDITIONAL = 1 << 5;
static final int HIDE_DYE_COLOR = 1 << 6; static final int HIDE_DYE_COLOR = 1 << 6;

View File

@ -17,8 +17,11 @@
*/ */
package com.viaversion.viaversion.util; package com.viaversion.viaversion.util;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import java.util.Collection;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
public final class KeyMappings { public final class KeyMappings {
@ -35,6 +38,14 @@ public final class KeyMappings {
} }
} }
public KeyMappings(final Collection<String> keys) {
this(keys.toArray(new String[0]));
}
public KeyMappings(final ListTag<StringTag> keys) {
this(keys.getValue().stream().map(StringTag::getValue).toArray(String[]::new));
}
public @Nullable String idToKey(final int id) { public @Nullable String idToKey(final int id) {
if (id < 0 || id >= keys.length) { if (id < 0 || id >= keys.length) {
return null; return null;