ViaVersion/common/src/main/java/com/viaversion/viaversion/rewriter/ItemRewriter.java

465 lines
18 KiB
Java
Raw Normal View History

/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
2024-01-01 12:39:45 +01:00
* 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/>.
*/
2021-04-26 21:16:10 +02:00
package com.viaversion.viaversion.rewriter;
2019-10-04 13:01:33 +02:00
2022-03-24 18:44:53 +01:00
import com.viaversion.viaversion.api.data.Mappings;
import com.viaversion.viaversion.api.data.ParticleMappings;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
2021-04-26 21:16:10 +02:00
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.rewriter.RewriterBase;
import com.viaversion.viaversion.api.type.Type;
import org.checkerframework.checker.nullness.qual.Nullable;
2019-10-04 13:01:33 +02:00
2023-10-19 01:28:12 +02:00
public class ItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
T extends Protocol<C, ?, ?, S>> extends RewriterBase<T> implements com.viaversion.viaversion.api.rewriter.ItemRewriter<T> {
2023-08-03 13:58:23 +02:00
private final Type<Item> itemType;
private final Type<Item[]> itemArrayType;
2019-10-04 13:01:33 +02:00
2023-08-03 13:58:23 +02:00
public ItemRewriter(T protocol, Type<Item> itemType, Type<Item[]> itemArrayType) {
super(protocol);
2023-08-03 13:58:23 +02:00
this.itemType = itemType;
this.itemArrayType = itemArrayType;
}
// These two methods always return the same item instance *for now*
// It is made this way, so it's easy to handle new instance creation/implementation changes
@Override
public @Nullable Item handleItemToClient(@Nullable Item item) {
if (item == null) return null;
if (protocol.getMappingData() != null && protocol.getMappingData().getItemMappings() != null) {
item.setIdentifier(protocol.getMappingData().getNewItemId(item.identifier()));
}
return item;
}
@Override
public @Nullable Item handleItemToServer(@Nullable Item item) {
if (item == null) return null;
if (protocol.getMappingData() != null && protocol.getMappingData().getItemMappings() != null) {
item.setIdentifier(protocol.getMappingData().getOldItemId(item.identifier()));
}
return item;
2019-10-04 13:01:33 +02:00
}
public void registerWindowItems(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
2019-10-04 13:01:33 +02:00
@Override
public void register() {
2021-10-20 17:24:57 +02:00
map(Type.UNSIGNED_BYTE); // Window id
map(itemArrayType); // Items
handler(itemArrayToClientHandler(itemArrayType));
2019-10-04 13:01:33 +02:00
}
});
}
public void registerWindowItems1_17_1(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
2021-10-20 17:24:57 +02:00
@Override
public void register() {
2021-10-20 17:24:57 +02:00
map(Type.UNSIGNED_BYTE); // Window id
map(Type.VAR_INT); // State id
handler(wrapper -> {
2023-08-03 13:58:23 +02:00
Item[] items = wrapper.passthrough(itemArrayType);
2021-10-20 17:24:57 +02:00
for (Item item : items) {
handleItemToClient(item);
}
2023-08-03 13:58:23 +02:00
handleItemToClient(wrapper.passthrough(itemType)); // Carried item
2021-10-20 17:24:57 +02:00
});
}
});
}
2023-03-22 18:49:18 +01:00
public void registerOpenWindow(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Type.VAR_INT); // Container id
handler(wrapper -> {
final int windowType = wrapper.read(Type.VAR_INT);
final int mappedId = protocol.getMappingData().getMenuMappings().getNewId(windowType);
if (mappedId == -1) {
wrapper.cancel();
return;
}
wrapper.write(Type.VAR_INT, mappedId);
});
}
});
}
public void registerSetSlot(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
2019-10-04 13:01:33 +02:00
@Override
public void register() {
2021-10-20 17:24:57 +02:00
map(Type.UNSIGNED_BYTE); // Window id
map(Type.SHORT); // Slot id
map(itemType); // Item
handler(itemToClientHandler(itemType));
2021-10-20 17:24:57 +02:00
}
});
}
2019-10-04 13:01:33 +02:00
public void registerSetSlot1_17_1(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
2021-10-20 17:24:57 +02:00
@Override
public void register() {
2021-10-20 17:24:57 +02:00
map(Type.UNSIGNED_BYTE); // Window id
map(Type.VAR_INT); // State id
map(Type.SHORT); // Slot id
2023-08-03 13:58:23 +02:00
map(itemType); // Item
handler(itemToClientHandler(itemType));
2019-10-04 13:01:33 +02:00
}
});
}
2020-06-16 18:38:16 +02:00
// Sub 1.16
public void registerEntityEquipment(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
2019-10-04 13:01:33 +02:00
@Override
public void register() {
2019-10-04 13:01:33 +02:00
map(Type.VAR_INT); // 0 - Entity ID
map(Type.VAR_INT); // 1 - Slot ID
map(itemType); // 2 - Item
2019-10-04 13:01:33 +02:00
handler(itemToClientHandler(itemType));
2019-10-04 13:01:33 +02:00
}
});
}
2020-06-16 18:38:16 +02:00
// 1.16+
public void registerEntityEquipmentArray(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
2020-06-16 18:38:16 +02:00
@Override
public void register() {
2020-06-16 18:38:16 +02:00
map(Type.VAR_INT); // 0 - Entity ID
handler(wrapper -> {
byte slot;
do {
2020-06-16 21:04:29 +02:00
slot = wrapper.passthrough(Type.BYTE);
// & 0x7F into an extra variable if slot is needed
2023-08-03 13:58:23 +02:00
handleItemToClient(wrapper.passthrough(itemType));
2024-02-10 17:58:54 +01:00
} while (slot < 0);
2020-06-16 18:38:16 +02:00
});
}
});
}
2023-10-19 02:53:14 +02:00
public void registerCreativeInvAction(S packetType) {
protocol.registerServerbound(packetType, new PacketHandlers() {
2019-10-04 13:01:33 +02:00
@Override
public void register() {
2019-10-04 13:01:33 +02:00
map(Type.SHORT); // 0 - Slot
map(itemType); // 1 - Clicked Item
handler(itemToServerHandler(itemType));
2019-10-04 13:01:33 +02:00
}
});
}
public void registerClickWindow(S packetType) {
protocol.registerServerbound(packetType, new PacketHandlers() {
2019-10-04 13:01:33 +02:00
@Override
public void register() {
2019-10-04 13:01:33 +02:00
map(Type.UNSIGNED_BYTE); // 0 - Window ID
map(Type.SHORT); // 1 - Slot
map(Type.BYTE); // 2 - Button
map(Type.SHORT); // 3 - Action number
map(Type.VAR_INT); // 4 - Mode
map(itemType); // 5 - Clicked Item
2019-10-04 13:01:33 +02:00
handler(itemToServerHandler(itemType));
2019-10-04 13:01:33 +02:00
}
});
}
public void registerClickWindow1_17_1(S packetType) {
protocol.registerServerbound(packetType, new PacketHandlers() {
2021-10-20 17:24:57 +02:00
@Override
public void register() {
2021-10-20 17:24:57 +02:00
map(Type.UNSIGNED_BYTE); // Window Id
map(Type.VAR_INT); // State id
map(Type.SHORT); // Slot
map(Type.BYTE); // Button
map(Type.VAR_INT); // Mode
handler(wrapper -> {
// Affected items
int length = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < length; i++) {
wrapper.passthrough(Type.SHORT); // Slot
2023-08-03 13:58:23 +02:00
handleItemToServer(wrapper.passthrough(itemType));
2021-10-20 17:24:57 +02:00
}
// Carried item
2023-08-03 13:58:23 +02:00
handleItemToServer(wrapper.passthrough(itemType));
2021-10-20 17:24:57 +02:00
});
}
});
}
public void registerSetCooldown(C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
int itemId = wrapper.read(Type.VAR_INT);
wrapper.write(Type.VAR_INT, protocol.getMappingData().getNewItemId(itemId));
});
}
// 1.14.4+
public void registerTradeList(C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Type.VAR_INT);
int size = wrapper.passthrough(Type.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
2023-08-03 13:58:23 +02:00
handleItemToClient(wrapper.passthrough(itemType)); // Input
handleItemToClient(wrapper.passthrough(itemType)); // Output
if (wrapper.passthrough(Type.BOOLEAN)) { // Has second item
2023-08-03 13:58:23 +02:00
handleItemToClient(wrapper.passthrough(itemType)); // Second Item
}
wrapper.passthrough(Type.BOOLEAN); // Trade disabled
wrapper.passthrough(Type.INT); // Number of tools uses
wrapper.passthrough(Type.INT); // Maximum number of trade uses
wrapper.passthrough(Type.INT); // XP
wrapper.passthrough(Type.INT); // Special price
wrapper.passthrough(Type.FLOAT); // Price multiplier
wrapper.passthrough(Type.INT); // Demand
}
//...
});
}
public void registerTradeList1_19(C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Type.VAR_INT); // Container id
int size = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < size; i++) {
2023-08-03 13:58:23 +02:00
handleItemToClient(wrapper.passthrough(itemType)); // Input
handleItemToClient(wrapper.passthrough(itemType)); // Output
handleItemToClient(wrapper.passthrough(itemType)); // Second Item
wrapper.passthrough(Type.BOOLEAN); // Trade disabled
wrapper.passthrough(Type.INT); // Number of tools uses
wrapper.passthrough(Type.INT); // Maximum number of trade uses
wrapper.passthrough(Type.INT); // XP
wrapper.passthrough(Type.INT); // Special price
wrapper.passthrough(Type.FLOAT); // Price multiplier
wrapper.passthrough(Type.INT); // Demand
2022-06-08 10:07:47 +02:00
}
});
}
public void registerAdvancements(C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Type.BOOLEAN); // Reset/clear
int size = wrapper.passthrough(Type.VAR_INT); // Mapping size
for (int i = 0; i < size; i++) {
wrapper.passthrough(Type.STRING); // Identifier
// Parent
if (wrapper.passthrough(Type.BOOLEAN))
wrapper.passthrough(Type.STRING);
// Display data
if (wrapper.passthrough(Type.BOOLEAN)) {
wrapper.passthrough(Type.COMPONENT); // Title
wrapper.passthrough(Type.COMPONENT); // Description
handleItemToClient(wrapper.passthrough(itemType)); // Icon
wrapper.passthrough(Type.VAR_INT); // Frame type
int flags = wrapper.passthrough(Type.INT); // Flags
if ((flags & 1) != 0) {
wrapper.passthrough(Type.STRING); // Background texture
}
wrapper.passthrough(Type.FLOAT); // X
wrapper.passthrough(Type.FLOAT); // Y
}
wrapper.passthrough(Type.STRING_ARRAY); // Criteria
int arrayLength = wrapper.passthrough(Type.VAR_INT);
for (int array = 0; array < arrayLength; array++) {
wrapper.passthrough(Type.STRING_ARRAY); // String array
}
}
});
}
2023-08-31 03:44:55 +02:00
public void registerAdvancements1_20_2(C packetType) {
registerAdvancements1_20_2(packetType, Type.COMPONENT);
}
public void registerAdvancements1_20_3(C packetType) {
registerAdvancements1_20_2(packetType, Type.TAG);
}
private void registerAdvancements1_20_2(C packetType, Type<?> componentType) {
2023-08-03 05:58:22 +02:00
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Type.BOOLEAN); // Reset/clear
int size = wrapper.passthrough(Type.VAR_INT); // Mapping size
for (int i = 0; i < size; i++) {
wrapper.passthrough(Type.STRING); // Identifier
// Parent
if (wrapper.passthrough(Type.BOOLEAN)) {
2023-08-03 05:58:22 +02:00
wrapper.passthrough(Type.STRING);
}
2023-08-03 05:58:22 +02:00
// Display data
if (wrapper.passthrough(Type.BOOLEAN)) {
wrapper.passthrough(componentType); // Title
wrapper.passthrough(componentType); // Description
2023-08-03 13:58:23 +02:00
handleItemToClient(wrapper.passthrough(itemType)); // Icon
2023-08-03 05:58:22 +02:00
wrapper.passthrough(Type.VAR_INT); // Frame type
int flags = wrapper.passthrough(Type.INT); // Flags
if ((flags & 1) != 0) {
wrapper.passthrough(Type.STRING); // Background texture
}
wrapper.passthrough(Type.FLOAT); // X
wrapper.passthrough(Type.FLOAT); // Y
}
2023-08-31 03:44:55 +02:00
int requirements = wrapper.passthrough(Type.VAR_INT);
for (int array = 0; array < requirements; array++) {
wrapper.passthrough(Type.STRING_ARRAY);
2023-08-03 05:58:22 +02:00
}
wrapper.passthrough(Type.BOOLEAN); // Send telemetry
}
});
}
public void registerWindowPropertyEnchantmentHandler(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
2022-03-24 18:44:53 +01:00
@Override
public void register() {
2022-03-24 18:44:53 +01:00
map(Type.UNSIGNED_BYTE); // Container id
handler(wrapper -> {
Mappings mappings = protocol.getMappingData().getEnchantmentMappings();
if (mappings == null) {
return;
}
2022-03-24 18:44:53 +01:00
short property = wrapper.passthrough(Type.SHORT);
if (property >= 4 && property <= 6) { // Enchantment id
short enchantmentId = (short) mappings.getNewId(wrapper.read(Type.SHORT));
wrapper.write(Type.SHORT, enchantmentId);
}
});
}
});
}
2020-09-21 09:53:04 +02:00
// Not the very best place for this, but has to stay here until *everything* is abstracted
public void registerSpawnParticle(C packetType, Type<?> coordType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
2020-09-21 09:53:04 +02:00
@Override
public void register() {
2020-09-21 09:53:04 +02:00
map(Type.INT); // 0 - Particle ID
map(Type.BOOLEAN); // 1 - Long Distance
map(coordType); // 2 - X
map(coordType); // 3 - Y
map(coordType); // 4 - Z
map(Type.FLOAT); // 5 - Offset X
map(Type.FLOAT); // 6 - Offset Y
map(Type.FLOAT); // 7 - Offset Z
map(Type.FLOAT); // 8 - Particle Data
map(Type.INT); // 9 - Particle Count
2023-08-04 04:35:35 +02:00
handler(getSpawnParticleHandler());
2020-09-21 09:53:04 +02:00
}
});
}
public void registerSpawnParticle1_19(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
2022-03-16 19:09:39 +01:00
@Override
public void register() {
2022-03-16 19:09:39 +01:00
map(Type.VAR_INT); // 0 - Particle ID
map(Type.BOOLEAN); // 1 - Long Distance
2022-10-16 10:13:05 +02:00
map(Type.DOUBLE); // 2 - X
map(Type.DOUBLE); // 3 - Y
map(Type.DOUBLE); // 4 - Z
2022-03-16 19:09:39 +01:00
map(Type.FLOAT); // 5 - Offset X
map(Type.FLOAT); // 6 - Offset Y
map(Type.FLOAT); // 7 - Offset Z
map(Type.FLOAT); // 8 - Particle Data
map(Type.INT); // 9 - Particle Count
2023-08-04 04:35:35 +02:00
handler(getSpawnParticleHandler(Type.VAR_INT));
2022-03-16 19:09:39 +01:00
}
});
}
2023-08-04 04:35:35 +02:00
public PacketHandler getSpawnParticleHandler() {
return getSpawnParticleHandler(Type.INT);
2022-03-19 15:56:22 +01:00
}
2023-08-04 04:35:35 +02:00
public PacketHandler getSpawnParticleHandler(Type<Integer> idType) {
return wrapper -> {
2022-03-19 15:56:22 +01:00
int id = wrapper.get(idType, 0);
2023-06-06 13:28:02 +02:00
if (id == -1) {
return;
}
ParticleMappings mappings = protocol.getMappingData().getParticleMappings();
if (mappings.isBlockParticle(id)) {
2022-03-19 15:56:22 +01:00
int data = wrapper.read(Type.VAR_INT);
wrapper.write(Type.VAR_INT, protocol.getMappingData().getNewBlockStateId(data));
} else if (mappings.isItemParticle(id)) {
handleItemToClient(wrapper.passthrough(itemType));
}
2023-06-06 13:28:02 +02:00
int mappedId = protocol.getMappingData().getNewParticleId(id);
if (mappedId != id) {
wrapper.set(idType, 0, mappedId);
}
};
}
2023-08-04 04:35:35 +02:00
public PacketHandler itemArrayToClientHandler(Type<Item[]> type) {
2019-10-04 13:01:33 +02:00
return wrapper -> {
Item[] items = wrapper.get(type, 0);
for (Item item : items) {
handleItemToClient(item);
2019-10-04 13:01:33 +02:00
}
};
}
public PacketHandler itemToClientHandler(Type<Item> type) {
return wrapper -> handleItemToClient(wrapper.get(type, 0));
2019-10-04 13:01:33 +02:00
}
public PacketHandler itemToServerHandler(Type<Item> type) {
return wrapper -> handleItemToServer(wrapper.get(type, 0));
2019-10-04 13:01:33 +02:00
}
public Type<Item> getItemType() {
return itemType;
}
public Type<Item[]> getItemArrayType() {
return itemArrayType;
}
2019-10-04 13:01:33 +02:00
}