ViaBackwards development - ViaVersion/ViaBackwards GitHub Wiki

Creating a protocol for a new major version

Here's a template to be copied when creating new protocol transformers for the very latest (!) Minecraft version. Only differences when compared to ViaVersion are commented.

Main protocol class

In the main protocol class, the transformation direction is of course the other way around, so

public final class Protocol1_19To1_19_1 extends BackwardsProtocol<ClientboundPackets1_19, ClientboundPackets1_19_1, ServerboundPackets1_19, ServerboundPackets1_19_1> {

from ViaVersion would become the following in ViaBackwards:

public final class Protocol1_19_1To1_19 extends BackwardsProtocol<ClientboundPackets1_19_1, ClientboundPackets1_19, ServerboundPackets1_19_1, ServerboundPackets1_19> {

First, copy the template from the ViaVersion wiki, then apply the required changed below.

    // ...
    // ViaBackwards uses its own mappings and also needs a translatablerewriter for translation mappings
    public static final BackwardsMappings MAPPINGS = new BackwardsMappings("1.x", "1.y", Protocol1_xTo1_y.class); // Uses the ViaVersion protocol class as a parameter!
    private final TranslatableRewriter<ClientboundPacketsOld> translatableRewriter = new TranslatableRewriter<>(this);

    @Override
    protected void registerPackets() {
        super.registerPackets();

        // Registers translatable mappings
        translatableRewriter.registerComponentPacket(ClientboundPacketsOld.ACTIONBAR);
        translatableRewriter.registerComponentPacket(ClientboundPacketsOld.TITLE_TEXT);
        translatableRewriter.registerComponentPacket(ClientboundPacketsOld.TITLE_SUBTITLE);
        translatableRewriter.registerBossBar(ClientboundPacketsOld.BOSSBAR);
        translatableRewriter.registerDisconnect(ClientboundPacketsOld.DISCONNECT);
        translatableRewriter.registerTabList(ClientboundPacketsOld.TAB_LIST);
        translatableRewriter.registerOpenWindow(ClientboundPacketsOld.OPEN_WINDOW);
        translatableRewriter.registerCombatKill(ClientboundPacketsOld.COMBAT_KILL);
        translatableRewriter.registerComponentPacket(ClientboundPacketsOld.SYSTEM_CHAT);
        translatableRewriter.registerComponentPacket(ClientboundPacketsOld.DISGUISED_CHAT);
        translatableRewriter.registerPing();
        // And more, like chat messages

        // ...
        // The sound rewriter also needs to register stop sound and named sound packets for the manual id mappings
        final SoundRewriter<ClientboundPacketsOld> soundRewriter = new SoundRewriter<>(this);
        soundRewriter.registerStopSound(ClientboundPacketsOld.STOP_SOUND);
        soundRewriter.register1_19_3Sound(ClientboundPacketsOld.SOUND);
        soundRewriter.registerSound(ClientboundPacketsOld.ENTITY_SOUND);
    }

    @Override
    public TranslatableRewriter getTranslatableRewriter() {
        return translatableRewriter;
    }

Entity data

    @Override
    public void registerRewrites() {
        /*filter().handler((event, meta) -> {
            int id = meta.metaType().typeId();
            if (id >= ac) {
                return;
            } else if (id >= ab) {
                id--;
            }

            meta.setMetaType(Types1_z.META_TYPES.byId(id));
        });*/
        registerMetaTypeHandler(Types1_z.META_TYPES.itemType, Types1_z.META_TYPES.blockStateType, Types1_z.META_TYPES.particleType, Types1_z.META_TYPES.optionalComponentType, Types1_z.META_TYPES.componentType);

        filter().filterFamily(Types1_z.MINECART_ABSTRACT).index(11).handler((event, meta) -> {
            final int blockState = meta.value();
            meta.setValue(protocol.getMappingData().getNewBlockStateId(blockState));
        });

        // Remove metadata of new entity type
        // filter().type(Entity1_xTypes.SNIFFER).removeIndex(newIndex);
    }

    @Override
    public void onMappingDataLoaded() {
        mapTypes();

        // mapEntityTypeWithData(Entity1_xTypes.SNIFFER, Entity1_xTypes.RAVAGER).jsonName();
    }

Mapping new to old entity types has to be done in code, same for their metadata and particle data. Most other registry type mappings (blocks, sounds, items, simple particles, enchantments, ...) are done via the json mappings.

Diff mappings

Wildcard blockstate mappings

Instead of manually mapping every single property iteration of a blockstate, use:

"minecraft:mangrove_wood": "minecraft:acacia_wood[",

The [ at the end signalized that properties are copied across the mappings.