Skip to content

Commit

Permalink
feat: velocity support
Browse files Browse the repository at this point in the history
  • Loading branch information
radstevee committed Dec 20, 2024
1 parent fcfbf58 commit 75efa28
Show file tree
Hide file tree
Showing 8 changed files with 249 additions and 1 deletion.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
plugins {
id("xyz.jpenilla.run-paper") version "2.3.1" apply false
id("xyz.jpenilla.run-velocity") version "2.3.1" apply false
id("io.papermc.paperweight.userdev") version "1.7.4" apply false
kotlin("jvm") version "2.1.0" apply false
java
Expand Down
30 changes: 30 additions & 0 deletions examples/velocity-example/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
plugins {
kotlin("jvm") version "2.1.0"
id("xyz.jpenilla.run-velocity")
id("com.gradleup.shadow") version "9.0.0-beta4"
}

repositories {
mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/")
}

dependencies {
implementation(project(":api"))
implementation(project(":velocity"))

compileOnly("io.netty:netty-all:4.1.97.Final")
compileOnly("org.slf4j:slf4j-api:1.7.30")

compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
compileOnly("com.velocitypowered:velocity-api:3.4.0-SNAPSHOT")
annotationProcessor("com.velocitypowered:velocity-api:3.4.0-SNAPSHOT")
}

tasks.runVelocity {
version("3.4.0-SNAPSHOT")
}

tasks.assemble {
dependsOn(tasks.shadowJar)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package net.mcbrawls.inject.examples.velocity;

import com.google.inject.Inject;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.proxy.ProxyServer;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import net.mcbrawls.inject.api.Injector;
import net.mcbrawls.inject.api.InjectorContext;
import net.mcbrawls.inject.api.PacketDirection;
import net.mcbrawls.inject.velocity.InjectVelocity;

@Plugin(id = "inject-velocity-example")
public final class InjectVelocityExample extends Injector {
@Inject
public InjectVelocityExample(ProxyServer server) {
InjectVelocity.INSTANCE.init(server);
InjectVelocity.INSTANCE.registerInjector(this);
}

@Override
public boolean isRelevant(InjectorContext ctx, PacketDirection direction) {
return true;
}

@Override
public boolean onRead(ChannelHandlerContext ctx, ByteBuf buf) throws Exception {
System.out.println("Packet received!");
return super.onRead(ctx, buf);
}
}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ yarn_mappings=1.21.1+build.3
loader_version=0.16.7

# Mod Properties
version=3.0.1
version=3.1.1
group=net.mcbrawls.inject
id=inject
2 changes: 2 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ plugins {
include(":api")
include(":fabric")
include(":spigot")
include(":velocity")
include(":http")
include(":examples")
include(":jetty")
Expand All @@ -25,3 +26,4 @@ include(":examples:http-example")
include(":examples:javalin-example")
include(":examples:spring-example")
include(":examples:ktor-example")
include(":examples:velocity-example")
61 changes: 61 additions & 0 deletions velocity/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
plugins {
java
`maven-publish`
}

base {
archivesName.set("${rootProject.name}-${project.name}")
}

repositories {
mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/")
}

dependencies {
implementation(project(":api"))
compileOnly("io.netty:netty-all:4.1.97.Final")
compileOnly("org.slf4j:slf4j-api:1.7.30")

compileOnly("com.velocitypowered:velocity-api:3.4.0-SNAPSHOT")
}

publishing {
publications {
create<MavenPublication>("mavenJava") {
artifactId = project.name
from(components["java"])

pom {
name = "Inject (Velocity)"
description = "A library for making injecting into Netty easier."
url = "https://mcbrawls.net"

licenses {
license {
name = "MIT"
url = "https://opensource.org/licenses/MIT"
distribution = "repo"
}
}
}
}
}

repositories {
runCatching { // getenv throws if variable doesn't exist
val mavenUser = System.getenv("MAVEN_USERNAME_ANDANTE")
val mavenPass = System.getenv("MAVEN_PASSWORD_ANDANTE")

maven {
name = "Andante"
url = uri("https://maven.andante.dev/releases/")

credentials {
username = mavenUser
password = mavenPass
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package net.mcbrawls.inject.velocity;

import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.plugin.PluginContainer;
import com.velocitypowered.api.proxy.ProxyServer;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import net.mcbrawls.inject.api.InjectPlatform;
import net.mcbrawls.inject.api.Injector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

public class InjectVelocity extends ChannelInitializer<Channel> implements InjectPlatform {
private static final Logger LOGGER = LoggerFactory.getLogger("inject");
public static InjectVelocity INSTANCE = new InjectVelocity();
private final List<Injector> injectors = new ArrayList<>();
private boolean hasInitialized = false;
private static Method INIT_CHANNEL;
private ChannelInitializer<Channel> wrappedInitializer = null;

private InjectVelocity() {
}

@Override
protected void initChannel(Channel channel) throws Exception {
if (INIT_CHANNEL == null) {
INIT_CHANNEL = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
INIT_CHANNEL.setAccessible(true);
}
INIT_CHANNEL.invoke(wrappedInitializer, channel);

injectors.forEach(channel.pipeline()::addFirst);
}

public void init(ProxyServer server) {
Object connectionManager = Reflection.getField(server, server.getClass(), 0, Reflection.CONNECTION_MANAGER);
Object proxyInitializerHolder = Reflection.getField(connectionManager, Reflection.CONNECTION_MANAGER, 0, Reflection.SERVER_INITIALIZER_HOLDER);
//noinspection unchecked
this.wrappedInitializer = ((Supplier<ChannelInitializer<Channel>>) proxyInitializerHolder).get();
try {
Reflection.SET_SERVER_INITIALIZER.invoke(proxyInitializerHolder, this);
} catch (InvocationTargetException | IllegalAccessException exception) {
throw new RuntimeException(exception);
}

hasInitialized = true;

LOGGER.info("Inject initialized");
}

@Override
public void registerInjector(Injector injector) {
injectors.add(injector);

if (!hasInitialized) {
throw new RuntimeException("inject velocity needs to be initialized before registering an injector! call #init(ProxyServer)!");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package net.mcbrawls.inject.velocity;

import io.netty.channel.ChannelInitializer;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.stream.Collectors;

final class Reflection {
private Reflection() {}

public static final Class<Object> CONNECTION_MANAGER = getClass("com.velocitypowered.proxy.network.ConnectionManager");
public static final Class<Object> SERVER_INITIALIZER_HOLDER = getClass("com.velocitypowered.proxy.network.ServerChannelInitializerHolder");
public static final Method SET_SERVER_INITIALIZER = getMethod(SERVER_INITIALIZER_HOLDER, 0, ChannelInitializer.class);

static <T, R> R getField(T instance, Class<? extends T> clazz, int idx, Class<R> type) {
Field declaredField = Arrays
.stream(clazz.getDeclaredFields())
.filter((field) -> field.getType().equals(type))
.toList()
.get(idx);
declaredField.setAccessible(true);

try {
//noinspection unchecked
return (R) declaredField.get(instance);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}

private static Method getMethod(Class<?> clazz, int idx, Class<?>... params) {
if (clazz == null) {
return null;
}
int currentIdx = 0;
for (Method method : clazz.getDeclaredMethods()) {
if ((params == null || Arrays.equals(method.getParameterTypes(), params)) && idx == currentIdx++) {
method.setAccessible(true);
return method;
}
}
if (clazz.getSuperclass() != null) {
return getMethod(clazz.getSuperclass(), idx, params);
}
return null;
}

private static Class<Object> getClass(String name) {
try {
//noinspection unchecked
return (Class<Object>) Class.forName(name);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Failed getting class: " + name);
}
}
}

0 comments on commit 75efa28

Please sign in to comment.