-
-
Notifications
You must be signed in to change notification settings - Fork 37
Creating plugins
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.
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.
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()
}
}
To build your ViaProxy plugin you can run gradlew build
To quickly test your ViaProxy plugin you can run gradlew runViaProxy
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.
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 |
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.
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) |
ViaProxy uses ViaVersion for protocol translation, so the ViaVersion API can be used in plugins.
Check out the ViaVersion repo for more information.
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).
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")));