6 Creating a new ViaVersion platform
RK_01 edited this page 2026-01-27 08:58:30 +01:00

Introduction

ViaVersion is a general-purpose protocol translation library for Minecraft, not just a Paper plugin. Its architecture is independent of specific server software or mod loaders, allowing it to be implemented in virtually any Minecraft-related application.

By default, the base ViaVersion JAR supports Paper and Velocity. Other environments—such as Fabric, NeoForge/Forge, or Sponge—use separate, platform-specific loader projects.

The bridge between ViaVersion and a server software or mod loader is called a platform. This guide explains how to implement such a platform from scratch.

Getting Started

Including ViaVersion

Any ViaVersion platform must comply with the GNU General Public License v3, as the viaversion-common artifact is required.

Refer to the Basic API usage documentation for the Maven coordinates. Ensure that you depend on viaversion-common, as it provides access to the required internal APIs.

Implicit Required Dependencies

ViaVersion depends on several libraries that must be present at runtime:

  • Netty (io.netty:netty-all:4.0.20.Final or newer) Used for packet handling and Netty pipeline injection
  • Gson (com.google.code.gson:gson:2.x) Used for JSON serialization and deserialization
  • Guava (com.google.guava:guava:17.0 or newer) Provides utility classes used throughout the project

These dependencies are typically already provided by Minecraft servers and proxies.

Add-ons

ViaVersion allows newer clients to join older server versions. The opposite direction, as well as more specialized versions (such as April Fools snapshots), requires additional add-ons:

  • ViaBackwards — Allows older clients to join newer server versions (requires ViaVersion)
  • ViaRewind — Allows 1.8.x and 1.7.x clients to join 1.9+ servers (requires ViaBackwards)
  • ViaLegacy — Allows clients to join servers running versions ≤ 1.7.10 (requires ViaVersion)
  • ViaAprilFools — Allows clients to join selected Minecraft snapshot versions (requires ViaBackwards)
  • ViaBedrock — Allows clients to join Bedrock Edition servers (requires the latest ViaVersion snapshot version)

Creating a Platform Implementation

Platform Base Class

Create a class named ProjectNamePlatform.

It is recommended to place all ViaVersion-related classes in a dedicated package, for example:

  • com.yourproject.viaversion
  • com.yourproject.protocoltranslator

Overrides of default classes should be prefixed with your project name:

public class ProjectNameInjector implements ViaInjector {}

Single-connection platforms

Extend UserConnectionViaVersionPlatform if your platform:

  • Does not have a custom player abstraction
  • Handles one connection per Netty channel

Multi-connection platforms

If your platform supports multiple connections (for example, a proxy or backend server) and has its own player object, implement:

ViaPlatform<ProjectPlayer>

This allows API methods in Via.getAPI() to directly accept your player object.

Caution

This guide focuses on UserConnectionViaVersionPlatform. For multi-connection platforms, additional methods must be implemented. See existing implementations here and here.

Some official implementations predate the current architecture and may not fully follow this guide.

Example Platform Implementation

public final class TestPlatform extends UserConnectionViaVersionPlatform {

    public TestPlatform() {
        // Folder for configuration files
        super(new File("ViaVersion"));
    }

    @Override
    public Logger createLogger(final String name) {
        // Required for ViaBackwards and other add-ons to have their own logger
        return Logger.getGlobal();
    }

    @Override
    public boolean isProxy() {
        // true:
        // - Proxy platforms (Velocity, BungeeCord)
        // - Client-side platforms (Fabric, Forge)
        //
        // false:
        // - Server-side platforms (Spigot, Paper)
        return true;
    }

    @Override
    public String getPlatformName() {
        return "Test"; // Project name
    }

    @Override
    public String getPlatformVersion() {
        return "test"; // Project version
    }
}

Version Provider

Create a class that implements ViaPlatformLoader to register platform-specific providers:

public final class TestPlatformLoader implements ViaPlatformLoader {

