protocol, final String version) {
super(protocol);
this.translatables = TranslatableMappings.translatablesFor(version);
}
@Override
protected void handleTranslate(final JsonObject root, final String translate) {
final String newTranslate = mappedTranslationKey(translate);
if (newTranslate != null) {
root.addProperty("translate", newTranslate);
}
}
@Override
protected void handleTranslate(final UserConnection connection, final CompoundTag parentTag, final StringTag translateTag) {
final String newTranslate = mappedTranslationKey(translateTag.getValue());
if (newTranslate != null) {
parentTag.put("translate", new StringTag(newTranslate));
}
}
@Override
public @Nullable String mappedTranslationKey(final String translationKey) {
return translatables.get(translationKey);
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/api/rewriters/text/TranslatableRewriter.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.api.rewriters.text;
import com.viaversion.viaversion.api.rewriter.ComponentRewriter;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface TranslatableRewriter extends ComponentRewriter {
@Nullable
String mappedTranslationKey(String translationKey);
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/item/DataItemWithExtras.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.item;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonParser;
import com.viaversion.viaversion.libs.gson.JsonPrimitive;
import com.viaversion.viaversion.libs.gson.JsonSyntaxException;
import java.util.ArrayList;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Prevent expensive parsing/toString by checking against cached JsonElement instances, used from 1.14 to 1.20.5.
*
* When using this, be careful not to break caching by modifying the display tag directly.
*/
public final class DataItemWithExtras extends DataItem {
private JsonElement name;
private List lore;
public DataItemWithExtras(final Item from) {
setIdentifier(from.identifier());
setAmount(from.amount());
setData(from.data());
setTag(from.tag());
if (tag() == null) {
return;
}
final CompoundTag display = tag().getCompoundTag("display");
if (display == null) {
return;
}
final StringTag name = display.getStringTag("Name");
if (name != null) {
this.name = parse(name.getValue());
}
final ListTag lore = display.getListTag("Lore", StringTag.class);
if (lore != null) {
this.lore = new ArrayList<>(lore.size());
for (int i = 0; i < lore.size(); i++) {
this.lore.add(parse(lore.get(i).getValue()));
}
}
}
public @Nullable JsonElement name() {
return name;
}
public @Nullable StringTag rawName() {
if (tag() == null) {
return null;
}
final CompoundTag display = tag().getCompoundTag("display");
return display != null ? display.getStringTag("Name") : null;
}
public @Nullable List lore() {
return lore;
}
public @Nullable ListTag rawLore() {
if (tag() == null) {
return null;
}
final CompoundTag display = tag().getCompoundTag("display");
return display != null ? display.getListTag("Lore", StringTag.class) : null;
}
private JsonElement parse(final String value) {
try {
return JsonParser.parseString(value);
} catch (final JsonSyntaxException e) {
return new JsonPrimitive(value);
}
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/registration/BackwardsRegistrations.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.registration;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.protocol.shared_registration.SharedRegistrations;
public final class BackwardsRegistrations {
private static final SharedRegistrations REGISTRATIONS = SharedRegistrations.create();
public static void apply() {
REGISTRATIONS.registrations()
.range(ProtocolVersion.v1_10, ProtocolVersion.v1_19_3, RegistryRegistrations::registerNamedSound1_10)
.since(ProtocolVersion.v1_14, RegistryRegistrations::registerStopSound1_14)
.register();
}
public static SharedRegistrations registrations() {
return REGISTRATIONS;
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/registration/RegistryRegistrations.java
================================================
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.registration;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.protocol.shared_registration.PacketBound;
import com.viaversion.viaversion.protocol.shared_registration.RegistrationContext;
import com.viaversion.viaversion.protocols.v1_13_2to1_14.packet.ClientboundPackets1_14;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
final class RegistryRegistrations {
static void registerNamedSound1_10(final RegistrationContext ctx) {
ctx.clientbound(ClientboundPackets1_9_3.CUSTOM_SOUND, new SoundRewriter<>(ctx.protocol())::registerNamedSound, PacketBound.REMOVED_AT_MAX);
}
static void registerStopSound1_14(final RegistrationContext ctx) {
ctx.clientbound(ClientboundPackets1_14.STOP_SOUND, new SoundRewriter<>(ctx.protocol())::registerStopSound);
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/template/BlockItemPacketRewriter99_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.template;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.rewriters.BackwardsStructuredItemRewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.protocols.v1_21_11to26_1.packet.ClientboundPacket26_1;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundPacket1_21_9;
// To replace if needed:
// ChunkType1_21_5
// RecipeDisplayRewriter
final class BlockItemPacketRewriter99_1 extends BackwardsStructuredItemRewriter {
public BlockItemPacketRewriter99_1(final Protocol99_1To98_1 protocol) {
super(protocol);
}
@Override
public void registerPackets() {
}
@Override
protected void handleItemDataComponentsToClient(final UserConnection connection, final Item item, final StructuredDataContainer container) {
super.handleItemDataComponentsToClient(connection, item, container);
// downgradeData(item, container); // static import VV method
}
@Override
protected void handleItemDataComponentsToServer(final UserConnection connection, final Item item, final StructuredDataContainer container) {
super.handleItemDataComponentsToServer(connection, item, container);
// upgradeData(item, container); // static import VV method
}
@Override
protected void restoreBackupData(final Item item, final StructuredDataContainer container, final CompoundTag customData) {
super.restoreBackupData(item, container, customData);
// restore any data if needed here
}
@Override
protected void backupInconvertibleData(final UserConnection connection, final Item item, final StructuredDataContainer dataContainer, final CompoundTag backupTag) {
super.backupInconvertibleData(connection, item, dataContainer, backupTag);
// back up any data if needed here, called before the method below
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/template/ComponentRewriter99_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.template;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.rewriters.text.NBTComponentRewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocols.v1_21_11to26_1.packet.ClientboundPacket26_1;
final class ComponentRewriter99_1 extends NBTComponentRewriter {
public ComponentRewriter99_1(final BackwardsProtocol protocol) {
super(protocol);
}
@Override
protected void handleShowItem(final UserConnection connection, final CompoundTag itemTag, final CompoundTag componentsTag) {
super.handleShowItem(connection, itemTag, componentsTag);
if (componentsTag == null) {
return;
}
// Remove or update data from componentsTag
// Newly added data which is not handled otherwise needs to be removed to prevent errors on the client
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/template/EntityPacketRewriter99_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.template;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_11;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes26_1;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.protocols.v1_21_11to26_1.packet.ClientboundPacket26_1;
// Replace if needed
// VersionedTypes
final class EntityPacketRewriter99_1 extends EntityRewriter {
private static final EntityDataTypes26_1 MAPPED_DATA_TYPES = VersionedTypes.V26_1.entityDataTypes;
public EntityPacketRewriter99_1(final Protocol99_1To98_1 protocol) {
super(protocol, MAPPED_DATA_TYPES.optionalComponentType, MAPPED_DATA_TYPES.booleanType);
}
@Override
public void registerPackets() {
}
@Override
protected void registerRewrites() {
dataTypeMapper().register();
/* ... or like this for additions and removals that are not at the very end
dataTypeMapper()
.added(MAPPED_DATA_TYPES.catSoundVariant)
.removed(MAPPED_DATA_TYPES.cowSoundVariant)
.skip(MAPPED_DATA_TYPES.pigSoundVariant) // if neither removed nor added, but the value type has to be changed separately
.register();*/
registerEntityDataTypeHandler1_20_3(
MAPPED_DATA_TYPES.itemType,
MAPPED_DATA_TYPES.blockStateType,
MAPPED_DATA_TYPES.optionalBlockStateType,
MAPPED_DATA_TYPES.particleType,
MAPPED_DATA_TYPES.particlesType,
MAPPED_DATA_TYPES.componentType,
MAPPED_DATA_TYPES.optionalComponentType
);
// Remove entity data of new entity type
// filter().type(EntityTypes1_21_11.SNIFFER).removeIndex(newIndex);
}
@Override
public void onMappingDataLoaded() {
super.onMappingDataLoaded();
// mapEntityTypeWithData(EntityTypes1_21_11.SNIFFER, EntityTypes1_21_11.RAVAGER).tagName();
}
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_21_11.getTypeFromId(type);
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/template/Protocol99_1To98_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.template;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.BackwardsRegistryRewriter;
import com.viaversion.viabackwards.api.rewriters.text.NBTComponentRewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_11;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType26_1;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.api.type.types.version.VersionedTypesHolder;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.data.item.ItemHasherBase;
import com.viaversion.viaversion.protocols.v1_21_11to26_1.Protocol1_21_11To26_1;
import com.viaversion.viaversion.protocols.v1_21_11to26_1.packet.ClientboundPacket26_1;
import com.viaversion.viaversion.protocols.v1_21_11to26_1.packet.ClientboundPackets26_1;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.rewriter.RecipeDisplayRewriter1_21_5;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ClientboundConfigurationPackets1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundConfigurationPackets1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundPacket1_21_9;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.block.BlockRewriter1_21_5;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
// Placeholders to replace (in the entire package):
// Protocol1_21_11To26_1 (the ViaVersion protocol class the mappings depend on)
// ClientboundPacket26_1
// ServerboundPacket1_21_9
// ClientboundConfigurationPackets1_21
// ServerboundConfigurationPackets1_20_5
// EntityTypes1_21_11 (UNMAPPED type)
// VersionedTypes.V26_1
// 99.1, 98.1
final class Protocol99_1To98_1 extends BackwardsProtocol {
// ViaBackwards uses its own mappings and also needs a translatablerewriter for translation mappings
public static final BackwardsMappingData MAPPINGS = new BackwardsMappingData("99.1", "98.1", Protocol1_21_11To26_1.class); // Change the VV (!) protocol class
private final EntityPacketRewriter99_1 entityRewriter = new EntityPacketRewriter99_1(this);
private final BlockItemPacketRewriter99_1 itemRewriter = new BlockItemPacketRewriter99_1(this);
private final ParticleRewriter particleRewriter = new ParticleRewriter<>(this);
private final NBTComponentRewriter translatableRewriter = new ComponentRewriter99_1(this);
private final TagRewriter tagRewriter = new TagRewriter<>(this);
private final BackwardsRegistryRewriter registryDataRewriter = new BackwardsRegistryRewriter(this);
private final BlockRewriter blockRewriter = new BlockRewriter1_21_5<>(this, ChunkType26_1::new);
private final RecipeDisplayRewriter recipeRewriter = new RecipeDisplayRewriter1_21_5<>(this);
public Protocol99_1To98_1() {
super(ClientboundPacket26_1.class, ClientboundPacket26_1.class, ServerboundPacket1_21_9.class, ServerboundPacket1_21_9.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
}
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_11.PLAYER));
addItemHasher(connection, new ItemHasherBase(this, connection));
}
@Override
public BackwardsMappingData getMappingData() {
return MAPPINGS;
}
@Override
public EntityPacketRewriter99_1 getEntityRewriter() {
return entityRewriter;
}
@Override
public BlockItemPacketRewriter99_1 getItemRewriter() {
return itemRewriter;
}
@Override
public BlockRewriter getBlockRewriter() {
return blockRewriter;
}
@Override
public RecipeDisplayRewriter getRecipeRewriter() {
return recipeRewriter;
}
@Override
public BackwardsRegistryRewriter getRegistryDataRewriter() {
return registryDataRewriter;
}
@Override
public ParticleRewriter getParticleRewriter() {
return particleRewriter;
}
@Override
public NBTComponentRewriter getComponentRewriter() {
return translatableRewriter;
}
@Override
public TagRewriter getTagRewriter() {
return tagRewriter;
}
@Override
public VersionedTypesHolder types() {
return VersionedTypes.V26_1;
}
@Override
public VersionedTypesHolder mappedTypes() {
return VersionedTypes.V26_1;
}
@Override
protected PacketTypesProvider createPacketTypesProvider() {
return new SimplePacketTypesProvider<>(
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets26_1.class, ClientboundConfigurationPackets1_21_9.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets26_1.class, ClientboundConfigurationPackets1_21_9.class),
packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_21_6.class, ServerboundConfigurationPackets1_21_9.class),
packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_21_6.class, ServerboundConfigurationPackets1_21_9.class)
);
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_10to1_9_3/Protocol1_10To1_9_3.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_10to1_9_3;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.SoundRewriter;
import com.viaversion.viabackwards.api.rewriters.text.JsonNBTComponentRewriter;
import com.viaversion.viabackwards.protocol.v1_10to1_9_3.rewriter.BlockItemPacketRewriter1_10;
import com.viaversion.viabackwards.protocol.v1_10to1_9_3.rewriter.EntityPacketRewriter1_10;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
public class Protocol1_10To1_9_3 extends BackwardsProtocol {
public static final BackwardsMappingData MAPPINGS = new BackwardsMappingData("1.10", "1.9.4");
private static final ValueTransformer TO_OLD_PITCH = new ValueTransformer<>(Types.UNSIGNED_BYTE) {
public Short transform(PacketWrapper packetWrapper, Float inputValue) {
return (short) Math.round(inputValue * 63.5F);
}
};
private final EntityPacketRewriter1_10 entityRewriter = new EntityPacketRewriter1_10(this);
private final BlockItemPacketRewriter1_10 itemRewriter = new BlockItemPacketRewriter1_10(this);
public Protocol1_10To1_9_3() {
super(ClientboundPackets1_9_3.class, ClientboundPackets1_9_3.class, ServerboundPackets1_9_3.class, ServerboundPackets1_9_3.class);
}
@Override
protected void registerPackets() {
entityRewriter.register();
itemRewriter.register();
SoundRewriter soundRewriter = new SoundRewriter<>(this);
replaceClientbound(ClientboundPackets1_9_3.CUSTOM_SOUND, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // 0 - Sound name
map(Types.VAR_INT); // 1 - Sound Category
map(Types.INT); // 2 - x
map(Types.INT); // 3 - y
map(Types.INT); // 4 - z
map(Types.FLOAT); // 5 - Volume
map(Types.FLOAT, TO_OLD_PITCH); // 6 - Pitch
handler(soundRewriter.getNamedSoundHandler());
}
});
replaceClientbound(ClientboundPackets1_9_3.SOUND, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Sound name
map(Types.VAR_INT); // 1 - Sound Category
map(Types.INT); // 2 - x
map(Types.INT); // 3 - y
map(Types.INT); // 4 - z
map(Types.FLOAT); // 5 - Volume
map(Types.FLOAT, TO_OLD_PITCH); // 6 - Pitch
handler(soundRewriter.getSoundHandler());
}
});
registerServerbound(ServerboundPackets1_9_3.RESOURCE_PACK, new PacketHandlers() {
@Override
public void register() {
read(Types.STRING); // 0 - Hash
map(Types.VAR_INT); // 1 - Result
}
});
JsonNBTComponentRewriter componentRewriter = new JsonNBTComponentRewriter<>(this, ComponentRewriterBase.ReadType.JSON);
componentRewriter.registerComponentPacket(ClientboundPackets1_9_3.CHAT);
}
@Override
public void init(UserConnection user) {
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_10.EntityType.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
}
@Override
public BackwardsMappingData getMappingData() {
return MAPPINGS;
}
@Override
public EntityPacketRewriter1_10 getEntityRewriter() {
return entityRewriter;
}
@Override
public BlockItemPacketRewriter1_10 getItemRewriter() {
return itemRewriter;
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_10to1_9_3/rewriter/BlockItemPacketRewriter1_10.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_10to1_9_3.rewriter;
import com.viaversion.viabackwards.api.rewriters.LegacyBlockItemRewriter;
import com.viaversion.viabackwards.protocol.v1_10to1_9_3.Protocol1_10To1_9_3;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
public class BlockItemPacketRewriter1_10 extends LegacyBlockItemRewriter {
public BlockItemPacketRewriter1_10(Protocol1_10To1_9_3 protocol) {
super(protocol, "1.10");
}
@Override
protected void registerPackets() {
registerBlockChange(ClientboundPackets1_9_3.BLOCK_UPDATE);
registerMultiBlockChange(ClientboundPackets1_9_3.CHUNK_BLOCKS_UPDATE);
registerSetSlot(ClientboundPackets1_9_3.CONTAINER_SET_SLOT);
registerSetContent(ClientboundPackets1_9_3.CONTAINER_SET_CONTENT);
registerSetEquippedItem(ClientboundPackets1_9_3.SET_EQUIPPED_ITEM);
registerCustomPayloadTradeList(ClientboundPackets1_9_3.CUSTOM_PAYLOAD);
registerContainerClick(ServerboundPackets1_9_3.CONTAINER_CLICK);
registerSetCreativeModeSlot(ServerboundPackets1_9_3.SET_CREATIVE_MODE_SLOT);
protocol.registerClientbound(ClientboundPackets1_9_3.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_10To1_9_3.class);
ChunkType1_9_3 type = ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment());
Chunk chunk = wrapper.passthrough(type);
handleChunk(chunk);
});
// Rewrite entity data items
protocol.getEntityRewriter().filter().handler((event, data) -> {
if (data.dataType().type().equals(Types.ITEM1_8)) // Is Item
data.setValue(handleItemToClient(event.user(), (Item) data.getValue()));
});
// Particle
protocol.registerClientbound(ClientboundPackets1_9_3.LEVEL_PARTICLES, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
map(Types.BOOLEAN);
map(Types.FLOAT);
map(Types.FLOAT);
map(Types.FLOAT);
map(Types.FLOAT);
map(Types.FLOAT);
map(Types.FLOAT);
map(Types.FLOAT);
map(Types.INT);
handler(wrapper -> {
int id = wrapper.get(Types.INT, 0);
if (id == 46) { // new falling_dust
wrapper.set(Types.INT, 0, 38); // -> block_dust
}
});
}
});
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_10to1_9_3/rewriter/EntityPacketRewriter1_10.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_10to1_9_3.rewriter;
import com.viaversion.viabackwards.api.entities.storage.EntityReplacement;
import com.viaversion.viabackwards.api.entities.storage.WrappedEntityData;
import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.v1_10to1_9_3.Protocol1_10To1_9_3;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_9;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import java.util.List;
public class EntityPacketRewriter1_10 extends LegacyEntityRewriter {
public EntityPacketRewriter1_10(Protocol1_10To1_9_3 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_9_3.ADD_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity id
map(Types.UUID); // 1 - UUID
map(Types.BYTE); // 2 - Type
map(Types.DOUBLE); // 3 - x
map(Types.DOUBLE); // 4 - y
map(Types.DOUBLE); // 5 - z
map(Types.BYTE); // 6 - Pitch
map(Types.BYTE); // 7 - Yaw
map(Types.INT); // 8 - data
// Track Entity
handler(getObjectTrackerHandler());
handler(getObjectRewriter(EntityTypes1_11.ObjectType::findById));
handler(protocol.getItemRewriter().getFallingBlockHandler());
}
});
registerTracker(ClientboundPackets1_9_3.ADD_EXPERIENCE_ORB, EntityTypes1_10.EntityType.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_9_3.ADD_GLOBAL_ENTITY, EntityTypes1_10.EntityType.LIGHTNING_BOLT);
protocol.registerClientbound(ClientboundPackets1_9_3.ADD_MOB, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity id
map(Types.UUID); // 1 - UUID
map(Types.UNSIGNED_BYTE); // 2 - Entity Type
map(Types.DOUBLE); // 3 - X
map(Types.DOUBLE); // 4 - Y
map(Types.DOUBLE); // 5 - Z
map(Types.BYTE); // 6 - Yaw
map(Types.BYTE); // 7 - Pitch
map(Types.BYTE); // 8 - Head Pitch
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types.ENTITY_DATA_LIST1_9); // 12 - Entity data
// Track entity
handler(getTrackerHandler(Types.UNSIGNED_BYTE, 0));
// Rewrite entity type / data
handler(wrapper -> {
int entityId = wrapper.get(Types.VAR_INT, 0);
EntityType type = tracker(wrapper.user()).entityType(entityId);
if (type == null) {
return;
}
List entityDataList = wrapper.get(Types.ENTITY_DATA_LIST1_9, 0);
handleEntityData(wrapper.get(Types.VAR_INT, 0), entityDataList, wrapper.user());
EntityReplacement entityReplacement = entityDataForType(type);
if (entityReplacement != null) {
WrappedEntityData storage = new WrappedEntityData(entityDataList);
wrapper.set(Types.UNSIGNED_BYTE, 0, (short) entityReplacement.replacementId());
if (entityReplacement.hasBaseData())
entityReplacement.defaultData().createData(storage);
}
});
}
});
registerTracker(ClientboundPackets1_9_3.ADD_PAINTING, EntityTypes1_10.EntityType.PAINTING);
registerJoinGame(ClientboundPackets1_9_3.LOGIN, EntityTypes1_10.EntityType.PLAYER);
registerRespawn(ClientboundPackets1_9_3.RESPAWN);
protocol.registerClientbound(ClientboundPackets1_9_3.ADD_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types.UUID); // 1 - Player UUID
map(Types.DOUBLE); // 2 - X
map(Types.DOUBLE); // 3 - Y
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types.ENTITY_DATA_LIST1_9); // 7 - Entity data list
handler(getTrackerAndDataHandler(Types.ENTITY_DATA_LIST1_9, EntityTypes1_11.EntityType.PLAYER));
}
});
registerRemoveEntities(ClientboundPackets1_9_3.REMOVE_ENTITIES);
registerSetEntityData(ClientboundPackets1_9_3.SET_ENTITY_DATA, Types.ENTITY_DATA_LIST1_9);
}
@Override
protected void registerRewrites() {
mapEntityTypeWithData(EntityTypes1_10.EntityType.POLAR_BEAR, EntityTypes1_10.EntityType.SHEEP).plainName();
// Change the sheep color when the polar bear is standing up (index 13 -> Standing up)
filter().type(EntityTypes1_10.EntityType.POLAR_BEAR).index(13).handler((event, data) -> {
boolean b = (boolean) data.getValue();
data.setTypeAndValue(EntityDataTypes1_9.BYTE, b ? (byte) (14 & 0x0F) : (byte) (0));
});
// Handle husk (index 13 -> Zombie Type)
filter().type(EntityTypes1_10.EntityType.ZOMBIE).index(13).handler((event, data) -> {
if ((int) data.getValue() == 6) { // Is type Husk
data.setValue(0);
}
});
// Handle Stray (index 12 -> Skeleton Type)
filter().type(EntityTypes1_10.EntityType.SKELETON).index(12).handler((event, data) -> {
if ((int) data.getValue() == 2) {
data.setValue(0); // Change to default skeleton
}
});
// Added index from incorrect entity data hierarchy, where potions add to item entities
filter().type(EntityTypes1_10.EntityType.POTION).addIndex(6);
// Handle the missing NoGravity tag for every entity data
filter().removeIndex(5);
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_10.EntityType.findById(typeId);
}
@Override
public EntityType objectTypeFromId(int typeId, int data) {
return EntityTypes1_10.ObjectType.getEntityType(typeId, data);
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_11_1to1_11/Protocol1_11_1To1_11.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_11_1to1_11;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.protocol.v1_11_1to1_11.rewriter.EntityPacketRewriter1_11_1;
import com.viaversion.viabackwards.protocol.v1_11_1to1_11.rewriter.ItemPacketRewriter1_11_1;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
public class Protocol1_11_1To1_11 extends BackwardsProtocol {
private final EntityPacketRewriter1_11_1 entityRewriter = new EntityPacketRewriter1_11_1(this);
private final ItemPacketRewriter1_11_1 itemRewriter = new ItemPacketRewriter1_11_1(this);
public Protocol1_11_1To1_11() {
super(ClientboundPackets1_9_3.class, ClientboundPackets1_9_3.class, ServerboundPackets1_9_3.class, ServerboundPackets1_9_3.class);
}
@Override
public void init(UserConnection user) {
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_11.EntityType.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
}
@Override
public EntityPacketRewriter1_11_1 getEntityRewriter() {
return entityRewriter;
}
@Override
public ItemPacketRewriter1_11_1 getItemRewriter() {
return itemRewriter;
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_11_1to1_11/rewriter/EntityPacketRewriter1_11_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_11_1to1_11.rewriter;
import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.v1_11_1to1_11.Protocol1_11_1To1_11;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
public class EntityPacketRewriter1_11_1 extends LegacyEntityRewriter {
public EntityPacketRewriter1_11_1(Protocol1_11_1To1_11 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_9_3.ADD_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity id
map(Types.UUID); // 1 - UUID
map(Types.BYTE); // 2 - Type
map(Types.DOUBLE); // 3 - x
map(Types.DOUBLE); // 4 - y
map(Types.DOUBLE); // 5 - z
map(Types.BYTE); // 6 - Pitch
map(Types.BYTE); // 7 - Yaw
map(Types.INT); // 8 - data
// Track Entity
handler(getObjectTrackerHandler());
handler(getObjectRewriter(EntityTypes1_11.ObjectType::findById));
}
});
registerTracker(ClientboundPackets1_9_3.ADD_EXPERIENCE_ORB, EntityTypes1_11.EntityType.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_9_3.ADD_GLOBAL_ENTITY, EntityTypes1_11.EntityType.LIGHTNING_BOLT);
protocol.registerClientbound(ClientboundPackets1_9_3.ADD_MOB, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity id
map(Types.UUID); // 1 - UUID
map(Types.VAR_INT); // 2 - Entity Type
map(Types.DOUBLE); // 3 - X
map(Types.DOUBLE); // 4 - Y
map(Types.DOUBLE); // 5 - Z
map(Types.BYTE); // 6 - Yaw
map(Types.BYTE); // 7 - Pitch
map(Types.BYTE); // 8 - Head Pitch
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types.ENTITY_DATA_LIST1_9); // 12 - Entity data
// Track entity
handler(getTrackerHandler());
// Rewrite entity type / data
handler(getMobSpawnRewriter1_11(Types.ENTITY_DATA_LIST1_9));
}
});
registerTracker(ClientboundPackets1_9_3.ADD_PAINTING, EntityTypes1_11.EntityType.PAINTING);
registerJoinGame(ClientboundPackets1_9_3.LOGIN, EntityTypes1_11.EntityType.PLAYER);
registerRespawn(ClientboundPackets1_9_3.RESPAWN);
protocol.registerClientbound(ClientboundPackets1_9_3.ADD_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types.UUID); // 1 - Player UUID
map(Types.DOUBLE); // 2 - X
map(Types.DOUBLE); // 3 - Y
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types.ENTITY_DATA_LIST1_9); // 7 - Entity data list
handler(getTrackerAndDataHandler(Types.ENTITY_DATA_LIST1_9, EntityTypes1_11.EntityType.PLAYER));
}
});
registerRemoveEntities(ClientboundPackets1_9_3.REMOVE_ENTITIES);
registerSetEntityData(ClientboundPackets1_9_3.SET_ENTITY_DATA, Types.ENTITY_DATA_LIST1_9);
}
@Override
protected void registerRewrites() {
// Handle non-existing firework entity data (index 7 entity id for boosting)
filter().type(EntityTypes1_11.EntityType.FIREWORK_ROCKET).cancel(7);
// Handle non-existing pig entity data (index 14 - boost time)
filter().type(EntityTypes1_11.EntityType.PIG).cancel(14);
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_11.EntityType.findById(typeId);
}
@Override
public EntityType objectTypeFromId(int typeId, int data) {
return EntityTypes1_11.ObjectType.getEntityType(typeId, data);
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_11_1to1_11/rewriter/ItemPacketRewriter1_11_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_11_1to1_11.rewriter;
import com.viaversion.viabackwards.api.rewriters.LegacyBlockItemRewriter;
import com.viaversion.viabackwards.api.rewriters.LegacyEnchantmentRewriter;
import com.viaversion.viabackwards.protocol.v1_11_1to1_11.Protocol1_11_1To1_11;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
public class ItemPacketRewriter1_11_1 extends LegacyBlockItemRewriter {
private LegacyEnchantmentRewriter enchantmentRewriter;
public ItemPacketRewriter1_11_1(Protocol1_11_1To1_11 protocol) {
super(protocol, "1.11.1");
}
@Override
protected void registerPackets() {
registerSetSlot(ClientboundPackets1_9_3.CONTAINER_SET_SLOT);
registerSetContent(ClientboundPackets1_9_3.CONTAINER_SET_CONTENT);
registerSetEquippedItem(ClientboundPackets1_9_3.SET_EQUIPPED_ITEM);
registerCustomPayloadTradeList(ClientboundPackets1_9_3.CUSTOM_PAYLOAD);
registerContainerClick(ServerboundPackets1_9_3.CONTAINER_CLICK);
registerSetCreativeModeSlot(ServerboundPackets1_9_3.SET_CREATIVE_MODE_SLOT);
// Handle item entity data
protocol.getEntityRewriter().filter().handler((event, data) -> {
if (data.dataType().type().equals(Types.ITEM1_8)) { // Is Item
data.setValue(handleItemToClient(event.user(), (Item) data.getValue()));
}
});
}
@Override
protected void registerRewrites() {
enchantmentRewriter = new LegacyEnchantmentRewriter(nbtTagName());
enchantmentRewriter.registerEnchantment(22, "§7Sweeping Edge");
}
@Override
public Item handleItemToClient(UserConnection connection, Item item) {
if (item == null) return null;
super.handleItemToClient(connection, item);
enchantmentRewriter.handleToClient(item);
return item;
}
@Override
public Item handleItemToServer(UserConnection connection, Item item) {
if (item == null) return null;
item = super.handleItemToServer(connection, item);
enchantmentRewriter.handleToServer(item);
return item;
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_11to1_10/Protocol1_11To1_10.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_11to1_10;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.text.JsonNBTComponentRewriter;
import com.viaversion.viabackwards.protocol.v1_11to1_10.rewriter.BlockItemPacketRewriter1_11;
import com.viaversion.viabackwards.protocol.v1_11to1_10.rewriter.EntityPacketRewriter1_11;
import com.viaversion.viabackwards.protocol.v1_11to1_10.rewriter.PlayerPacketRewriter1_11;
import com.viaversion.viabackwards.protocol.v1_11to1_10.storage.WindowTracker;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
public class Protocol1_11To1_10 extends BackwardsProtocol {
public static final BackwardsMappingData MAPPINGS = new BackwardsMappingData("1.11", "1.10");
private final EntityPacketRewriter1_11 entityRewriter = new EntityPacketRewriter1_11(this);
private final BlockItemPacketRewriter1_11 itemRewriter = new BlockItemPacketRewriter1_11(this);
private JsonNBTComponentRewriter componentRewriter;
public Protocol1_11To1_10() {
super(ClientboundPackets1_9_3.class, ClientboundPackets1_9_3.class, ServerboundPackets1_9_3.class, ServerboundPackets1_9_3.class);
}
@Override
protected void registerPackets() {
entityRewriter.register();
itemRewriter.register();
PlayerPacketRewriter1_11.register(this);
componentRewriter = new JsonNBTComponentRewriter<>(this, ComponentRewriterBase.ReadType.JSON);
componentRewriter.registerComponentPacket(ClientboundPackets1_9_3.CHAT);
}
@Override
public void init(UserConnection user) {
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_11.EntityType.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
if (!user.has(WindowTracker.class)) {
user.put(new WindowTracker());
}
}
@Override
public BackwardsMappingData getMappingData() {
return MAPPINGS;
}
@Override
public EntityPacketRewriter1_11 getEntityRewriter() {
return entityRewriter;
}
@Override
public BlockItemPacketRewriter1_11 getItemRewriter() {
return itemRewriter;
}
@Override
public JsonNBTComponentRewriter getComponentRewriter() {
return componentRewriter;
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_11to1_10/data/SplashPotionMappings1_10.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_11to1_10.data;
import com.viaversion.viaversion.libs.fastutil.ints.Int2IntMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2IntOpenHashMap;
public class SplashPotionMappings1_10 {
private static final Int2IntMap DATA = new Int2IntOpenHashMap(14, 0.99F);
static {
DATA.defaultReturnValue(-1);
DATA.put(2039713, 5); // night vision
DATA.put(8356754, 7); // invisibility
DATA.put(2293580, 9); // jump boost
DATA.put(14981690, 12); // fire resistance
DATA.put(8171462, 14); // swiftness
DATA.put(5926017, 17); // slowness
DATA.put(3035801, 19); // water breathing
DATA.put(16262179, 21); // instant health
DATA.put(4393481, 23); // instant damage
DATA.put(5149489, 25); // poison
DATA.put(13458603, 28); // regeneration
DATA.put(9643043, 31); // strength
DATA.put(4738376, 34); // weakness
DATA.put(3381504, 36); // luck
}
public static int getOldData(int data) {
return DATA.get(data);
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_11to1_10/rewriter/BlockItemPacketRewriter1_11.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_11to1_10.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viabackwards.api.data.MappedLegacyBlockItem;
import com.viaversion.viabackwards.api.rewriters.LegacyBlockItemRewriter;
import com.viaversion.viabackwards.api.rewriters.LegacyEnchantmentRewriter;
import com.viaversion.viabackwards.protocol.v1_11to1_10.Protocol1_11To1_10;
import com.viaversion.viabackwards.protocol.v1_11to1_10.storage.ChestedHorseStorage;
import com.viaversion.viabackwards.protocol.v1_11to1_10.storage.WindowTracker;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_9_3;
import com.viaversion.viaversion.protocols.v1_10to1_11.data.EntityMappings1_11;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
import com.viaversion.viaversion.util.IdAndData;
import java.util.Arrays;
import java.util.Optional;
public class BlockItemPacketRewriter1_11 extends LegacyBlockItemRewriter {
private LegacyEnchantmentRewriter enchantmentRewriter;
public BlockItemPacketRewriter1_11(Protocol1_11To1_10 protocol) {
super(protocol, "1.11");
}
@Override
protected void registerPackets() {
registerBlockChange(ClientboundPackets1_9_3.BLOCK_UPDATE);
registerMultiBlockChange(ClientboundPackets1_9_3.CHUNK_BLOCKS_UPDATE);
protocol.registerClientbound(ClientboundPackets1_9_3.CONTAINER_SET_SLOT, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE); // 0 - Window ID
map(Types.SHORT); // 1 - Slot ID
map(Types.ITEM1_8); // 2 - Slot Value
handler(wrapper -> handleItemToClient(wrapper.user(), wrapper.get(Types.ITEM1_8, 0)));
// Handle Llama
handler(wrapper -> {
if (isLlama(wrapper.user())) {
Optional horse = getChestedHorse(wrapper.user());
if (horse.isEmpty()) {
return;
}
ChestedHorseStorage storage = horse.get();
int currentSlot = wrapper.get(Types.SHORT, 0);
wrapper.set(Types.SHORT, 0, ((Integer) (currentSlot = getNewSlotId(storage, currentSlot))).shortValue());
wrapper.set(Types.ITEM1_8, 0, getNewItem(storage, currentSlot, wrapper.get(Types.ITEM1_8, 0)));
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.CONTAINER_SET_CONTENT, new PacketHandlers() {
@Override
public void register() {
map(Types.UNSIGNED_BYTE); // 0 - Window ID
map(Types.ITEM1_8_SHORT_ARRAY); // 1 - Window Values
handler(wrapper -> {
Item[] stacks = wrapper.get(Types.ITEM1_8_SHORT_ARRAY, 0);
for (int i = 0; i < stacks.length; i++)
stacks[i] = handleItemToClient(wrapper.user(), stacks[i]);
if (isLlama(wrapper.user())) {
Optional horse = getChestedHorse(wrapper.user());
if (horse.isEmpty()) {
return;
}
ChestedHorseStorage storage = horse.get();
stacks = Arrays.copyOf(stacks, !storage.isChested() ? 38 : 53);
for (int i = stacks.length - 1; i >= 0; i--) {
stacks[getNewSlotId(storage, i)] = stacks[i];
stacks[i] = getNewItem(storage, i, stacks[i]);
}
wrapper.set(Types.ITEM1_8_SHORT_ARRAY, 0, stacks);
}
});
}
});
registerSetEquippedItem(ClientboundPackets1_9_3.SET_EQUIPPED_ITEM);
registerCustomPayloadTradeList(ClientboundPackets1_9_3.CUSTOM_PAYLOAD);
protocol.registerServerbound(ServerboundPackets1_9_3.CONTAINER_CLICK, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE); // 0 - Window ID
map(Types.SHORT); // 1 - Slot
map(Types.BYTE); // 2 - Button
map(Types.SHORT); // 3 - Action number
map(Types.VAR_INT); // 4 - Mode
map(Types.ITEM1_8); // 5 - Clicked Item
handler(wrapper -> handleItemToServer(wrapper.user(), wrapper.get(Types.ITEM1_8, 0)));
// Llama slot
handler(wrapper -> {
if (isLlama(wrapper.user())) {
Optional horse = getChestedHorse(wrapper.user());
if (horse.isEmpty()) {
return;
}
ChestedHorseStorage storage = horse.get();
int clickSlot = wrapper.get(Types.SHORT, 0);
int correctSlot = getOldSlotId(storage, clickSlot);
wrapper.set(Types.SHORT, 0, ((Integer) correctSlot).shortValue());
}
});
}
});
registerSetCreativeModeSlot(ServerboundPackets1_9_3.SET_CREATIVE_MODE_SLOT);
protocol.registerClientbound(ClientboundPackets1_9_3.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_11To1_10.class);
ChunkType1_9_3 type = ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment()); // Use the 1.10 Chunk type since nothing changed.
Chunk chunk = wrapper.passthrough(type);
handleChunk(chunk);
// only patch it for signs for now
for (CompoundTag tag : chunk.getBlockEntities()) {
StringTag idTag = tag.getStringTag("id");
if (idTag == null) continue;
String id = idTag.getValue();
if (id.equals("minecraft:sign")) {
idTag.setValue("Sign");
}
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.BLOCK_ENTITY_DATA, new PacketHandlers() {
@Override
public void register() {
map(Types.BLOCK_POSITION1_8); // 0 - Position
map(Types.UNSIGNED_BYTE); // 1 - Action
map(Types.NAMED_COMPOUND_TAG); // 2 - NBT
handler(wrapper -> {
// Remove on shulkerbox decleration
if (wrapper.get(Types.UNSIGNED_BYTE, 0) == 10) {
wrapper.cancel();
}
// Handler Spawners
if (wrapper.get(Types.UNSIGNED_BYTE, 0) == 1) {
CompoundTag tag = wrapper.get(Types.NAMED_COMPOUND_TAG, 0);
EntityMappings1_11.toClientSpawner(tag, true);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.OPEN_SCREEN, new PacketHandlers() {
@Override
public void register() {
map(Types.UNSIGNED_BYTE); // 0 - Window ID
map(Types.STRING); // 1 - Window Type
map(Types.COMPONENT); // 2 - Title
map(Types.UNSIGNED_BYTE); // 3 - Slots
handler(wrapper -> {
int entityId = -1;
// Passthrough Entity ID
if (wrapper.get(Types.STRING, 0).equals("EntityHorse")) {
entityId = wrapper.passthrough(Types.INT);
}
// Rewrite window title
protocol.getComponentRewriter().processText(wrapper.user(), wrapper.get(Types.COMPONENT, 0));
// Track Inventory
String inventory = wrapper.get(Types.STRING, 0);
WindowTracker windowTracker = wrapper.user().get(WindowTracker.class);
windowTracker.setInventory(inventory);
windowTracker.setEntityId(entityId);
// Change llama slotcount to the donkey one
if (isLlama(wrapper.user())) {
wrapper.set(Types.UNSIGNED_BYTE, 1, (short) 17);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.CONTAINER_CLOSE, new PacketHandlers() {
@Override
public void register() {
// Inventory tracking
handler(wrapper -> {
WindowTracker windowTracker = wrapper.user().get(WindowTracker.class);
windowTracker.setInventory(null);
windowTracker.setEntityId(-1);
});
}
});
protocol.registerServerbound(ServerboundPackets1_9_3.CONTAINER_CLOSE, new PacketHandlers() {
@Override
public void register() {
// Inventory tracking
handler(wrapper -> {
WindowTracker windowTracker = wrapper.user().get(WindowTracker.class);
windowTracker.setInventory(null);
windowTracker.setEntityId(-1);
});
}
});
protocol.getEntityRewriter().filter().handler((event, data) -> {
if (data.dataType().type().equals(Types.ITEM1_8)) // Is Item
data.setValue(handleItemToClient(event.user(), (Item) data.getValue()));
});
}
@Override
protected void registerRewrites() {
// Handle spawner block entity (map to itself with custom handler)
MappedLegacyBlockItem data = itemReplacements.computeIfAbsent(IdAndData.toRawData(52), s -> new MappedLegacyBlockItem(52));
data.setBlockEntityHandler((b, tag) -> EntityMappings1_11.toClientSpawner(tag, true));
enchantmentRewriter = new LegacyEnchantmentRewriter(nbtTagName());
enchantmentRewriter.registerEnchantment(71, "§cCurse of Vanishing");
enchantmentRewriter.registerEnchantment(10, "§cCurse of Binding");
enchantmentRewriter.setHideLevelForEnchants(71, 10); // Curses do not display their level
}
@Override
public Item handleItemToClient(UserConnection connection, Item item) {
if (item == null) return null;
super.handleItemToClient(connection, item);
CompoundTag tag = item.tag();
if (tag == null) return item;
// Rewrite spawn eggs (id checks are done in the method itself)
EntityMappings1_11.toClientItem(item, true);
enchantmentRewriter.handleToClient(item);
return item;
}
@Override
public Item handleItemToServer(UserConnection connection, Item item) {
if (item == null) return null;
item = super.handleItemToServer(connection, item);
CompoundTag tag = item.tag();
if (tag == null) return item;
// Rewrite spawn eggs (id checks are done in the method itself)
EntityMappings1_11.toServerItem(item, true);
enchantmentRewriter.handleToServer(item);
return item;
}
private boolean isLlama(UserConnection user) {
WindowTracker tracker = user.get(WindowTracker.class);
if (tracker.getInventory() != null && tracker.getInventory().equals("EntityHorse")) {
EntityTracker entTracker = user.getEntityTracker(Protocol1_11To1_10.class);
StoredEntityData entityData = entTracker.entityData(tracker.getEntityId());
return entityData != null && entityData.type().is(EntityTypes1_11.EntityType.LLAMA);
}
return false;
}
private Optional getChestedHorse(UserConnection user) {
WindowTracker tracker = user.get(WindowTracker.class);
if (tracker.getInventory() != null && tracker.getInventory().equals("EntityHorse")) {
EntityTracker entTracker = user.getEntityTracker(Protocol1_11To1_10.class);
StoredEntityData entityData = entTracker.entityData(tracker.getEntityId());
if (entityData != null)
return Optional.of(entityData.get(ChestedHorseStorage.class));
}
return Optional.empty();
}
private int getNewSlotId(ChestedHorseStorage storage, int slotId) {
int totalSlots = !storage.isChested() ? 38 : 53;
int strength = storage.isChested() ? storage.getLiamaStrength() : 0;
int startNonExistingFormula = 2 + 3 * strength;
int offsetForm = 15 - (3 * strength);
if (slotId >= startNonExistingFormula && totalSlots > (slotId + offsetForm))
return offsetForm + slotId;
if (slotId == 1)
return 0;
return slotId;
}
private int getOldSlotId(ChestedHorseStorage storage, int slotId) {
int strength = storage.isChested() ? storage.getLiamaStrength() : 0;
int startNonExistingFormula = 2 + 3 * strength;
int endNonExistingFormula = 2 + 3 * (storage.isChested() ? 5 : 0);
int offsetForm = endNonExistingFormula - startNonExistingFormula;
if (slotId == 1 || slotId >= startNonExistingFormula && slotId < endNonExistingFormula)
return 0;
if (slotId >= endNonExistingFormula)
return slotId - offsetForm;
if (slotId == 0)
return 1;
return slotId;
}
private Item getNewItem(ChestedHorseStorage storage, int slotId, Item current) {
int strength = storage.isChested() ? storage.getLiamaStrength() : 0;
int startNonExistingFormula = 2 + 3 * strength;
int endNonExistingFormula = 2 + 3 * (storage.isChested() ? 5 : 0);
if (slotId >= startNonExistingFormula && slotId < endNonExistingFormula)
return new DataItem(166, (byte) 1, (short) 0, getNamedTag("§4SLOT DISABLED"));
if (slotId == 1)
return null;
return current;
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_11to1_10/rewriter/EntityPacketRewriter1_11.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_11to1_10.rewriter;
import com.viaversion.viabackwards.api.entities.storage.WrappedEntityData;
import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.v1_11to1_10.Protocol1_11To1_10;
import com.viaversion.viabackwards.protocol.v1_11to1_10.data.SplashPotionMappings1_10;
import com.viaversion.viabackwards.protocol.v1_11to1_10.storage.ChestedHorseStorage;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_9;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import java.util.List;
public class EntityPacketRewriter1_11 extends LegacyEntityRewriter {
public EntityPacketRewriter1_11(Protocol1_11To1_10 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_9_3.LEVEL_EVENT, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
map(Types.BLOCK_POSITION1_8);
map(Types.INT);
handler(wrapper -> {
int type = wrapper.get(Types.INT, 0);
if (type == 2002 || type == 2007) {
// 2007 potion id doesn't exist in 1.10
if (type == 2007) {
wrapper.set(Types.INT, 0, 2002);
}
int mappedData = SplashPotionMappings1_10.getOldData(wrapper.get(Types.INT, 1));
if (mappedData != -1) {
wrapper.set(Types.INT, 1, mappedData);
}
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.ADD_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity id
map(Types.UUID); // 1 - UUID
map(Types.BYTE); // 2 - Type
map(Types.DOUBLE); // 3 - x
map(Types.DOUBLE); // 4 - y
map(Types.DOUBLE); // 5 - z
map(Types.BYTE); // 6 - Pitch
map(Types.BYTE); // 7 - Yaw
map(Types.INT); // 8 - data
// Track Entity
handler(getObjectTrackerHandler());
handler(getObjectRewriter(EntityTypes1_11.ObjectType::findById));
handler(protocol.getItemRewriter().getFallingBlockHandler());
}
});
registerTracker(ClientboundPackets1_9_3.ADD_EXPERIENCE_ORB, EntityTypes1_11.EntityType.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_9_3.ADD_GLOBAL_ENTITY, EntityTypes1_11.EntityType.LIGHTNING_BOLT);
protocol.registerClientbound(ClientboundPackets1_9_3.ADD_MOB, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity id
map(Types.UUID); // 1 - UUID
map(Types.VAR_INT, Types.UNSIGNED_BYTE); // 2 - Entity Type
map(Types.DOUBLE); // 3 - X
map(Types.DOUBLE); // 4 - Y
map(Types.DOUBLE); // 5 - Z
map(Types.BYTE); // 6 - Yaw
map(Types.BYTE); // 7 - Pitch
map(Types.BYTE); // 8 - Head Pitch
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types.ENTITY_DATA_LIST1_9); // 12 - Entity data
// Track entity
handler(getTrackerHandler(Types.UNSIGNED_BYTE, 0));
// Rewrite entity type / data
handler(getMobSpawnRewriter(Types.ENTITY_DATA_LIST1_9));
// Sub 1.11 clients will error if the list is empty
handler(wrapper -> {
List entityDataList = wrapper.get(Types.ENTITY_DATA_LIST1_9, 0);
if (entityDataList.isEmpty()) {
entityDataList.add(new EntityData(0, EntityDataTypes1_9.BYTE, (byte) 0));
}
});
}
});
registerTracker(ClientboundPackets1_9_3.ADD_PAINTING, EntityTypes1_11.EntityType.PAINTING);
registerJoinGame(ClientboundPackets1_9_3.LOGIN, EntityTypes1_11.EntityType.PLAYER);
registerRespawn(ClientboundPackets1_9_3.RESPAWN);
protocol.registerClientbound(ClientboundPackets1_9_3.ADD_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types.UUID); // 1 - Player UUID
map(Types.DOUBLE); // 2 - X
map(Types.DOUBLE); // 3 - Y
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types.ENTITY_DATA_LIST1_9); // 7 - Entity data list
handler(getTrackerAndDataHandler(Types.ENTITY_DATA_LIST1_9, EntityTypes1_11.EntityType.PLAYER));
handler(wrapper -> {
// Sub 1.11 clients will cry if the list is empty
List entityDataList = wrapper.get(Types.ENTITY_DATA_LIST1_9, 0);
if (entityDataList.isEmpty()) {
entityDataList.add(new EntityData(0, EntityDataTypes1_9.BYTE, (byte) 0));
}
});
}
});
registerRemoveEntities(ClientboundPackets1_9_3.REMOVE_ENTITIES);
registerSetEntityData(ClientboundPackets1_9_3.SET_ENTITY_DATA, Types.ENTITY_DATA_LIST1_9);
protocol.registerClientbound(ClientboundPackets1_9_3.ENTITY_EVENT, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Entity ID
map(Types.BYTE); // 1 - Entity Status
handler(wrapper -> {
final int entityId = wrapper.get(Types.INT, 0);
if (entityId != tracker(wrapper.user()).clientEntityId()) {
// Entity events are sent for all players, but we only want to apply this for the self player
return;
}
final byte entityStatus = wrapper.get(Types.BYTE, 0);
if (entityStatus == 35) {
// TODO spawn particles?
wrapper.clearPacket();
wrapper.setPacketType(ClientboundPackets1_9_3.GAME_EVENT);
wrapper.write(Types.UNSIGNED_BYTE, (short) 10); // Play Elder Guardian animation
wrapper.write(Types.FLOAT, 0F);
}
});
}
});
}
@Override
protected void registerRewrites() {
// Guardian
mapEntityTypeWithData(EntityTypes1_11.EntityType.ELDER_GUARDIAN, EntityTypes1_11.EntityType.GUARDIAN);
// Skeletons
mapEntityTypeWithData(EntityTypes1_11.EntityType.WITHER_SKELETON, EntityTypes1_11.EntityType.SKELETON).spawnEntityData(storage -> storage.add(getSkeletonTypeData(1)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.STRAY, EntityTypes1_11.EntityType.SKELETON).plainName().spawnEntityData(storage -> storage.add(getSkeletonTypeData(2)));
// Zombies
mapEntityTypeWithData(EntityTypes1_11.EntityType.HUSK, EntityTypes1_11.EntityType.ZOMBIE).plainName().spawnEntityData(storage -> handleZombieType(storage, 6));
mapEntityTypeWithData(EntityTypes1_11.EntityType.ZOMBIE_VILLAGER, EntityTypes1_11.EntityType.ZOMBIE).spawnEntityData(storage -> handleZombieType(storage, 1));
// Horses
mapEntityTypeWithData(EntityTypes1_11.EntityType.HORSE, EntityTypes1_11.EntityType.HORSE).spawnEntityData(storage -> storage.add(getHorseDataType(0))); // Nob able to ride the horse without having the EntityDataType sent.
mapEntityTypeWithData(EntityTypes1_11.EntityType.DONKEY, EntityTypes1_11.EntityType.HORSE).spawnEntityData(storage -> storage.add(getHorseDataType(1)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.MULE, EntityTypes1_11.EntityType.HORSE).spawnEntityData(storage -> storage.add(getHorseDataType(2)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.SKELETON_HORSE, EntityTypes1_11.EntityType.HORSE).spawnEntityData(storage -> storage.add(getHorseDataType(4)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.ZOMBIE_HORSE, EntityTypes1_11.EntityType.HORSE).spawnEntityData(storage -> storage.add(getHorseDataType(3)));
// New mobs
mapEntityTypeWithData(EntityTypes1_11.EntityType.EVOKER_FANGS, EntityTypes1_11.EntityType.SHULKER);
mapEntityTypeWithData(EntityTypes1_11.EntityType.EVOKER, EntityTypes1_11.EntityType.VILLAGER).plainName();
mapEntityTypeWithData(EntityTypes1_11.EntityType.VEX, EntityTypes1_11.EntityType.BAT).plainName();
mapEntityTypeWithData(EntityTypes1_11.EntityType.VINDICATOR, EntityTypes1_11.EntityType.VILLAGER).plainName().spawnEntityData(storage -> storage.add(new EntityData(13, EntityDataTypes1_9.VAR_INT, 4))); // Base Profession
mapEntityTypeWithData(EntityTypes1_11.EntityType.LLAMA, EntityTypes1_11.EntityType.HORSE).plainName().spawnEntityData(storage -> storage.add(getHorseDataType(1)));
mapEntityTypeWithData(EntityTypes1_11.EntityType.LLAMA_SPIT, EntityTypes1_11.EntityType.SNOWBALL);
mapObjectType(EntityTypes1_11.ObjectType.LLAMA_SPIT, EntityTypes1_11.ObjectType.SNOWBALL, -1);
// Replace with endertorchthingies
mapObjectType(EntityTypes1_11.ObjectType.EVOKER_FANGS, EntityTypes1_11.ObjectType.FALLING_BLOCK, 198 | 1 << 12);
// Handle ElderGuardian & target entity data
filter().type(EntityTypes1_11.EntityType.GUARDIAN).index(12).handler((event, data) -> {
boolean b = (boolean) data.getValue();
int bitmask = b ? 0x02 : 0;
if (event.entityType() == EntityTypes1_11.EntityType.ELDER_GUARDIAN) {
bitmask |= 0x04;
}
data.setTypeAndValue(EntityDataTypes1_9.BYTE, (byte) bitmask);
});
// Handle skeleton swing
filter().type(EntityTypes1_11.EntityType.ABSTRACT_SKELETON).index(12).toIndex(13);
/*
ZOMBIE CHANGES
*/
filter().type(EntityTypes1_11.EntityType.ZOMBIE).handler((event, data) -> {
switch (data.id()) {
case 13 -> event.cancel();
case 14 -> event.setIndex(15);
case 15 -> event.setIndex(14);
case 16 -> {
// Profession
event.setIndex(13);
data.setValue(1 + (int) data.getValue());
}
}
});
// Handle Evocation Illager
filter().type(EntityTypes1_11.EntityType.EVOKER).index(12).handler((event, data) -> {
event.setIndex(13);
data.setTypeAndValue(EntityDataTypes1_9.VAR_INT, ((Byte) data.getValue()).intValue()); // Change the profession for the states
});
// Handle Vex (Remove this field completely since the position is not updated correctly when idling for bats. Sad ):
filter().type(EntityTypes1_11.EntityType.VEX).index(12).handler((event, data) -> {
data.setValue((byte) 0x00);
});
// Handle VindicationIllager
filter().type(EntityTypes1_11.EntityType.VINDICATOR).index(12).handler((event, data) -> {
event.setIndex(13);
data.setTypeAndValue(EntityDataTypes1_9.VAR_INT, ((Number) data.getValue()).intValue() == 1 ? 2 : 4);
});
/*
HORSES
*/
// Handle horse flags
filter().type(EntityTypes1_11.EntityType.ABSTRACT_HORSE).index(13).handler((event, data) -> {
StoredEntityData entityData = storedEntityData(event);
byte b = (byte) data.getValue();
if (entityData.has(ChestedHorseStorage.class) && entityData.get(ChestedHorseStorage.class).isChested()) {
b |= 0x08; // Chested
data.setValue(b);
}
});
// Create chested horse storage
filter().type(EntityTypes1_11.EntityType.CHESTED_HORSE).handler((event, data) -> {
StoredEntityData entityData = storedEntityData(event);
if (!entityData.has(ChestedHorseStorage.class)) {
entityData.put(new ChestedHorseStorage());
}
});
// Handle horse armor
filter().type(EntityTypes1_11.EntityType.HORSE).index(16).toIndex(17);
// Handle chested horse
filter().type(EntityTypes1_11.EntityType.CHESTED_HORSE).index(15).handler((event, data) -> {
StoredEntityData entityData = storedEntityData(event);
ChestedHorseStorage storage = entityData.get(ChestedHorseStorage.class);
boolean b = (boolean) data.getValue();
storage.setChested(b);
event.cancel();
});
// Get rid of Liama entity data
filter().type(EntityTypes1_11.EntityType.LLAMA).handler((event, data) -> {
StoredEntityData entityData = storedEntityData(event);
ChestedHorseStorage storage = entityData.get(ChestedHorseStorage.class);
int index = event.index();
// Store them for later (:
switch (index) {
case 16 -> {
storage.setLiamaStrength((int) data.getValue());
event.cancel();
}
case 17 -> {
storage.setLiamaCarpetColor((int) data.getValue());
event.cancel();
}
case 18 -> {
storage.setLiamaVariant((int) data.getValue());
event.cancel();
}
}
});
// Handle Horse (Correct owner)
filter().type(EntityTypes1_11.EntityType.ABSTRACT_HORSE).index(14).toIndex(16);
// Handle villager - Change non-existing profession
filter().type(EntityTypes1_11.EntityType.VILLAGER).index(13).handler((event, data) -> {
if ((int) data.getValue() == 5) {
data.setValue(0);
}
});
// handle new Shulker color data
filter().type(EntityTypes1_11.EntityType.SHULKER).cancel(15);
}
/*
0 - Skeleton
1 - Wither Skeleton
2 - Stray
*/
private EntityData getSkeletonTypeData(int type) {
return new EntityData(12, EntityDataTypes1_9.VAR_INT, type);
}
/*
0 - Zombie
1-5 - Villager with profession
6 - Husk
*/
private EntityData getZombieTypeData(int type) {
return new EntityData(13, EntityDataTypes1_9.VAR_INT, type);
}
private void handleZombieType(WrappedEntityData storage, int type) {
EntityData meta = storage.get(13);
if (meta == null) {
storage.add(getZombieTypeData(type));
}
}
/*
Horse 0
Donkey 1
Mule 2
Zombie horse 3
Skeleton horse 4
*/
private EntityData getHorseDataType(int type) {
return new EntityData(14, EntityDataTypes1_9.VAR_INT, type);
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_11.EntityType.findById(typeId);
}
@Override
public EntityType objectTypeFromId(int typeId, int data) {
return EntityTypes1_11.ObjectType.getEntityType(typeId, data);
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_11to1_10/rewriter/PlayerPacketRewriter1_11.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_11to1_10.rewriter;
import com.viaversion.viabackwards.protocol.v1_11to1_10.Protocol1_11To1_10;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
import com.viaversion.viaversion.util.ComponentUtil;
public class PlayerPacketRewriter1_11 {
private static final ValueTransformer TO_NEW_FLOAT = new ValueTransformer<>(Types.FLOAT) {
@Override
public Float transform(PacketWrapper wrapper, Short inputValue) {
return inputValue / 16f;
}
};
public static void register(Protocol1_11To1_10 protocol) {
protocol.registerClientbound(ClientboundPackets1_9_3.SET_TITLES, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Action
handler(wrapper -> {
int action = wrapper.get(Types.VAR_INT, 0);
if (action == 2) { // Handle the new ActionBar
JsonElement message = wrapper.read(Types.COMPONENT);
wrapper.clearPacket();
wrapper.setPacketType(ClientboundPackets1_9_3.CHAT);
// https://bugs.mojang.com/browse/MC-119145
String legacy = ComponentUtil.jsonToLegacy(message);
message = new JsonObject();
message.getAsJsonObject().addProperty("text", legacy);
wrapper.write(Types.COMPONENT, message);
wrapper.write(Types.BYTE, (byte) 2);
} else if (action > 2) {
wrapper.set(Types.VAR_INT, 0, action - 1); // Move everything one position down
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.TAKE_ITEM_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Collected entity id
map(Types.VAR_INT); // 1 - Collector entity id
handler(wrapper -> wrapper.read(Types.VAR_INT)); // Ignore item pickup count
}
});
protocol.registerServerbound(ServerboundPackets1_9_3.USE_ITEM_ON, new PacketHandlers() {
@Override
public void register() {
map(Types.BLOCK_POSITION1_8); // 0 - Location
map(Types.VAR_INT); // 1 - Face
map(Types.VAR_INT); // 2 - Hand
map(Types.UNSIGNED_BYTE, TO_NEW_FLOAT);
map(Types.UNSIGNED_BYTE, TO_NEW_FLOAT);
map(Types.UNSIGNED_BYTE, TO_NEW_FLOAT);
}
});
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_11to1_10/storage/ChestedHorseStorage.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_11to1_10.storage;
public class ChestedHorseStorage {
private boolean chested;
private int liamaStrength;
private int liamaCarpetColor = -1;
private int liamaVariant;
public boolean isChested() {
return chested;
}
public void setChested(boolean chested) {
this.chested = chested;
}
public int getLiamaStrength() {
return liamaStrength;
}
public void setLiamaStrength(int liamaStrength) {
this.liamaStrength = liamaStrength;
}
public int getLiamaCarpetColor() {
return liamaCarpetColor;
}
public void setLiamaCarpetColor(int liamaCarpetColor) {
this.liamaCarpetColor = liamaCarpetColor;
}
public int getLiamaVariant() {
return liamaVariant;
}
public void setLiamaVariant(int liamaVariant) {
this.liamaVariant = liamaVariant;
}
@Override
public String toString() {
return "ChestedHorseStorage{" + "chested=" + chested + ", liamaStrength=" + liamaStrength + ", liamaCarpetColor=" + liamaCarpetColor + ", liamaVariant=" + liamaVariant + '}';
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_11to1_10/storage/WindowTracker.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_11to1_10.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
public class WindowTracker implements StorableObject {
private String inventory;
private int entityId = -1;
public String getInventory() {
return inventory;
}
public void setInventory(String inventory) {
this.inventory = inventory;
}
public int getEntityId() {
return entityId;
}
public void setEntityId(int entityId) {
this.entityId = entityId;
}
@Override
public String toString() {
return "WindowTracker{" + "inventory='" + inventory + '\'' + ", entityId=" + entityId + '}';
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_12_1to1_12/Protocol1_12_1To1_12.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_12_1to1_12;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ClientboundPackets1_12;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ServerboundPackets1_12;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ClientboundPackets1_12_1;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ServerboundPackets1_12_1;
public class Protocol1_12_1To1_12 extends BackwardsProtocol {
public Protocol1_12_1To1_12() {
super(ClientboundPackets1_12_1.class, ClientboundPackets1_12.class, ServerboundPackets1_12_1.class, ServerboundPackets1_12.class);
}
@Override
protected void registerPackets() {
cancelClientbound(ClientboundPackets1_12_1.PLACE_GHOST_RECIPE);
cancelServerbound(ServerboundPackets1_12.CRAFTING_RECIPE_PLACEMENT);
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_12_2to1_12_1/Protocol1_12_2To1_12_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_12_2to1_12_1;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.protocol.v1_12_2to1_12_1.storage.KeepAliveTracker;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ClientboundPackets1_12_1;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ServerboundPackets1_12_1;
public class Protocol1_12_2To1_12_1 extends BackwardsProtocol {
public Protocol1_12_2To1_12_1() {
super(ClientboundPackets1_12_1.class, ClientboundPackets1_12_1.class, ServerboundPackets1_12_1.class, ServerboundPackets1_12_1.class);
}
@Override
protected void registerPackets() {
registerClientbound(ClientboundPackets1_12_1.KEEP_ALIVE, new PacketHandlers() {
@Override
public void register() {
handler(packetWrapper -> {
Long keepAlive = packetWrapper.read(Types.LONG);
packetWrapper.user().get(KeepAliveTracker.class).setKeepAlive(keepAlive);
packetWrapper.write(Types.VAR_INT, keepAlive.hashCode());
});
}
});
registerServerbound(ServerboundPackets1_12_1.KEEP_ALIVE, new PacketHandlers() {
@Override
public void register() {
handler(packetWrapper -> {
int keepAlive = packetWrapper.read(Types.VAR_INT);
long realKeepAlive = packetWrapper.user().get(KeepAliveTracker.class).getKeepAlive();
if (keepAlive != Long.hashCode(realKeepAlive)) {
packetWrapper.cancel(); // Wrong data, cancel packet
return;
}
packetWrapper.write(Types.LONG, realKeepAlive);
// Reset KeepAliveTracker (to prevent sending same valid value in a row causing a timeout)
packetWrapper.user().get(KeepAliveTracker.class).setKeepAlive(Integer.MAX_VALUE);
});
}
});
}
@Override
public void init(UserConnection userConnection) {
userConnection.put(new KeepAliveTracker());
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_12_2to1_12_1/storage/KeepAliveTracker.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_12_2to1_12_1.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
public class KeepAliveTracker implements StorableObject {
private long keepAlive = Integer.MAX_VALUE;
public long getKeepAlive() {
return keepAlive;
}
public void setKeepAlive(long keepAlive) {
this.keepAlive = keepAlive;
}
@Override
public String toString() {
return "KeepAliveTracker{" + "keepAlive=" + keepAlive + '}';
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_12to1_11_1/Protocol1_12To1_11_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_12to1_11_1;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter.BlockItemPacketRewriter1_12;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter.ComponentRewriter1_12;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter.EntityPacketRewriter1_12;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter.SoundPacketRewriter1_12;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.storage.ShoulderTracker;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_12;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ClientboundPackets1_12;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ServerboundPackets1_12;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.SerializerVersion;
public class Protocol1_12To1_11_1 extends BackwardsProtocol {
private static final BackwardsMappingData MAPPINGS = new BackwardsMappingData("1.12", "1.11");
private final EntityPacketRewriter1_12 entityRewriter = new EntityPacketRewriter1_12(this);
private final BlockItemPacketRewriter1_12 itemRewriter = new BlockItemPacketRewriter1_12(this);
private final ComponentRewriter1_12 componentRewriter = new ComponentRewriter1_12(this);
public Protocol1_12To1_11_1() {
super(ClientboundPackets1_12.class, ClientboundPackets1_9_3.class, ServerboundPackets1_12.class, ServerboundPackets1_9_3.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
componentRewriter.registerComponentPacket(ClientboundPackets1_12.CHAT);
new SoundPacketRewriter1_12(this).register();
registerClientbound(ClientboundPackets1_12.SET_TITLES, wrapper -> {
int action = wrapper.passthrough(Types.VAR_INT);
if (action >= 0 && action <= 2) {
// Should be done globally in the component rewriter, but /shrug for now
String component = wrapper.read(Types.COMPONENT).toString();
wrapper.write(Types.COMPONENT, ComponentUtil.convertJsonOrEmpty(component, SerializerVersion.V1_12, SerializerVersion.V1_9));
}
});
cancelClientbound(ClientboundPackets1_12.UPDATE_ADVANCEMENTS);
cancelClientbound(ClientboundPackets1_12.RECIPE);
cancelClientbound(ClientboundPackets1_12.SELECT_ADVANCEMENTS_TAB);
}
@Override
public void init(UserConnection user) {
user.addEntityTracker(this.getClass(), new EntityTrackerBase(user, EntityTypes1_12.EntityType.PLAYER));
user.addClientWorld(this.getClass(), new ClientWorld());
user.put(new ShoulderTracker(user));
}
@Override
public BackwardsMappingData getMappingData() {
return MAPPINGS;
}
@Override
public EntityPacketRewriter1_12 getEntityRewriter() {
return entityRewriter;
}
@Override
public BlockItemPacketRewriter1_12 getItemRewriter() {
return itemRewriter;
}
@Override
public ComponentRewriter1_12 getComponentRewriter() {
return componentRewriter;
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_12to1_11_1/data/BlockColors1_11_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_12to1_11_1.data;
public class BlockColors1_11_1 {
private static final String[] COLORS = new String[16];
static {
COLORS[0] = "White";
COLORS[1] = "Orange";
COLORS[2] = "Magenta";
COLORS[3] = "Light Blue";
COLORS[4] = "Yellow";
COLORS[5] = "Lime";
COLORS[6] = "Pink";
COLORS[7] = "Gray";
COLORS[8] = "Light Gray";
COLORS[9] = "Cyan";
COLORS[10] = "Purple";
COLORS[11] = "Blue";
COLORS[12] = "Brown";
COLORS[13] = "Green";
COLORS[14] = "Red";
COLORS[15] = "Black";
}
public static String get(int key) {
return key >= 0 && key < COLORS.length ? COLORS[key] : "Unknown color";
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_12to1_11_1/data/MapColorMappings1_11_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_12to1_11_1.data;
import com.viaversion.viaversion.libs.fastutil.ints.Int2IntMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2IntOpenHashMap;
public class MapColorMappings1_11_1 {
private static final Int2IntMap MAPPING = new Int2IntOpenHashMap(64, 0.99F);
static {
MAPPING.defaultReturnValue(-1);
MAPPING.put(144, 59); // (148, 124, 114) -> (148, 124, 114)
MAPPING.put(145, 56); // (180, 153, 139) -> (180, 153, 139)
MAPPING.put(146, 56); // (209, 177, 161) -> (209, 177, 161)
MAPPING.put(147, 45); // (111, 94, 85) -> (111, 94, 85)
MAPPING.put(148, 63); // (112, 58, 25) -> (112, 58, 25)
MAPPING.put(149, 60); // (137, 71, 31) -> (137, 71, 31)
MAPPING.put(150, 60); // (159, 82, 36) -> (159, 82, 36)
MAPPING.put(151, 136); // (84, 43, 19) -> (84, 43, 19)
MAPPING.put(152, 83); // (105, 61, 76) -> (105, 61, 76)
MAPPING.put(153, 83); // (129, 75, 93) -> (129, 75, 93)
MAPPING.put(154, 80); // (149, 87, 108) -> (149, 87, 108)
MAPPING.put(155, 115); // (79, 46, 57) -> (79, 46, 57)
MAPPING.put(156, 39); // (79, 76, 97) -> (79, 76, 97)
MAPPING.put(157, 39); // (97, 93, 119) -> (97, 93, 119)
MAPPING.put(158, 36); // (112, 108, 138) -> (112, 108, 138)
MAPPING.put(159, 47); // (59, 57, 73) -> (59, 57, 73)
MAPPING.put(160, 60); // (131, 94, 25) -> (131, 94, 25)
MAPPING.put(161, 61); // (160, 115, 31) -> (160, 115, 31)
MAPPING.put(162, 62); // (186, 133, 36) -> (186, 133, 36)
MAPPING.put(163, 137); // (98, 70, 19) -> (98, 70, 19)
MAPPING.put(164, 108); // (73, 83, 37) -> (73, 83, 37)
MAPPING.put(165, 108); // (89, 101, 46) -> (89, 101, 46)
MAPPING.put(166, 109); // (103, 117, 53) -> (103, 117, 53)
MAPPING.put(167, 111); // (55, 62, 28) -> (55, 62, 28)
MAPPING.put(168, 112); // (113, 54, 55) -> (113, 54, 55)
MAPPING.put(169, 113); // (138, 66, 67) -> (138, 66, 67)
MAPPING.put(170, 114); // (160, 77, 78) -> (160, 77, 78)
MAPPING.put(171, 115); // (85, 41, 41) -> (85, 41, 41)
MAPPING.put(172, 118); // (40, 29, 25) -> (40, 29, 25)
MAPPING.put(173, 107); // (49, 35, 30) -> (49, 35, 30)
MAPPING.put(174, 107); // (57, 41, 35) -> (57, 41, 35)
MAPPING.put(175, 118); // (30, 22, 19) -> (30, 22, 19)
MAPPING.put(176, 91); // (95, 76, 69) -> (95, 76, 69)
MAPPING.put(177, 45); // (116, 92, 85) -> (116, 92, 85)
MAPPING.put(178, 46); // (135, 107, 98) -> (135, 107, 98)
MAPPING.put(179, 47); // (71, 57, 52) -> (71, 57, 52)
MAPPING.put(180, 85); // (61, 65, 65) -> (61, 65, 65)
MAPPING.put(181, 44); // (75, 79, 79) -> (75, 79, 79)
MAPPING.put(182, 27); // (87, 92, 92) -> (87, 92, 92)
MAPPING.put(183, 84); // (46, 49, 49) -> (46, 49, 49)
MAPPING.put(184, 83); // (86, 52, 62) -> (86, 52, 62)
MAPPING.put(185, 83); // (105, 63, 76) -> (105, 63, 76)
MAPPING.put(186, 83); // (122, 73, 88) -> (122, 73, 88)
MAPPING.put(187, 84); // (65, 39, 47) -> (65, 39, 47)
MAPPING.put(188, 84); // (54, 44, 65) -> (54, 44, 65)
MAPPING.put(189, 71); // (66, 53, 79) -> (66, 53, 79)
MAPPING.put(190, 71); // (76, 62, 92) -> (76, 62, 92)
MAPPING.put(191, 87); // (40, 33, 49) -> (40, 33, 49)
MAPPING.put(192, 107); // (54, 35, 25) -> (54, 35, 25)
MAPPING.put(193, 139); // (66, 43, 30) -> (66, 43, 30)
MAPPING.put(194, 43); // (76, 50, 35) -> (76, 50, 35)
MAPPING.put(195, 107); // (40, 26, 19) -> (40, 26, 19)
MAPPING.put(196, 111); // (54, 58, 30) -> (54, 58, 30)
MAPPING.put(197, 111); // (66, 71, 36) -> (66, 71, 36)
MAPPING.put(198, 111); // (76, 82, 42) -> (76, 82, 42)
MAPPING.put(199, 107); // (40, 43, 22) -> (40, 43, 22)
MAPPING.put(200, 112); // (100, 42, 32) -> (100, 42, 32)
MAPPING.put(201, 113); // (123, 52, 40) -> (123, 52, 40)
MAPPING.put(202, 113); // (142, 60, 46) -> (142, 60, 46)
MAPPING.put(203, 115); // (75, 32, 24) -> (75, 32, 24)
MAPPING.put(204, 116); // (26, 16, 11) -> (26, 16, 11)
MAPPING.put(205, 117); // (32, 19, 14) -> (32, 19, 14)
MAPPING.put(206, 107); // (37, 22, 16) -> (37, 22, 16)
MAPPING.put(207, 119); // (20, 12, 8) -> (20, 12, 8)
}
public static int getNearestOldColor(int color) {
return MAPPING.getOrDefault(color, color);
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_12to1_11_1/rewriter/BlockItemPacketRewriter1_12.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntArrayTag;
import com.viaversion.nbt.tag.LongArrayTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.api.rewriters.LegacyBlockItemRewriter;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.data.MapColorMappings1_11_1;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_9_3;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ClientboundPackets1_12;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ServerboundPackets1_12;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.SerializerVersion;
import java.util.Iterator;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BlockItemPacketRewriter1_12 extends LegacyBlockItemRewriter {
public BlockItemPacketRewriter1_12(Protocol1_12To1_11_1 protocol) {
super(protocol, "1.12");
}
@Override
protected void registerPackets() {
registerBlockChange(ClientboundPackets1_12.BLOCK_UPDATE);
registerMultiBlockChange(ClientboundPackets1_12.CHUNK_BLOCKS_UPDATE);
protocol.registerClientbound(ClientboundPackets1_12.MAP_ITEM_DATA, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT);
map(Types.BYTE);
map(Types.BOOLEAN);
handler(wrapper -> {
int count = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < count * 3; i++) {
wrapper.passthrough(Types.BYTE);
}
});
handler(wrapper -> {
short columns = wrapper.passthrough(Types.UNSIGNED_BYTE);
if (columns <= 0) return;
wrapper.passthrough(Types.UNSIGNED_BYTE); // Rows
wrapper.passthrough(Types.UNSIGNED_BYTE); // X
wrapper.passthrough(Types.UNSIGNED_BYTE); // Z
byte[] data = wrapper.read(Types.BYTE_ARRAY_PRIMITIVE);
for (int i = 0; i < data.length; i++) {
short color = (short) (data[i] & 0xFF);
if (color > 143) {
color = (short) MapColorMappings1_11_1.getNearestOldColor(color);
data[i] = (byte) color;
}
}
wrapper.write(Types.BYTE_ARRAY_PRIMITIVE, data);
});
}
});
registerSetSlot(ClientboundPackets1_12.CONTAINER_SET_SLOT);
registerSetContent(ClientboundPackets1_12.CONTAINER_SET_CONTENT);
registerSetEquippedItem(ClientboundPackets1_12.SET_EQUIPPED_ITEM);
registerCustomPayloadTradeList(ClientboundPackets1_12.CUSTOM_PAYLOAD);
protocol.registerServerbound(ServerboundPackets1_9_3.CONTAINER_CLICK, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE); // 0 - Window ID
map(Types.SHORT); // 1 - Slot
map(Types.BYTE); // 2 - Button
map(Types.SHORT); // 3 - Action number
map(Types.VAR_INT); // 4 - Mode
map(Types.ITEM1_8); // 5 - Clicked Item
handler(wrapper -> {
if (wrapper.get(Types.VAR_INT, 0) == 1) { // Shift click
// https://github.com/ViaVersion/ViaVersion/pull/754
// Previously clients grab the item from the clicked slot *before* it has
// been moved however now they grab the slot item *after* it has been moved
// and send that in the packet.
wrapper.set(Types.ITEM1_8, 0, null); // Set null item (probably will work)
// Apologize (may happen in some cases, maybe if inventory is full?)
PacketWrapper confirm = wrapper.create(ServerboundPackets1_12.CONTAINER_ACK);
confirm.write(Types.BYTE, wrapper.get(Types.BYTE, 0));
confirm.write(Types.SHORT, wrapper.get(Types.SHORT, 1));
confirm.write(Types.BOOLEAN, true); // Success - not used
wrapper.sendToServer(Protocol1_12To1_11_1.class);
wrapper.cancel();
confirm.sendToServer(Protocol1_12To1_11_1.class);
return;
}
Item item = wrapper.get(Types.ITEM1_8, 0);
handleItemToServer(wrapper.user(), item);
});
}
});
registerSetCreativeModeSlot(ServerboundPackets1_9_3.SET_CREATIVE_MODE_SLOT);
protocol.registerClientbound(ClientboundPackets1_12.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_12To1_11_1.class);
ChunkType1_9_3 type = ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment()); // Use the 1.9.4 Chunk type since nothing changed.
Chunk chunk = wrapper.passthrough(type);
handleChunk(chunk);
for (final CompoundTag tag : chunk.getBlockEntities()) {
final String id = tag.getString("id");
if (id == null) {
continue;
}
if (Key.stripMinecraftNamespace(id).equals("sign")) {
handleSignText(tag);
}
}
});
protocol.registerClientbound(ClientboundPackets1_12.BLOCK_ENTITY_DATA, new PacketHandlers() {
@Override
public void register() {
map(Types.BLOCK_POSITION1_8); // 0 - Position
map(Types.UNSIGNED_BYTE); // 1 - Action
map(Types.NAMED_COMPOUND_TAG); // 2 - NBT
handler(wrapper -> {
final short type = wrapper.get(Types.UNSIGNED_BYTE, 0);
if (type == 9) {
final CompoundTag tag = wrapper.get(Types.NAMED_COMPOUND_TAG, 0);
handleSignText(tag);
} else if (type == 11) {
// Remove bed color
wrapper.cancel();
}
});
}
});
protocol.getEntityRewriter().filter().handler((event, data) -> {
if (data.dataType().type().equals(Types.ITEM1_8)) // Is Item
data.setValue(handleItemToClient(event.user(), (Item) data.getValue()));
});
protocol.registerServerbound(ServerboundPackets1_9_3.CLIENT_COMMAND, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Action ID
handler(wrapper -> {
// Open Inventory
if (wrapper.get(Types.VAR_INT, 0) == 2) {
wrapper.cancel();
}
});
}
});
}
private void handleSignText(final CompoundTag tag) {
// Push signs through component conversion, fixes https://github.com/ViaVersion/ViaBackwards/issues/835
for (int i = 0; i < 4; i++) {
final StringTag lineTag = tag.getStringTag("Text" + (i + 1));
if (lineTag == null) {
continue;
}
lineTag.setValue(ComponentUtil.convertJsonOrEmpty(lineTag.getValue(), SerializerVersion.V1_12, SerializerVersion.V1_9).toString());
}
}
@Override
public @Nullable Item handleItemToClient(UserConnection connection, Item item) {
if (item == null) return null;
super.handleItemToClient(connection, item);
if (item.tag() != null) {
CompoundTag backupTag = new CompoundTag();
if (handleNbtToClient(item.tag(), backupTag)) {
item.tag().put("Via|LongArrayTags", backupTag);
}
}
return item;
}
private boolean handleNbtToClient(CompoundTag compoundTag, CompoundTag backupTag) {
// Long array tags were introduced in 1.12 - just remove them
// Only save the removed tags instead of blindly copying the entire nbt again
Iterator> iterator = compoundTag.iterator();
boolean hasLongArrayTag = false;
while (iterator.hasNext()) {
Map.Entry entry = iterator.next();
if (entry.getValue() instanceof CompoundTag tag) {
CompoundTag nestedBackupTag = new CompoundTag();
backupTag.put(entry.getKey(), nestedBackupTag);
hasLongArrayTag |= handleNbtToClient(tag, nestedBackupTag);
} else if (entry.getValue() instanceof LongArrayTag tag) {
backupTag.put(entry.getKey(), fromLongArrayTag(tag));
iterator.remove();
hasLongArrayTag = true;
}
}
return hasLongArrayTag;
}
@Override
public @Nullable Item handleItemToServer(UserConnection connection, Item item) {
if (item == null) return null;
item = super.handleItemToServer(connection, item);
if (item.tag() != null) {
if (item.tag().remove("Via|LongArrayTags") instanceof CompoundTag tag) {
handleNbtToServer(item.tag(), tag);
}
}
return item;
}
private void handleNbtToServer(CompoundTag compoundTag, CompoundTag backupTag) {
// Restore the removed long array tags
for (Map.Entry entry : backupTag) {
if (entry.getValue() instanceof CompoundTag) {
CompoundTag nestedTag = compoundTag.getCompoundTag(entry.getKey());
handleNbtToServer(nestedTag, (CompoundTag) entry.getValue());
} else {
compoundTag.put(entry.getKey(), fromIntArrayTag((IntArrayTag) entry.getValue()));
}
}
}
private IntArrayTag fromLongArrayTag(LongArrayTag tag) {
int[] intArray = new int[tag.length() * 2];
long[] longArray = tag.getValue();
int i = 0;
for (long l : longArray) {
intArray[i++] = (int) (l >> 32);
intArray[i++] = (int) l;
}
return new IntArrayTag(intArray);
}
private LongArrayTag fromIntArrayTag(IntArrayTag tag) {
long[] longArray = new long[tag.length() / 2];
int[] intArray = tag.getValue();
for (int i = 0, j = 0; i < intArray.length; i += 2, j++) {
longArray[j] = (long) intArray[i] << 32 | ((long) intArray[i + 1] & 0xFFFFFFFFL);
}
return new LongArrayTag(longArray);
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_12to1_11_1/rewriter/ComponentRewriter1_12.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter;
import com.viaversion.viabackwards.api.rewriters.text.JsonNBTComponentRewriter;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ClientboundPackets1_12;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
public class ComponentRewriter1_12 extends JsonNBTComponentRewriter {
public ComponentRewriter1_12(Protocol1_12To1_11_1 protocol) {
super(protocol, ComponentRewriterBase.ReadType.JSON);
}
@Override
public void processText(UserConnection connection, JsonElement element) {
super.processText(connection, element);
if (element == null || !element.isJsonObject()) {
return;
}
JsonObject object = element.getAsJsonObject();
JsonElement keybind = object.remove("keybind");
if (keybind == null) {
return;
}
//TODO Add nicer text for the key, also use this component rewriter in more packets
object.addProperty("text", keybind.getAsString());
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_12to1_11_1/rewriter/EntityPacketRewriter1_12.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.storage.ParrotStorage;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.storage.ShoulderTracker;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_12;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_12;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ClientboundPackets1_12;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
public class EntityPacketRewriter1_12 extends LegacyEntityRewriter {
public EntityPacketRewriter1_12(Protocol1_12To1_11_1 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_12.ADD_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity id
map(Types.UUID); // 1 - UUID
map(Types.BYTE); // 2 - Type
map(Types.DOUBLE); // 3 - x
map(Types.DOUBLE); // 4 - y
map(Types.DOUBLE); // 5 - z
map(Types.BYTE); // 6 - Pitch
map(Types.BYTE); // 7 - Yaw
map(Types.INT); // 8 - data
// Track Entity
handler(getObjectTrackerHandler());
handler(getObjectRewriter(EntityTypes1_12.ObjectType::findById));
handler(protocol.getItemRewriter().getFallingBlockHandler());
}
});
registerTracker(ClientboundPackets1_12.ADD_EXPERIENCE_ORB, EntityTypes1_12.EntityType.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_12.ADD_GLOBAL_ENTITY, EntityTypes1_12.EntityType.LIGHTNING_BOLT);
protocol.registerClientbound(ClientboundPackets1_12.ADD_MOB, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity id
map(Types.UUID); // 1 - UUID
map(Types.VAR_INT); // 2 - Entity Type
map(Types.DOUBLE); // 3 - X
map(Types.DOUBLE); // 4 - Y
map(Types.DOUBLE); // 5 - Z
map(Types.BYTE); // 6 - Yaw
map(Types.BYTE); // 7 - Pitch
map(Types.BYTE); // 8 - Head Pitch
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types.ENTITY_DATA_LIST1_12, Types.ENTITY_DATA_LIST1_9); // 12 - Entity data
// Track entity
handler(getTrackerHandler());
// Rewrite entity type / data
handler(getMobSpawnRewriter1_11(Types.ENTITY_DATA_LIST1_9));
}
});
registerTracker(ClientboundPackets1_12.ADD_PAINTING, EntityTypes1_12.EntityType.PAINTING);
protocol.registerClientbound(ClientboundPackets1_12.ADD_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types.UUID); // 1 - Player UUID
map(Types.DOUBLE); // 2 - X
map(Types.DOUBLE); // 3 - Y
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types.ENTITY_DATA_LIST1_12, Types.ENTITY_DATA_LIST1_9); // 7 - Entity data list
handler(getTrackerAndDataHandler(Types.ENTITY_DATA_LIST1_9, EntityTypes1_12.EntityType.PLAYER));
}
});
protocol.registerClientbound(ClientboundPackets1_12.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Entity ID
map(Types.UNSIGNED_BYTE); // 1 - Gamemode
map(Types.INT); // 2 - Dimension
handler(getDimensionHandler(1));
handler(getPlayerTrackerHandler());
handler(wrapper -> {
ShoulderTracker tracker = wrapper.user().get(ShoulderTracker.class);
tracker.setEntityId(wrapper.get(Types.INT, 0));
});
// Send fake inventory achievement
handler(packetWrapper -> {
PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_9_3.AWARD_STATS, packetWrapper.user());
wrapper.write(Types.VAR_INT, 1);
wrapper.write(Types.STRING, "achievement.openInventory");
wrapper.write(Types.VAR_INT, 1);
wrapper.scheduleSend(Protocol1_12To1_11_1.class);
});
}
});
registerRespawn(ClientboundPackets1_12.RESPAWN);
registerRemoveEntities(ClientboundPackets1_12.REMOVE_ENTITIES);
registerSetEntityData(ClientboundPackets1_12.SET_ENTITY_DATA, Types.ENTITY_DATA_LIST1_12, Types.ENTITY_DATA_LIST1_9);
protocol.registerClientbound(ClientboundPackets1_12.UPDATE_ATTRIBUTES, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT);
map(Types.INT);
handler(wrapper -> {
int size = wrapper.get(Types.INT, 0);
int newSize = size;
for (int i = 0; i < size; i++) {
String key = wrapper.read(Types.STRING);
// Remove new attribute
if (key.equals("generic.flyingSpeed")) {
newSize--;
wrapper.read(Types.DOUBLE);
int modSize = wrapper.read(Types.VAR_INT);
for (int j = 0; j < modSize; j++) {
wrapper.read(Types.UUID);
wrapper.read(Types.DOUBLE);
wrapper.read(Types.BYTE);
}
} else {
wrapper.write(Types.STRING, key);
wrapper.passthrough(Types.DOUBLE);
int modSize = wrapper.passthrough(Types.VAR_INT);
for (int j = 0; j < modSize; j++) {
wrapper.passthrough(Types.UUID);
wrapper.passthrough(Types.DOUBLE);
wrapper.passthrough(Types.BYTE);
}
}
}
if (newSize != size) {
wrapper.set(Types.INT, 0, newSize);
}
});
}
});
}
@Override
protected void registerRewrites() {
mapEntityTypeWithData(EntityTypes1_12.EntityType.PARROT, EntityTypes1_12.EntityType.BAT).plainName().spawnEntityData(storage -> storage.add(new EntityData(12, EntityDataTypes1_12.BYTE, (byte) 0x00)));
mapEntityTypeWithData(EntityTypes1_12.EntityType.ILLUSIONER, EntityTypes1_12.EntityType.EVOKER).plainName();
filter().handler((event, data) -> {
if (data.dataType() == EntityDataTypes1_12.COMPONENT) {
protocol.getComponentRewriter().processText(event.user(), (JsonElement) data.getValue());
}
});
// Handle Illager
filter().type(EntityTypes1_12.EntityType.EVOKER).removeIndex(12);
filter().type(EntityTypes1_12.EntityType.ILLUSIONER).index(0).handler((event, data) -> {
byte mask = (byte) data.getValue();
if ((mask & 0x20) == 0x20) {
mask &= ~0x20;
}
data.setValue(mask);
});
// Create Parrot storage
filter().type(EntityTypes1_12.EntityType.PARROT).handler((event, data) -> {
StoredEntityData entityData = storedEntityData(event);
if (!entityData.has(ParrotStorage.class)) {
entityData.put(new ParrotStorage());
}
});
// Parrot remove animal entity data
filter().type(EntityTypes1_12.EntityType.PARROT).cancel(12); // Is baby
filter().type(EntityTypes1_12.EntityType.PARROT).index(13).handler((event, data) -> {
StoredEntityData entityData = storedEntityData(event);
ParrotStorage storage = entityData.get(ParrotStorage.class);
boolean isSitting = (((byte) data.getValue()) & 0x01) == 0x01;
boolean isTamed = (((byte) data.getValue()) & 0x04) == 0x04;
if (!storage.isTamed() && isTamed) {
// TODO do something to let the user know it's done
}
storage.setTamed(isTamed);
if (isSitting) {
event.setIndex(12);
data.setValue((byte) 0x01);
storage.setSitting(true);
} else if (storage.isSitting()) {
event.setIndex(12);
data.setValue((byte) 0x00);
storage.setSitting(false);
} else {
event.cancel();
}
}); // Flags (Is sitting etc, might be useful in the future
filter().type(EntityTypes1_12.EntityType.PARROT).cancel(14); // Owner
filter().type(EntityTypes1_12.EntityType.PARROT).cancel(15); // Variant
// Left shoulder entity data
filter().type(EntityTypes1_12.EntityType.PLAYER).index(15).handler((event, data) -> {
CompoundTag tag = (CompoundTag) data.getValue();
ShoulderTracker tracker = event.user().get(ShoulderTracker.class);
if (tag.isEmpty() && tracker.getLeftShoulder() != null) {
tracker.setLeftShoulder(null);
tracker.update();
} else if (tag.getStringTag("id") != null && event.entityId() == tracker.getEntityId()) {
String id = tag.getStringTag("id").getValue();
if (tracker.getLeftShoulder() == null || !tracker.getLeftShoulder().equals(id)) {
tracker.setLeftShoulder(id);
tracker.update();
}
}
event.cancel();
});
// Right shoulder entity data
filter().type(EntityTypes1_12.EntityType.PLAYER).index(16).handler((event, data) -> {
CompoundTag tag = (CompoundTag) event.data().getValue();
ShoulderTracker tracker = event.user().get(ShoulderTracker.class);
if (tag.isEmpty() && tracker.getRightShoulder() != null) {
tracker.setRightShoulder(null);
tracker.update();
} else if (tag.getStringTag("id") != null && event.entityId() == tracker.getEntityId()) {
String id = tag.getStringTag("id").getValue();
if (tracker.getRightShoulder() == null || !tracker.getRightShoulder().equals(id)) {
tracker.setRightShoulder(id);
tracker.update();
}
}
event.cancel();
});
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_12.EntityType.findById(typeId);
}
@Override
public EntityType objectTypeFromId(int typeId, int data) {
return EntityTypes1_12.ObjectType.getEntityType(typeId, data);
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_12to1_11_1/rewriter/SoundPacketRewriter1_12.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_12to1_11_1.rewriter;
import com.viaversion.viabackwards.api.rewriters.LegacySoundRewriter;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ClientboundPackets1_12;
public class SoundPacketRewriter1_12 extends LegacySoundRewriter {
public SoundPacketRewriter1_12(Protocol1_12To1_11_1 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.replaceClientbound(ClientboundPackets1_12.SOUND, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Sound name
map(Types.VAR_INT); // 1 - Sound Category
map(Types.INT); // 2 - x
map(Types.INT); // 3 - y
map(Types.INT); // 4 - z
map(Types.FLOAT); // 5 - Volume
map(Types.FLOAT); // 6 - Pitch
handler(wrapper -> {
int oldId = wrapper.get(Types.VAR_INT, 0);
int newId = handleSounds(oldId);
if (newId == -1) {
wrapper.cancel();
return;
}
if (hasPitch(oldId)) {
wrapper.set(Types.FLOAT, 1, handlePitch(oldId));
}
wrapper.set(Types.VAR_INT, 0, newId);
});
}
});
}
@Override
protected void registerRewrites() {
//TODO use the diff file to also have named sound remaps
// (there were *A LOT* of refactored names)
// Replacement sounds, suggestions are always welcome
// Automatically generated from PAaaS
added(26, 277, 1.4f); // block.end_portal.spawn -> entity.lightning.thunder
added(27, -1); // block.end_portal_frame.fill
added(72, 70); // block.note.bell -> block.note.harp
added(73, 70); // block.note.chime -> block.note.harp
added(74, 70); // block.note.flute -> block.note.harp
added(75, 70); // block.note.guitar -> block.note.harp
added(80, 70); // block.note.xylophone -> block.note.harp
added(150, -1); // entity.boat.paddle_land
added(151, -1); // entity.boat.paddle_water
added(152, -1); // entity.bobber.retrieve
added(195, -1); // entity.endereye.death
added(274, 198, 0.8f); // entity.illusion_illager.ambient -> entity.evocation_illager.ambient
added(275, 199, 0.8f); // entity.illusion_illager.cast_spell -> entity.evocation_illager.cast_spell
added(276, 200, 0.8f); // entity.illusion_illager.death -> entity.evocation_illager.death
added(277, 201, 0.8f); // entity.illusion_illager.hurt -> entity.evocation_illager.hurt
added(278, 191, 0.9f); // entity.illusion_illager.mirror_move -> entity.endermen.teleport
added(279, 203, 1.5f); // entity.illusion_illager.prepare_blindness -> entity.evocation_illager.prepare_summon
added(280, 202, 0.8f); // entity.illusion_illager.prepare_mirror -> entity.evocation_illager.prepare_attack
added(319, 133, 0.6f); // entity.parrot.ambient -> entity.bat.ambient
added(320, 134, 1.7f); // entity.parrot.death -> entity.bat.death
added(321, 219, 1.5f); // entity.parrot.eat -> entity.generic.eat
added(322, 136, 0.7f); // entity.parrot.fly -> entity.bat.loop
added(323, 135, 1.6f); // entity.parrot.hurt -> entity.bat.hurt
added(324, 138, 1.5f); // entity.parrot.imitate.blaze -> entity.blaze.ambient
added(325, 163, 1.5f); // entity.parrot.imitate.creeper -> entity.creeper.primed
added(326, 170, 1.5f); // entity.parrot.imitate.elder_guardian -> entity.elder_guardian.ambient
added(327, 178, 1.5f); // entity.parrot.imitate.enderdragon -> entity.enderdragon.ambient
added(328, 186, 1.5f); // entity.parrot.imitate.enderman -> entity.endermen.ambient
added(329, 192, 1.5f); // entity.parrot.imitate.endermite -> entity.endermite.ambient
added(330, 198, 1.5f); // entity.parrot.imitate.evocation_illager -> entity.evocation_illager.ambient
added(331, 226, 1.5f); // entity.parrot.imitate.ghast -> entity.ghast.ambient
added(332, 259, 1.5f); // entity.parrot.imitate.husk -> entity.husk.ambient
added(333, 198, 1.3f); // entity.parrot.imitate.illusion_illager -> entity.evocation_illager.ambient
added(334, 291, 1.5f); // entity.parrot.imitate.magmacube -> entity.magmacube.squish
added(335, 321, 1.5f); // entity.parrot.imitate.polar_bear -> entity.polar_bear.ambient
added(336, 337, 1.5f); // entity.parrot.imitate.shulker -> entity.shulker.ambient
added(337, 347, 1.5f); // entity.parrot.imitate.silverfish -> entity.silverfish.ambient
added(338, 351, 1.5f); // entity.parrot.imitate.skeleton -> entity.skeleton.ambient
added(339, 363, 1.5f); // entity.parrot.imitate.slime -> entity.slime.squish
added(340, 376, 1.5f); // entity.parrot.imitate.spider -> entity.spider.ambient
added(341, 385, 1.5f); // entity.parrot.imitate.stray -> entity.stray.ambient
added(342, 390, 1.5f); // entity.parrot.imitate.vex -> entity.vex.ambient
added(343, 400, 1.5f); // entity.parrot.imitate.vindication_illager -> entity.vindication_illager.ambient
added(344, 403, 1.5f); // entity.parrot.imitate.witch -> entity.witch.ambient
added(345, 408, 1.5f); // entity.parrot.imitate.wither -> entity.wither.ambient
added(346, 414, 1.5f); // entity.parrot.imitate.wither_skeleton -> entity.wither_skeleton.ambient
added(347, 418, 1.5f); // entity.parrot.imitate.wolf -> entity.wolf.ambient
added(348, 427, 1.5f); // entity.parrot.imitate.zombie -> entity.zombie.ambient
added(349, 438, 1.5f); // entity.parrot.imitate.zombie_pigman -> entity.zombie_pig.ambient
added(350, 442, 1.5f); // entity.parrot.imitate.zombie_villager -> entity.zombie_villager.ambient
added(351, 155); // entity.parrot.step -> entity.chicken.step
added(368, 316); // entity.player.hurt_drown -> entity.player.hurt
added(369, 316); // entity.player.hurt_on_fire -> entity.player.hurt
// No replacement sounds for these, since it could be confusing, the toast doesn't show up
added(544, -1); // ui.toast.in
added(545, -1); // ui.toast.out
added(546, 317, 1.5f); // ui.toast.challenge_complete
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_12to1_11_1/storage/ParrotStorage.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_12to1_11_1.storage;
public class ParrotStorage {
private boolean tamed = true;
private boolean sitting = true;
public boolean isTamed() {
return tamed;
}
public void setTamed(boolean tamed) {
this.tamed = tamed;
}
public boolean isSitting() {
return sitting;
}
public void setSitting(boolean sitting) {
this.sitting = sitting;
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_12to1_11_1/storage/ShoulderTracker.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_12to1_11_1.storage;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1;
import com.viaversion.viaversion.api.connection.StoredObject;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ClientboundPackets1_12;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.Key;
import java.util.Locale;
public class ShoulderTracker extends StoredObject {
private int entityId;
private String leftShoulder;
private String rightShoulder;
public ShoulderTracker(UserConnection user) {
super(user);
}
public void update() {
PacketWrapper wrapper = PacketWrapper.create(ClientboundPackets1_12.CHAT, getUser());
try {
wrapper.write(Types.COMPONENT, ComponentUtil.plainToJson(generateString()));
} catch (final Exception e) {
throw new RuntimeException(e);
}
wrapper.write(Types.BYTE, (byte) 2);
try {
wrapper.scheduleSend(Protocol1_12To1_11_1.class);
} catch (Exception e) {
ViaBackwards.getPlatform().getLogger().severe("Failed to send the shoulder indication");
e.printStackTrace();
}
}
// Does actionbar not support json colors? :(
private String generateString() {
StringBuilder builder = new StringBuilder();
// Empty spaces because the non-json formatting is weird
builder.append(" ");
if (leftShoulder == null) {
builder.append("§4§lNothing");
} else {
builder.append("§2§l").append(getName(leftShoulder));
}
builder.append("§8§l <- §7§lShoulders§8§l -> ");
if (rightShoulder == null) {
builder.append("§4§lNothing");
} else {
builder.append("§2§l").append(getName(rightShoulder));
}
return builder.toString();
}
private String getName(String current) {
current = Key.stripMinecraftNamespace(current);
String[] array = current.split("_");
StringBuilder builder = new StringBuilder();
for (String s : array) {
builder.append(s.substring(0, 1).toUpperCase(Locale.ROOT))
.append(s.substring(1))
.append(" ");
}
return builder.toString();
}
public int getEntityId() {
return entityId;
}
public void setEntityId(int entityId) {
this.entityId = entityId;
}
public String getLeftShoulder() {
return leftShoulder;
}
public void setLeftShoulder(String leftShoulder) {
this.leftShoulder = leftShoulder;
}
public String getRightShoulder() {
return rightShoulder;
}
public void setRightShoulder(String rightShoulder) {
this.rightShoulder = rightShoulder;
}
@Override
public String toString() {
return "ShoulderTracker{" + "entityId=" + entityId + ", leftShoulder='" + leftShoulder + '\'' + ", rightShoulder='" + rightShoulder + '\'' + '}';
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_13_1to1_13/Protocol1_13_1To1_13.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_13_1to1_13;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.data.BackwardsMappingData;
import com.viaversion.viabackwards.api.rewriters.text.JsonNBTComponentRewriter;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.rewriter.CommandRewriter1_13_1;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.rewriter.EntityPacketRewriter1_13_1;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.rewriter.ItemPacketRewriter1_13_1;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.rewriter.WorldPacketRewriter1_13_1;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.RegistryType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_13;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ServerboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_13to1_13_1.Protocol1_13To1_13_1;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.util.ComponentUtil;
public class Protocol1_13_1To1_13 extends BackwardsProtocol {
public static final BackwardsMappingData MAPPINGS = new BackwardsMappingData("1.13.2", "1.13", Protocol1_13To1_13_1.class);
private final EntityPacketRewriter1_13_1 entityRewriter = new EntityPacketRewriter1_13_1(this);
private final ItemPacketRewriter1_13_1 itemRewriter = new ItemPacketRewriter1_13_1(this);
private final ParticleRewriter particleRewriter = new ParticleRewriter<>(this);
private final JsonNBTComponentRewriter translatableRewriter = new JsonNBTComponentRewriter<>(this, ComponentRewriterBase.ReadType.JSON);
private final TagRewriter tagRewriter = new TagRewriter<>(this);
public Protocol1_13_1To1_13() {
super(ClientboundPackets1_13.class, ClientboundPackets1_13.class, ServerboundPackets1_13.class, ServerboundPackets1_13.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
WorldPacketRewriter1_13_1.register(this);
new CommandRewriter1_13_1(this).registerDeclareCommands(ClientboundPackets1_13.COMMANDS);
registerServerbound(ServerboundPackets1_13.COMMAND_SUGGESTION, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT);
map(Types.STRING, new ValueTransformer<>(Types.STRING) {
@Override
public String transform(PacketWrapper wrapper, String inputValue) {
// 1.13 starts sending slash at start, so we remove it for compatibility
return !inputValue.startsWith("/") ? "/" + inputValue : inputValue;
}
});
}
});
registerServerbound(ServerboundPackets1_13.EDIT_BOOK, wrapper -> {
final Item item = itemRewriter.handleItemToServer(wrapper.user(), wrapper.read(Types.ITEM1_13));
wrapper.write(Types.ITEM1_13, item);
wrapper.passthrough(Types.BOOLEAN);
wrapper.write(Types.VAR_INT, 0);
});
registerClientbound(ClientboundPackets1_13.OPEN_SCREEN, new PacketHandlers() {
@Override
public void register() {
map(Types.UNSIGNED_BYTE); // Id
map(Types.STRING); // Window Type
handler(wrapper -> {
JsonElement title = wrapper.passthrough(Types.COMPONENT);
translatableRewriter.processText(wrapper.user(), title);
if (ViaBackwards.getConfig().fix1_13FormattedInventoryTitle()) {
if (title.isJsonObject() && title.getAsJsonObject().size() == 1
&& title.getAsJsonObject().has("translate")) {
// Hotfix simple translatable components from being converted to legacy text
return;
}
// https://bugs.mojang.com/browse/MC-124543
JsonObject legacyComponent = new JsonObject();
legacyComponent.addProperty("text", ComponentUtil.jsonToLegacy(title));
wrapper.set(Types.COMPONENT, 0, legacyComponent);
}
});
}
});
registerClientbound(ClientboundPackets1_13.COMMAND_SUGGESTIONS, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Transaction id
map(Types.VAR_INT); // Start
map(Types.VAR_INT); // Length
map(Types.VAR_INT); // Count
handler(wrapper -> {
int start = wrapper.get(Types.VAR_INT, 1);
wrapper.set(Types.VAR_INT, 1, start - 1); // Offset by +1 to take into account / at beginning
// Passthrough suggestions
int count = wrapper.get(Types.VAR_INT, 3);
for (int i = 0; i < count; i++) {
wrapper.passthrough(Types.STRING);
wrapper.passthrough(Types.OPTIONAL_COMPONENT); // Tooltip
}
});
}
});
replaceClientbound(ClientboundPackets1_13.BOSS_EVENT, new PacketHandlers() {
@Override
public void register() {
map(Types.UUID);
map(Types.VAR_INT);
handler(wrapper -> {
int action = wrapper.get(Types.VAR_INT, 0);
if (action == 0 || action == 3) {
translatableRewriter.processText(wrapper.user(), wrapper.passthrough(Types.COMPONENT));
if (action == 0) {
wrapper.passthrough(Types.FLOAT);
wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.VAR_INT);
short flags = wrapper.read(Types.UNSIGNED_BYTE);
if ((flags & 0x04) != 0) flags |= 0x02;
wrapper.write(Types.UNSIGNED_BYTE, flags);
}
}
});
}
});
tagRewriter.register(ClientboundPackets1_13.UPDATE_TAGS, RegistryType.ITEM);
}
@Override
public void init(UserConnection user) {
user.addEntityTracker(getClass(), new EntityTrackerBase(user, EntityTypes1_13.EntityType.PLAYER));
user.addClientWorld(getClass(), new ClientWorld());
}
@Override
public BackwardsMappingData getMappingData() {
return MAPPINGS;
}
@Override
public EntityPacketRewriter1_13_1 getEntityRewriter() {
return entityRewriter;
}
@Override
public ItemPacketRewriter1_13_1 getItemRewriter() {
return itemRewriter;
}
@Override
public ParticleRewriter getParticleRewriter() {
return particleRewriter;
}
@Override
public JsonNBTComponentRewriter getComponentRewriter() {
return translatableRewriter;
}
public JsonNBTComponentRewriter translatableRewriter() {
return translatableRewriter;
}
@Override
public TagRewriter getTagRewriter() {
return tagRewriter;
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_13_1to1_13/rewriter/CommandRewriter1_13_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_13_1to1_13.rewriter;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.Protocol1_13_1To1_13;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.rewriter.CommandRewriter;
import org.checkerframework.checker.nullness.qual.Nullable;
public class CommandRewriter1_13_1 extends CommandRewriter {
public CommandRewriter1_13_1(Protocol1_13_1To1_13 protocol) {
super(protocol);
this.parserHandlers.put("minecraft:dimension", wrapper -> wrapper.write(Types.VAR_INT, 0)); // Single word
}
@Override
public @Nullable String handleArgumentType(String argumentType) {
if (argumentType.equals("minecraft:column_pos")) {
return "minecraft:vec2";
} else if (argumentType.equals("minecraft:dimension")) {
return "brigadier:string";
}
return super.handleArgumentType(argumentType);
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_13_1to1_13/rewriter/EntityPacketRewriter1_13_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_13_1to1_13.rewriter;
import com.viaversion.viabackwards.api.rewriters.LegacyEntityRewriter;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.Protocol1_13_1To1_13;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_13;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_13;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import java.util.List;
public class EntityPacketRewriter1_13_1 extends LegacyEntityRewriter {
public EntityPacketRewriter1_13_1(Protocol1_13_1To1_13 protocol) {
super(protocol);
}
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_13.ADD_ENTITY, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity id
map(Types.UUID); // 1 - UUID
map(Types.BYTE); // 2 - Type
map(Types.DOUBLE); // 3 - X
map(Types.DOUBLE); // 4 - Y
map(Types.DOUBLE); // 5 - Z
map(Types.BYTE); // 6 - Pitch
map(Types.BYTE); // 7 - Yaw
map(Types.INT); // 8 - Data
handler(wrapper -> {
int entityId = wrapper.get(Types.VAR_INT, 0);
byte type = wrapper.get(Types.BYTE, 0);
int data = wrapper.get(Types.INT, 0);
EntityTypes1_13.EntityType entType = EntityTypes1_13.ObjectType.getEntityType(type, data);
if (entType == null) {
return;
}
// Rewrite falling block
if (entType.is(EntityTypes1_13.EntityType.FALLING_BLOCK)) {
wrapper.set(Types.INT, 0, protocol.getMappingData().getNewBlockStateId(data));
}
// Track Entity
tracker(wrapper.user()).addEntity(entityId, entType);
});
}
});
registerTracker(ClientboundPackets1_13.ADD_EXPERIENCE_ORB, EntityTypes1_13.EntityType.EXPERIENCE_ORB);
registerTracker(ClientboundPackets1_13.ADD_GLOBAL_ENTITY, EntityTypes1_13.EntityType.LIGHTNING_BOLT);
protocol.registerClientbound(ClientboundPackets1_13.ADD_MOB, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types.UUID); // 1 - Entity UUID
map(Types.VAR_INT); // 2 - Entity Type
map(Types.DOUBLE); // 3 - X
map(Types.DOUBLE); // 4 - Y
map(Types.DOUBLE); // 5 - Z
map(Types.BYTE); // 6 - Yaw
map(Types.BYTE); // 7 - Pitch
map(Types.BYTE); // 8 - Head Pitch
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types1_13.ENTITY_DATA_LIST); // 12 - Entity data
// Track Entity
handler(getTrackerHandler());
// Rewrite Entity data
handler(wrapper -> {
List entityDataList = wrapper.get(Types1_13.ENTITY_DATA_LIST, 0);
handleEntityData(wrapper.get(Types.VAR_INT, 0), entityDataList, wrapper.user());
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.ADD_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types.UUID); // 1 - Player UUID
map(Types.DOUBLE); // 2 - X
map(Types.DOUBLE); // 3 - Y
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types1_13.ENTITY_DATA_LIST); // 7 - Entity data
handler(getTrackerAndDataHandler(Types1_13.ENTITY_DATA_LIST, EntityTypes1_13.EntityType.PLAYER));
}
});
registerTracker(ClientboundPackets1_13.ADD_PAINTING, EntityTypes1_13.EntityType.PAINTING);
registerJoinGame(ClientboundPackets1_13.LOGIN, EntityTypes1_13.EntityType.PLAYER);
registerRespawn(ClientboundPackets1_13.RESPAWN);
registerSetEntityData(ClientboundPackets1_13.SET_ENTITY_DATA, Types1_13.ENTITY_DATA_LIST);
}
@Override
protected void registerRewrites() {
// Rewrite items & blocks
filter().handler((event, data) -> {
if (data.dataType() == Types1_13.ENTITY_DATA_TYPES.itemType) {
data.setValue(protocol.getItemRewriter().handleItemToClient(event.user(), (Item) data.getValue()));
} else if (data.dataType() == Types1_13.ENTITY_DATA_TYPES.optionalBlockStateType) {
// Convert to new block id
int value = (int) data.getValue();
data.setValue(protocol.getMappingData().getNewBlockStateId(value));
} else if (data.dataType() == Types1_13.ENTITY_DATA_TYPES.particleType) {
protocol.getParticleRewriter().rewriteParticle(event.user(), (Particle) data.getValue());
} else if (data.dataType() == Types1_13.ENTITY_DATA_TYPES.optionalComponentType || data.dataType() == Types1_13.ENTITY_DATA_TYPES.componentType) {
JsonElement element = data.value();
protocol.translatableRewriter().processText(event.user(), element);
}
});
// Remove shooter UUID
filter().type(EntityTypes1_13.EntityType.ABSTRACT_ARROW).cancel(7);
// Move colors to old position
filter().type(EntityTypes1_13.EntityType.SPECTRAL_ARROW).index(8).toIndex(7);
// Move loyalty level to old position
filter().type(EntityTypes1_13.EntityType.TRIDENT).index(8).toIndex(7);
// Rewrite Minecart blocks
registerBlockStateHandler(EntityTypes1_13.EntityType.ABSTRACT_MINECART, 9);
}
@Override
public EntityType typeFromId(int typeId) {
return EntityTypes1_13.EntityType.findById(typeId);
}
@Override
public EntityType objectTypeFromId(int typeId, int data) {
return EntityTypes1_13.ObjectType.getEntityType(typeId, data);
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_13_1to1_13/rewriter/ItemPacketRewriter1_13_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_13_1to1_13.rewriter;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.Protocol1_13_1To1_13;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ServerboundPackets1_13;
import com.viaversion.viaversion.rewriter.ItemRewriter;
public class ItemPacketRewriter1_13_1 extends ItemRewriter {
public ItemPacketRewriter1_13_1(Protocol1_13_1To1_13 protocol) {
super(protocol, Types.ITEM1_13, Types.ITEM1_13_SHORT_ARRAY);
}
@Override
public void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_13.CUSTOM_PAYLOAD, wrapper -> {
String channel = wrapper.passthrough(Types.STRING);
if (channel.equals("minecraft:trader_list")) {
wrapper.passthrough(Types.INT); //Passthrough Window ID
int size = wrapper.passthrough(Types.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
passthroughClientboundItem(wrapper); // Input
passthroughClientboundItem(wrapper); // Output
boolean secondItem = wrapper.passthrough(Types.BOOLEAN); //Has second item
if (secondItem) {
passthroughClientboundItem(wrapper); // Second item
}
wrapper.passthrough(Types.BOOLEAN); //Trade disabled
wrapper.passthrough(Types.INT); //Number of tools uses
wrapper.passthrough(Types.INT); //Maximum number of trade uses
}
}
});
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_13_1to1_13/rewriter/WorldPacketRewriter1_13_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_13_1to1_13.rewriter;
import com.viaversion.viabackwards.protocol.v1_13_1to1_13.Protocol1_13_1To1_13;
import com.viaversion.viaversion.api.minecraft.BlockFace;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.rewriter.BlockRewriter;
public class WorldPacketRewriter1_13_1 {
public static void register(Protocol1_13_1To1_13 protocol) {
BlockRewriter blockRewriter = BlockRewriter.legacy(protocol);
protocol.registerClientbound(ClientboundPackets1_13.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_13_1To1_13.class);
Chunk chunk = wrapper.passthrough(ChunkType1_13.forEnvironment(clientWorld.getEnvironment()));
blockRewriter.handleChunk(chunk);
});
blockRewriter.registerBlockEvent(ClientboundPackets1_13.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_13.BLOCK_UPDATE);
blockRewriter.registerChunkBlocksUpdate(ClientboundPackets1_13.CHUNK_BLOCKS_UPDATE);
protocol.registerClientbound(ClientboundPackets1_13.LEVEL_EVENT, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // Effect Id
map(Types.BLOCK_POSITION1_8); // Location
map(Types.INT); // Data
handler(wrapper -> {
int id = wrapper.get(Types.INT, 0);
int data = wrapper.get(Types.INT, 1);
if (id == 1010) { // Play record
wrapper.set(Types.INT, 1, protocol.getMappingData().getNewItemId(data));
} else if (id == 2001) { // Block break + block break sound
wrapper.set(Types.INT, 1, protocol.getMappingData().getNewBlockStateId(data));
} else if (id == 2000) { // Smoke
switch (data) { // Down
case 0, 1 -> { // Up
BlockPosition pos = wrapper.get(Types.BLOCK_POSITION1_8, 0);
BlockFace relative = data == 0 ? BlockFace.BOTTOM : BlockFace.TOP;
wrapper.set(Types.BLOCK_POSITION1_8, 0, pos.getRelative(relative)); // Y Offset
wrapper.set(Types.INT, 1, 4); // Self
}
case 2 -> wrapper.set(Types.INT, 1, 1); // North
case 3 -> wrapper.set(Types.INT, 1, 7); // South
case 4 -> wrapper.set(Types.INT, 1, 3); // West
case 5 -> wrapper.set(Types.INT, 1, 5); // East
}
}
});
}
});
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_13_2to1_13_1/Protocol1_13_2To1_13_1.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_13_2to1_13_1;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.rewriter.EntityPacketRewriter1_13_2;
import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.rewriter.ItemPacketRewriter1_13_2;
import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.rewriter.WorldPacketRewriter1_13_2;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ServerboundPackets1_13;
public class Protocol1_13_2To1_13_1 extends BackwardsProtocol {
public Protocol1_13_2To1_13_1() {
super(ClientboundPackets1_13.class, ClientboundPackets1_13.class, ServerboundPackets1_13.class, ServerboundPackets1_13.class);
}
@Override
protected void registerPackets() {
ItemPacketRewriter1_13_2.register(this);
WorldPacketRewriter1_13_2.register(this);
EntityPacketRewriter1_13_2.register(this);
registerServerbound(ServerboundPackets1_13.EDIT_BOOK, new PacketHandlers() {
@Override
public void register() {
map(Types.ITEM1_13, Types.ITEM1_13_2);
}
});
registerClientbound(ClientboundPackets1_13.UPDATE_ADVANCEMENTS, wrapper -> {
wrapper.passthrough(Types.BOOLEAN); // Reset/clear
int size = wrapper.passthrough(Types.VAR_INT); // Mapping size
for (int i = 0; i < size; i++) {
wrapper.passthrough(Types.STRING); // Identifier
wrapper.passthrough(Types.OPTIONAL_STRING); // Parent
// Display data
if (wrapper.passthrough(Types.BOOLEAN)) {
wrapper.passthrough(Types.COMPONENT); // Title
wrapper.passthrough(Types.COMPONENT); // Description
Item icon = wrapper.read(Types.ITEM1_13_2);
wrapper.write(Types.ITEM1_13, icon);
wrapper.passthrough(Types.VAR_INT); // Frame type
int flags = wrapper.passthrough(Types.INT); // Flags
if ((flags & 1) != 0)
wrapper.passthrough(Types.STRING); // Background texture
wrapper.passthrough(Types.FLOAT); // X
wrapper.passthrough(Types.FLOAT); // Y
}
wrapper.passthrough(Types.STRING_ARRAY); // Criteria
int arrayLength = wrapper.passthrough(Types.VAR_INT);
for (int array = 0; array < arrayLength; array++) {
wrapper.passthrough(Types.STRING_ARRAY); // String array
}
}
});
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_13_2to1_13_1/rewriter/EntityPacketRewriter1_13_2.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.rewriter;
import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.Protocol1_13_2To1_13_1;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_13;
import com.viaversion.viaversion.api.type.types.version.Types1_13_2;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
public class EntityPacketRewriter1_13_2 {
public static void register(Protocol1_13_2To1_13_1 protocol) {
protocol.registerClientbound(ClientboundPackets1_13.ADD_MOB, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types.UUID); // 1 - Entity UUID
map(Types.VAR_INT); // 2 - Entity Type
map(Types.DOUBLE); // 3 - X
map(Types.DOUBLE); // 4 - Y
map(Types.DOUBLE); // 5 - Z
map(Types.BYTE); // 6 - Yaw
map(Types.BYTE); // 7 - Pitch
map(Types.BYTE); // 8 - Head Pitch
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types1_13_2.ENTITY_DATA_LIST, Types1_13.ENTITY_DATA_LIST); // 12 - Entity data
handler(EntityPacketRewriter1_13_2::updateEntityData);
}
});
protocol.registerClientbound(ClientboundPackets1_13.ADD_PLAYER, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types.UUID); // 1 - Player UUID
map(Types.DOUBLE); // 2 - X
map(Types.DOUBLE); // 3 - Y
map(Types.DOUBLE); // 4 - Z
map(Types.BYTE); // 5 - Yaw
map(Types.BYTE); // 6 - Pitch
map(Types1_13_2.ENTITY_DATA_LIST, Types1_13.ENTITY_DATA_LIST); // 7 - Entity data
handler(EntityPacketRewriter1_13_2::updateEntityData);
}
});
protocol.registerClientbound(ClientboundPackets1_13.SET_ENTITY_DATA, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types1_13_2.ENTITY_DATA_LIST, Types1_13.ENTITY_DATA_LIST); // 1 - Entity data list
handler(EntityPacketRewriter1_13_2::updateEntityData);
}
});
}
private static void updateEntityData(final PacketWrapper wrapper) {
for (final EntityData data : wrapper.get(Types1_13.ENTITY_DATA_LIST, 0)) {
final EntityDataType dataType = Types1_13.ENTITY_DATA_TYPES.byId(data.dataType().typeId());
data.setDataType(dataType);
if (dataType == Types1_13.ENTITY_DATA_TYPES.particleType) {
final Particle particle = data.value();
if (particle.id() == 27) {
final Item item = particle.- getArgument(0).getValue();
particle.set(0, Types.ITEM1_13, item);
}
}
}
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_13_2to1_13_1/rewriter/ItemPacketRewriter1_13_2.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.rewriter;
import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.Protocol1_13_2To1_13_1;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ServerboundPackets1_13;
public class ItemPacketRewriter1_13_2 {
public static void register(Protocol1_13_2To1_13_1 protocol) {
protocol.registerClientbound(ClientboundPackets1_13.CONTAINER_SET_SLOT, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE); // 0 - Window ID
map(Types.SHORT); // 1 - Slot ID
map(Types.ITEM1_13_2, Types.ITEM1_13); // 2 - Slot Value
}
});
protocol.registerClientbound(ClientboundPackets1_13.CONTAINER_SET_CONTENT, new PacketHandlers() {
@Override
public void register() {
map(Types.UNSIGNED_BYTE); // 0 - Window ID
map(Types.ITEM1_13_2_SHORT_ARRAY, Types.ITEM1_13_SHORT_ARRAY); // 1 - Window Values
}
});
protocol.registerClientbound(ClientboundPackets1_13.CUSTOM_PAYLOAD, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Channel
handler(wrapper -> {
String channel = wrapper.get(Types.STRING, 0);
if (channel.equals("minecraft:trader_list") || channel.equals("trader_list")) {
wrapper.passthrough(Types.INT); // Passthrough Window ID
int size = wrapper.passthrough(Types.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
// Input Item
wrapper.write(Types.ITEM1_13, wrapper.read(Types.ITEM1_13_2));
// Output Item
wrapper.write(Types.ITEM1_13, wrapper.read(Types.ITEM1_13_2));
boolean secondItem = wrapper.passthrough(Types.BOOLEAN); // Has second item
if (secondItem) {
wrapper.write(Types.ITEM1_13, wrapper.read(Types.ITEM1_13_2));
}
wrapper.passthrough(Types.BOOLEAN); // Trade disabled
wrapper.passthrough(Types.INT); // Number of tools uses
wrapper.passthrough(Types.INT); // Maximum number of trade uses
}
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.SET_EQUIPPED_ITEM, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // 0 - Entity ID
map(Types.VAR_INT); // 1 - Slot ID
map(Types.ITEM1_13_2, Types.ITEM1_13); // 2 - Item
}
});
protocol.registerClientbound(ClientboundPackets1_13.UPDATE_RECIPES, wrapper -> {
int recipesNo = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < recipesNo; i++) {
wrapper.passthrough(Types.STRING); // Id
String type = wrapper.passthrough(Types.STRING);
if (type.equals("crafting_shapeless")) {
wrapper.passthrough(Types.STRING); // Group
int ingredientsNo = wrapper.passthrough(Types.VAR_INT);
for (int i1 = 0; i1 < ingredientsNo; i1++) {
wrapper.write(Types.ITEM1_13_ARRAY, wrapper.read(Types.ITEM1_13_2_ARRAY));
}
wrapper.write(Types.ITEM1_13, wrapper.read(Types.ITEM1_13_2));
} else if (type.equals("crafting_shaped")) {
int ingredientsNo = wrapper.passthrough(Types.VAR_INT) * wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.STRING); // Group
for (int i1 = 0; i1 < ingredientsNo; i1++) {
wrapper.write(Types.ITEM1_13_ARRAY, wrapper.read(Types.ITEM1_13_2_ARRAY));
}
wrapper.write(Types.ITEM1_13, wrapper.read(Types.ITEM1_13_2));
} else if (type.equals("smelting")) {
wrapper.passthrough(Types.STRING); // Group
// Ingredient start
wrapper.write(Types.ITEM1_13_ARRAY, wrapper.read(Types.ITEM1_13_2_ARRAY));
// Ingredient end
wrapper.write(Types.ITEM1_13, wrapper.read(Types.ITEM1_13_2));
wrapper.passthrough(Types.FLOAT); // EXP
wrapper.passthrough(Types.VAR_INT); // Cooking time
}
}
});
protocol.registerServerbound(ServerboundPackets1_13.CONTAINER_CLICK, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE); // 0 - Window ID
map(Types.SHORT); // 1 - Slot
map(Types.BYTE); // 2 - Button
map(Types.SHORT); // 3 - Action number
map(Types.VAR_INT); // 4 - Mode
map(Types.ITEM1_13, Types.ITEM1_13_2); // 5 - Clicked Item
}
});
protocol.registerServerbound(ServerboundPackets1_13.SET_CREATIVE_MODE_SLOT, new PacketHandlers() {
@Override
public void register() {
map(Types.SHORT); // 0 - Slot
map(Types.ITEM1_13, Types.ITEM1_13_2); // 1 - Clicked Item
}
});
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_13_2to1_13_1/rewriter/WorldPacketRewriter1_13_2.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.rewriter;
import com.viaversion.viabackwards.protocol.v1_13_2to1_13_1.Protocol1_13_2To1_13_1;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
public class WorldPacketRewriter1_13_2 {
public static void register(Protocol1_13_2To1_13_1 protocol) {
protocol.registerClientbound(ClientboundPackets1_13.LEVEL_PARTICLES, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Particle ID
map(Types.BOOLEAN); // 1 - Long Distance
map(Types.FLOAT); // 2 - X
map(Types.FLOAT); // 3 - Y
map(Types.FLOAT); // 4 - Z
map(Types.FLOAT); // 5 - Offset X
map(Types.FLOAT); // 6 - Offset Y
map(Types.FLOAT); // 7 - Offset Z
map(Types.FLOAT); // 8 - Particle Data
map(Types.INT); // 9 - Particle Count
handler(wrapper -> {
int id = wrapper.get(Types.INT, 0);
if (id == 27) {
wrapper.write(Types.ITEM1_13, wrapper.read(Types.ITEM1_13_2));
}
});
}
});
}
}
================================================
FILE: common/src/main/java/com/viaversion/viabackwards/protocol/v1_13to1_12_2/Protocol1_13To1_12_2.java
================================================
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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 .
*/
package com.viaversion.viabackwards.protocol.v1_13to1_12_2;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.BackwardsProtocol;
import com.viaversion.viabackwards.api.rewriters.text.JsonNBTComponentRewriter;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.data.BackwardsMappingData1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.data.PaintingNames1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.provider.BackwardsBlockEntityProvider;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.rewriter.BlockItemPacketRewriter1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.rewriter.EntityPacketRewriter1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.rewriter.PlayerPacketRewriter1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.rewriter.SoundPacketRewriter1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.BackwardsBlockStorage;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.NoteBlockStorage;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.PlayerPositionStorage1_13;
import com.viaversion.viabackwards.protocol.v1_13to1_12_2.storage.TabCompleteStorage;
import com.viaversion.viabackwards.utils.BackwardsProtocolLogger;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_13;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.libs.gson.JsonParser;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ServerboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ClientboundPackets1_12_1;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ServerboundPackets1_12_1;
import com.viaversion.viaversion.rewriter.text.ComponentRewriterBase;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.ProtocolLogger;
import org.checkerframework.checker.nullness.qual.Nullable;
public class Protocol1_13To1_12_2 extends BackwardsProtocol {
public static final BackwardsMappingData1_13 MAPPINGS = new BackwardsMappingData1_13();
public static final ProtocolLogger LOGGER = new BackwardsProtocolLogger(Protocol1_13To1_12_2.class);
private final EntityPacketRewriter1_13 entityRewriter = new EntityPacketRewriter1_13(this);
private final BlockItemPacketRewriter1_13 blockItemPackets = new BlockItemPacketRewriter1_13(this);
private final JsonNBTComponentRewriter translatableRewriter = new JsonNBTComponentRewriter<>(this, ComponentRewriterBase.ReadType.JSON) {
@Override
protected void handleTranslate(JsonObject root, String translate) {
String mappedKey = mappedTranslationKey(translate);
if (mappedKey != null || (mappedKey = getMappingData().getTranslateMappings().get(translate)) != null) {
root.addProperty("translate", mappedKey);
}
}
};
private final JsonNBTComponentRewriter