Compare commits

...
Author SHA1 Message Date
Nassim Jahnke eb74cbde1b Add entity equipment read type 2025-12-14 10:06:37 +01:00
9 changed files with 177 additions and 45 deletions

No files matched your search

@@ -0,0 +1,37 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 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;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.util.Rewritable;
public record EntityEquipment(int slot, Item item) implements Rewritable {
@Override
public EntityEquipment rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final Item item = clientbound ? protocol.getItemRewriter().handleItemToClient(connection, this.item) : protocol.getItemRewriter().handleItemToServer(connection, this.item);
return new EntityEquipment(this.slot, item);
}
}
@@ -27,6 +27,7 @@ import com.viaversion.viaversion.api.minecraft.item.HashedItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.misc.EntityEquipmentType;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface ItemRewriter<T extends Protocol<?, ?, ?, ?>> extends Rewriter<T> {
@@ -120,4 +121,12 @@ public interface ItemRewriter<T extends Protocol<?, ?, ?, ?>> extends Rewriter<T
default String nbtTagName(final String nbt) {
return nbtTagName() + "|" + nbt;
}
default EntityEquipmentType equipmentType() {
return null;
}
default EntityEquipmentType mappedEquipmentType() {
return null;
}
}
@@ -0,0 +1,68 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 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.type.types.misc;
import com.viaversion.viaversion.api.minecraft.EntityEquipment;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
import java.util.List;
public final class EntityEquipmentType extends Type<List<EntityEquipment>> {
private final Type<Item> itemType;
public EntityEquipmentType(final Type<Item> itemType) {
super(List.class);
this.itemType = itemType;
}
@Override
public List<EntityEquipment> read(final ByteBuf buffer) {
final List<EntityEquipment> list = new ArrayList<>();
byte rawSlot;
do {
rawSlot = Types.BYTE.readPrimitive(buffer);
final Item item = itemType.read(buffer);
list.add(new EntityEquipment((byte) (rawSlot & 0x7F), item));
} while (rawSlot < 0);
return list;
}
@Override
public void write(final ByteBuf buffer, final List<EntityEquipment> value) {
for (int i = 0; i < value.size(); i++) {
final EntityEquipment equipment = value.get(i);
final boolean more = i < value.size() - 1;
Types.BYTE.writePrimitive(buffer, more ? (byte) (equipment.slot() | -128) : (byte) equipment.slot());
itemType.write(buffer, equipment.item());
}
}
@Override
public Class<? extends Type<?>> getBaseClass() {
return EntityEquipmentType.class;
}
}
@@ -23,6 +23,7 @@ import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.NumberTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.EntityEquipment;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
@@ -38,6 +39,8 @@ import com.viaversion.viaversion.rewriter.ItemRewriter;
import com.viaversion.viaversion.rewriter.RecipeRewriter;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.UUIDUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class ItemPacketRewriter1_16 extends ItemRewriter<ClientboundPackets1_15, ServerboundPackets1_16, Protocol1_15_2To1_16> {
@@ -119,8 +122,11 @@ public class ItemPacketRewriter1_16 extends ItemRewriter<ClientboundPackets1_15,
handler(wrapper -> {
int slot = wrapper.read(Types.VAR_INT);
wrapper.write(Types.BYTE, (byte) slot);
handleItemToClient(wrapper.user(), wrapper.passthrough(Types.ITEM1_13_2));
Item item = handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_13_2));
List<EntityEquipment> list = new ArrayList<>(1);
list.add(new EntityEquipment((byte) slot, item));
wrapper.write(mappedEquipmentType(), list);
});
}
});
@@ -28,6 +28,7 @@ import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.ParticleMappings;
import com.viaversion.viaversion.api.minecraft.EntityEquipment;
import com.viaversion.viaversion.api.minecraft.GameProfile;
import com.viaversion.viaversion.api.minecraft.GlobalBlockPosition;
import com.viaversion.viaversion.api.minecraft.Holder;
@@ -39,6 +40,8 @@ import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
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.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.StructuredItem;
@@ -173,6 +176,22 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
wrapper.write(Types.COMPOUND_TAG, tag);
});
protocol.registerClientbound(ClientboundPackets1_20_3.SET_EQUIPMENT, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT); // Entity id
final EntityType type = protocol.getEntityRewriter().tracker(wrapper.user()).entityType(entityId);
final List<EntityEquipment> equipmentArray = wrapper.read(equipmentType());
equipmentArray.replaceAll(equipment -> {
int slot = equipment.slot();
Item item = handleItemToClient(wrapper.user(), equipment.item());
if (type != null && type.isOrHasParent(EntityTypes1_20_5.ABSTRACT_HORSE) && equipment.slot() == 4) {
slot = 6;
}
return new EntityEquipment(slot, item);
});
wrapper.write(mappedEquipmentType(), equipmentArray);
});
registerCooldown(ClientboundPackets1_20_3.COOLDOWN);
registerSetContent1_17_1(ClientboundPackets1_20_3.CONTAINER_SET_CONTENT);
registerSetSlot1_17_1(ClientboundPackets1_20_3.CONTAINER_SET_SLOT);
@@ -24,6 +24,7 @@ import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.DimensionData;
import com.viaversion.viaversion.api.minecraft.EntityEquipment;
import com.viaversion.viaversion.api.minecraft.GameMode;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
@@ -55,7 +56,9 @@ import com.viaversion.viaversion.util.KeyMappings;
import com.viaversion.viaversion.util.TagUtil;
import it.unimi.dsi.fastutil.ints.IntArraySet;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -77,25 +80,6 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
registerSetEntityData(ClientboundPackets1_20_3.SET_ENTITY_DATA, Types1_20_3.ENTITY_DATA_LIST, VersionedTypes.V1_20_5.entityDataList);
registerRemoveEntities(ClientboundPackets1_20_3.REMOVE_ENTITIES);
protocol.registerClientbound(ClientboundPackets1_20_3.SET_EQUIPMENT, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT); // Entity id
final EntityType type = tracker(wrapper.user()).entityType(entityId);
byte slot;
do {
slot = wrapper.read(Types.BYTE);
final int rawSlot = slot & 0x7F;
if (type != null && type.isOrHasParent(EntityTypes1_20_5.ABSTRACT_HORSE) && rawSlot == 4) {
final boolean lastSlot = (slot & 0xFFFFFF80) == 0;
slot = (byte) (lastSlot ? 6 : 6 | 0xFFFFFF80); // Map chest slot index to body slot index for horses
}
wrapper.write(Types.BYTE, slot);
Item item = protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_20_2));
wrapper.write(VersionedTypes.V1_20_5.item, item);
} while ((slot & 0xFFFFFF80) != 0);
});
protocol.registerClientbound(ClientboundConfigurationPackets1_20_3.REGISTRY_DATA, wrapper -> {
final PacketWrapper knownPacksPacket = wrapper.create(ClientboundConfigurationPackets1_20_5.SELECT_KNOWN_PACKS);
knownPacksPacket.write(Types.VAR_INT, 0); // No known packs, everything is sent here
@@ -483,8 +467,10 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
// Convert dyed color id to carpet item id
final PacketWrapper setEquipment = PacketWrapper.create(ClientboundPackets1_20_5.SET_EQUIPMENT, event.user());
setEquipment.write(Types.VAR_INT, event.entityId());
setEquipment.write(Types.BYTE, (byte) 6);
setEquipment.write(VersionedTypes.V1_20_5.item, new StructuredItem(color + 446, 1, new StructuredDataContainer()));
final List<EntityEquipment> equipmentList = new ArrayList<>(1);
equipmentList.add(new EntityEquipment(6, new StructuredItem(color + 446, 1, new StructuredDataContainer())));
setEquipment.write(protocol.getItemRewriter().mappedEquipmentType(), equipmentList);
setEquipment.scheduleSend(Protocol1_20_3To1_20_5.class);
} else if (dataIndex > 20) {
event.setIndex(dataIndex - 1);
@@ -31,7 +31,6 @@ import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_18;
@@ -150,19 +149,7 @@ public final class BlockItemPacketRewriter1_20_2 extends ItemRewriter<Clientboun
wrapper.passthrough(Types.BOOLEAN); // Send telemetry
}
});
protocol.registerClientbound(ClientboundPackets1_19_4.SET_EQUIPMENT, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
handler(wrapper -> {
byte slot;
do {
slot = wrapper.passthrough(Types.BYTE);
wrapper.write(Types.ITEM1_20_2, handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_13_2)));
} while ((slot & 0xFFFFFF80) != 0);
});
}
});
registerSetEquipment(ClientboundPackets1_19_4.SET_EQUIPMENT);
new RecipeRewriter1_19_4<>(protocol) {
@Override
@@ -19,6 +19,7 @@ package com.viaversion.viaversion.protocols.v1_21_4to1_21_5.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.EntityEquipment;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.minecraft.WolfVariant;
@@ -36,6 +37,8 @@ import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacke
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandlerEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
@@ -274,8 +277,9 @@ public final class EntityPacketRewriter1_21_5 extends EntityRewriter<Clientbound
private void sendSaddleEquipment(final EntityDataHandlerEvent event, final boolean saddled) {
final PacketWrapper equipmentPacket = PacketWrapper.create(ClientboundPackets1_21_5.SET_EQUIPMENT, event.user());
equipmentPacket.write(Types.VAR_INT, event.entityId());
equipmentPacket.write(Types.BYTE, SADDLE_EQUIPMENT_SLOT);
equipmentPacket.write(VersionedTypes.V1_21_5.item, saddled ? new StructuredItem(SADDLE_ITEM_ID, 1) : StructuredItem.empty());
final List<EntityEquipment> equipmentList = new ArrayList<>(1);
equipmentList.add(new EntityEquipment(SADDLE_EQUIPMENT_SLOT, saddled ? new StructuredItem(SADDLE_ITEM_ID, 1) : StructuredItem.empty()));
equipmentPacket.write(protocol.getItemRewriter().mappedEquipmentType(), equipmentList);
equipmentPacket.send(Protocol1_21_4To1_21_5.class);
}
@@ -24,6 +24,7 @@ import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.data.Mappings;
import com.viaversion.viaversion.api.data.item.ItemHasher;
import com.viaversion.viaversion.api.minecraft.EntityEquipment;
import com.viaversion.viaversion.api.minecraft.item.HashedItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.Protocol;
@@ -35,12 +36,14 @@ import com.viaversion.viaversion.api.rewriter.ComponentRewriter;
import com.viaversion.viaversion.api.rewriter.RewriterBase;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.EntityEquipmentType;
import com.viaversion.viaversion.api.type.types.version.VersionedTypesHolder;
import com.viaversion.viaversion.data.item.ItemHasherBase;
import com.viaversion.viaversion.util.Limit;
import com.viaversion.viaversion.util.Rewritable;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
public class ItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
@@ -53,6 +56,8 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
private final Type<Item> mappedItemCostType;
private final Type<Item> optionalItemCostType;
private final Type<Item> mappedOptionalItemCostType;
private final EntityEquipmentType equipmentType;
private final EntityEquipmentType mappedEquipmentType;
public ItemRewriter(T protocol) {
super(protocol);
@@ -66,6 +71,8 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
this.mappedItemCostType = mappedTypes.itemCost();
this.optionalItemCostType = types.optionalItemCost();
this.mappedOptionalItemCostType = mappedTypes.optionalItemCost();
this.equipmentType = new EntityEquipmentType(itemType);
this.mappedEquipmentType = new EntityEquipmentType(mappedItemType);
}
public ItemRewriter(T protocol, Type<Item> itemType, Type<Item[]> itemArrayType, Type<Item> mappedItemType, Type<Item[]> mappedItemArrayType) {
@@ -78,6 +85,8 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
this.mappedItemCostType = null;
this.optionalItemCostType = null;
this.mappedOptionalItemCostType = null;
this.equipmentType = new EntityEquipmentType(itemType);
this.mappedEquipmentType = new EntityEquipmentType(mappedItemType);
}
public ItemRewriter(T protocol, Type<Item> itemType, Type<Item[]> itemArrayType) {
@@ -219,12 +228,9 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Entity ID
byte slot;
do {
slot = wrapper.passthrough(Types.BYTE);
// & 0x7F into an extra variable if slot is needed
passthroughClientboundItem(wrapper);
} while (slot < 0);
final List<EntityEquipment> equipmentArray = wrapper.read(equipmentType);
equipmentArray.replaceAll(equipment -> equipment.rewrite(wrapper.user(), protocol, true));
wrapper.write(mappedEquipmentType, equipmentArray);
});
}
@@ -616,4 +622,14 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
public Type<Item[]> mappedItemArrayType() {
return mappedItemArrayType;
}
@Override
public EntityEquipmentType equipmentType() {
return equipmentType;
}
@Override
public EntityEquipmentType mappedEquipmentType() {
return mappedEquipmentType;
}
}