    @Override
    public void load() {
        Via.getManager().getProviders().use(VersionProvider.class, new BaseVersionProvider() {
            @Override
            public ProtocolVersion getClosestServerProtocol(UserConnection connection) {
                // Change the logic here to select the target server version
                return ProtocolVersion.v1_8;
            }
        });
    }

    @Override
    public void unload() {
    }
}

Providers allow the common ViaVersion code to interact with platform-specific features or retrieve data that can only be accessed through platform APIs.

The only mandatory provider is VersionProvider, which determines the target protocol version for each connection.

Initializing ViaVersion

The initAndLoad Call

Once your platform and (optional) platform loader are implemented, initialize ViaVersion:

ViaManagerImpl.initAndLoad(
    new TestPlatform(),
    new NoopInjector(),
    new ViaCommandHandler(false /* if true, a command for toggling check-for-updates in ViaVersion's config will be registered */),
    new TestPlatformLoader()
);

This bootstraps all internal ViaVersion systems.

You can verify successful initialization with:

Via.isLoaded();

Netty Modifications

ViaVersion must be injected into the Netty pipeline of each player connection in order to intercept and modify packets. In the example above, a NoopInjector was passed to initAndLoad, which performs no injection. This injector is intended for platforms that either have direct API access to modify the pipeline or use alternative injection mechanisms (for example, Mixins or ASM).

If your platform targets a server or proxy where reflection-based injection is required, review the ViaInjector interface and the Bukkit or Velocity implementations for reference.

Decoder/Encoder vs. Codec Pipeline

ViaVersion supports two approaches for Netty pipeline injection:

  1. Separate decoder and encoder handlers (ViaDecodeHandler and ViaEncodeHandler)
  2. A single codec handler for both directions (ViaCodecHandler)

The appropriate approach depends on the software you are integrating with. If the target software uses a split pipeline (such as Spigot or Paper), you should also use the split approach.

When using the codec approach, extend NoopInjector with a custom implementation:

public final class TestInjector extends NoopInjector {

    @Override
    public String getEncoderName() {
        return ViaCodecHandler.NAME;
    }

    @Override
    public String getDecoderName() {
        return ViaCodecHandler.NAME;
    }
}

Both methods must return the name of the pipeline handler. By default, ViaVersion uses ViaEncodeHandler.NAME and ViaDecodeHandler.NAME.

Injecting into the Pipeline

// clientside = true: proxy software (frontend connection, client <-> proxy) or client mods
// clientside = false: proxy software (backend connection, proxy <-> server) or server software
final UserConnection connection = ViaChannelInitializer.createUserConnection(channel, true /* clientside */);

final ViaInjector injector = Via.getManager().getInjector();
channel.pipeline().addBefore("packet_decoder", injector.getDecoderName(), new ViaDecodeHandler(connection));
channel.pipeline().addBefore("packet_encoder", injector.getEncoderName(), new ViaEncodeHandler(connection));
//channel.pipeline().addBefore("packet_codec", injector.getEncoderName(), new ViaCodecHandler(connection));

If you are using ViaLegacy, consult its README for required Netty pipeline changes.

Caution

Depending on your integration point, you may need to ensure that the pipeline maintains the correct handler order. Vanilla Minecraft clients and servers modify the pipeline when compression handlers are added. You must ensure that the Via* handlers remain in the correct positions. See existing implementations here and here.

Moving Forward

This guide covers only the minimum requirements to get ViaVersion running on a new platform.

Additional features—such as command registration and configuration management—may require further implementation to function fully.

UserConnectionViaVersionPlatform (or ViaPlatform<T> with only the mandatory overrides) omits several optional methods that must be implemented to achieve full functionality.

For example, the Server & Player Details Protocol requires overriding the sendCustomPayload and sendCustomPayloadToClient methods in your platform class.

Most internal components include JavaDoc to aid understanding. We also recommend reviewing existing implementations within our GitHub organization or seeking help on our Discord server.