Skip to content

Commit 67c1a23

Browse files
committed
fix: Velocity injection
- Updated Lombok version from 6.3.0 to 8.6 in build.gradle.kts - Added .DS_Store to .gitignore - Introduced .vscode/settings.json for Java null analysis configuration - Set Java source and target compatibility to 1.8 in build-logic/build.gradle.kts - Updated nettyVersion from 4.1.49.Final to 4.2.3.Final in Versions.kt - Upgraded Gradle wrapper to version 8.5 - Added ConnectWatchedSingleThreadIoEventLoop for custom event loop handling in VelocityInjector.java - Refactored VelocityInjector to use LocalIoHandler-based event loops for better compatibility
1 parent 76edf92 commit 67c1a23

File tree

8 files changed

+103
-6
lines changed

8 files changed

+103
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ local.properties
1313
.settings/
1414
.loadpath
1515
.recommenders
16+
.DS_Store
1617

1718
# External tool builders
1819
.externalToolBuilders/

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"java.compile.nullAnalysis.mode": "automatic"
3+
}

build-logic/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ dependencies {
1414
implementation("gradle.plugin.com.github.johnrengelman", "shadow", "7.1.1")
1515
}
1616

17+
java {
18+
sourceCompatibility = JavaVersion.VERSION_1_8
19+
targetCompatibility = JavaVersion.VERSION_1_8
20+
}
21+
1722
tasks.withType<KotlinCompile> {
1823
kotlinOptions {
1924
jvmTarget = "1.8"

build-logic/src/main/kotlin/Versions.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ object Versions {
2727
const val spigotVersion = "1.19.4-R0.1-SNAPSHOT"
2828
const val configUtilsVersion = "1.0-SNAPSHOT"
2929
const val guiceVersion = "6.0.0"
30-
const val nettyVersion = "4.1.49.Final"
30+
const val nettyVersion = "4.2.3.Final"
3131
const val snakeyamlVersion = "1.28"
3232
const val cloudVersion = "1.5.0"
3333
const val adventureApiVersion = "4.10.0"

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
plugins {
22
`java-library`
33
id("connect.build-logic")
4-
id("io.freefair.lombok") version "6.3.0" apply false
4+
id("io.freefair.lombok") version "8.6" apply false
55
}
66

77
allprojects {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
* THE SOFTWARE.
21+
*
22+
* @author GeyserMC
23+
* @link https://github.com/GeyserMC/Geyser
24+
*/
25+
26+
package com.minekube.connect.inject.velocity;
27+
28+
import io.netty.channel.Channel;
29+
import io.netty.channel.ChannelFuture;
30+
import io.netty.channel.EventLoopGroup;
31+
import io.netty.channel.IoEventLoopGroup;
32+
import io.netty.channel.IoHandlerFactory;
33+
import io.netty.channel.SingleThreadIoEventLoop;
34+
35+
import java.util.concurrent.Executor;
36+
37+
public class ConnectWatchedSingleThreadIoEventLoop extends SingleThreadIoEventLoop {
38+
private final EventLoopGroup trueWorkerGroup;
39+
40+
public ConnectWatchedSingleThreadIoEventLoop(EventLoopGroup trueWorkerGroup, IoEventLoopGroup parent,
41+
Executor executor, IoHandlerFactory ioHandlerFactory) {
42+
super(parent, executor, ioHandlerFactory);
43+
this.trueWorkerGroup = trueWorkerGroup;
44+
}
45+
46+
@Override
47+
@SuppressWarnings("deprecation")
48+
public ChannelFuture register(Channel channel) {
49+
if (channel.getClass().getName().startsWith("com.minekube.connect")) {
50+
return super.register(channel);
51+
}
52+
// Starting with Netty 4.2, channels/event loops are very picky with what can be accepted for each.
53+
// For example, IoUringIoHandler (on a Linux machine, what Velocity's worker group will be)
54+
// will not accept LocalChannels on bootstrap creation in VelocityInjector.
55+
// And using a MultiThreadEventLoopGroup with LocalIoHandler will throw an error when trying to
56+
// connect to the backend server.
57+
// Inserting ourselves here allows our local channels to use the event loop made for LocalChannels,
58+
// while re-using the settings and style of Velocity.
59+
return this.trueWorkerGroup.register(channel);
60+
}
61+
}

velocity/src/main/java/com/minekube/connect/inject/velocity/VelocityInjector.java

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,15 @@
4040
import io.netty.channel.ChannelInitializer;
4141
import io.netty.channel.ChannelOption;
4242
import io.netty.channel.EventLoopGroup;
43+
import io.netty.channel.IoEventLoop;
44+
import io.netty.channel.IoHandlerFactory;
45+
import io.netty.channel.MultiThreadIoEventLoopGroup;
4346
import io.netty.channel.WriteBufferWaterMark;
4447
import io.netty.channel.local.LocalAddress;
48+
import io.netty.channel.local.LocalIoHandler;
49+
import io.netty.util.concurrent.DefaultThreadFactory;
50+
import java.util.concurrent.Executor;
51+
import java.util.concurrent.ThreadFactory;
4552
import java.lang.reflect.Method;
4653
import lombok.Getter;
4754
import lombok.RequiredArgsConstructor;
@@ -86,13 +93,33 @@ public boolean inject() {
8693
WriteBufferWaterMark serverWriteMark = getCastedValue(connectionManager,
8794
"SERVER_WRITE_MARK");
8895

89-
EventLoopGroup bossGroup = castedInvoke(connectionManager, "getBossGroup");
90-
EventLoopGroup workerGroup = getCastedValue(connectionManager, "workerGroup");
96+
// Use LocalIoHandler-based event loops that are compatible with LocalServerChannel
97+
// while still integrating with Velocity's system (Geyser approach with ConnectWatchedSingleThreadIoEventLoop)
98+
EventLoopGroup velocityWorkerGroup = getCastedValue(connectionManager, "workerGroup");
99+
100+
EventLoopGroup localBossGroup = new MultiThreadIoEventLoopGroup(LocalIoHandler.newFactory()) {
101+
@Override
102+
protected ThreadFactory newDefaultThreadFactory() {
103+
return new DefaultThreadFactory("Connect Local Boss Group");
104+
}
105+
};
106+
107+
EventLoopGroup localWorkerGroup = new MultiThreadIoEventLoopGroup(LocalIoHandler.newFactory()) {
108+
@Override
109+
protected ThreadFactory newDefaultThreadFactory() {
110+
return new DefaultThreadFactory("Connect Local Worker Group");
111+
}
112+
113+
@Override
114+
protected IoEventLoop newChild(Executor executor, IoHandlerFactory ioHandlerFactory, Object... args) {
115+
return new ConnectWatchedSingleThreadIoEventLoop(velocityWorkerGroup, this, executor, ioHandlerFactory);
116+
}
117+
};
91118

92119
ChannelFuture channelFuture = (new ServerBootstrap()
93120
.channel(LocalServerChannelWrapper.class)
94121
.childHandler(serverInitializer)
95-
.group(bossGroup, workerGroup) // Cannot be DefaultEventLoopGroup
122+
.group(localBossGroup, localWorkerGroup) // Use LocalIoHandler-based event loops
96123
.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK,
97124
serverWriteMark) // Required or else rare network freezes can occur
98125
.localAddress(LocalAddress.ANY))

0 commit comments

Comments
 (0)