Skip to content

Creating plugins

RK_01 edited this page Oct 30, 2024 · 10 revisions

ViaProxy plugins are written in Java or any other JVM language (e.g. Kotlin, Scala, Groovy, etc.). The target version of Java is 17.
On startup, ViaProxy will look for plugins in the plugins directory. If a compatible plugin is found, it will be loaded. Both UI and CLI modes support plugins.
The plugin loading occurs pretty early in the startup process, so plugins have the ability to modify the proxy's behavior in many ways or add new features.

Basics

ViaProxy plugins have basic requirements to be loaded by ViaProxy:

  • The plugin must be a JAR file
  • It must contain a viaproxy.yml file in the root of the JAR file
  • The main class must extend ViaProxyPlugin If these requirements are met, ViaProxy will load the plugin.

Gradle project setup

To start developing a ViaProxy plugin you need set up a Java project. Here is an example gradle buildscript:

plugins {
    id "java-library"
}

base {
    java.toolchain.languageVersion = JavaLanguageVersion.of(17)
    compileJava.options.encoding = "UTF-8"
}

repositories {
    mavenCentral()
    maven {
        name = "ViaVersion"
        url = "https://repo.viaversion.com"
    }
}

dependencies {
    implementation "net.raphimc:ViaProxy:x.x.x" // Get latest version from releases
}

tasks.register("runViaProxy", JavaExec) {
    dependsOn tasks.jar

    mainClass = "net.raphimc.viaproxy.ViaProxy"
    classpath = sourceSets.main.compileClasspath
    workingDir = file("run")
    jvmArgs = ["-DskipUpdateCheck"]

    doFirst {
        def pluginsDir = file("$workingDir/plugins")
        pluginsDir.mkdirs()
        file("$pluginsDir/${project.name}.jar").bytes = tasks.jar.archiveFile.get().asFile.bytes
    }

    doLast {
        file("$workingDir/plugins/${project.name}.jar").delete()
        file("$workingDir/logs").deleteDir()
    }
}

Building

To build your ViaProxy plugin you can run gradlew build

Testing

To quickly test your ViaProxy plugin you can run gradlew runViaProxy

viaproxy.yml

The viaproxy.yml file is used to define the plugin's metadata. It must be in the root of the JAR file.
Here is an example of a viaproxy.yml file with all possible fields and their descriptions:

#The name of the plugin
name: "CoolPlugin"
#The version of the plugin
version: "1.0.0"
#The plugin author
author: "ExampleDude"
#The main class (must extend ViaProxyPlugin)
main: "com.exampledude.coolplugin.Main"
#The minimum version of ViaProxy required to run the plugin
min-version: "3.0.0"
#Plugin dependencies
depends:
 - "OtherPlugin"

The name, version, author and main fields are required.
The min-version field is optional and can be used to specify the minimum version of ViaProxy required to run the plugin. If the current version of ViaProxy is lower than the specified version, the plugin will not be loaded. It is recommended to use this field to prevent issues with older versions of ViaProxy, but is not required.
If the plugin has dependencies, they can be specified in the depends field. If a plugin has dependencies, they will be loaded before the plugin itself. Currently only one dependency is supported.

Main class

The main class of the plugin must extend ViaProxyPlugin and needs to override the onEnable method and optionally the onDisable method.
Here is an example of a main class:

public class PluginMain extends ViaProxyPlugin {

    @Override
    public void onEnable() {
        System.out.println("CoolPlugin enabled!");
    }

    @Override
    public void onDisable() { //Optional
        System.out.println("CoolPlugin disabled!");
    }

}

The ViaProxyPlugin class has a few methods which can be accessed but not overridden:

Method Description
disable() Disable the plugin if it fails to load (protected access)
getDataFolder() Get the plugin's data folder for saving files
getName() Get the plugin's name
getAuthor() Get the plugin's author
getVersion() Get the plugin's version
getDepends() Get the plugin's dependencies
getClassLoader() Get the URLClassLoader used to load the plugin
isEnabled() Check if the plugin is enabled

Interfacing with ViaProxy

Events

The main way of interfacing with ViaProxy is by using events. Events are fired by ViaProxy in various situations and can be listened to by plugins.
To listen to an event, the plugin must register a listener in the ViaProxy.EVENT_MANAGER:

//for non-static listeners:
ViaProxy.EVENT_MANAGER.register(new MyListener());

//for static listeners:
ViaProxy.EVENT_MANAGER.register(MyListener.class);

Handling events is done by creating a method in the listener class annotated with @EventHandler:

public class MyListener {

    @EventHandler
    public /*static*/ void onProxyStart(ProxyStartEvent event) {
        System.out.println("Proxy started!");
    }

}

A list of all available events can be found here.
A more detailed explanation of the event system can be found here.

ViaProxy class

The ViaProxy class is the main class of ViaProxy and thus contains useful methods for accessing the proxy's internals:

Method Description
getCwd() Get the current working directory of the proxy
getPluginManager() Access the plugin manager and other plugins
getSaveManager() Access save files like accounts and ui settings
getConfig() Access the proxy's configuration
getConnectedClients() Get a list of all connected clients
getCurrentProxyServer() Get the instance of the proxy server (can be null)
getViaProxyWindow() Get the UI window of ViaProxy (can be null)
getForegroundWindow() Get the current foreground window (splash screen or UI window)

ViaVersion API

ViaProxy uses ViaVersion for protocol translation, so the ViaVersion API can be used in plugins.
Check out the ViaVersion repo for more information.

Plugin configuration

Plugins can have their own config files. Modifying the proxy's config file is not supported.
ViaProxy uses optconfig for configuration files. It uses yaml files to store the configuration and supports comments (check out the readme for examples and more information).

Quick example

Config class:

@OptConfig //Required annotation
public class MyConfig {

    @Option("StringOption") //The name of the option
    @Description("Testing") //The description of the option 
    public static String stringOption = "This is a test option"; //The default value of the option

    @Option("ListOption")
    @Description("More testing")
    public static List<String> listOption = List.of("Entry 1", "Entry 2");

}

Output yaml file:

#Testing
StringOption: "This is a test option"

#More testing
ListOption:
 - "Entry 1"
 - "Entry 2"

Loading the config:

ConfigLoader<MyConfig> configLoader = new ConfigLoader<>(MyConfig.class);
configLoader.loadStatic(ConfigProvider.file(new File(myPlugin.getDataFolder(), "config.yml")));