Fix initial item sending, add some data translation and more rigid data structures

This commit is contained in:
Nassim Jahnke 2024-02-29 16:05:30 +01:00
parent 01bb8dedda
commit e51d7b3fdb
No known key found for this signature in database
GPG Key ID: EF6771C01F6EF02F
17 changed files with 522 additions and 154 deletions

View File

@ -109,13 +109,13 @@ public interface MappingData {
@Nullable Mappings getAttributeMappings();
@Nullable Mappings getPaintingMappings();
@Nullable FullMappings getEntityMappings();
@Nullable FullMappings getArgumentTypeMappings();
@Nullable FullMappings getRecipeSerializerMappings();
FullMappings getDataComponentSerializerMappings();
@Nullable Mappings getPaintingMappings();
@Nullable FullMappings getDataComponentSerializerMappings();
}

View File

@ -29,43 +29,38 @@ import io.netty.buffer.ByteBuf;
public final class StructuredData<T> implements IdHolder {
private final Type<T> type;
private final StructuredDataKey<T> key;
private T value;
private int id;
public StructuredData(final Type<T> type, final T value, final int id) {
this.type = type;
public StructuredData(final StructuredDataKey<T> key, final T value, final int id) {
this.key = key;
this.value = value;
this.id = id;
}
public static StructuredData<?> empty(final int id) {
// Indicates empty structures, whereas an empty optional is used to remove default values
return new StructuredData<>(Type.UNIT, Unit.INSTANCE, id);
}
public boolean isEmpty() {
return type == Type.UNIT;
return key.type() == Type.UNIT;
}
public void setValue(final T value) {
if (value != null && !type.getOutputClass().isAssignableFrom(value.getClass())) {
throw new IllegalArgumentException("Item data type and value are incompatible. Type=" + type
if (value != null && !key.type().getOutputClass().isAssignableFrom(value.getClass())) {
throw new IllegalArgumentException("Item data type and value are incompatible. Type=" + key
+ ", value=" + value + " (" + value.getClass().getSimpleName() + ")");
}
this.value = value;
}
public void write(final ByteBuf buffer) throws Exception {
type.write(buffer, value);
key.type().write(buffer, value);
}
public void setId(final int id) {
this.id = id;
}
public Type<T> type() {
return type;
public StructuredDataKey<T> key() {
return key;
}
public T value() {

View File

@ -0,0 +1,120 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.data;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.Protocol;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.Optional;
public final class StructuredDataContainer {
private final Int2ObjectMap<Optional<StructuredData<?>>> data; // Bless Optionals in a map
public StructuredDataContainer(final Int2ObjectMap<Optional<StructuredData<?>>> data) {
this.data = data;
}
public StructuredDataContainer() {
this(new Int2ObjectOpenHashMap<>());
}
/**
* Returns structured data by id. You might want to call {@link #contains(int)} first.
*
* @param id serializer id
* @param <T> data type
* @return structured data
*/
public <T> Optional<StructuredData<T>> get(final int id) {
final Optional<StructuredData<?>> data = this.data.getOrDefault(id, Optional.empty());
//noinspection unchecked
return data.map(value -> (StructuredData<T>) value);
}
/**
* Returns structured data by id. You might want to call {@link #contains(Protocol, StructuredDataKey)} first.
*
* @param protocol protocol to retreive the id of the serializer from
* @param key serializer id
* @param <T> data type
* @return structured data
*/
public <T> Optional<StructuredData<T>> get(final Protocol<?, ?, ?, ?> protocol, final StructuredDataKey<T> key) {
final Optional<StructuredData<?>> data = this.data.getOrDefault(serializerId(protocol, key), Optional.empty());
//noinspection unchecked
return data.map(value -> (StructuredData<T>) value);
}
public void add(final StructuredData<?> data) {
this.data.put(data.id(), Optional.of(data));
}
public <T> void add(final Protocol<?, ?, ?, ?> protocol, final StructuredDataKey<T> key, final T value) {
final int id = serializerId(protocol, key);
if (id != -1) {
add(new StructuredData<>(key, value, id));
}
}
public <T> void addEmpty(final Protocol<?, ?, ?, ?> protocol, final StructuredDataKey<T> key) {
final int id = serializerId(protocol, key);
if (id != -1) {
this.data.put(id, Optional.empty());
}
}
public void remove(final int id) {
this.data.remove(id);
}
public void removeDefault(final int id) {
// Empty optional to override the Minecraft default
this.data.put(id, Optional.empty());
}
public boolean contains(final int id) {
return this.data.containsKey(id);
}
public boolean contains(final Protocol<?, ?, ?, ?> protocol, final StructuredDataKey<?> key) {
return this.data.containsKey(serializerId(protocol, key));
}
public StructuredDataContainer copy() {
return new StructuredDataContainer(new Int2ObjectOpenHashMap<>(data));
}
private int serializerId(final Protocol<?, ?, ?, ?> protocol, final StructuredDataKey<?> key) {
final int id = protocol.getMappingData().getDataComponentSerializerMappings().mappedId(key.identifier());
if (id == -1) {
Via.getPlatform().getLogger().severe("Could not find item data serializer for type " + key);
}
return id;
}
public Int2ObjectMap<Optional<StructuredData<?>>> data() {
return data;
}
}

View File

@ -0,0 +1,105 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.data;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.data.BannerPattern;
import com.viaversion.viaversion.api.minecraft.item.data.Bee;
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.Enchantments;
import com.viaversion.viaversion.api.minecraft.item.data.GameProfile;
import com.viaversion.viaversion.api.minecraft.item.data.LodestoneTarget;
import com.viaversion.viaversion.api.minecraft.item.data.WrittenBook;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.util.Unit;
public final class StructuredDataKey<T> {
public static final StructuredDataKey<CompoundTag> CUSTOM_DATA = new StructuredDataKey<>("custom_data", Type.COMPOUND_TAG);
public static final StructuredDataKey<Integer> DAMAGE = new StructuredDataKey<>("damage", Type.VAR_INT);
public static final StructuredDataKey<Boolean> UNBREAKABLE = new StructuredDataKey<>("unbreakable", Type.BOOLEAN);
public static final StructuredDataKey<Tag> CUSTOM_NAME = new StructuredDataKey<>("custom_name", Type.TAG);
public static final StructuredDataKey<Tag[]> LORE = new StructuredDataKey<>("lore", Type.TAG_ARRAY);
public static final StructuredDataKey<Enchantments> ENCHANTMENTS = new StructuredDataKey<>("enchantments", Enchantments.TYPE);
public static final StructuredDataKey<?> CAN_PLACE_ON = new StructuredDataKey<>("can_place_on", Type.UNIT); // TODO
public static final StructuredDataKey<?> CAN_BREAK = new StructuredDataKey<>("can_break", Type.UNIT); // TODO
public static final StructuredDataKey<?> ATTRIBUTE_MODIFIERS = new StructuredDataKey<>("attribute_modifiers", Type.UNIT); // TODO
public static final StructuredDataKey<Integer> CUSTOM_MODEL_DATA = new StructuredDataKey<>("custom_model_data", Type.VAR_INT);
public static final StructuredDataKey<Unit> HIDE_ADDITIONAL_TOOLTIP = new StructuredDataKey<>("hide_additional_tooltip", Type.UNIT);
public static final StructuredDataKey<Integer> REPAIR_COST = new StructuredDataKey<>("repair_cost", Type.VAR_INT);
public static final StructuredDataKey<Unit> CREATIVE_SLOT_LOCK = new StructuredDataKey<>("creative_slot_lock", Type.UNIT);
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.UNIT);
public static final StructuredDataKey<Enchantments> STORED_ENCHANTMENTS = new StructuredDataKey<>("storded_enchantments", Enchantments.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_ID = new StructuredDataKey<>("map_id", Type.VAR_INT);
public static final StructuredDataKey<CompoundTag> MAP_DECORATIONS = new StructuredDataKey<>("map_decorations", Type.COMPOUND_TAG);
public static final StructuredDataKey<Integer> MAP_POST_PROCESSING = new StructuredDataKey<>("map_post_processing", Type.VAR_INT);
public static final StructuredDataKey<Item[]> CHARGED_PROJECTILES = new StructuredDataKey<>("charged_projectiles", Types1_20_5.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> BUNDLE_CONTENTS = new StructuredDataKey<>("bundle_contents", Types1_20_5.ITEM_ARRAY);
public static final StructuredDataKey<?> POTION_CONTENTS = new StructuredDataKey<>("potion_contents", Type.UNIT); // TODO
public static final StructuredDataKey<?> SUSPICIOUS_STEW_EFFECTS = new StructuredDataKey<>("suspicious_stew_effects", Type.UNIT); // TODO
public static final StructuredDataKey<String[]> WRITABLE_BOOK_CONTENT = new StructuredDataKey<>("writable_book_content", Type.STRING_ARRAY);
public static final StructuredDataKey<WrittenBook> WRITTEN_BOOK_CONTENT = new StructuredDataKey<>("written_book_content", WrittenBook.TYPE);
public static final StructuredDataKey<?> TRIM = new StructuredDataKey<>("trim", Type.UNIT); // TODO
public static final StructuredDataKey<CompoundTag> DEBUG_STICK_STATE = new StructuredDataKey<>("debug_stick_state", Type.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> ENTITY_DATA = new StructuredDataKey<>("entity_data", Type.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> BUCKET_ENTITY_DATA = new StructuredDataKey<>("bucket_entity_data", Type.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> BLOCK_ENTITY_DATA = new StructuredDataKey<>("block_entity_data", Type.COMPOUND_TAG);
public static final StructuredDataKey<?> INSTRUMENT = new StructuredDataKey<>("instrument", Type.UNIT); // TODO
public static final StructuredDataKey<String[]> RECIPES = new StructuredDataKey<>("recipes", Type.STRING_ARRAY);
public static final StructuredDataKey<LodestoneTarget> LODESTONE_TARGET = new StructuredDataKey<>("lodestone_target", LodestoneTarget.TYPE);
public static final StructuredDataKey<?> FIREWORK_EXPLOSION = new StructuredDataKey<>("firework_explosion", Type.UNIT); // TODO
public static final StructuredDataKey<?> FIREWORKS = new StructuredDataKey<>("fireworks", Type.UNIT); // TODO
public static final StructuredDataKey<GameProfile> PROFILE = new StructuredDataKey<>("profile", GameProfile.TYPE);
public static final StructuredDataKey<String> NOTE_BLOCK_SOUND = new StructuredDataKey<>("note_block_sound", Type.STRING);
public static final StructuredDataKey<BannerPattern[]> BANNER_PATTERNS = new StructuredDataKey<>("banner_patterns", BannerPattern.ARRAY_TYPE);
public static final StructuredDataKey<Integer> BASE_COLOR = new StructuredDataKey<>("base_color", Type.VAR_INT);
public static final StructuredDataKey<int[]> POT_DECORATIONS = new StructuredDataKey<>("pot_decorations", Type.VAR_INT_ARRAY_PRIMITIVE);
public static final StructuredDataKey<Item[]> CONTAINER = new StructuredDataKey<>("container", Types1_20_5.ITEM_ARRAY);
public static final StructuredDataKey<BlockStateProperties> BLOCK_STATE = new StructuredDataKey<>("block_state", BlockStateProperties.TYPE);
public static final StructuredDataKey<Bee[]> BEES = new StructuredDataKey<>("bees", Bee.ARRAY_TYPE);
public static final StructuredDataKey<CompoundTag> LOCK = new StructuredDataKey<>("lock", Type.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> CONTAINER_LOOT = new StructuredDataKey<>("container_loot", Type.COMPOUND_TAG);
private final String identifier;
private final Type<T> type;
public StructuredDataKey(final String identifier, Type<T> type) {
this.identifier = identifier;
this.type = type;
}
public Type<T> type() {
return type;
}
public String identifier() {
return identifier;
}
}

View File

@ -24,10 +24,8 @@ package com.viaversion.viaversion.api.minecraft.item;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.google.gson.annotations.SerializedName;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import java.util.Objects;
import java.util.Optional;
import org.checkerframework.checker.nullness.qual.Nullable;
public class DataItem implements Item {
@ -95,17 +93,7 @@ public class DataItem implements Item {
}
@Override
public Int2ObjectMap<Optional<StructuredData<?>>> structuredData() {
throw new UnsupportedOperationException();
}
@Override
public void addData(final StructuredData<?> data) {
throw new UnsupportedOperationException();
}
@Override
public void removeDefaultData(final int id) {
public StructuredDataContainer structuredData() {
throw new UnsupportedOperationException();
}

View File

@ -23,9 +23,7 @@
package com.viaversion.viaversion.api.minecraft.item;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import java.util.Optional;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface Item {
@ -91,11 +89,7 @@ public interface Item {
*/
void setTag(@Nullable CompoundTag tag);
Int2ObjectMap<Optional<StructuredData<?>>> structuredData();
void addData(StructuredData<?> data);
void removeDefaultData(int id);
StructuredDataContainer structuredData();
/**
* Returns a copy of the item.

View File

@ -23,22 +23,19 @@
package com.viaversion.viaversion.api.minecraft.item;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.Optional;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import org.checkerframework.checker.nullness.qual.Nullable;
public class StructuredItem implements Item {
private final Int2ObjectMap<Optional<StructuredData<?>>> data;
private final StructuredDataContainer data;
private int identifier;
private byte amount;
public StructuredItem() {
this(0, (byte) 0, new Int2ObjectOpenHashMap<>());
this(0, (byte) 0, new StructuredDataContainer());
}
public StructuredItem(final int identifier, final byte amount, final Int2ObjectMap<Optional<StructuredData<?>>> data) {
public StructuredItem(final int identifier, final byte amount, final StructuredDataContainer data) {
this.identifier = identifier;
this.amount = amount;
this.data = data;
@ -78,24 +75,13 @@ public class StructuredItem implements Item {
}
@Override
public Int2ObjectMap<Optional<StructuredData<?>>> structuredData() {
public StructuredDataContainer structuredData() {
return data;
}
@Override
public void addData(final StructuredData<?> data) {
this.data.put(data.id(), Optional.of(data));
}
@Override
public void removeDefaultData(final int id) {
// Empty optional to override the Minecraft default
this.data.put(id, Optional.empty());
}
@Override
public StructuredItem copy() {
return new StructuredItem(identifier, amount, new Int2ObjectOpenHashMap<>(data));
return new StructuredItem(identifier, amount, data.copy());
}
@Override

View File

@ -47,7 +47,7 @@ public final class Enchantments {
public void write(final ByteBuf buffer, final Enchantments value) {
Type.VAR_INT.writePrimitive(buffer, value.enchantments.size());
for (final Int2IntMap.Entry entry : value.enchantments.int2IntEntrySet()) {
Type.VAR_INT.writePrimitive(buffer, entry.getIntValue());
Type.VAR_INT.writePrimitive(buffer, entry.getIntKey());
Type.VAR_INT.writePrimitive(buffer, entry.getIntValue());
}
buffer.writeBoolean(value.showInTooltip());
@ -66,6 +66,10 @@ public final class Enchantments {
return enchantments;
}
public int size() {
return enchantments.size();
}
public boolean showInTooltip() {
return showInTooltip;
}

View File

@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.type.types.item;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.item.StructuredItem;
@ -50,7 +51,7 @@ public class ItemType1_20_5 extends Type<Item> {
final int id = Type.VAR_INT.readPrimitive(buffer);
final Int2ObjectMap<Optional<StructuredData<?>>> data = readData(buffer);
return new StructuredItem(id, amount, data);
return new StructuredItem(id, amount, new StructuredDataContainer(data));
}
private Int2ObjectMap<Optional<StructuredData<?>>> readData(final ByteBuf buffer) throws Exception {
@ -83,7 +84,7 @@ public class ItemType1_20_5 extends Type<Item> {
buffer.writeByte(object.amount());
Type.VAR_INT.writePrimitive(buffer, object.identifier());
final Int2ObjectMap<Optional<StructuredData<?>>> data = object.structuredData();
final Int2ObjectMap<Optional<StructuredData<?>>> data = object.structuredData().data();
int valuesSize = 0;
int markersSize = 0;
for (final Int2ObjectMap.Entry<Optional<StructuredData<?>>> entry : data.int2ObjectEntrySet()) {

View File

@ -24,6 +24,7 @@ package com.viaversion.viaversion.api.type.types.item;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
@ -32,7 +33,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class StructuredDataType extends Type<StructuredData<?>> {
private final Int2ObjectMap<Type<?>> types = new Int2ObjectOpenHashMap<>();
private final Int2ObjectMap<StructuredDataKey<?>> types = new Int2ObjectOpenHashMap<>();
public StructuredDataType() {
super(StructuredData.class);
@ -47,15 +48,15 @@ public class StructuredDataType extends Type<StructuredData<?>> {
@Override
public StructuredData<?> read(final ByteBuf buffer) throws Exception {
final int id = Type.VAR_INT.readPrimitive(buffer);
final Type<?> type = this.types.get(id);
if (type != null) {
return readData(buffer, type, id);
final StructuredDataKey<?> key = this.types.get(id);
if (key != null) {
return readData(buffer, key, id);
}
throw new IllegalArgumentException("Unknown item data type id: " + id);
throw new IllegalArgumentException("No data component serializer found for id " + id);
}
private <T> StructuredData<T> readData(final ByteBuf buffer, final Type<T> type, final int id) throws Exception {
return new StructuredData<>(type, type.read(buffer), id);
private <T> StructuredData<T> readData(final ByteBuf buffer, final StructuredDataKey<T> key, final int id) throws Exception {
return new StructuredData<>(key, key.type().read(buffer), id);
}
public DataFiller filler(final Protocol<?, ?, ?, ?> protocol) {
@ -76,13 +77,8 @@ public class StructuredDataType extends Type<StructuredData<?>> {
this.useMappedNames = useMappedNames;
}
public DataFiller reader(final String identifier, final Type<?> reader) {
types.put(useMappedNames ? mappings.mappedId(identifier) : mappings.id(identifier), reader);
return this;
}
public DataFiller reader(final int id, final Type<?> type) {
types.put(id, type);
public DataFiller add(final StructuredDataKey<?> reader) {
types.put(useMappedNames ? mappings.mappedId(reader.identifier()) : mappings.id(reader.identifier()), reader);
return this;
}
}

View File

@ -71,7 +71,12 @@ public class InventoryPackets extends ItemRewriter<ClientboundPackets1_12_1, Ser
map(Type.UNSIGNED_BYTE); // 0 - Window ID
map(Type.ITEM1_8_SHORT_ARRAY, Type.ITEM1_13_SHORT_ARRAY); // 1 - Window Values
handler(itemArrayToClientHandler(Type.ITEM1_13_SHORT_ARRAY));
handler(wrapper -> {
Item[] items = wrapper.get(Type.ITEM1_13_SHORT_ARRAY, 0);
for (Item item : items) {
handleItemToClient(item);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_12_1.WINDOW_PROPERTY, new PacketHandlers() {

View File

@ -21,6 +21,7 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.data.MappingDataBase;
import com.viaversion.viaversion.api.minecraft.RegistryType;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.BannerPattern;
import com.viaversion.viaversion.api.minecraft.item.data.Bee;
@ -120,47 +121,53 @@ public final class Protocol1_20_5To1_20_3 extends AbstractProtocol<ClientboundPa
.reader("sculk_charge", ParticleType.Readers.SCULK_CHARGE)
.reader("shriek", ParticleType.Readers.SHRIEK);
Types1_20_5.ITEM_DATA.filler(this)
.reader("damage", Type.VAR_INT)
.reader("unbreakable", Type.BOOLEAN)
.reader("custom_name", Type.TAG)
.reader("lore", Type.TAG_ARRAY)
.reader("enchantments", Enchantments.TYPE)
.reader("can_place_on", Type.UNIT) // TODO
.reader("can_break", Type.UNIT) // TODO
.reader("attribute_modifiers", Type.UNIT) // TODO
.reader("custom_model_data", Type.VAR_INT)
.reader("hide_additional_tooltip", Type.UNIT)
.reader("repair_cost", Type.VAR_INT)
.reader("creative_slot_lock", Type.UNIT)
.reader("enchantment_glint_override", Type.BOOLEAN)
.reader("intangible_projectile", Type.UNIT)
.reader("stored_enchantments", Enchantments.TYPE)
.reader("dyed_color", DyedColor.TYPE)
.reader("map_color", Type.INT)
.reader("map_id", Type.VAR_INT)
.reader("map_post_processing", Type.VAR_INT)
.reader("charged_projectiles", Types1_20_5.ITEM_ARRAY)
.reader("bundle_contents", Types1_20_5.ITEM_ARRAY)
.reader("potion_contents", Type.UNIT) // TODO
.reader("suspicious_stew_effects", Type.UNIT) // TODO
.reader("writable_book_content", Type.STRING_ARRAY)
.reader("written_book_content", WrittenBook.TYPE)
.reader("trim", Type.UNIT) // TODO
.reader("entity_data", Type.COMPOUND_TAG)
.reader("bucket_entity_data", Type.COMPOUND_TAG)
.reader("block_entity_data", Type.COMPOUND_TAG)
.reader("instrument", Type.VAR_INT) // TODO
.reader("lodestone_target", LodestoneTarget.TYPE)
.reader("firework_explosion", Type.UNIT) // TODO
.reader("fireworks", Type.UNIT) // TODO
.reader("profile", GameProfile.TYPE)
.reader("note_block_sound", Type.STRING)
.reader("banner_patterns", BannerPattern.ARRAY_TYPE)
.reader("base_color", Type.VAR_INT)
.reader("pot_decorations", Types1_20_5.ITEM_ARRAY)
.reader("container", Types1_20_5.ITEM_ARRAY)
.reader("block_state", BlockStateProperties.TYPE)
.reader("bees", Bee.ARRAY_TYPE);
.add(StructuredDataKey.CUSTOM_DATA)
.add(StructuredDataKey.DAMAGE)
.add(StructuredDataKey.UNBREAKABLE)
.add(StructuredDataKey.CUSTOM_NAME)
.add(StructuredDataKey.LORE)
.add(StructuredDataKey.ENCHANTMENTS)
.add(StructuredDataKey.CAN_PLACE_ON)
.add(StructuredDataKey.CAN_BREAK)
.add(StructuredDataKey.ATTRIBUTE_MODIFIERS)
.add(StructuredDataKey.CUSTOM_MODEL_DATA)
.add(StructuredDataKey.HIDE_ADDITIONAL_TOOLTIP)
.add(StructuredDataKey.REPAIR_COST)
.add(StructuredDataKey.CREATIVE_SLOT_LOCK)
.add(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE)
.add(StructuredDataKey.INTANGIBLE_PROJECTILE)
.add(StructuredDataKey.STORED_ENCHANTMENTS)
.add(StructuredDataKey.DYED_COLOR)
.add(StructuredDataKey.MAP_COLOR)
.add(StructuredDataKey.MAP_ID)
.add(StructuredDataKey.MAP_DECORATIONS)
.add(StructuredDataKey.MAP_POST_PROCESSING)
.add(StructuredDataKey.CHARGED_PROJECTILES)
.add(StructuredDataKey.BUNDLE_CONTENTS)
.add(StructuredDataKey.POTION_CONTENTS)
.add(StructuredDataKey.SUSPICIOUS_STEW_EFFECTS)
.add(StructuredDataKey.WRITABLE_BOOK_CONTENT)
.add(StructuredDataKey.WRITTEN_BOOK_CONTENT)
.add(StructuredDataKey.TRIM)
.add(StructuredDataKey.DEBUG_STICK_STATE)
.add(StructuredDataKey.ENTITY_DATA)
.add(StructuredDataKey.BUCKET_ENTITY_DATA)
.add(StructuredDataKey.BLOCK_ENTITY_DATA)
.add(StructuredDataKey.INSTRUMENT)
.add(StructuredDataKey.RECIPES)
.add(StructuredDataKey.LODESTONE_TARGET)
.add(StructuredDataKey.FIREWORK_EXPLOSION)
.add(StructuredDataKey.FIREWORKS)
.add(StructuredDataKey.PROFILE)
.add(StructuredDataKey.NOTE_BLOCK_SOUND)
.add(StructuredDataKey.BANNER_PATTERNS)
.add(StructuredDataKey.BASE_COLOR)
.add(StructuredDataKey.POT_DECORATIONS)
.add(StructuredDataKey.CONTAINER)
.add(StructuredDataKey.BLOCK_STATE)
.add(StructuredDataKey.BEES)
.add(StructuredDataKey.LOCK)
.add(StructuredDataKey.CONTAINER_LOOT);
tagRewriter.addTag(RegistryType.ITEM, "minecraft:dyeable", 853, 854, 855, 856, 1120);
}

View File

@ -0,0 +1,83 @@
/*
* 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 EnchantmentMappings {
public static final String[] ENCHANTMENTS = {
"protection",
"fire_protection",
"feather_falling",
"blast_protection",
"projectile_protection",
"respiration",
"aqua_affinity",
"thorns",
"depth_strider",
"frost_walker",
"binding_curse",
"soul_speed",
"swift_sneak",
"sharpness",
"smite",
"bane_of_arthropods",
"knockback",
"fire_aspect",
"looting",
"sweeping",
"efficiency",
"silk_touch",
"unbreaking",
"fortune",
"power",
"punch",
"flame",
"infinity",
"luck_of_the_sea",
"lure",
"loyalty",
"impaling",
"riptide",
"channeling",
"multishot",
"quick_charge",
"piercing",
"mending",
"vanishing_curse"
};
private static final Object2IntMap<String> STRING_TO_ID = new Object2IntOpenHashMap<>();
static {
for (int i = 0; i < ENCHANTMENTS.length; i++) {
STRING_TO_ID.put(ENCHANTMENTS[i], i);
}
}
public static @Nullable String enchantment(final int id) {
return id >= 0 && id < ENCHANTMENTS.length ? ENCHANTMENTS[id] : null;
}
public static int id(final String attribute) {
return STRING_TO_ID.getOrDefault(Key.stripMinecraftNamespace(attribute), -1);
}
}

View File

@ -18,14 +18,20 @@
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.ListTag;
import com.github.steveice10.opennbt.tag.builtin.NumberTag;
import com.viaversion.viaversion.api.Via;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.api.data.ParticleMappings;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.StructuredItem;
import com.viaversion.viaversion.api.minecraft.item.data.BlockStateProperties;
import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
import com.viaversion.viaversion.api.type.types.version.Types1_20_3;
@ -34,12 +40,16 @@ import com.viaversion.viaversion.protocols.protocol1_20_3to1_20_2.packet.Clientb
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_5to1_20_3.Protocol1_20_5To1_20_3;
import com.viaversion.viaversion.protocols.protocol1_20_5to1_20_3.data.EnchantmentMappings;
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.ServerboundPackets1_20_5;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.ItemRewriter;
import com.viaversion.viaversion.util.Key;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
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> {
@ -186,44 +196,128 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
return toOldItem(item);
}
public static Item toOldItem(final Item item) {
final CompoundTag tag = new CompoundTag();
public Item toOldItem(final Item item) {
final StructuredDataContainer data = item.structuredData();
final Optional<StructuredData<CompoundTag>> customData = data.get(protocol, StructuredDataKey.CUSTOM_DATA);
// Start out with custom data and add the rest on top
final CompoundTag tag = customData.map(StructuredData::value).orElse(new CompoundTag());
// TODO
return new DataItem(item.identifier(), (byte) item.amount(), (short) 0, tag);
}
public static Item toStructuredItem(final Item old) {
public Item toStructuredItem(final Item old) {
final CompoundTag tag = old.tag();
final StructuredItem item = new StructuredItem(old.identifier(), (byte) old.amount(), new Int2ObjectOpenHashMap<>());
final StructuredItem item = new StructuredItem(old.identifier(), (byte) old.amount(), new StructuredDataContainer());
final StructuredDataContainer data = item.structuredData();
if (tag == null) {
return item;
}
// Rewrite nbt to new data structures
final NumberTag damage = tag.getNumberTag("Damage");
if (damage != null) {
addData(item, "damage", Type.VAR_INT, damage.asInt());
if (damage != null && damage.asInt() != 0) {
tag.remove("Damage");
data.add(protocol, StructuredDataKey.DAMAGE, damage.asInt());
}
final NumberTag repairCost = tag.getNumberTag("RepairCost");
if (repairCost != null) {
addData(item, "repair_cost", Type.VAR_INT, repairCost.asInt());
if (repairCost != null && repairCost.asInt() != 0) {
tag.remove("RepairCost");
data.add(protocol, StructuredDataKey.REPAIR_COST, repairCost.asInt());
}
final NumberTag customModelData = tag.getNumberTag("CustomModelData");
if (customModelData != null) {
tag.remove("CustomModelData");
data.add(protocol, StructuredDataKey.CUSTOM_MODEL_DATA, customModelData.asInt());
}
final CompoundTag blockState = tag.getCompoundTag("BlockStateTag");
if (blockState != null) {
tag.remove("BlockStateTag");
final Map<String, String> properties = new HashMap<>();
for (final Map.Entry<String, Tag> entry : blockState.entrySet()) {
if (entry.getValue() instanceof StringTag) {
properties.put(entry.getKey(), ((StringTag) entry.getValue()).getValue());
}
}
data.add(protocol, StructuredDataKey.BLOCK_STATE, new BlockStateProperties(properties));
}
final CompoundTag entityTag = tag.getCompoundTag("EntityTag");
if (entityTag != null) {
tag.remove("EntityTag");
data.add(protocol, StructuredDataKey.ENTITY_DATA, entityTag);
}
final CompoundTag blockEntityTag = tag.getCompoundTag("BlockEntityTag");
if (blockEntityTag != null) {
// TODO lots of stuff
// item.structuredData().add(protocol, "block_entity_data", Type.COMPOUND_TAG, blockEntityTag);
}
final NumberTag hideFlags = tag.getNumberTag("HideFlags");
final int hideFlagsValue = hideFlags != null ? hideFlags.asInt() : 0;
tag.remove("HideFlags");
final NumberTag unbreakable = tag.getNumberTag("Unbreakable");
if (unbreakable != null && unbreakable.asBoolean()) {
tag.remove("Unbreakable");
if ((hideFlagsValue & 0x04) != 0) {
data.add(protocol, StructuredDataKey.UNBREAKABLE, true); // TODO Value is hide, should have a wrapper
} else {
data.addEmpty(protocol, StructuredDataKey.UNBREAKABLE);
}
}
updateEnchantments(data, tag, "Enchantments", StructuredDataKey.ENCHANTMENTS, (hideFlagsValue & 0x01) != 0);
updateEnchantments(data, tag, "StoredEnchantments", StructuredDataKey.STORED_ENCHANTMENTS, (hideFlagsValue & 0x20) != 0);
// TODO
// Add the rest as custom data
data.add(protocol, StructuredDataKey.CUSTOM_DATA, tag);
return item;
}
private static <T> void addData(final StructuredItem item, final String serializer, final Type<T> type, final T value) {
final int id = serializerId(serializer);
if (id == -1) {
Via.getPlatform().getLogger().severe("Could not find item data serializer for type " + type);
private void updateEnchantments(final StructuredDataContainer data, final CompoundTag tag, final String key,
final StructuredDataKey<Enchantments> newKey, final boolean hide) {
final ListTag enchantmentsTag = tag.getListTag(key);
if (enchantmentsTag == null) {
return;
}
item.addData(new StructuredData<>(type, value, id));
}
tag.remove(key);
private static int serializerId(final String type) {
return Protocol1_20_5To1_20_3.MAPPINGS.getDataComponentSerializerMappings().mappedId(type);
final Enchantments enchantments = new Enchantments(new Int2IntOpenHashMap(), !hide);
for (final Tag enchantment : enchantmentsTag) {
if (!(enchantment instanceof CompoundTag)) {
continue;
}
final CompoundTag compound = (CompoundTag) enchantment;
final StringTag id = compound.getStringTag("id");
final NumberTag lvl = compound.getNumberTag("lvl");
if (id == null || lvl == null) {
continue;
}
final int intId = EnchantmentMappings.id(id.getValue());
if (intId == -1) {
continue;
}
enchantments.enchantments().put(intId, lvl.asInt());
}
data.add(protocol, newKey, enchantments);
// Add glint if none of the enchantments were valid
if (enchantments.size() == 0 && !enchantmentsTag.isEmpty()) {
data.add(protocol, StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, true);
}
}
}

View File

@ -214,7 +214,7 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
filter().handler((event, meta) -> {
final MetaType type = meta.metaType();
if (type == itemType) {
protocol.getItemRewriter().handleItemToClient(meta.value());
meta.setValue(protocol.getItemRewriter().handleItemToClient(meta.value()));
} else if (type == blockStateType) {
int data = meta.value();
meta.setValue(protocol.getMappingData().getNewBlockStateId(data));

View File

@ -78,8 +78,8 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
handler(wrapper -> {
Item[] items = wrapper.read(itemArrayType);
wrapper.write(mappedItemArrayType, items);
for (Item item : items) {
handleItemToClient(item);
for (int i = 0; i < items.length; i++) {
items[i] = handleItemToClient(items[i]);
}
});
}
@ -95,8 +95,8 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
handler(wrapper -> {
Item[] items = wrapper.read(itemArrayType);
wrapper.write(mappedItemArrayType, items);
for (Item item : items) {
handleItemToClient(item);
for (int i = 0; i < items.length; i++) {
items[i] = handleItemToClient(items[i]);
}
handleClientboundItem(wrapper);
@ -519,15 +519,6 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
};
}
public PacketHandler itemArrayToClientHandler(Type<Item[]> type) {
return wrapper -> {
Item[] items = wrapper.get(type, 0);
for (Item item : items) {
handleItemToClient(item);
}
};
}
private void handleClientboundItem(final PacketWrapper wrapper) throws Exception {
final Item item = handleItemToClient(wrapper.read(itemType));
wrapper.write(mappedItemType, item);
@ -540,14 +531,13 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
protected void rewriteParticle(Particle particle) {
ParticleMappings mappings = protocol.getMappingData().getParticleMappings();
int id = particle.getId();
int id = particle.id();
if (mappings.isBlockParticle(id)) {
Particle.ParticleData<Integer> data = particle.getArgument(0);
data.setValue(protocol.getMappingData().getNewBlockStateId(data.getValue()));
} else if (mappings.isItemParticle(id)) {
Particle.ParticleData<Item> data = particle.getArgument(0);
Item item = data.getValue();
handleItemToClient(item);
data.setValue(handleItemToClient(data.getValue()));
}
particle.setId(protocol.getMappingData().getNewParticleId(id));

View File

@ -4,7 +4,7 @@ metadata.format.version = "1.1"
gson = "2.10.1"
fastutil = "8.5.12"
vianbt = "4.2.0"
vianbt = "4.3.0"
mcstructs = "2.4.2-SNAPSHOT"
# Common provided