├── .github
└── workflows
│ ├── deploy-release.yml
│ ├── deploy-snapshot.yml
│ └── deploy.yml
├── .gitignore
├── .idea
└── copyright
│ ├── APL.xml
│ └── profiles_settings.xml
├── LICENSE
├── README.md
├── build.gradle.kts
├── codec-query
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── cloudburstmc
│ └── netty
│ └── handler
│ └── codec
│ └── query
│ ├── QueryEventListener.java
│ ├── QueryNetworkListener.java
│ ├── QueryPacket.java
│ ├── QueryUtil.java
│ ├── codec
│ └── QueryPacketCodec.java
│ ├── enveloped
│ └── DirectAddressedQueryPacket.java
│ ├── handler
│ └── QueryPacketHandler.java
│ └── packet
│ ├── HandshakePacket.java
│ └── StatisticsPacket.java
├── codec-rcon
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── cloudburstmc
│ └── netty
│ └── handler
│ └── codec
│ └── rcon
│ ├── RconCodec.java
│ ├── RconEventListener.java
│ ├── RconMessage.java
│ ├── RconNetworkListener.java
│ └── handler
│ └── RconHandler.java
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle.kts
└── transport-raknet
├── README.md
├── build.gradle.kts
└── src
├── main
└── java
│ └── org
│ └── cloudburstmc
│ └── netty
│ ├── channel
│ ├── proxy
│ │ ├── ProxyChannel.java
│ │ └── package-info.java
│ └── raknet
│ │ ├── RakChannel.java
│ │ ├── RakChannelFactory.java
│ │ ├── RakChannelPipeline.java
│ │ ├── RakChildChannel.java
│ │ ├── RakClientChannel.java
│ │ ├── RakConstants.java
│ │ ├── RakDisconnectReason.java
│ │ ├── RakEvent.java
│ │ ├── RakOfflineState.java
│ │ ├── RakPing.java
│ │ ├── RakPong.java
│ │ ├── RakPriority.java
│ │ ├── RakReliability.java
│ │ ├── RakServerChannel.java
│ │ ├── RakSlidingWindow.java
│ │ ├── RakState.java
│ │ ├── config
│ │ ├── DefaultRakClientConfig.java
│ │ ├── DefaultRakServerConfig.java
│ │ ├── DefaultRakSessionConfig.java
│ │ ├── RakChannelConfig.java
│ │ ├── RakChannelMetrics.java
│ │ ├── RakChannelOption.java
│ │ ├── RakServerChannelConfig.java
│ │ ├── RakServerMetrics.java
│ │ └── package-info.java
│ │ ├── package-info.java
│ │ └── packet
│ │ ├── EncapsulatedPacket.java
│ │ ├── RakDatagramPacket.java
│ │ ├── RakMessage.java
│ │ └── package-info.java
│ ├── handler
│ └── codec
│ │ └── raknet
│ │ ├── AdvancedChannelInboundHandler.java
│ │ ├── ProxyInboundRouter.java
│ │ ├── ProxyOutboundRouter.java
│ │ ├── client
│ │ ├── RakClientOfflineHandler.java
│ │ ├── RakClientOnlineInitialHandler.java
│ │ ├── RakClientProxyRouteHandler.java
│ │ ├── RakClientRouteHandler.java
│ │ └── package-info.java
│ │ ├── common
│ │ ├── ConnectedPingHandler.java
│ │ ├── ConnectedPongHandler.java
│ │ ├── DisconnectNotificationHandler.java
│ │ ├── EncapsulatedToMessageHandler.java
│ │ ├── RakAcknowledgeHandler.java
│ │ ├── RakDatagramCodec.java
│ │ ├── RakSessionCodec.java
│ │ ├── RakUnhandledMessagesQueue.java
│ │ ├── UnconnectedPingEncoder.java
│ │ ├── UnconnectedPongDecoder.java
│ │ ├── UnconnectedPongEncoder.java
│ │ └── package-info.java
│ │ ├── package-info.java
│ │ └── server
│ │ ├── RakChildDatagramHandler.java
│ │ ├── RakServerOfflineHandler.java
│ │ ├── RakServerOnlineInitialHandler.java
│ │ ├── RakServerRateLimiter.java
│ │ ├── RakServerRouteHandler.java
│ │ ├── RakServerTailHandler.java
│ │ └── package-info.java
│ └── util
│ ├── BitQueue.java
│ ├── FastBinaryMinHeap.java
│ ├── IntRange.java
│ ├── IpDontFragmentProvider.java
│ ├── RakUtils.java
│ ├── RoundRobinArray.java
│ ├── RoundRobinIterator.java
│ ├── SecureAlgorithmProvider.java
│ ├── SplitPacketHelper.java
│ └── package-info.java
└── test
└── java
└── org
└── cloudburstmc
└── netty
├── BitQueueTests.java
└── RakTests.java
/.github/workflows/deploy-release.yml:
--------------------------------------------------------------------------------
1 | name: Deploy Release
2 | on:
3 | push:
4 | tags:
5 | - '*'
6 |
7 | jobs:
8 | deploy:
9 | uses: CloudburstMC/Network/.github/workflows/deploy.yml@develop
10 | with:
11 | deploy-url: "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
12 | secrets:
13 | DEPLOY_USERNAME: ${{ secrets.OSSRH_USERNAME }}
14 | DEPLOY_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
15 | PGP_SECRET: ${{ secrets.MAVEN_CENTRAL_SECRET }}
16 | PGP_PASSPHRASE: ${{ secrets.MAVEN_CENTRAL_PASSPHRASE }}
17 |
--------------------------------------------------------------------------------
/.github/workflows/deploy-snapshot.yml:
--------------------------------------------------------------------------------
1 | name: Deploy Snapshot
2 | on:
3 | push:
4 | branches:
5 | - 'develop'
6 |
7 | jobs:
8 | deploy:
9 | uses: CloudburstMC/Network/.github/workflows/deploy.yml@develop
10 | with:
11 | deploy-url: "https://repo.opencollab.dev/maven-snapshots/"
12 | secrets:
13 | DEPLOY_USERNAME: ${{ secrets.OPENCOLLAB_USERNAME }}
14 | DEPLOY_PASSWORD: ${{ secrets.OPENCOLLAB_PASSWORD }}
15 | PGP_SECRET: ${{ secrets.MAVEN_CENTRAL_SECRET }}
16 | PGP_PASSPHRASE: ${{ secrets.MAVEN_CENTRAL_PASSPHRASE }}
17 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | on:
2 | workflow_call:
3 | inputs:
4 | deploy-url:
5 | description: 'The maven repository to deploy to'
6 | required: true
7 | type: string
8 | secrets:
9 | DEPLOY_USERNAME:
10 | required: true
11 | DEPLOY_PASSWORD:
12 | required: true
13 | PGP_SECRET:
14 | required: true
15 | PGP_PASSPHRASE:
16 | required: true
17 |
18 | jobs:
19 | publish:
20 | runs-on: ubuntu-latest
21 | steps:
22 | - uses: actions/checkout@v3
23 | - uses: actions/setup-java@v3
24 | with:
25 | distribution: 'temurin'
26 | java-version: '8'
27 | - name: Validate Gradle Wrapper
28 | uses: gradle/wrapper-validation-action@v1
29 | - name: Build
30 | uses: gradle/gradle-build-action@v2
31 | with:
32 | gradle-version: wrapper
33 | arguments: "publish"
34 | env:
35 | MAVEN_DEPLOY_USERNAME: ${{ secrets.DEPLOY_USERNAME }}
36 | MAVEN_DEPLOY_PASSWORD: ${{ secrets.DEPLOY_PASSWORD }}
37 | PGP_SECRET: ${{ secrets.PGP_SECRET }}
38 | PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
39 | MAVEN_DEPLOY_URL: ${{ inputs.deploy-url }}
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.toptal.com/developers/gitignore/api/java,gradle,eclipse,netbeans,intellij+all
2 | # Edit at https://www.toptal.com/developers/gitignore?templates=java,gradle,eclipse,netbeans,intellij+all
3 |
4 | ### Eclipse ###
5 | .metadata
6 | bin/
7 | tmp/
8 | *.tmp
9 | *.bak
10 | *.swp
11 | *~.nib
12 | local.properties
13 | .settings/
14 | .loadpath
15 | .recommenders
16 |
17 | # External tool builders
18 | .externalToolBuilders/
19 |
20 | # Locally stored "Eclipse launch configurations"
21 | *.launch
22 |
23 | # PyDev specific (Python IDE for Eclipse)
24 | *.pydevproject
25 |
26 | # CDT-specific (C/C++ Development Tooling)
27 | .cproject
28 |
29 | # CDT- autotools
30 | .autotools
31 |
32 | # Java annotation processor (APT)
33 | .factorypath
34 |
35 | # PDT-specific (PHP Development Tools)
36 | .buildpath
37 |
38 | # sbteclipse plugin
39 | .target
40 |
41 | # Tern plugin
42 | .tern-project
43 |
44 | # TeXlipse plugin
45 | .texlipse
46 |
47 | # STS (Spring Tool Suite)
48 | .springBeans
49 |
50 | # Code Recommenders
51 | .recommenders/
52 |
53 | # Annotation Processing
54 | .apt_generated/
55 | .apt_generated_test/
56 |
57 | # Scala IDE specific (Scala & Java development for Eclipse)
58 | .cache-main
59 | .scala_dependencies
60 | .worksheet
61 |
62 | # Uncomment this line if you wish to ignore the project description file.
63 | # Typically, this file would be tracked if it contains build/dependency configurations:
64 | #.project
65 |
66 | ### Eclipse Patch ###
67 | # Spring Boot Tooling
68 | .sts4-cache/
69 |
70 | ### Intellij+all ###
71 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
72 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
73 |
74 | # User-specific stuff
75 | .idea/**/workspace.xml
76 | .idea/**/tasks.xml
77 | .idea/**/usage.statistics.xml
78 | .idea/**/dictionaries
79 | .idea/**/shelf
80 |
81 | # AWS User-specific
82 | .idea/**/aws.xml
83 |
84 | # Generated files
85 | .idea/**/contentModel.xml
86 |
87 | # Sensitive or high-churn files
88 | .idea/**/dataSources/
89 | .idea/**/dataSources.ids
90 | .idea/**/dataSources.local.xml
91 | .idea/**/sqlDataSources.xml
92 | .idea/**/dynamic.xml
93 | .idea/**/uiDesigner.xml
94 | .idea/**/dbnavigator.xml
95 |
96 | # Gradle
97 | .idea/**/gradle.xml
98 | .idea/**/libraries
99 |
100 | # Gradle and Maven with auto-import
101 | # When using Gradle or Maven with auto-import, you should exclude module files,
102 | # since they will be recreated, and may cause churn. Uncomment if using
103 | # auto-import.
104 | .idea/artifacts
105 | .idea/compiler.xml
106 | .idea/jarRepositories.xml
107 | .idea/modules.xml
108 | .idea/*.iml
109 | .idea/modules
110 | *.iml
111 | *.ipr
112 | .idea/codeStyles/*
113 |
114 | # CMake
115 | cmake-build-*/
116 |
117 | # Mongo Explorer plugin
118 | .idea/**/mongoSettings.xml
119 |
120 | # File-based project format
121 | *.iws
122 |
123 | # IntelliJ
124 | out/
125 |
126 | # mpeltonen/sbt-idea plugin
127 | .idea_modules/
128 |
129 | # JIRA plugin
130 | atlassian-ide-plugin.xml
131 |
132 | # Cursive Clojure plugin
133 | .idea/replstate.xml
134 |
135 | # SonarLint plugin
136 | .idea/sonarlint/
137 |
138 | # Crashlytics plugin (for Android Studio and IntelliJ)
139 | com_crashlytics_export_strings.xml
140 | crashlytics.properties
141 | crashlytics-build.properties
142 | fabric.properties
143 |
144 | # Editor-based Rest Client
145 | .idea/httpRequests
146 |
147 | # Android studio 3.1+ serialized cache file
148 | .idea/caches/build_file_checksums.ser
149 |
150 | ### Intellij+all Patch ###
151 | # Ignore everything but code style settings and run configurations
152 | # that are supposed to be shared within teams.
153 |
154 | .idea/*
155 |
156 | !.idea/codeStyles
157 | !.idea/runConfigurations
158 |
159 | ### Java ###
160 | # Compiled class file
161 | *.class
162 |
163 | # Log file
164 | *.log
165 |
166 | # BlueJ files
167 | *.ctxt
168 |
169 | # Mobile Tools for Java (J2ME)
170 | .mtj.tmp/
171 |
172 | # Package Files #
173 | *.jar
174 | *.war
175 | *.nar
176 | *.ear
177 | *.zip
178 | *.tar.gz
179 | *.rar
180 |
181 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
182 | hs_err_pid*
183 | replay_pid*
184 |
185 | ### NetBeans ###
186 | **/nbproject/private/
187 | **/nbproject/Makefile-*.mk
188 | **/nbproject/Package-*.bash
189 | build/
190 | nbbuild/
191 | dist/
192 | nbdist/
193 | .nb-gradle/
194 |
195 | ### Gradle ###
196 | .gradle
197 | **/build/
198 | !src/**/build/
199 |
200 | # Ignore Gradle GUI config
201 | gradle-app.setting
202 |
203 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
204 | !gradle-wrapper.jar
205 |
206 | # Avoid ignore Gradle wrappper properties
207 | !gradle-wrapper.properties
208 |
209 | # Cache of project
210 | .gradletasknamecache
211 |
212 | # Eclipse Gradle plugin generated files
213 | # Eclipse Core
214 | .project
215 | # JDT-specific (Eclipse Java Development Tools)
216 | .classpath
217 |
218 | ### Gradle Patch ###
219 | # Java heap dump
220 | *.hprof
221 |
222 | # End of https://www.toptal.com/developers/gitignore/api/java,gradle,eclipse,netbeans,intellij+all
223 |
--------------------------------------------------------------------------------
/.idea/copyright/APL.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Network
2 |
3 | ### Introduction
4 |
5 | Network components used within Cloudburst projects.
6 |
7 | ### Components
8 |
9 | - [`netty-transport-raknet`](transport-raknet/README.md) - A RakNet implementation based on Netty patterns
10 |
11 | ### Maven
12 |
13 | ##### Repository:
14 |
15 | For releases, use Maven Central.
16 | Snapshots can be found in the repository below.
17 |
18 |
19 | Gradle (Kotlin DSL)
20 |
21 | ```kotlin
22 | repositories {
23 | maven("https://repo.opencollab.dev/maven-snapshots/")
24 | }
25 | ```
26 |
27 |
28 |
29 | Gradle
30 |
31 | ```groovy
32 | repositories {
33 | maven {
34 | url 'https://repo.opencollab.dev/maven-snapshots/'
35 | }
36 | }
37 | ```
38 |
39 |
40 |
41 | Maven
42 |
43 | ```xml
44 |
45 |
46 |
47 | opencollab-snapshots
48 | https://repo.opencollab.dev/maven-snapshots/
49 |
50 |
51 | ```
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 CloudburstMC
3 | *
4 | * CloudburstMC licenses this file to you under the Apache License,
5 | * version 2.0 (the "License"); you may not use this file except in compliance
6 | * with the License. You may obtain a copy of the License at:
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | */
16 |
17 | subprojects {
18 | apply(plugin = "java-library")
19 | apply(plugin = "maven-publish")
20 | apply(plugin = "signing")
21 |
22 | group = "org.cloudburstmc.netty"
23 | version = rootProject.property("version") as String
24 |
25 | repositories {
26 | mavenLocal()
27 | mavenCentral()
28 | }
29 |
30 | configure {
31 | toolchain {
32 | languageVersion.set(JavaLanguageVersion.of(8))
33 | }
34 | withJavadocJar()
35 | withSourcesJar()
36 | }
37 |
38 | configure {
39 | repositories {
40 | maven {
41 | name = "maven-deploy"
42 | url = uri(
43 | System.getenv("MAVEN_DEPLOY_URL")
44 | ?: "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
45 | )
46 | credentials {
47 | username = System.getenv("MAVEN_DEPLOY_USERNAME") ?: "username"
48 | password = System.getenv("MAVEN_DEPLOY_PASSWORD") ?: "password"
49 | }
50 | }
51 | }
52 | publications {
53 | create("maven") {
54 | artifactId = "netty-${project.name}"
55 |
56 | from(components["java"])
57 |
58 | pom {
59 | description.set(project.description)
60 | url.set("https://github.com/CloudburstMC/Network")
61 | inceptionYear.set("2018")
62 | licenses {
63 | license {
64 | name.set("The Apache License, Version 2.0")
65 | url.set("https://www.apache.org/licenses/LICENSE-2.0.txt")
66 | }
67 | }
68 | developers {
69 | developer {
70 | name.set("CloudburstMC Team")
71 | organization.set("CloudburstMC")
72 | organizationUrl.set("https://github.com/CloudburstMC")
73 | }
74 | }
75 | scm {
76 | connection.set("scm:git:git://github.com/CloudburstMC/Network.git")
77 | developerConnection.set("scm:git:ssh://github.com:CloudburstMC/my-library.git")
78 | url.set("https://github.com/CloudburstMC/Network")
79 | }
80 | ciManagement {
81 | system.set("GitHub Actions")
82 | url.set("https://github.com/CloudburstMC/Network/actions")
83 | }
84 | issueManagement {
85 | system.set("GitHub Issues")
86 | url.set("https://github.com/CloudburstMC/Network/issues")
87 | }
88 | }
89 | }
90 | }
91 | }
92 |
93 | configure {
94 | if (System.getenv("PGP_SECRET") != null && System.getenv("PGP_PASSPHRASE") != null) {
95 | useInMemoryPgpKeys(System.getenv("PGP_SECRET"), System.getenv("PGP_PASSPHRASE"))
96 | sign(project.extensions.getByType(PublishingExtension::class).publications["maven"])
97 | }
98 | }
99 |
100 | tasks {
101 | named("compileJava") {
102 | options.encoding = "UTF-8"
103 | }
104 | named("test") {
105 | minHeapSize = "512m"
106 | maxHeapSize = "1024m"
107 | jvmArgs = listOf("-XX:MaxMetaspaceSize=512m")
108 | useJUnitPlatform()
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/codec-query/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | cloudburstmc-netty-parent
7 | org.cloudburstmc.netty
8 | 1.0.0.Final-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | netty-codec-query
13 | Netty/Codec/Query
14 |
15 |
16 |
17 | io.netty
18 | netty-common
19 | ${netty.version}
20 |
21 |
22 | io.netty
23 | netty-buffer
24 | ${netty.version}
25 |
26 |
27 | io.netty
28 | netty-codec
29 | ${netty.version}
30 |
31 |
32 |
--------------------------------------------------------------------------------
/codec-query/src/main/java/org/cloudburstmc/netty/handler/codec/query/QueryEventListener.java:
--------------------------------------------------------------------------------
1 | package org.cloudburstmc.netty.handler.codec.query;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import io.netty.buffer.ByteBufAllocator;
5 | import lombok.Value;
6 | import lombok.experimental.NonFinal;
7 |
8 | import java.net.InetSocketAddress;
9 | import java.util.HashMap;
10 | import java.util.Map;
11 | import java.util.StringJoiner;
12 |
13 | public interface QueryEventListener {
14 |
15 | Data onQuery(InetSocketAddress address);
16 |
17 | @Value
18 | class Data {
19 | private final String hostname;
20 | private final String gametype;
21 | private final String map;
22 | private final int playerCount;
23 | private final int maxPlayerCount;
24 | private final int hostport;
25 | private final String hostip;
26 | private final String gameId;
27 | private final String version;
28 | private final String softwareVersion;
29 | private final boolean whitelisted;
30 | private final String[] plugins;
31 | private final String[] players;
32 | @NonFinal
33 | private transient ByteBuf longStats;
34 | @NonFinal
35 | private transient ByteBuf shortStats;
36 |
37 | public ByteBuf getLongStats() {
38 | if (longStats != null) {
39 | return longStats;
40 | }
41 |
42 | longStats = ByteBufAllocator.DEFAULT.buffer();
43 |
44 | longStats.writeBytes(QueryUtil.LONG_RESPONSE_PADDING_TOP);
45 |
46 | StringJoiner plugins = new StringJoiner(";");
47 | if (this.plugins != null) {
48 | for (String plugin : this.plugins) {
49 | plugins.add(plugin);
50 | }
51 | }
52 |
53 | Map kvs = new HashMap<>();
54 | kvs.put("hostname", hostname);
55 | kvs.put("gametype", gametype);
56 | kvs.put("map", map);
57 | kvs.put("numplayers", Integer.toString(playerCount));
58 | kvs.put("maxplayers", Integer.toString(maxPlayerCount));
59 | kvs.put("hostport", Integer.toString(hostport));
60 | kvs.put("hostip", hostip);
61 | kvs.put("game_id", gameId);
62 | kvs.put("version", version);
63 | kvs.put("plugins", softwareVersion + plugins.toString());
64 | kvs.put("whitelist", whitelisted ? "on" : "off");
65 |
66 | kvs.forEach((key, value) -> {
67 | QueryUtil.writeNullTerminatedString(longStats, key);
68 | QueryUtil.writeNullTerminatedString(longStats, value);
69 | });
70 |
71 | longStats.writeByte(0);
72 | longStats.writeBytes(QueryUtil.LONG_RESPONSE_PADDING_BOTTOM);
73 |
74 | if (players != null) {
75 | for (String player : players) {
76 | QueryUtil.writeNullTerminatedString(longStats, player);
77 | }
78 | }
79 | longStats.writeByte(0);
80 |
81 | return longStats;
82 | }
83 |
84 | public ByteBuf getShortStats() {
85 | if (shortStats != null) {
86 | return shortStats;
87 | }
88 |
89 | shortStats = ByteBufAllocator.DEFAULT.buffer();
90 |
91 | QueryUtil.writeNullTerminatedString(shortStats, hostname);
92 | QueryUtil.writeNullTerminatedString(shortStats, gametype);
93 | QueryUtil.writeNullTerminatedString(shortStats, map);
94 | QueryUtil.writeNullTerminatedString(shortStats, Integer.toString(playerCount));
95 | QueryUtil.writeNullTerminatedString(shortStats, Integer.toString(maxPlayerCount));
96 | shortStats.writeShortLE(hostport);
97 | QueryUtil.writeNullTerminatedString(shortStats, hostip);
98 |
99 | return shortStats;
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/codec-query/src/main/java/org/cloudburstmc/netty/handler/codec/query/QueryNetworkListener.java:
--------------------------------------------------------------------------------
1 | package org.cloudburstmc.netty.handler.codec.query;
2 |
3 | import com.nukkitx.network.NetworkListener;
4 | import com.nukkitx.network.util.Bootstraps;
5 | import com.nukkitx.network.util.EventLoops;
6 | import com.nukkitx.network.util.Preconditions;
7 | import io.netty.bootstrap.Bootstrap;
8 | import io.netty.buffer.ByteBufAllocator;
9 | import io.netty.channel.ChannelFuture;
10 | import io.netty.channel.ChannelInitializer;
11 | import io.netty.channel.ChannelOption;
12 | import io.netty.channel.socket.DatagramChannel;
13 | import org.cloudburstmc.netty.handler.codec.query.codec.QueryPacketCodec;
14 | import org.cloudburstmc.netty.handler.codec.query.handler.QueryPacketHandler;
15 |
16 | import java.net.InetSocketAddress;
17 |
18 | public class QueryNetworkListener extends ChannelInitializer implements NetworkListener {
19 | private final InetSocketAddress address;
20 | private final QueryEventListener eventListener;
21 | private final Bootstrap bootstrap;
22 | private DatagramChannel channel;
23 |
24 | public QueryNetworkListener(InetSocketAddress address, QueryEventListener eventListener) {
25 | this.address = address;
26 | this.eventListener = eventListener;
27 |
28 | bootstrap = new Bootstrap().option(ChannelOption.ALLOCATOR, ByteBufAllocator.DEFAULT).handler(this);
29 |
30 | Bootstraps.setupBootstrap(bootstrap, true);
31 | this.bootstrap.group(EventLoops.commonGroup());
32 | }
33 |
34 | @Override
35 | public boolean bind() {
36 | Preconditions.checkState(channel == null, "Channel already initialized");
37 |
38 | ChannelFuture future = bootstrap.bind(address).awaitUninterruptibly();
39 |
40 | return future.isSuccess();
41 | }
42 |
43 | @Override
44 | public void close() {
45 | if (channel != null) {
46 | channel.close().syncUninterruptibly();
47 | }
48 | }
49 |
50 | @Override
51 | public InetSocketAddress getAddress() {
52 | return address;
53 | }
54 |
55 | @Override
56 | protected void initChannel(DatagramChannel datagramChannel) throws Exception {
57 | this.channel = datagramChannel;
58 | channel.pipeline()
59 | .addLast("queryPacketCodec", new QueryPacketCodec())
60 | .addLast("queryPacketHandler", new QueryPacketHandler(eventListener));
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/codec-query/src/main/java/org/cloudburstmc/netty/handler/codec/query/QueryPacket.java:
--------------------------------------------------------------------------------
1 | package org.cloudburstmc.netty.handler.codec.query;
2 |
3 | import io.netty.buffer.ByteBuf;
4 |
5 | public interface QueryPacket {
6 |
7 | void encode(ByteBuf buf);
8 |
9 | void decode(ByteBuf buf);
10 |
11 | int getSessionId();
12 |
13 | void setSessionId(int sessionId);
14 |
15 | short getId();
16 | }
17 |
--------------------------------------------------------------------------------
/codec-query/src/main/java/org/cloudburstmc/netty/handler/codec/query/QueryUtil.java:
--------------------------------------------------------------------------------
1 | package org.cloudburstmc.netty.handler.codec.query;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import lombok.experimental.UtilityClass;
5 |
6 | import java.nio.charset.StandardCharsets;
7 |
8 | @UtilityClass
9 | public class QueryUtil {
10 | public static final byte[] LONG_RESPONSE_PADDING_TOP = new byte[]{115, 112, 108, 105, 116, 110, 117, 109, 0, -128, 0};
11 | public static final byte[] LONG_RESPONSE_PADDING_BOTTOM = new byte[]{1, 112, 108, 97, 121, 101, 114, 95, 0, 0};
12 |
13 | public static void writeNullTerminatedByteArray(ByteBuf buf, byte[] array) {
14 | if (array != null) {
15 | buf.writeBytes(array);
16 | }
17 | buf.writeByte(0); // Null byte
18 | }
19 |
20 | public static String readNullTerminatedString(ByteBuf in) {
21 | StringBuilder read = new StringBuilder();
22 | byte readIn;
23 | while ((readIn = in.readByte()) != '\0') {
24 | read.append((char) readIn);
25 | }
26 | return read.toString();
27 | }
28 |
29 | public static void writeNullTerminatedString(ByteBuf buf, String string) {
30 | writeNullTerminatedByteArray(buf, string.getBytes(StandardCharsets.UTF_8));
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/codec-query/src/main/java/org/cloudburstmc/netty/handler/codec/query/codec/QueryPacketCodec.java:
--------------------------------------------------------------------------------
1 | package org.cloudburstmc.netty.handler.codec.query.codec;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import io.netty.buffer.ByteBufAllocator;
5 | import io.netty.channel.ChannelHandlerContext;
6 | import io.netty.channel.socket.DatagramPacket;
7 | import io.netty.handler.codec.MessageToMessageCodec;
8 | import org.cloudburstmc.netty.handler.codec.query.QueryPacket;
9 | import org.cloudburstmc.netty.handler.codec.query.enveloped.DirectAddressedQueryPacket;
10 | import org.cloudburstmc.netty.handler.codec.query.packet.HandshakePacket;
11 | import org.cloudburstmc.netty.handler.codec.query.packet.StatisticsPacket;
12 |
13 | import java.util.Arrays;
14 | import java.util.List;
15 |
16 | public class QueryPacketCodec extends MessageToMessageCodec {
17 | private static final byte[] QUERY_SIGNATURE = new byte[]{(byte) 0xFE, (byte) 0xFD};
18 | private static final int HANDSHAKE = 0x09;
19 | private static final short STATISTICS = 0x00;
20 |
21 | @Override
22 | protected void encode(ChannelHandlerContext channelHandlerContext, DirectAddressedQueryPacket packet, List