├── .github └── workflows │ ├── build.yml │ └── checkMappings.yml ├── .gitignore ├── .gitmodules ├── .run ├── BungeeCord Server.run.xml └── Velocity Server.run.xml ├── HEADER.txt ├── Jenkinsfile ├── LICENSE ├── README.md ├── build.gradle ├── buildSrc ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── ishland │ └── buildscript │ └── ParseGItHubActionChangelog.java ├── bungee ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── ishland │ │ └── raknetify │ │ └── bungee │ │ ├── RaknetifyBungeePlugin.java │ │ ├── connection │ │ ├── RakNetBungeeClientChannelEventListener.java │ │ ├── RakNetBungeeConnectionUtil.java │ │ ├── RakNetBungeePingUpdater.java │ │ ├── RakNetBungeeServerChannelEventListener.java │ │ └── StripFrameHandler.java │ │ └── init │ │ ├── BungeeRaknetifyServer.java │ │ └── InjectedSet.java │ └── resources │ └── bungee.yml ├── common ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── ishland │ │ └── raknetify │ │ └── common │ │ ├── Constants.java │ │ ├── connection │ │ ├── ByteBufCopyDecoder.java │ │ ├── FrameDataBlocker.java │ │ ├── MetricsSynchronizationHandler.java │ │ ├── MultiChannelingStreamingCompression.java │ │ ├── MultiChannellingEncryption.java │ │ ├── NoFlush.java │ │ ├── PacketEncryptionManager.java │ │ ├── RakNetConnectionUtil.java │ │ ├── RakNetSimpleMultiChannelCodec.java │ │ ├── RaknetifyEventLoops.java │ │ ├── SimpleMetricsLogger.java │ │ ├── SynchronizationLayer.java │ │ └── multichannel │ │ │ └── CustomPayloadChannel.java │ │ ├── data │ │ └── ProtocolMultiChannelMappings.java │ │ ├── package-info.java │ │ └── util │ │ ├── DebugUtil.java │ │ ├── MathUtil.java │ │ ├── NetworkInterfaceListener.java │ │ ├── PrefixUtil.java │ │ ├── ReflectionUtil.java │ │ └── ThreadLocalUtil.java │ └── resources │ └── raknetify-channel-mappings.json ├── fabric ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── ishland │ │ └── raknetify │ │ └── fabric │ │ ├── RaknetifyFabric.java │ │ ├── common │ │ ├── compat │ │ │ ├── package-info.java │ │ │ └── viafabric │ │ │ │ └── ViaFabricCompatInjector.java │ │ ├── connection │ │ │ ├── MultiChannellingPacketCapture.java │ │ │ ├── RakNetClientConnectionUtil.java │ │ │ ├── RakNetCompressionCompatibilityHandler.java │ │ │ ├── RakNetFabricChannelEventListener.java │ │ │ ├── RakNetFabricConnectionUtil.java │ │ │ ├── RakNetMultiChannel.java │ │ │ ├── RakNetNetworkTransitionUtil.java │ │ │ └── encryption │ │ │ │ └── PacketEncryptionManagerInterface.java │ │ ├── package-info.java │ │ ├── quirks │ │ │ └── ClientHungerManager.java │ │ └── util │ │ │ ├── FieldSignatureParser.java │ │ │ ├── MultiVersionUtil.java │ │ │ └── NetworkStates.java │ │ └── mixin │ │ ├── RaknetifyFabricMixinPlugin.java │ │ ├── access │ │ ├── IClientConnection.java │ │ ├── IClientPlayNetworkHandler.java │ │ ├── INetworkState1_20_4.java │ │ ├── INetworkStateInternalPacketHandler.java │ │ ├── IPacketCodecDispatcher.java │ │ ├── IPacketCodecDispatcherPacketType.java │ │ ├── IPacketEncryptionManager.java │ │ └── IServerPlayNetworkHandler.java │ │ ├── client │ │ ├── MixinClientPlayNetworkHandler.java │ │ ├── MixinConnectionScreen1.java │ │ ├── MixinMultiplayerServerListPinger.java │ │ ├── MixinMultiplayerServerListPinger1.java │ │ ├── MixinMultiplayerServerListPinger1_20_2.java │ │ ├── MixinMultiplayerServerListPinger1_20_5.java │ │ └── hud │ │ │ └── MixinDebugHud.java │ │ ├── common │ │ ├── MixinCCConnect.java │ │ ├── MixinClientConnection.java │ │ ├── MixinClientConnection1.java │ │ ├── MixinClientConnection1_20_2.java │ │ ├── MixinServerAddress.java │ │ ├── encryption │ │ │ ├── MixinClientConnection.java │ │ │ ├── MixinPacketDecryptor.java │ │ │ ├── MixinPacketEncryptionManager.java │ │ │ └── MixinPacketEncryptor.java │ │ └── quirks │ │ │ ├── MixinPlayerEntity.java │ │ │ └── MixinSampleSubscriptionTracker.java │ │ ├── compat │ │ ├── fabricapi │ │ │ └── MixinServerLoginNetworkAddon.java │ │ ├── krypton │ │ │ └── MixinServerLoginNetworkHandler.java │ │ ├── package-info.java │ │ └── qsl │ │ │ └── MixinServerLoginNetworkAddon.java │ │ ├── package-info.java │ │ └── server │ │ ├── MixinPlayerManager1_20_1.java │ │ ├── MixinPlayerManager1_20_2.java │ │ ├── MixinServerCommonNetworkHandler.java │ │ ├── MixinServerLoginNetworkHandler.java │ │ ├── MixinServerNetworkIo.java │ │ ├── MixinServerNetworkIo1.java │ │ └── MixinServerPlayNetworkHandler1_20_1.java │ └── resources │ ├── fabric.mod.json │ ├── raknetify-fabric.accesswidener │ └── raknetify-fabric.mixins.json ├── genMappings.sh ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jitpack.yml ├── modrinth_license.txt ├── settings.gradle └── velocity ├── HEADER.txt ├── LICENSE ├── build.gradle └── src └── main ├── java └── com │ └── ishland │ └── raknetify │ └── velocity │ ├── RaknetifyVelocityLaunchWrapper.java │ ├── RaknetifyVelocityPlugin.java │ ├── connection │ ├── RakNetVelocityChannelEventListener.java │ ├── RakNetVelocityConnectionUtil.java │ └── RakNetVelocityServerChannelEventListener.java │ └── init │ ├── VelocityPacketRegistryInjector.java │ └── VelocityRaknetifyServer.java └── resources └── velocity-plugin.json /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # Automatically build the project and run any configured tests for every push 2 | # and submitted pull request. This can help catch issues that only occur on 3 | # certain platforms or Java versions, and provides a first line of defence 4 | # against bad commits. 5 | 6 | name: build 7 | on: [pull_request, push] 8 | 9 | jobs: 10 | build: 11 | strategy: 12 | matrix: 13 | # Use these Java versions 14 | java: [ 15 | 21, # Current Java LTS & minimum supported by Minecraft 16 | ] 17 | # and run on both Linux and Windows 18 | os: [ubuntu-24.04] 19 | runs-on: ${{ matrix.os }} 20 | steps: 21 | - name: checkout repository 22 | uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | submodules: true 26 | - name: validate gradle wrapper 27 | uses: gradle/wrapper-validation-action@v1 28 | - name: setup jdk ${{ matrix.java }} 29 | uses: actions/setup-java@v2 30 | with: 31 | distribution: 'zulu' 32 | java-version: ${{ matrix.java }} 33 | java-package: jdk 34 | - uses: actions/cache@v4 35 | with: 36 | path: | 37 | ~/.gradle/caches 38 | ~/.gradle/wrapper 39 | ./.gradle/loom-cache 40 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} 41 | restore-keys: | 42 | ${{ runner.os }}-gradle- 43 | - name: build 44 | run: ./gradlew build 45 | - name: upload to modrinth and curseforge 46 | run: ./gradlew modrinth curseforge 47 | if: github.ref == 'refs/heads/master' 48 | env: 49 | MODRINTH_TOKEN: ${{ secrets.MODRINTH_UPLOAD_TOKEN }} 50 | CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_API_TOKEN }} 51 | GITHUB_EVENT_RAW_PATH: ${{ github.event_path }} 52 | continue-on-error: true 53 | - name: capture build artifacts 54 | if: ${{ runner.os == 'Linux' && matrix.java == '21' }} # Only upload artifacts built from latest java on one OS 55 | uses: actions/upload-artifact@v4 56 | with: 57 | name: Artifacts 58 | path: ./**/build/libs/*-all.jar 59 | -------------------------------------------------------------------------------- /.github/workflows/checkMappings.yml: -------------------------------------------------------------------------------- 1 | name: check mappings 2 | on: [pull_request, push] 3 | 4 | jobs: 5 | checkMappings: 6 | strategy: 7 | matrix: 8 | # Use these Java versions 9 | java: [ 10 | 21, # Current Java LTS & minimum supported by Minecraft 11 | ] 12 | # and run on both Linux and Windows 13 | os: [ubuntu-24.04] 14 | runs-on: ${{ matrix.os }} 15 | steps: 16 | - name: checkout repository 17 | uses: actions/checkout@v2 18 | with: 19 | fetch-depth: 0 20 | submodules: true 21 | - name: validate gradle wrapper 22 | uses: gradle/wrapper-validation-action@v1 23 | - name: setup jdk ${{ matrix.java }} 24 | uses: actions/setup-java@v2 25 | with: 26 | distribution: 'zulu' 27 | java-version: ${{ matrix.java }} 28 | java-package: jdk 29 | - uses: actions/cache@v4 30 | with: 31 | path: | 32 | ~/.gradle/caches 33 | ~/.gradle/wrapper 34 | ./.gradle/loom-cache 35 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} 36 | restore-keys: | 37 | ${{ runner.os }}-gradle- 38 | - name: "cache mappingsGen" 39 | uses: actions/cache@v4 40 | with: 41 | path: | 42 | ./run-mappingsGen 43 | key: ${{ runner.os }}-mappingsGen-${{ hashFiles('./genMappings.sh') }} 44 | restore-keys: | 45 | ${{ runner.os }}-mappingsGen- 46 | - name: generate mappings 47 | env: 48 | MAPPINGS_GEN_FRESH: true 49 | run: ./genMappings.sh 50 | - name: fail if mappings changed 51 | run: | 52 | git update-index --refresh 53 | if ! git diff-index --quiet HEAD --; then 54 | echo "Mappings changed, please commit them" 55 | git diff 56 | git diff --staged 57 | exit 1 58 | fi 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | .gradle/ 4 | build/ 5 | out/ 6 | classes/ 7 | 8 | # eclipse 9 | 10 | *.launch 11 | 12 | # idea 13 | 14 | .idea/ 15 | *.iml 16 | *.ipr 17 | *.iws 18 | 19 | # vscode 20 | 21 | .settings/ 22 | .vscode/ 23 | bin/ 24 | .classpath 25 | .project 26 | 27 | # macos 28 | 29 | *.DS_Store 30 | 31 | # fabric 32 | 33 | run*/ 34 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "netty-raknet"] 2 | path = netty-raknet 3 | url = https://github.com/RelativityMC/netty-raknet.git 4 | -------------------------------------------------------------------------------- /.run/BungeeCord Server.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 18 | -------------------------------------------------------------------------------- /.run/Velocity Server.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | -------------------------------------------------------------------------------- /HEADER.txt: -------------------------------------------------------------------------------- 1 | This file is a part of the Raknetify project, licensed under MIT. 2 | 3 | Copyright (c) 2022-2025 ishland 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent { label 'slave' } 3 | options { timestamps() } 4 | stages { 5 | stage('SCM-SKIP') { 6 | steps { 7 | scmSkip(skipPattern:'.*\\[ci skip\\].*') 8 | } 9 | } 10 | stage('Build') { 11 | tools { 12 | jdk "OpenJDK 21" 13 | } 14 | steps { 15 | withMaven( 16 | maven: '3', 17 | mavenLocalRepo: '.repository', 18 | publisherStrategy: 'EXPLICIT' 19 | ) { 20 | sh 'git fetch --tags' 21 | sh 'git reset --hard' 22 | sh './gradlew clean build' 23 | } 24 | } 25 | post { 26 | success { 27 | archiveArtifacts artifacts: "**/build/libs/*-all.jar", fingerprint: true 28 | } 29 | failure { 30 | cleanWs() 31 | } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022-2025 ishland 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raknetify 2 | A Fabric mod / Velocity plugin / BungeeCord plugin that uses RakNet to improve multiplayer experience significantly 3 | under unreliable and rate-limited connections. 4 | 5 | # Features 6 | - Higher reliability and lower latency under unreliable and rate-limited client connections. 7 | - Uses RakNet's multiple channels with priorities to achieve higher responsiveness. 8 | - Supports ViaVersion client-side and ViaVersion server-side. 9 | 10 | # How to use it? 11 | 12 | ## Prerequisites 13 | - Raknetify is designed to work on Minecraft 1.17.1+ 14 | Note: On proxies such as Velocity and BungeeCord, **unsupported client version** will cause 15 | multi-channelling failing to initialize, causing **reduced responsiveness**. 16 | - You need to have a UDP port opened at the same port number of your normal server port. 17 | 18 | ## Installation and usage 19 | - Download the latest release from 20 | [GitHub](https://github.com/RelativityMC/raknetify/releases) 21 | [Modrinth (Fabric)](https://modrinth.com/mod/raknetify/versions) 22 | [CurseForge (Fabric)](https://www.curseforge.com/minecraft/mc-mods/raknetify/files) 23 | [SpigotMC (BungeeCord)](https://www.spigotmc.org/resources/raknetify-bungeecord.102509/) 24 | or development builds from [CodeMC](https://ci.codemc.io/job/RelativityMC/job/raknetify/) 25 | - Install the mod on both client and server. (Installation on backend servers are not needed if using on proxies) 26 | - Prefix your server address with `raknet;` (or `raknetl;` to use high mtu) and save or connect directly. 27 | (e.g. `raknet;example.com`) 28 | - Enjoy! 29 | 30 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'fabric-loom' version '1.8-SNAPSHOT' apply false 3 | id 'com.github.johnrengelman.shadow' version '7.1.0' apply false 4 | id 'org.cadixdev.licenser' version '0.6.1' apply false 5 | id 'com.modrinth.minotaur' version '2.+' apply false 6 | id 'com.matthewprenger.cursegradle' version '1.4.0' apply false 7 | } 8 | 9 | subprojects { 10 | apply plugin: 'java' 11 | apply plugin: 'java-library' 12 | apply plugin: 'maven-publish' 13 | apply plugin: 'org.cadixdev.licenser' 14 | 15 | sourceCompatibility = JavaVersion.VERSION_17 16 | targetCompatibility = JavaVersion.VERSION_17 17 | 18 | version = project.mod_version + "." + getVersionSuffix() 19 | 20 | license { 21 | header = rootProject.file('HEADER.txt') 22 | } 23 | 24 | repositories { 25 | mavenCentral() 26 | maven { url 'https://jitpack.io' } 27 | maven { url 'https://repo.codemc.org/repository/maven-public' } 28 | maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } 29 | } 30 | 31 | // configure the maven publication 32 | publishing { 33 | publications { 34 | mavenJava(MavenPublication) { 35 | from components.java 36 | } 37 | } 38 | 39 | // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. 40 | repositories { 41 | // Add repositories to publish to here. 42 | // Notice: This block does NOT have the same function as the block in the top level. 43 | // The repositories here will be used for publishing your artifact, not for 44 | // retrieving dependencies. 45 | } 46 | } 47 | 48 | tasks.withType(AbstractArchiveTask) { 49 | preserveFileTimestamps = false 50 | reproducibleFileOrder = true 51 | } 52 | 53 | afterEvaluate { 54 | if (it.plugins.hasPlugin("com.modrinth.minotaur")) { 55 | modrinth { 56 | token = System.getenv("MODRINTH_TOKEN") // This is the default. Remember to have the MODRINTH_TOKEN environment variable set or else this will fail, or set it to whatever you want - just make sure it stays private! 57 | projectId = "raknetify" // This can be the project ID or the slug. Either will work! 58 | // versionNumber = project.version + "+" + project.minecraft_version // You don't need to set this manually. Will fail if Modrinth has this version already 59 | // versionName = project.version + " devbuild for " + project.minecraft_version 60 | versionType = "alpha" // This is the default -- can also be `beta` or `alpha` 61 | // uploadFile = remapShadowJar // With Loom, this MUST be set to `remapJar` instead of `jar`! 62 | gameVersions = ["1.17", "1.17.1", "1.18", "1.18.1", "1.18.2", "1.19", "1.19.1", "1.19.2", "1.19.3", "1.19.4", "1.20", "1.20.1", "1.20.2", "1.20.3", "1.20.4", "1.20.5", "1.20.6", "1.21", "1.21.1", "1.21.2", "1.21.3", "1.21.4", "1.21.5"] 63 | // loaders = ["fabric"] 64 | changelog = com.ishland.buildscript.ParseGItHubActionChangelog.getChangelog() 65 | } 66 | } 67 | } 68 | 69 | } 70 | 71 | afterEvaluate { 72 | logger.lifecycle("Version String: ${project.mod_version + '.' + getVersionSuffix()}") 73 | logger.lifecycle(com.ishland.buildscript.ParseGItHubActionChangelog.getChangelog()) 74 | } 75 | 76 | String getVersionSuffix() { 77 | def stdout = new ByteArrayOutputStream() 78 | exec { 79 | commandLine 'git', 'describe', '--tags', '--dirty' 80 | standardOutput = stdout 81 | } 82 | stdout = stdout.toString().strip() 83 | def suffix = "" 84 | if (stdout.endsWith("-dirty")) { 85 | stdout = stdout.substring(0, stdout.length() - "-dirty".length()) 86 | suffix = "-dirty" 87 | } 88 | if (stdout.indexOf('-') < 0) { 89 | return "0" + suffix; 90 | } 91 | def split = stdout.split('-') 92 | return split[split.length - 2] + suffix 93 | } 94 | -------------------------------------------------------------------------------- /buildSrc/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | } 4 | 5 | sourceCompatibility = JavaVersion.VERSION_17 6 | targetCompatibility = JavaVersion.VERSION_17 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | // https://mvnrepository.com/artifact/com.google.code.gson/gson 14 | implementation 'com.google.code.gson:gson:+' 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/com/ishland/buildscript/ParseGItHubActionChangelog.java: -------------------------------------------------------------------------------- 1 | package com.ishland.buildscript; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonArray; 5 | import com.google.gson.JsonElement; 6 | import com.google.gson.JsonObject; 7 | 8 | import java.nio.file.Files; 9 | import java.nio.file.Path; 10 | 11 | public class ParseGItHubActionChangelog { 12 | 13 | public static String getChangelog() throws Throwable { 14 | final String path = System.getenv("GITHUB_EVENT_RAW_PATH"); 15 | if (path == null || path.isBlank()) return "No changelog was specified. "; 16 | final JsonObject jsonObject = new Gson().fromJson(Files.readString(Path.of(path)), JsonObject.class); 17 | 18 | StringBuilder builder = new StringBuilder(); 19 | builder.append("This version is uploaded automatically by GitHub Actions. \n\n") 20 | .append("Changelog: \n"); 21 | final JsonArray commits = jsonObject.getAsJsonArray("commits"); 22 | if (commits.isEmpty()) { 23 | builder.append("No changes detected. \n"); 24 | } else { 25 | for (JsonElement commit : commits) { 26 | JsonObject object = commit.getAsJsonObject(); 27 | builder.append("- "); 28 | builder.append('[').append(object.get("id").getAsString(), 0, 8).append(']') 29 | .append('(').append(object.get("url").getAsString()).append(')'); 30 | builder.append(' '); 31 | builder.append(object.get("message").getAsString().split("\n")[0]); 32 | builder.append(" - "); 33 | builder.append(object.get("author").getAsJsonObject().get("name").getAsString()); 34 | builder.append(" ").append('\n'); 35 | } 36 | } 37 | return builder.toString(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /bungee/build.gradle: -------------------------------------------------------------------------------- 1 | import java.nio.file.Files 2 | import java.nio.file.StandardCopyOption 3 | 4 | evaluationDependsOn(":") 5 | 6 | apply plugin: 'com.github.johnrengelman.shadow' 7 | apply plugin: 'com.modrinth.minotaur' 8 | 9 | archivesBaseName = project.archives_base_name + "-bungee" 10 | group = project.maven_group + ".bungee" 11 | 12 | repositories { 13 | ivy { 14 | url 'https://ci.md-5.net/job/' 15 | patternLayout { 16 | // artifact "[organization]/versions/[module]/builds/[revision]/downloads/[organization]-[module]-[revision](.[ext])" 17 | // https://ci.md-5.net/job/BungeeCord/1636/artifact/bootstrap/target/BungeeCord.jar 18 | artifact "[module]/[revision]/artifact/bootstrap/target/BungeeCord(.[ext])" 19 | } 20 | metadataSources { 21 | it.artifact() 22 | } 23 | } 24 | } 25 | 26 | configurations { 27 | shadowInclude 28 | } 29 | 30 | dependencies { 31 | implementation 'bungee:BungeeCord:1934' 32 | // implementation "net.md-5:bungeecord-proxy:1.+" 33 | // compileOnly 'org.projectlombok:lombok:1.18.24' // for bungeecord sources 34 | 35 | shadowInclude implementation(project(":common")) 36 | } 37 | 38 | processResources { 39 | inputs.property "version", project.version 40 | 41 | filesMatching("bungee.yml") { 42 | expand "version": project.version 43 | } 44 | } 45 | 46 | jar { 47 | exclude "META-INF/LICENSE.txt" 48 | exclude "META-INF/NOTICE.txt" 49 | from "LICENSE" 50 | } 51 | 52 | shadowJar { 53 | // dependencies { 54 | // exclude(dependency('it.unimi.dsi:fastutil')) 55 | // } 56 | exclude "META-INF/LICENSE.txt" 57 | exclude "META-INF/NOTICE.txt" 58 | minimize() 59 | archiveClassifier = "all" 60 | configurations = [ project.configurations.shadowInclude ] 61 | from "LICENSE" 62 | } 63 | 64 | assemble.dependsOn(shadowJar) 65 | 66 | tasks.withType(AbstractArchiveTask) { 67 | preserveFileTimestamps = false 68 | reproducibleFileOrder = true 69 | } 70 | 71 | modrinth { 72 | versionNumber = project.version + "+bungeecord" 73 | versionName = project.version + " devbuild for BungeeCord" 74 | uploadFile = shadowJar 75 | loaders = ["bungeecord", "waterfall"] 76 | } 77 | 78 | task("prepareRunBungee", dependsOn: shadowJar) { 79 | doFirst { 80 | Files.createDirectories(rootProject.projectDir.toPath().resolve("run-bungee").resolve("plugins")) 81 | Files.copy(shadowJar.archiveFile.getAsFile().get().toPath(), rootProject.projectDir.toPath().resolve("run-bungee").resolve("plugins").resolve("raknetify-bungee-devlaunch.jar"), StandardCopyOption.REPLACE_EXISTING) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /bungee/src/main/java/com/ishland/raknetify/bungee/RaknetifyBungeePlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.bungee; 26 | 27 | import com.ishland.raknetify.bungee.connection.RakNetBungeeConnectionUtil; 28 | import com.ishland.raknetify.bungee.init.BungeeRaknetifyServer; 29 | import com.ishland.raknetify.common.data.ProtocolMultiChannelMappings; 30 | import net.md_5.bungee.api.event.PostLoginEvent; 31 | import net.md_5.bungee.api.event.ServerConnectedEvent; 32 | import net.md_5.bungee.api.plugin.Listener; 33 | import net.md_5.bungee.api.plugin.Plugin; 34 | import net.md_5.bungee.event.EventHandler; 35 | 36 | import java.util.logging.Logger; 37 | 38 | public class RaknetifyBungeePlugin extends Plugin implements Listener { 39 | 40 | public static Logger LOGGER; 41 | public static RaknetifyBungeePlugin INSTANCE; 42 | 43 | @Override 44 | public void onEnable() { 45 | super.onEnable(); 46 | 47 | INSTANCE = this; 48 | LOGGER = this.getLogger(); 49 | 50 | ProtocolMultiChannelMappings.init(); 51 | 52 | BungeeRaknetifyServer.inject(); 53 | 54 | this.getProxy().getPluginManager().registerListener(this, this); 55 | } 56 | 57 | @Override 58 | public void onDisable() { 59 | super.onDisable(); 60 | 61 | BungeeRaknetifyServer.disable(); 62 | } 63 | 64 | @EventHandler 65 | public void onPostLogin(PostLoginEvent evt) { 66 | RakNetBungeeConnectionUtil.onPlayerLogin(evt); 67 | } 68 | 69 | @EventHandler 70 | public void handleServerSwitch(ServerConnectedEvent evt) { 71 | RakNetBungeeConnectionUtil.handleServerSwitch(evt); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /bungee/src/main/java/com/ishland/raknetify/bungee/connection/RakNetBungeePingUpdater.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.bungee.connection; 26 | 27 | import com.google.common.base.Preconditions; 28 | import io.netty.channel.ChannelDuplexHandler; 29 | import io.netty.channel.ChannelHandlerContext; 30 | import io.netty.util.concurrent.ScheduledFuture; 31 | import net.md_5.bungee.UserConnection; 32 | import net.md_5.bungee.api.connection.ProxiedPlayer; 33 | import network.ycc.raknet.RakNet; 34 | import network.ycc.raknet.packet.Ping; 35 | 36 | import java.util.Objects; 37 | import java.util.concurrent.TimeUnit; 38 | 39 | public class RakNetBungeePingUpdater extends ChannelDuplexHandler { 40 | 41 | public static final String NAME = "raknetify-bungee-ping-updater"; 42 | 43 | private final UserConnection player; 44 | 45 | ScheduledFuture updateTask = null; 46 | 47 | public RakNetBungeePingUpdater(UserConnection player) { 48 | this.player = Objects.requireNonNull(player); 49 | } 50 | 51 | public void handlerAdded(ChannelHandlerContext ctx) { 52 | if (ctx.channel().config() instanceof RakNet.Config config) { 53 | updateTask = ctx.channel().eventLoop().scheduleAtFixedRate( 54 | () -> player.setPing((int) ((config.getRTTNanos() + config.getRTTStdDevNanos()) / 1_000_000)), 55 | 0, 1000, TimeUnit.MILLISECONDS 56 | ); 57 | } 58 | } 59 | 60 | public void handlerRemoved(ChannelHandlerContext ctx) { 61 | if (updateTask != null) { 62 | updateTask.cancel(false); 63 | updateTask = null; 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /bungee/src/main/java/com/ishland/raknetify/bungee/connection/RakNetBungeeServerChannelEventListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.bungee.connection; 26 | 27 | import com.google.common.base.Preconditions; 28 | import com.ishland.raknetify.bungee.RaknetifyBungeePlugin; 29 | import com.ishland.raknetify.common.Constants; 30 | import com.ishland.raknetify.common.connection.SynchronizationLayer; 31 | import io.netty.channel.Channel; 32 | import io.netty.channel.ChannelDuplexHandler; 33 | import io.netty.channel.ChannelHandler; 34 | import io.netty.channel.ChannelHandlerContext; 35 | import net.md_5.bungee.api.ProxyServer; 36 | import net.md_5.bungee.protocol.DefinedPacket; 37 | import net.md_5.bungee.protocol.PacketWrapper; 38 | import net.md_5.bungee.protocol.packet.KeepAlive; 39 | import net.md_5.bungee.protocol.packet.Respawn; 40 | import network.ycc.raknet.RakNet; 41 | 42 | import java.util.Map; 43 | import java.util.concurrent.TimeUnit; 44 | 45 | public class RakNetBungeeServerChannelEventListener extends ChannelDuplexHandler { 46 | 47 | public static final String NAME = "raknetify-bungee-downstream-event-listener"; 48 | 49 | private final Channel clientChannel; 50 | 51 | public RakNetBungeeServerChannelEventListener(Channel clientChannel) { 52 | Preconditions.checkArgument(clientChannel.config() instanceof RakNet.Config); 53 | this.clientChannel = clientChannel; 54 | } 55 | 56 | @Override 57 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 58 | if (msg instanceof PacketWrapper wrapper) { 59 | final DefinedPacket packet = wrapper.packet; 60 | if (packet instanceof Respawn) { 61 | clientChannel.write(SynchronizationLayer.SYNC_REQUEST_OBJECT); 62 | } else if (packet instanceof KeepAlive) { 63 | if (Constants.DEBUG) RaknetifyBungeePlugin.LOGGER.info("Received downstream keepalive, swallowing it"); 64 | final long rttNanos = RakNet.config(clientChannel).getRTTNanos(); 65 | // ProxyServer.getInstance().getScheduler() 66 | // .schedule(RaknetifyBungeePlugin.INSTANCE, () -> ctx.write(packet), Math.max(rttNanos - 4_000_000, 0), TimeUnit.NANOSECONDS); // reduce delay to aid scheduling overhead 67 | ctx.channel().eventLoop().schedule(() -> ctx.writeAndFlush(packet), Math.max(rttNanos - 4_000_000, 0), TimeUnit.NANOSECONDS); // reduce delay to aid scheduling overhead 68 | return; // prevent keepalive from being sent to clients 69 | } 70 | } 71 | super.channelRead(ctx, msg); 72 | } 73 | 74 | @Override 75 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 76 | super.exceptionCaught(ctx, cause); 77 | cause.printStackTrace(); 78 | for (Map.Entry entry : ctx.channel().pipeline().toMap().entrySet()) { 79 | System.out.println("%s: %s".formatted(entry.getKey(), entry.getValue().getClass().getName())); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /bungee/src/main/java/com/ishland/raknetify/bungee/connection/StripFrameHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.bungee.connection; 26 | 27 | import io.netty.buffer.ByteBuf; 28 | import io.netty.channel.ChannelHandler; 29 | import io.netty.channel.ChannelHandlerContext; 30 | import io.netty.channel.ChannelOutboundHandlerAdapter; 31 | import io.netty.channel.ChannelPromise; 32 | import net.md_5.bungee.protocol.DefinedPacket; 33 | 34 | @ChannelHandler.Sharable 35 | public class StripFrameHandler extends ChannelOutboundHandlerAdapter { 36 | 37 | public static final String NAME = "raknetify-bungee-strip-frame"; 38 | 39 | public static final StripFrameHandler INSTANCE = new StripFrameHandler(); 40 | 41 | private StripFrameHandler() { 42 | } 43 | 44 | @Override 45 | public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { 46 | if (msg instanceof ByteBuf buf) { 47 | DefinedPacket.readVarInt(buf); 48 | ctx.write(buf.slice(), promise); 49 | return; 50 | } 51 | super.write(ctx, msg, promise); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /bungee/src/main/java/com/ishland/raknetify/bungee/init/InjectedSet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.bungee.init; 26 | 27 | import com.google.common.collect.ForwardingSet; 28 | import com.ishland.raknetify.bungee.RaknetifyBungeePlugin; 29 | import io.netty.channel.Channel; 30 | import net.md_5.bungee.BungeeCord; 31 | import net.md_5.bungee.api.ProxyServer; 32 | 33 | import java.util.Set; 34 | import java.util.concurrent.TimeUnit; 35 | 36 | public class InjectedSet extends ForwardingSet { 37 | 38 | private final Set delegate; 39 | 40 | public InjectedSet(Set delegate) { 41 | this.delegate = delegate; 42 | } 43 | 44 | @Override 45 | public boolean add(Channel element) { 46 | ProxyServer.getInstance().getScheduler().schedule( 47 | RaknetifyBungeePlugin.INSTANCE, 48 | () -> BungeeRaknetifyServer.injectChannel((BungeeCord) ProxyServer.getInstance(), element, false), 49 | 100, TimeUnit.MILLISECONDS); 50 | 51 | return super.add(element); 52 | } 53 | 54 | @Override 55 | public void clear() { 56 | BungeeRaknetifyServer.stopAll(); 57 | 58 | super.clear(); 59 | } 60 | 61 | @Override 62 | protected Set delegate() { 63 | return this.delegate; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /bungee/src/main/resources/bungee.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This file is a part of the Raknetify project, licensed under MIT. 3 | # 4 | # Copyright (c) 2022-2025 ishland 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | # 24 | 25 | name: raknetify 26 | main: com.ishland.raknetify.bungee.RaknetifyBungeePlugin 27 | version: ${version} 28 | author: ishland 29 | softDepends: 30 | - ViaVersion 31 | -------------------------------------------------------------------------------- /common/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | api("com.github.RelativityMC.netty-raknet:netty-raknet-common") { 3 | transitive = false 4 | } 5 | api("com.github.RelativityMC.netty-raknet:netty-raknet-client") 6 | api("com.github.RelativityMC.netty-raknet:netty-raknet-server") 7 | api("org.apache.commons:commons-math3:3.6.1") 8 | 9 | //noinspection GradlePackageUpdate 10 | compileOnly("io.netty:netty-all:4.1.25.Final") 11 | 12 | compileOnly("com.google.code.gson:gson:2.9.0") 13 | compileOnly("com.google.guava:guava:31.1-jre") 14 | } 15 | -------------------------------------------------------------------------------- /common/src/main/java/com/ishland/raknetify/common/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.common; 26 | 27 | public class Constants { 28 | 29 | public static final boolean DEBUG = Boolean.getBoolean("raknetify.debug"); 30 | 31 | public static final String RAKNET_PREFIX = "raknet;"; 32 | public static final String RAKNET_LARGE_MTU_PREFIX = "raknetl;"; 33 | public static final int RAKNET_PING_PACKET_ID = 0xFA; 34 | public static final int RAKNET_GAME_PACKET_ID = 0xFD; 35 | public static final int RAKNET_STREAMING_COMPRESSION_PACKET_ID = 0xED; 36 | public static final int RAKNET_STREAMING_COMPRESSION_HANDSHAKE_PACKET_ID = 0xEC; 37 | public static final int RAKNET_SYNC_PACKET_ID = 0xFC; 38 | public static final int RAKNET_METRICS_SYNC_PACKET_ID = 0xFB; 39 | public static final int MAX_QUEUED_SIZE = 256 * 1024 * 1024; 40 | public static final int DEFAULT_MTU = 1400; 41 | public static final int LARGE_MTU = 8192; 42 | public static final int MAX_PENDING_FRAME_SETS = 512; 43 | public static final int DEFAULT_PENDING_FRAME_SETS = 4; 44 | public static final int[] SYNC_IGNORE_CHANNELS = new int[] {1}; 45 | 46 | private Constants() { 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /common/src/main/java/com/ishland/raknetify/common/connection/ByteBufCopyDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.common.connection; 26 | 27 | import io.netty.buffer.ByteBuf; 28 | import io.netty.channel.ChannelHandlerContext; 29 | import io.netty.channel.ChannelInboundHandlerAdapter; 30 | 31 | public class ByteBufCopyDecoder extends ChannelInboundHandlerAdapter { 32 | 33 | public static final String NAME = "raknetify-byte-buf-copy-decoder"; 34 | 35 | @Override 36 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 37 | if (msg instanceof ByteBuf buf && !buf.hasMemoryAddress()) { 38 | ctx.fireChannelRead(ctx.alloc().directBuffer(buf.readableBytes()).writeBytes(buf)); 39 | buf.release(); 40 | return; 41 | } 42 | super.channelRead(ctx, msg); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /common/src/main/java/com/ishland/raknetify/common/connection/FrameDataBlocker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.common.connection; 26 | 27 | import io.netty.channel.ChannelHandlerContext; 28 | import io.netty.channel.ChannelInboundHandlerAdapter; 29 | import network.ycc.raknet.frame.FrameData; 30 | 31 | public class FrameDataBlocker extends ChannelInboundHandlerAdapter { 32 | 33 | private static final boolean printBlockedFrames = Boolean.getBoolean("raknetify.printBlockedFrames"); 34 | 35 | @Override 36 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 37 | if (msg instanceof FrameData data) { 38 | if (printBlockedFrames) System.out.println("Blocked %s".formatted(msg)); 39 | data.release(); 40 | return; 41 | } 42 | ctx.fireChannelRead(msg); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /common/src/main/java/com/ishland/raknetify/common/connection/NoFlush.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.common.connection; 26 | 27 | import io.netty.channel.ChannelDuplexHandler; 28 | import io.netty.channel.ChannelHandlerContext; 29 | 30 | public class NoFlush extends ChannelDuplexHandler { 31 | 32 | @Override 33 | public void flush(ChannelHandlerContext ctx) { 34 | // no-op 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /common/src/main/java/com/ishland/raknetify/common/connection/PacketEncryptionManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.common.connection; 26 | 27 | import io.netty.buffer.ByteBuf; 28 | 29 | import javax.crypto.Cipher; 30 | import java.security.GeneralSecurityException; 31 | 32 | // TODO [VanillaCopy] from fabric 33 | public class PacketEncryptionManager { 34 | private final Cipher cipher; 35 | private byte[] conversionBuffer = new byte[0]; 36 | private byte[] encryptionBuffer = new byte[0]; 37 | 38 | protected PacketEncryptionManager(Cipher cipher) { 39 | this.cipher = cipher; 40 | } 41 | 42 | private byte[] toByteArray(ByteBuf buf) { 43 | int i = buf.readableBytes(); 44 | if (this.conversionBuffer.length < i) { 45 | this.conversionBuffer = new byte[i]; 46 | } 47 | 48 | buf.readBytes(this.conversionBuffer, 0, i); 49 | return this.conversionBuffer; 50 | } 51 | 52 | public void doWork(ByteBuf buf, ByteBuf result) throws GeneralSecurityException { 53 | int i = buf.readableBytes(); 54 | byte[] bs = this.toByteArray(buf); 55 | int outputSize = this.cipher.getOutputSize(i); 56 | if (this.encryptionBuffer.length < outputSize) { 57 | this.encryptionBuffer = new byte[outputSize]; 58 | } 59 | 60 | result.writeBytes(this.encryptionBuffer, 0, this.cipher.doFinal(bs, 0, i, this.encryptionBuffer)); 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /common/src/main/java/com/ishland/raknetify/common/connection/multichannel/CustomPayloadChannel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.common.connection.multichannel; 26 | 27 | import com.ishland.raknetify.common.Constants; 28 | import com.ishland.raknetify.common.connection.RakNetSimpleMultiChannelCodec; 29 | import com.ishland.raknetify.common.util.MathUtil; 30 | import io.netty.buffer.ByteBuf; 31 | import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; 32 | 33 | import java.util.Objects; 34 | import java.util.function.IntPredicate; 35 | 36 | public class CustomPayloadChannel { 37 | 38 | public static final Object2IntOpenHashMap identifier2channel; 39 | 40 | static { 41 | // See .fabric.common.connection.RakNetMultiChannel 42 | 43 | identifier2channel = new Object2IntOpenHashMap<>(); 44 | identifier2channel.defaultReturnValue(0); 45 | identifier2channel.put("porting_lib:extra_data_entity_spawn", 2); 46 | identifier2channel.put("porting_lib:extra_entity_spawn_data", 2); // https://github.com/Fabricators-of-Create/Porting-Lib/commit/4b0cd845731f89eafd9fb39e13e1a7d87f5e14a4 47 | } 48 | 49 | public static class OverrideHandler implements RakNetSimpleMultiChannelCodec.OverrideHandler { 50 | 51 | private final IntPredicate isCustomPayload; 52 | 53 | public OverrideHandler(IntPredicate isCustomPayload) { 54 | this.isCustomPayload = Objects.requireNonNull(isCustomPayload); 55 | } 56 | 57 | @Override 58 | public int getChannelOverride(ByteBuf origBuf, boolean suppressWarning) { 59 | ByteBuf buf = origBuf.slice(); 60 | final int packetId = MathUtil.readVarInt(buf); 61 | if (isCustomPayload.test(packetId)) { 62 | final String identifier = MathUtil.readString(buf); // we assume modern custom payloads 63 | if (Constants.DEBUG) System.out.println("Raknetify: Handling custom payload: " + identifier); 64 | return identifier2channel.getInt(identifier); 65 | } else { 66 | return 0; 67 | } 68 | } 69 | 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /common/src/main/java/com/ishland/raknetify/common/data/ProtocolMultiChannelMappings.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.common.data; 26 | 27 | import com.google.gson.Gson; 28 | import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; 29 | import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; 30 | import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; 31 | 32 | import java.io.IOException; 33 | import java.io.InputStream; 34 | import java.io.InputStreamReader; 35 | 36 | public class ProtocolMultiChannelMappings { 37 | 38 | public static final ProtocolMultiChannelMappings INSTANCE; 39 | 40 | static { 41 | final InputStream resource = ProtocolMultiChannelMappings.class.getClassLoader().getResourceAsStream("raknetify-channel-mappings.json"); 42 | if (resource == null) { 43 | System.err.println("Raknetify: Failed to load raknetify channel mappings"); 44 | INSTANCE = new ProtocolMultiChannelMappings(); 45 | } else { 46 | ProtocolMultiChannelMappings read = new ProtocolMultiChannelMappings(); 47 | try (var in = resource; 48 | var reader = new InputStreamReader(resource)) { 49 | final Gson gson = new Gson(); 50 | read = gson.fromJson(reader, ProtocolMultiChannelMappings.class); 51 | } catch (IOException e) { 52 | System.err.println("Raknetify: Failed to load raknetify channel mappings"); 53 | e.printStackTrace(); 54 | } 55 | INSTANCE = read; 56 | } 57 | } 58 | 59 | public static void init() { 60 | } 61 | 62 | public Int2ObjectArrayMap mappings = new Int2ObjectArrayMap<>(); 63 | 64 | public static class VersionMapping { 65 | public Int2IntArrayMap s2c = new Int2IntArrayMap(); 66 | public Int2IntArrayMap c2s = new Int2IntArrayMap(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /common/src/main/java/com/ishland/raknetify/common/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.common; 26 | -------------------------------------------------------------------------------- /common/src/main/java/com/ishland/raknetify/common/util/MathUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.common.util; 26 | 27 | import com.google.common.base.Charsets; 28 | import io.netty.buffer.ByteBuf; 29 | 30 | import java.text.CharacterIterator; 31 | import java.text.StringCharacterIterator; 32 | 33 | public class MathUtil { 34 | 35 | public static String humanReadableByteCountBin(long bytes) { 36 | long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes); 37 | if (absB < 1024) { 38 | return bytes + " B"; 39 | } 40 | long value = absB; 41 | CharacterIterator ci = new StringCharacterIterator("KMGTPE"); 42 | for (int i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10) { 43 | value >>= 10; 44 | ci.next(); 45 | } 46 | value *= Long.signum(bytes); 47 | return String.format("%.2f %ciB", value / 1024.0, ci.current()); 48 | } 49 | 50 | public static int readVarInt(ByteBuf buf) { 51 | // TODO [VanillaCopy] 52 | int i = 0; 53 | int j = 0; 54 | 55 | byte b; 56 | do { 57 | b = buf.readByte(); 58 | i |= (b & 127) << j++ * 7; 59 | if (j > 5) { 60 | throw new RuntimeException("VarInt too big"); 61 | } 62 | } while ((b & 128) == 128); 63 | 64 | return i; 65 | } 66 | 67 | public static String readString(ByteBuf buf) { 68 | return readString(buf, Short.MAX_VALUE); 69 | } 70 | 71 | public static String readString(ByteBuf buf, int maxLen) { 72 | // Copied from BungeeCord 73 | int len = readVarInt(buf); 74 | if (len > maxLen * 3) { 75 | throw new IllegalArgumentException("Cannot receive string longer than " + maxLen * 3 + " (got " + len + " bytes)"); 76 | } 77 | 78 | String s = buf.toString(buf.readerIndex(), len, Charsets.UTF_8); 79 | buf.readerIndex(buf.readerIndex() + len); 80 | 81 | if (s.length() > maxLen) { 82 | throw new IllegalArgumentException("Cannot receive string longer than " + maxLen + " (got " + s.length() + " characters)"); 83 | } 84 | 85 | return s; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /common/src/main/java/com/ishland/raknetify/common/util/PrefixUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.common.util; 26 | 27 | import com.ishland.raknetify.common.Constants; 28 | 29 | public class PrefixUtil { 30 | 31 | public static Info getInfo(String address) { 32 | if (address.startsWith(Constants.RAKNET_PREFIX)) { 33 | return new Info(true, address.substring(Constants.RAKNET_PREFIX.length()), false); 34 | } else if (address.startsWith(Constants.RAKNET_LARGE_MTU_PREFIX)) { 35 | return new Info(true, address.substring(Constants.RAKNET_LARGE_MTU_PREFIX.length()), true); 36 | } else { 37 | return new Info(false, address, false); 38 | } 39 | } 40 | 41 | public record Info(boolean useRakNet, String stripped, boolean largeMTU) { 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /common/src/main/java/com/ishland/raknetify/common/util/ReflectionUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.common.util; 26 | 27 | import java.lang.reflect.Field; 28 | import java.lang.reflect.Method; 29 | 30 | public class ReflectionUtil { 31 | 32 | public static Field accessible(Field field) { 33 | field.setAccessible(true); 34 | return field; 35 | } 36 | 37 | public static Method accessible(Method method) { 38 | method.setAccessible(true); 39 | return method; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /common/src/main/java/com/ishland/raknetify/common/util/ThreadLocalUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.common.util; 26 | 27 | public class ThreadLocalUtil { 28 | 29 | private ThreadLocalUtil() { 30 | } 31 | 32 | private static final ThreadLocal initializingRaknet = ThreadLocal.withInitial(() -> false); 33 | private static final ThreadLocal initializingRaknetLargeMTU = ThreadLocal.withInitial(() -> false); 34 | 35 | public static void setInitializingRaknet(boolean value) { 36 | initializingRaknet.set(value); 37 | } 38 | 39 | public static void setInitializingRaknetLargeMTU(boolean value) { 40 | initializingRaknetLargeMTU.set(value); 41 | } 42 | 43 | public static boolean isInitializingRaknet() { 44 | return initializingRaknet.get(); 45 | } 46 | 47 | public static boolean isInitializingRaknetLargeMTU() { 48 | return initializingRaknetLargeMTU.get(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /fabric/build.gradle: -------------------------------------------------------------------------------- 1 | evaluationDependsOn(":") 2 | 3 | apply plugin: 'fabric-loom' 4 | apply plugin: 'com.github.johnrengelman.shadow' 5 | apply plugin: 'com.modrinth.minotaur' 6 | apply plugin: 'com.matthewprenger.cursegradle' 7 | 8 | archivesBaseName = project.archives_base_name + "-fabric" 9 | group = project.maven_group + ".fabric" 10 | 11 | configurations { 12 | shadowInclude 13 | } 14 | 15 | dependencies { 16 | // To change the versions see the gradle.properties file 17 | minecraft "com.mojang:minecraft:${project.minecraft_version}" 18 | mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" 19 | modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" 20 | 21 | shadowInclude implementation(project(":common")) 22 | 23 | // Fabric API. This is technically optional, but you probably want it anyway. 24 | // modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" 25 | } 26 | 27 | processResources { 28 | inputs.property "version", project.version 29 | 30 | filesMatching("fabric.mod.json") { 31 | expand "version": project.version 32 | } 33 | } 34 | 35 | tasks.withType(JavaCompile).configureEach { 36 | // Minecraft 1.18 (1.18-pre2) upwards uses Java 17. 37 | it.options.release = 17 38 | } 39 | 40 | java { 41 | // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task 42 | // if it is present. 43 | // If you remove this line, sources will not be generated. 44 | withSourcesJar() 45 | } 46 | 47 | loom { 48 | accessWidenerPath = file("src/main/resources/raknetify-fabric.accesswidener") 49 | runs { 50 | server { 51 | vmArgs "-Draknetify.debug=true", "-Dio.netty.leakDetection.level=advanced" 52 | ideConfigGenerated(true) 53 | } 54 | client { 55 | vmArgs "-Draknetify.debug=true", "-Dio.netty.leakDetection.level=advanced" 56 | ideConfigGenerated(true) 57 | } 58 | } 59 | } 60 | 61 | jar { 62 | exclude "META-INF/LICENSE.txt" 63 | exclude "META-INF/NOTICE.txt" 64 | from "../LICENSE" 65 | } 66 | 67 | shadowJar { 68 | dependencies { 69 | exclude(dependency('it.unimi.dsi:fastutil')) 70 | } 71 | exclude "META-INF/LICENSE.txt" 72 | exclude "META-INF/NOTICE.txt" 73 | minimize() 74 | archiveClassifier = "all-dev" 75 | configurations = [ project.configurations.shadowInclude ] 76 | from "../LICENSE" 77 | } 78 | 79 | //noinspection UnnecessaryQualifiedReference 80 | task("remapShadowJar", type: net.fabricmc.loom.task.RemapJarTask, dependsOn: shadowJar) { 81 | input = shadowJar.archiveFile 82 | archiveFileName = shadowJar.archiveFileName.get().replaceAll("-dev\\.jar\$", ".jar") 83 | addNestedDependencies = true 84 | } 85 | 86 | assemble.dependsOn(remapShadowJar) 87 | 88 | afterEvaluate { 89 | migrateMappings.configure { 90 | outputDir = project.file("build/remappedSrc") 91 | doLast { 92 | copy { 93 | from project.file("build/remappedSrc") 94 | into project.file("src/main/java") 95 | } 96 | } 97 | } 98 | } 99 | 100 | tasks.withType(AbstractArchiveTask) { 101 | preserveFileTimestamps = false 102 | reproducibleFileOrder = true 103 | } 104 | 105 | modrinth { 106 | versionNumber = project.version 107 | versionName = project.version + " devbuild" 108 | uploadFile = remapShadowJar 109 | loaders = ["fabric", "quilt"] 110 | } 111 | 112 | if (System.getenv("CURSEFORGE_TOKEN")) { 113 | curseforge { 114 | apiKey = System.getenv("CURSEFORGE_TOKEN") 115 | project { 116 | id = '631457' 117 | changelogType = "markdown" 118 | changelog = com.ishland.buildscript.ParseGItHubActionChangelog.getChangelog() 119 | releaseType = 'alpha' 120 | 121 | addGameVersion "1.17" 122 | addGameVersion "1.17.1" 123 | addGameVersion "1.18" 124 | addGameVersion "1.18.1" 125 | addGameVersion "1.18.2" 126 | addGameVersion "1.19" 127 | addGameVersion "1.19.1" 128 | addGameVersion "1.19.2" 129 | addGameVersion "1.19.3" 130 | addGameVersion "1.19.4" 131 | addGameVersion "1.20" 132 | addGameVersion "1.20.1" 133 | addGameVersion "1.20.2" 134 | addGameVersion "1.20.3" 135 | addGameVersion "1.20.4" 136 | addGameVersion "1.20.5" 137 | addGameVersion "1.20.6" 138 | addGameVersion "1.21" 139 | addGameVersion "1.21.1" 140 | addGameVersion "1.21.2" 141 | addGameVersion "1.21.3" 142 | addGameVersion "1.21.4" 143 | addGameVersion "1.21.5" 144 | addGameVersion "Fabric" 145 | addGameVersion "Java 17" 146 | addGameVersion "Java 18" 147 | addGameVersion "Java 19" 148 | addGameVersion "Java 20" 149 | addGameVersion "Java 21" 150 | addGameVersion "Java 22" 151 | 152 | mainArtifact(remapShadowJar) { 153 | displayName = project.version + " devbuild" 154 | } 155 | } 156 | options { 157 | forgeGradleIntegration = false 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/common/compat/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.common.compat; 26 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/common/connection/MultiChannellingPacketCapture.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.common.connection; 26 | 27 | import com.ishland.raknetify.common.connection.RakNetSimpleMultiChannelCodec; 28 | import com.ishland.raknetify.common.connection.multichannel.CustomPayloadChannel; 29 | import io.netty.buffer.ByteBuf; 30 | import io.netty.channel.ChannelHandler; 31 | import io.netty.channel.ChannelHandlerContext; 32 | import io.netty.channel.ChannelOutboundHandlerAdapter; 33 | import io.netty.channel.ChannelPromise; 34 | import net.minecraft.network.packet.c2s.common.CustomPayloadC2SPacket; 35 | import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket; 36 | 37 | @ChannelHandler.Sharable 38 | public class MultiChannellingPacketCapture extends ChannelOutboundHandlerAdapter { 39 | 40 | private Class packetClass = null; 41 | 42 | @Override 43 | public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { 44 | this.packetClass = msg.getClass(); 45 | try { 46 | ctx.write(msg, promise); 47 | } finally { 48 | this.packetClass = null; 49 | } 50 | } 51 | 52 | public Class getPacketClass() { 53 | return this.packetClass; 54 | } 55 | 56 | public void setPacketClass(Class packetClass) { 57 | this.packetClass = packetClass; 58 | } 59 | 60 | public RakNetSimpleMultiChannelCodec.OverrideHandler getCaptureBasedHandler() { 61 | return new CaptureBasedHandler(); 62 | } 63 | 64 | public RakNetSimpleMultiChannelCodec.OverrideHandler getCustomPayloadHandler() { 65 | return new CustomPayloadChannel.OverrideHandler(value -> packetClass == CustomPayloadS2CPacket.class || packetClass == CustomPayloadC2SPacket.class); 66 | } 67 | 68 | private class CaptureBasedHandler implements RakNetSimpleMultiChannelCodec.OverrideHandler { 69 | 70 | @Override 71 | public int getChannelOverride(ByteBuf buf, boolean suppressWarning) { 72 | return RakNetMultiChannel.getPacketChannelOverride(packetClass, suppressWarning); 73 | } 74 | 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/common/connection/RakNetClientConnectionUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.common.connection; 26 | 27 | import com.ishland.raknetify.common.util.ThreadLocalUtil; 28 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 29 | import io.netty.channel.ChannelFuture; 30 | import net.minecraft.network.ClientConnection; 31 | 32 | import java.net.InetSocketAddress; 33 | 34 | public class RakNetClientConnectionUtil { 35 | 36 | private RakNetClientConnectionUtil() { 37 | } 38 | 39 | public static ClientConnection connect(InetSocketAddress address, boolean useEpoll, boolean largeMTU, Operation original, boolean hasPerformanceLog) { 40 | System.out.println("aaa"); 41 | try { 42 | ThreadLocalUtil.setInitializingRaknet(true); 43 | ThreadLocalUtil.setInitializingRaknetLargeMTU(largeMTU); 44 | if (hasPerformanceLog) { 45 | return original.call(address, useEpoll, null); 46 | } else { 47 | return original.call(address, useEpoll); 48 | } 49 | } finally { 50 | ThreadLocalUtil.setInitializingRaknet(false); 51 | ThreadLocalUtil.setInitializingRaknetLargeMTU(false); 52 | } 53 | } 54 | 55 | public static ChannelFuture connect(InetSocketAddress address, boolean useEpoll, boolean largeMTU, ClientConnection connection) { 56 | System.out.println("aaaa"); 57 | try { 58 | ThreadLocalUtil.setInitializingRaknet(true); 59 | ThreadLocalUtil.setInitializingRaknetLargeMTU(largeMTU); 60 | return ClientConnection.connect(address, useEpoll, connection); 61 | } finally { 62 | ThreadLocalUtil.setInitializingRaknet(false); 63 | ThreadLocalUtil.setInitializingRaknetLargeMTU(false); 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/common/connection/RakNetCompressionCompatibilityHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.common.connection; 26 | 27 | import io.netty.channel.ChannelDuplexHandler; 28 | import io.netty.channel.ChannelHandlerContext; 29 | import io.netty.channel.ChannelPromise; 30 | import net.minecraft.network.packet.s2c.login.LoginCompressionS2CPacket; 31 | 32 | public class RakNetCompressionCompatibilityHandler extends ChannelDuplexHandler { 33 | 34 | @Override 35 | public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { 36 | if (msg instanceof LoginCompressionS2CPacket) { 37 | promise.trySuccess(); 38 | ctx.write(msg); 39 | ctx.pipeline().remove(this); 40 | return; 41 | } 42 | super.write(ctx, msg, promise); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/common/connection/RakNetFabricChannelEventListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.common.connection; 26 | 27 | import com.ishland.raknetify.common.connection.RakNetSimpleMultiChannelCodec; 28 | import com.ishland.raknetify.common.connection.SynchronizationLayer; 29 | import com.ishland.raknetify.fabric.mixin.RaknetifyFabricMixinPlugin; 30 | import io.netty.channel.ChannelDuplexHandler; 31 | import io.netty.channel.ChannelHandlerContext; 32 | import io.netty.channel.ChannelPromise; 33 | import net.minecraft.network.handler.NetworkStateTransitions; 34 | import net.minecraft.network.packet.c2s.play.AcknowledgeReconfigurationC2SPacket; 35 | import net.minecraft.network.packet.s2c.play.CommandTreeS2CPacket; 36 | import net.minecraft.network.packet.s2c.play.EnterReconfigurationS2CPacket; 37 | import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket; 38 | import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket; 39 | 40 | public class RakNetFabricChannelEventListener extends ChannelDuplexHandler { 41 | 42 | public static final String NAME = "raknetify-fabric-event-listener"; 43 | 44 | private static final boolean isReconfigurationSupported; 45 | 46 | static { 47 | boolean isReconfigurationSupported0; 48 | try { 49 | EnterReconfigurationS2CPacket.class.getName(); 50 | isReconfigurationSupported0 = true; 51 | } catch (NoClassDefFoundError e) { 52 | isReconfigurationSupported0 = false; 53 | } 54 | isReconfigurationSupported = isReconfigurationSupported0; 55 | } 56 | 57 | @Override 58 | public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { 59 | if (msg instanceof PlayerRespawnS2CPacket || msg instanceof GameJoinS2CPacket) { 60 | ctx.write(SynchronizationLayer.SYNC_REQUEST_OBJECT); 61 | } 62 | if (isReconfigurationSupported) { 63 | if (msg instanceof EnterReconfigurationS2CPacket || msg instanceof AcknowledgeReconfigurationC2SPacket) { 64 | ctx.write(SynchronizationLayer.SYNC_REQUEST_OBJECT); 65 | } 66 | } 67 | if (msg instanceof CommandTreeS2CPacket) { 68 | ctx.write(RakNetSimpleMultiChannelCodec.SIGNAL_START_MULTICHANNEL); 69 | } 70 | if (RaknetifyFabricMixinPlugin.AFTER_1_20_5) { 71 | if (msg instanceof NetworkStateTransitions.DecoderTransitioner || msg instanceof NetworkStateTransitions.EncoderTransitioner) { 72 | ctx.write(RakNetNetworkTransitionUtil.handleTransition(msg), promise); 73 | return; 74 | } 75 | } 76 | super.write(ctx, msg, promise); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/common/connection/RakNetFabricConnectionUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.common.connection; 26 | 27 | import com.ishland.raknetify.common.Constants; 28 | import com.ishland.raknetify.common.connection.MultiChannelingStreamingCompression; 29 | import com.ishland.raknetify.common.connection.RakNetConnectionUtil; 30 | import com.ishland.raknetify.common.connection.RakNetSimpleMultiChannelCodec; 31 | import com.ishland.raknetify.fabric.common.compat.viafabric.ViaFabricCompatInjector; 32 | import io.netty.channel.Channel; 33 | import io.netty.channel.ChannelDuplexHandler; 34 | import io.netty.channel.ChannelHandler; 35 | import io.netty.channel.ChannelHandlerContext; 36 | import io.netty.channel.ChannelPipeline; 37 | import network.ycc.raknet.RakNet; 38 | 39 | public class RakNetFabricConnectionUtil { 40 | 41 | public static final String NAME_RAKNETIFY_MULTI_CHANNEL_PACKET_CATURE = "raknetify-multi-channel-packet-cature"; 42 | 43 | private RakNetFabricConnectionUtil() { 44 | } 45 | 46 | public static void initChannel(Channel channel) { 47 | if (channel.config() instanceof RakNet.Config) { 48 | RakNetConnectionUtil.initChannel(channel); 49 | channel.pipeline().addAfter(MultiChannelingStreamingCompression.NAME, RakNetSimpleMultiChannelCodec.NAME, new RakNetSimpleMultiChannelCodec(Constants.RAKNET_GAME_PACKET_ID)); 50 | } 51 | } 52 | 53 | public static void postInitChannel(Channel channel, boolean isClientSide) { 54 | if (channel.config() instanceof RakNet.Config) { 55 | ViaFabricCompatInjector.inject(channel, isClientSide); 56 | channel.pipeline().replace("timeout", "timeout", new ChannelDuplexHandler()); // no-op 57 | channel.pipeline().replace("splitter", "splitter", new ChannelDuplexHandler()); // no-op 58 | channel.pipeline().replace("prepender", "prepender", new ChannelDuplexHandler()); // no-op 59 | final MultiChannellingPacketCapture handler = new MultiChannellingPacketCapture(); 60 | channel.pipeline().addLast(NAME_RAKNETIFY_MULTI_CHANNEL_PACKET_CATURE, handler); 61 | onPipelineReorder(channel.pipeline()); 62 | channel.pipeline().get(RakNetSimpleMultiChannelCodec.class) 63 | .addHandler(handler.getCustomPayloadHandler()) 64 | .addHandler(handler.getCaptureBasedHandler()); 65 | channel.pipeline().addLast("raknetify-handle-compression-compatibility", new RakNetCompressionCompatibilityHandler()); 66 | channel.pipeline().addBefore("packet_handler", RakNetFabricChannelEventListener.NAME, new RakNetFabricChannelEventListener()); 67 | } 68 | } 69 | 70 | static void onPipelineReorder(ChannelPipeline pipeline) { 71 | if (pipeline.get("encoder") == null) { 72 | // System.out.println("Reordering failed: no encoder"); 73 | return; 74 | } 75 | // System.out.println("Reordering"); 76 | ChannelHandler handler = pipeline.remove(RakNetFabricConnectionUtil.NAME_RAKNETIFY_MULTI_CHANNEL_PACKET_CATURE); 77 | if (handler != null) { 78 | pipeline.addAfter("encoder", RakNetFabricConnectionUtil.NAME_RAKNETIFY_MULTI_CHANNEL_PACKET_CATURE, handler); 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/common/connection/RakNetNetworkTransitionUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.common.connection; 26 | 27 | import net.minecraft.network.handler.NetworkStateTransitions; 28 | 29 | public class RakNetNetworkTransitionUtil { 30 | 31 | static Object handleTransition(Object msg) { 32 | if (msg instanceof NetworkStateTransitions.DecoderTransitioner transitioner) { 33 | return transitioner.andThen(context -> RakNetFabricConnectionUtil.onPipelineReorder(context.pipeline())); 34 | } else if (msg instanceof NetworkStateTransitions.EncoderTransitioner transitioner) { 35 | return transitioner.andThen(context -> RakNetFabricConnectionUtil.onPipelineReorder(context.pipeline())); 36 | } 37 | return msg; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/common/connection/encryption/PacketEncryptionManagerInterface.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.common.connection.encryption; 26 | 27 | import io.netty.channel.ChannelHandlerContext; 28 | 29 | public interface PacketEncryptionManagerInterface { 30 | 31 | void setContext(ChannelHandlerContext ctx); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/common/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.common; 26 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/common/quirks/ClientHungerManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.common.quirks; 26 | 27 | import net.minecraft.component.type.FoodComponent; 28 | import net.minecraft.entity.player.HungerManager; 29 | import net.minecraft.nbt.NbtCompound; 30 | 31 | public class ClientHungerManager extends HungerManager { 32 | 33 | public static ClientHungerManager from(HungerManager hungerManager) { 34 | ClientHungerManager clientHungerManager = new ClientHungerManager(); 35 | NbtCompound compound = new NbtCompound(); 36 | hungerManager.writeNbt(compound); 37 | clientHungerManager.readNbt(compound); 38 | return clientHungerManager; 39 | } 40 | 41 | public void add(int food, float saturationModifier) { 42 | // nop 43 | } 44 | 45 | public void eat(FoodComponent foodComponent) { 46 | // nop 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/common/util/FieldSignatureParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.common.util; 26 | 27 | import org.objectweb.asm.Type; 28 | import org.objectweb.asm.signature.SignatureReader; 29 | import org.objectweb.asm.signature.SignatureVisitor; 30 | import org.spongepowered.asm.util.asm.ASM; 31 | 32 | import java.util.ArrayList; 33 | import java.util.List; 34 | 35 | public class FieldSignatureParser extends SignatureVisitor { 36 | 37 | private final List results = new ArrayList<>(); 38 | 39 | private FieldSignatureParser() { 40 | super(ASM.API_VERSION); 41 | } 42 | 43 | public static List parse(String signature) { 44 | if (signature == null || signature.isEmpty()) { 45 | return List.of(); 46 | } 47 | FieldSignatureParser parser = new FieldSignatureParser(); 48 | new SignatureReader(signature).acceptType(parser); 49 | return parser.results; 50 | } 51 | 52 | @Override 53 | public void visitClassType(String name) { 54 | results.add(Type.getObjectType(name)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/common/util/NetworkStates.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.common.util; 26 | 27 | import net.minecraft.network.NetworkPhase; 28 | 29 | public class NetworkStates { 30 | 31 | public static String getName(NetworkPhase state) { 32 | return switch (state) { 33 | case HANDSHAKING -> "HANDSHAKING"; 34 | case PLAY -> "PLAY"; 35 | case STATUS -> "STATUS"; 36 | case LOGIN -> "LOGIN"; 37 | default -> state.toString(); 38 | }; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/access/IClientConnection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.access; 26 | 27 | import io.netty.channel.Channel; 28 | import net.minecraft.network.ClientConnection; 29 | import org.spongepowered.asm.mixin.Mixin; 30 | import org.spongepowered.asm.mixin.gen.Accessor; 31 | 32 | @Mixin(ClientConnection.class) 33 | public interface IClientConnection { 34 | 35 | @Accessor 36 | Channel getChannel(); 37 | 38 | @Accessor 39 | void setEncrypted(boolean encrypted); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/access/IClientPlayNetworkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.access; 26 | 27 | import net.minecraft.client.network.ClientPlayNetworkHandler; 28 | import net.minecraft.network.ClientConnection; 29 | import org.spongepowered.asm.mixin.Mixin; 30 | import org.spongepowered.asm.mixin.gen.Accessor; 31 | 32 | @Mixin(ClientPlayNetworkHandler.class) 33 | public interface IClientPlayNetworkHandler { 34 | 35 | } 36 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/access/INetworkState1_20_4.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.access; 26 | 27 | import net.minecraft.network.NetworkPhase; 28 | import net.minecraft.network.NetworkSide; 29 | import org.spongepowered.asm.mixin.Dynamic; 30 | import org.spongepowered.asm.mixin.Mixin; 31 | import org.spongepowered.asm.mixin.Pseudo; 32 | import org.spongepowered.asm.mixin.gen.Accessor; 33 | 34 | import java.util.Map; 35 | 36 | @Pseudo 37 | @Mixin(targets = "net/minecraft/class_2539") 38 | public interface INetworkState1_20_4 { 39 | 40 | @Dynamic 41 | @Accessor(value = "field_20595", remap = false) 42 | Map getPacketHandlers(); 43 | 44 | } 45 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/access/INetworkStateInternalPacketHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.access; 26 | 27 | import it.unimi.dsi.fastutil.objects.Object2IntMap; 28 | import net.minecraft.network.NetworkPhase; 29 | import net.minecraft.network.packet.Packet; 30 | import org.spongepowered.asm.mixin.Mixin; 31 | import org.spongepowered.asm.mixin.gen.Accessor; 32 | 33 | @Mixin(targets = "net/minecraft/class_2539$class_4532") 34 | public interface INetworkStateInternalPacketHandler { 35 | 36 | @Accessor(value = "field_20596") 37 | Object2IntMap>> getPacketIds(); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/access/IPacketCodecDispatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.access; 26 | 27 | import io.netty.buffer.ByteBuf; 28 | import net.minecraft.network.handler.PacketCodecDispatcher; 29 | import org.spongepowered.asm.mixin.Mixin; 30 | import org.spongepowered.asm.mixin.gen.Accessor; 31 | 32 | import java.util.List; 33 | 34 | @Mixin(PacketCodecDispatcher.class) 35 | public interface IPacketCodecDispatcher { 36 | 37 | @Accessor 38 | List> getPacketTypes(); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/access/IPacketCodecDispatcherPacketType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.access; 26 | 27 | import net.minecraft.network.handler.PacketCodecDispatcher; 28 | import org.spongepowered.asm.mixin.Mixin; 29 | 30 | @Mixin(PacketCodecDispatcher.PacketType.class) 31 | public interface IPacketCodecDispatcherPacketType { 32 | } 33 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/access/IPacketEncryptionManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.access; 26 | 27 | import io.netty.buffer.ByteBuf; 28 | import io.netty.channel.ChannelHandlerContext; 29 | import net.minecraft.network.encryption.PacketEncryptionManager; 30 | import org.spongepowered.asm.mixin.Mixin; 31 | import org.spongepowered.asm.mixin.gen.Invoker; 32 | 33 | import javax.crypto.ShortBufferException; 34 | 35 | @Mixin(PacketEncryptionManager.class) 36 | public interface IPacketEncryptionManager { 37 | 38 | @Invoker 39 | ByteBuf invokeDecrypt(ChannelHandlerContext context, ByteBuf buf) throws ShortBufferException; 40 | 41 | @Invoker 42 | void invokeEncrypt(ByteBuf buf, ByteBuf result) throws ShortBufferException; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/access/IServerPlayNetworkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.access; 26 | 27 | import net.minecraft.server.network.ServerPlayNetworkHandler; 28 | import org.spongepowered.asm.mixin.Mixin; 29 | 30 | @Mixin(ServerPlayNetworkHandler.class) 31 | public interface IServerPlayNetworkHandler { 32 | 33 | } 34 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/client/MixinClientPlayNetworkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.client; 26 | 27 | import com.ishland.raknetify.common.connection.RakNetSimpleMultiChannelCodec; 28 | import com.ishland.raknetify.fabric.common.util.MultiVersionUtil; 29 | import com.ishland.raknetify.fabric.mixin.access.IClientConnection; 30 | import io.netty.channel.Channel; 31 | import net.minecraft.client.network.ClientPlayNetworkHandler; 32 | import net.minecraft.network.ClientConnection; 33 | import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket; 34 | import org.spongepowered.asm.mixin.Final; 35 | import org.spongepowered.asm.mixin.Mixin; 36 | import org.spongepowered.asm.mixin.Shadow; 37 | import org.spongepowered.asm.mixin.injection.At; 38 | import org.spongepowered.asm.mixin.injection.Inject; 39 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 40 | 41 | @Mixin(ClientPlayNetworkHandler.class) 42 | public class MixinClientPlayNetworkHandler { 43 | 44 | @Inject(method = "onGameJoin", at = @At("RETURN")) 45 | private void postGameJoin(GameJoinS2CPacket packet, CallbackInfo ci) { 46 | final Channel channel = ((IClientConnection) MultiVersionUtil.ClientPlayNetworkHandler$connection.get((ClientPlayNetworkHandler) (Object) this)).getChannel(); 47 | if (channel == null) { 48 | //noinspection RedundantStringFormatCall 49 | System.err.println("Raknetify: Warning: %s don't have valid channel when logged in, not sending sync packet".formatted(this)); 50 | return; 51 | } 52 | channel.eventLoop().execute(() -> channel.write(RakNetSimpleMultiChannelCodec.SIGNAL_START_MULTICHANNEL)); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/client/MixinConnectionScreen1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.client; 26 | 27 | import com.ishland.raknetify.fabric.common.connection.RakNetClientConnectionUtil; 28 | import com.ishland.raknetify.common.util.PrefixUtil; 29 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 30 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 31 | import io.netty.channel.ChannelFuture; 32 | import net.minecraft.client.network.ServerAddress; 33 | import net.minecraft.network.ClientConnection; 34 | import org.spongepowered.asm.mixin.Dynamic; 35 | import org.spongepowered.asm.mixin.Final; 36 | import org.spongepowered.asm.mixin.Mixin; 37 | import org.spongepowered.asm.mixin.Mutable; 38 | import org.spongepowered.asm.mixin.Shadow; 39 | import org.spongepowered.asm.mixin.Unique; 40 | import org.spongepowered.asm.mixin.injection.At; 41 | import org.spongepowered.asm.mixin.injection.Inject; 42 | import org.spongepowered.asm.mixin.injection.Redirect; 43 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 44 | 45 | import java.net.InetSocketAddress; 46 | 47 | @Mixin(targets = "net/minecraft/client/gui/screen/multiplayer/ConnectScreen$1") 48 | public class MixinConnectionScreen1 extends Thread { 49 | 50 | @Mutable 51 | @Shadow 52 | @Final 53 | ServerAddress field_33737; 54 | 55 | @Unique 56 | private boolean isRaknet = false; 57 | 58 | @Unique 59 | private boolean raknetLargeMTU = false; 60 | 61 | @Inject(method = "*", at = @At("RETURN"), remap = false) 62 | private void onInit(CallbackInfo ci) { 63 | final PrefixUtil.Info info = PrefixUtil.getInfo(this.field_33737.getAddress()); 64 | if (info.useRakNet()) { 65 | this.isRaknet = true; 66 | this.raknetLargeMTU = info.largeMTU(); 67 | this.field_33737 = new ServerAddress(info.stripped(), this.field_33737.getPort()); 68 | } 69 | } 70 | 71 | @Dynamic 72 | @WrapOperation(method = "run()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;method_10753(Ljava/net/InetSocketAddress;Z)Lnet/minecraft/network/ClientConnection;"), require = 0) 73 | private ClientConnection connectRaknet(InetSocketAddress address, boolean useEpoll, Operation original) { 74 | return this.isRaknet ? RakNetClientConnectionUtil.connect(address, useEpoll, this.raknetLargeMTU, original, false) : original.call(address, useEpoll); 75 | } 76 | 77 | @WrapOperation(method = "run()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;connect(Ljava/net/InetSocketAddress;ZLnet/minecraft/network/ClientConnection;)Lio/netty/channel/ChannelFuture;"), require = 0) 78 | private ChannelFuture connectRaknet(InetSocketAddress address, boolean useEpoll, ClientConnection connection, Operation original) { 79 | return this.isRaknet ? RakNetClientConnectionUtil.connect(address, useEpoll, this.raknetLargeMTU, connection) : original.call(address, useEpoll, connection); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/client/MixinMultiplayerServerListPinger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.client; 26 | 27 | import com.ishland.raknetify.fabric.common.connection.RakNetClientConnectionUtil; 28 | import com.ishland.raknetify.common.util.PrefixUtil; 29 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 30 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 31 | import net.minecraft.client.network.MultiplayerServerListPinger; 32 | import net.minecraft.client.network.ServerAddress; 33 | import net.minecraft.client.network.ServerInfo; 34 | import net.minecraft.network.ClientConnection; 35 | import org.spongepowered.asm.mixin.Dynamic; 36 | import org.spongepowered.asm.mixin.Mixin; 37 | import org.spongepowered.asm.mixin.injection.At; 38 | import org.spongepowered.asm.mixin.injection.Redirect; 39 | 40 | import java.net.InetSocketAddress; 41 | 42 | @Mixin(MultiplayerServerListPinger.class) 43 | public abstract class MixinMultiplayerServerListPinger { 44 | 45 | @Dynamic 46 | @WrapOperation(method = {"add", "method_3003"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ServerAddress;parse(Ljava/lang/String;)Lnet/minecraft/client/network/ServerAddress;")) 47 | private ServerAddress modifyRaknetAddress(String address, Operation original) { 48 | final PrefixUtil.Info info = PrefixUtil.getInfo(address); 49 | return original.call(info.stripped()); 50 | } 51 | 52 | @Dynamic 53 | @WrapOperation(method = {"add", "method_3003"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;method_10753(Ljava/net/InetSocketAddress;Z)Lnet/minecraft/network/ClientConnection;"), require = 0) 54 | private ClientConnection redirectConnect(InetSocketAddress address, boolean useEpoll, Operation original, ServerInfo entry, Runnable runnable) { 55 | final PrefixUtil.Info info = PrefixUtil.getInfo(entry.address); 56 | return info.useRakNet() ? RakNetClientConnectionUtil.connect(address, useEpoll, info.largeMTU(), original, false) : original.call(address, useEpoll); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/client/MixinMultiplayerServerListPinger1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.client; 26 | 27 | import com.ishland.raknetify.fabric.mixin.access.IClientConnection; 28 | import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; 29 | import io.netty.channel.Channel; 30 | import net.minecraft.client.network.MultiplayerServerListPinger; 31 | import net.minecraft.client.network.ServerAddress; 32 | import net.minecraft.client.network.ServerInfo; 33 | import net.minecraft.network.ClientConnection; 34 | import net.minecraft.network.listener.ClientQueryPacketListener; 35 | import network.ycc.raknet.RakNet; 36 | import org.spongepowered.asm.mixin.Dynamic; 37 | import org.spongepowered.asm.mixin.Final; 38 | import org.spongepowered.asm.mixin.Mixin; 39 | import org.spongepowered.asm.mixin.Shadow; 40 | import org.spongepowered.asm.mixin.injection.At; 41 | import org.spongepowered.asm.mixin.injection.Inject; 42 | import org.spongepowered.asm.mixin.injection.Redirect; 43 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 44 | 45 | import java.net.InetSocketAddress; 46 | 47 | @Mixin(targets = "net/minecraft/client/network/MultiplayerServerListPinger$1") 48 | public abstract class MixinMultiplayerServerListPinger1 implements ClientQueryPacketListener { 49 | 50 | @Shadow 51 | @Final 52 | ClientConnection field_3774; // synthetic 53 | 54 | @Shadow 55 | @Final 56 | ServerInfo field_3776; // synthetic 57 | 58 | @Inject(method = "onResponse(Lnet/minecraft/network/packet/s2c/query/QueryResponseS2CPacket;)V", at = @At("RETURN")) 59 | private void setPingImmediately(CallbackInfo ci) { 60 | final Channel channel = ((IClientConnection) field_3774).getChannel(); 61 | if (channel.config() instanceof RakNet.Config config) { 62 | field_3776.ping = config.getRTTNanos() / 1_000_000; 63 | } 64 | } 65 | 66 | @Dynamic 67 | @WrapWithCondition(method = {"method_10839(Lnet/minecraft/class_2561;)V", "onDisconnected"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/MultiplayerServerListPinger;ping(Ljava/net/InetSocketAddress;Lnet/minecraft/client/network/ServerAddress;Lnet/minecraft/client/network/ServerInfo;)V"), require = 0) 68 | private boolean noPingRaknet(MultiplayerServerListPinger instance, InetSocketAddress socketAddress, ServerAddress address, ServerInfo serverInfo) { 69 | final Channel channel = ((IClientConnection) field_3774).getChannel(); 70 | return !(channel.config() instanceof RakNet.Config); 71 | } 72 | 73 | @Dynamic 74 | @WrapWithCondition(method = "method_10839(Lnet/minecraft/class_2561;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/MultiplayerServerListPinger;method_3001(Ljava/net/InetSocketAddress;Lnet/minecraft/client/network/ServerInfo;)V"), require = 0) 75 | private boolean noPingRaknet(MultiplayerServerListPinger instance, InetSocketAddress address, ServerInfo info) { 76 | final Channel channel = ((IClientConnection) field_3774).getChannel(); 77 | return !(channel.config() instanceof RakNet.Config); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/client/MixinMultiplayerServerListPinger1_20_2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.client; 26 | 27 | import com.ishland.raknetify.common.util.PrefixUtil; 28 | import com.ishland.raknetify.fabric.common.connection.RakNetClientConnectionUtil; 29 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 30 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 31 | import net.minecraft.client.network.MultiplayerServerListPinger; 32 | import net.minecraft.client.network.ServerInfo; 33 | import net.minecraft.network.ClientConnection; 34 | import net.minecraft.util.profiler.log.DebugSampleLog; 35 | import org.spongepowered.asm.mixin.Dynamic; 36 | import org.spongepowered.asm.mixin.Mixin; 37 | import org.spongepowered.asm.mixin.injection.At; 38 | 39 | import java.net.InetSocketAddress; 40 | 41 | @Mixin(MultiplayerServerListPinger.class) 42 | public class MixinMultiplayerServerListPinger1_20_2 { 43 | 44 | @Dynamic 45 | @WrapOperation(method = {"add", "method_3003"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;method_10753(Ljava/net/InetSocketAddress;ZLnet/minecraft/class_8743;)Lnet/minecraft/network/ClientConnection;")) 46 | private ClientConnection redirectConnect(InetSocketAddress address, boolean useEpoll, DebugSampleLog log, Operation original, ServerInfo entry, Runnable runnable) { 47 | final PrefixUtil.Info info = PrefixUtil.getInfo(entry.address); 48 | return info.useRakNet() ? RakNetClientConnectionUtil.connect(address, useEpoll, info.largeMTU(), original, true) : original.call(address, useEpoll, null); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/client/MixinMultiplayerServerListPinger1_20_5.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.client; 26 | 27 | import com.ishland.raknetify.common.util.PrefixUtil; 28 | import com.ishland.raknetify.fabric.common.connection.RakNetClientConnectionUtil; 29 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 30 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 31 | import net.minecraft.client.network.MultiplayerServerListPinger; 32 | import net.minecraft.client.network.ServerInfo; 33 | import net.minecraft.network.ClientConnection; 34 | import net.minecraft.util.profiler.MultiValueDebugSampleLogImpl; 35 | import net.minecraft.util.profiler.log.DebugSampleLog; 36 | import net.minecraft.util.profiler.log.MultiValueDebugSampleLog; 37 | import org.spongepowered.asm.mixin.Dynamic; 38 | import org.spongepowered.asm.mixin.Mixin; 39 | import org.spongepowered.asm.mixin.injection.At; 40 | 41 | import java.net.InetSocketAddress; 42 | 43 | @Mixin(MultiplayerServerListPinger.class) 44 | public class MixinMultiplayerServerListPinger1_20_5 { 45 | 46 | @WrapOperation(method = "add", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;connect(Ljava/net/InetSocketAddress;ZLnet/minecraft/util/profiler/MultiValueDebugSampleLogImpl;)Lnet/minecraft/network/ClientConnection;")) 47 | private ClientConnection redirectConnect(InetSocketAddress address, boolean useEpoll, MultiValueDebugSampleLogImpl log, Operation original, ServerInfo entry, Runnable runnable) { 48 | final PrefixUtil.Info info = PrefixUtil.getInfo(entry.address); 49 | return info.useRakNet() ? RakNetClientConnectionUtil.connect(address, useEpoll, info.largeMTU(), original, true) : original.call(address, useEpoll, null); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/common/MixinClientConnection1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.common; 26 | 27 | import com.ishland.raknetify.fabric.common.connection.RakNetFabricConnectionUtil; 28 | import io.netty.channel.Channel; 29 | import io.netty.channel.ChannelInitializer; 30 | import org.spongepowered.asm.mixin.Mixin; 31 | import org.spongepowered.asm.mixin.injection.At; 32 | import org.spongepowered.asm.mixin.injection.Inject; 33 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 34 | 35 | @Mixin(targets = "net/minecraft/network/ClientConnection$1") 36 | public abstract class MixinClientConnection1 extends ChannelInitializer { 37 | 38 | @Inject(method = "initChannel(Lio/netty/channel/Channel;)V", at = @At("HEAD")) 39 | private void onChannelInit(Channel channel, CallbackInfo ci) { 40 | RakNetFabricConnectionUtil.initChannel(channel); 41 | } 42 | 43 | @Inject(method = "initChannel(Lio/netty/channel/Channel;)V", at = @At("RETURN")) 44 | private void postChannelInit(Channel channel, CallbackInfo ci) { 45 | RakNetFabricConnectionUtil.postInitChannel(channel, true); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/common/MixinClientConnection1_20_2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.common; 26 | 27 | import com.ishland.raknetify.common.connection.SimpleMetricsLogger; 28 | import io.netty.channel.Channel; 29 | import net.minecraft.network.ClientConnection; 30 | import net.minecraft.network.handler.PacketSizeLogger; 31 | import network.ycc.raknet.RakNet; 32 | import org.jetbrains.annotations.Nullable; 33 | import org.spongepowered.asm.mixin.Mixin; 34 | import org.spongepowered.asm.mixin.Shadow; 35 | import org.spongepowered.asm.mixin.Unique; 36 | import org.spongepowered.asm.mixin.injection.At; 37 | import org.spongepowered.asm.mixin.injection.Inject; 38 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 39 | 40 | @Mixin(ClientConnection.class) 41 | public class MixinClientConnection1_20_2 { 42 | 43 | @Shadow private Channel channel; 44 | @Shadow private @Nullable PacketSizeLogger packetSizeLogger; 45 | 46 | @Unique 47 | private long raknetify$lastBytesIn = 0L; 48 | 49 | @Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/handler/PacketSizeLogger;push()V")) 50 | private void onPacketLoggerPush(CallbackInfo ci) { 51 | PacketSizeLogger logger = this.packetSizeLogger; 52 | if (logger != null && this.channel.config() instanceof RakNet.Config config && config.getMetrics() instanceof SimpleMetricsLogger simpleMetricsLogger) { 53 | long bytesIn = simpleMetricsLogger.getBytesIn(); 54 | logger.increment((int) (bytesIn - this.raknetify$lastBytesIn)); 55 | this.raknetify$lastBytesIn = bytesIn; 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/common/MixinServerAddress.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.common; 26 | 27 | import com.ishland.raknetify.common.Constants; 28 | import com.ishland.raknetify.common.util.PrefixUtil; 29 | import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; 30 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 31 | import net.minecraft.client.network.ServerAddress; 32 | import org.spongepowered.asm.mixin.Mixin; 33 | 34 | @Mixin(ServerAddress.class) 35 | public class MixinServerAddress { 36 | 37 | @WrapMethod(method = "parse") 38 | private static ServerAddress wrapParsing(String address, Operation original) { 39 | PrefixUtil.Info info = PrefixUtil.getInfo(address); 40 | if (info.useRakNet()) { 41 | ServerAddress addr = original.call(info.stripped()); 42 | return new ServerAddress( 43 | (info.largeMTU() ? Constants.RAKNET_LARGE_MTU_PREFIX : Constants.RAKNET_PREFIX) + addr.getAddress(), 44 | addr.getPort() 45 | ); 46 | } else { 47 | return original.call(address); 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/common/encryption/MixinClientConnection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.common.encryption; 26 | 27 | import com.ishland.raknetify.common.connection.MultiChannelingStreamingCompression; 28 | import com.ishland.raknetify.common.connection.MultiChannellingEncryption; 29 | import io.netty.channel.Channel; 30 | import net.minecraft.network.ClientConnection; 31 | import net.minecraft.network.encryption.PacketDecryptor; 32 | import net.minecraft.network.encryption.PacketEncryptionManager; 33 | import net.minecraft.network.encryption.PacketEncryptor; 34 | import network.ycc.raknet.RakNet; 35 | import org.spongepowered.asm.mixin.Mixin; 36 | import org.spongepowered.asm.mixin.Overwrite; 37 | import org.spongepowered.asm.mixin.Shadow; 38 | import org.spongepowered.asm.mixin.injection.At; 39 | import org.spongepowered.asm.mixin.injection.Inject; 40 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 41 | 42 | import javax.crypto.Cipher; 43 | 44 | @Mixin(ClientConnection.class) 45 | public class MixinClientConnection { 46 | 47 | @Shadow 48 | private boolean encrypted; 49 | 50 | @Shadow 51 | private Channel channel; 52 | 53 | @Inject(method = "setupEncryption", at = @At("HEAD"), cancellable = true) 54 | public void beforeSetupEncryption(Cipher decryptionCipher, Cipher encryptionCipher, CallbackInfo ci) { 55 | if (this.channel.config() instanceof RakNet.Config) { 56 | ci.cancel(); 57 | this.encrypted = true; 58 | try { 59 | this.channel.pipeline().remove("decrypt"); 60 | this.channel.pipeline().remove("encrypt"); 61 | } catch (Throwable ignored) { 62 | } 63 | try { 64 | this.channel.pipeline().remove(MultiChannellingEncryption.NAME); 65 | } catch (Throwable ignored) { 66 | } 67 | this.channel.pipeline().addBefore(MultiChannelingStreamingCompression.NAME, MultiChannellingEncryption.NAME, 68 | new MultiChannellingEncryption(decryptionCipher, encryptionCipher)); 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/common/encryption/MixinPacketDecryptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.common.encryption; 26 | 27 | import com.ishland.raknetify.fabric.common.connection.encryption.PacketEncryptionManagerInterface; 28 | import io.netty.buffer.ByteBuf; 29 | import io.netty.channel.ChannelHandlerContext; 30 | import net.minecraft.network.encryption.PacketDecryptor; 31 | import net.minecraft.network.encryption.PacketEncryptionManager; 32 | import org.spongepowered.asm.mixin.Final; 33 | import org.spongepowered.asm.mixin.Mixin; 34 | import org.spongepowered.asm.mixin.Shadow; 35 | import org.spongepowered.asm.mixin.injection.At; 36 | import org.spongepowered.asm.mixin.injection.Inject; 37 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 38 | 39 | import java.util.List; 40 | 41 | @Mixin(PacketDecryptor.class) 42 | public class MixinPacketDecryptor { 43 | 44 | @Shadow @Final private PacketEncryptionManager manager; 45 | 46 | @Inject(method = "decode(Lio/netty/channel/ChannelHandlerContext;Lio/netty/buffer/ByteBuf;Ljava/util/List;)V", at = @At("HEAD")) 47 | private void preDecrypt(ChannelHandlerContext ctx, ByteBuf byteBuf, List list, CallbackInfo ci) { 48 | ((PacketEncryptionManagerInterface) this.manager).setContext(ctx); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/common/encryption/MixinPacketEncryptionManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.common.encryption; 26 | 27 | import com.ishland.raknetify.fabric.common.connection.encryption.PacketEncryptionManagerInterface; 28 | import io.netty.channel.ChannelHandlerContext; 29 | import net.minecraft.network.encryption.PacketEncryptionManager; 30 | import network.ycc.raknet.RakNet; 31 | import org.spongepowered.asm.mixin.Mixin; 32 | import org.spongepowered.asm.mixin.Unique; 33 | import org.spongepowered.asm.mixin.injection.At; 34 | import org.spongepowered.asm.mixin.injection.Redirect; 35 | 36 | import javax.crypto.BadPaddingException; 37 | import javax.crypto.Cipher; 38 | import javax.crypto.IllegalBlockSizeException; 39 | import javax.crypto.ShortBufferException; 40 | 41 | @Mixin(PacketEncryptionManager.class) 42 | public class MixinPacketEncryptionManager implements PacketEncryptionManagerInterface { 43 | 44 | @Unique 45 | private ChannelHandlerContext ctx; 46 | 47 | @Override 48 | public void setContext(ChannelHandlerContext ctx) { 49 | this.ctx = ctx; 50 | } 51 | 52 | @Redirect(method = "decrypt", at = @At(value = "INVOKE", target = "Ljavax/crypto/Cipher;update([BII[BI)I")) 53 | private int redirectDecrypt(Cipher instance, byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { 54 | if (ctx.channel().config() instanceof RakNet.Config) { 55 | return instance.doFinal(input, inputOffset, inputLen, output, outputOffset); 56 | } else { 57 | return instance.update(input, inputOffset, inputLen, output, outputOffset); 58 | } 59 | } 60 | 61 | @Redirect(method = "encrypt", at = @At(value = "INVOKE", target = "Ljavax/crypto/Cipher;update([BII[B)I")) 62 | private int redirectEncrypt(Cipher instance, byte[] input, int inputOffset, int inputLen, byte[] output) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException { 63 | if (ctx.channel().config() instanceof RakNet.Config) { 64 | return instance.doFinal(input, inputOffset, inputLen, output); 65 | } else { 66 | return instance.update(input, inputOffset, inputLen, output); 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/common/encryption/MixinPacketEncryptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.common.encryption; 26 | 27 | import com.ishland.raknetify.fabric.common.connection.encryption.PacketEncryptionManagerInterface; 28 | import io.netty.buffer.ByteBuf; 29 | import io.netty.channel.ChannelHandlerContext; 30 | import net.minecraft.network.encryption.PacketEncryptionManager; 31 | import net.minecraft.network.encryption.PacketEncryptor; 32 | import org.spongepowered.asm.mixin.Final; 33 | import org.spongepowered.asm.mixin.Mixin; 34 | import org.spongepowered.asm.mixin.Shadow; 35 | import org.spongepowered.asm.mixin.injection.At; 36 | import org.spongepowered.asm.mixin.injection.Inject; 37 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 38 | 39 | @Mixin(PacketEncryptor.class) 40 | public class MixinPacketEncryptor { 41 | 42 | @Shadow @Final private PacketEncryptionManager manager; 43 | 44 | @Inject(method = "encode(Lio/netty/channel/ChannelHandlerContext;Lio/netty/buffer/ByteBuf;Lio/netty/buffer/ByteBuf;)V", at = @At("HEAD")) 45 | private void preEncrypt(ChannelHandlerContext ctx, ByteBuf byteBuf, ByteBuf byteBuf2, CallbackInfo ci) { 46 | ((PacketEncryptionManagerInterface) this.manager).setContext(ctx); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/common/quirks/MixinPlayerEntity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.common.quirks; 26 | 27 | import com.ishland.raknetify.fabric.common.quirks.ClientHungerManager; 28 | import net.minecraft.entity.EntityType; 29 | import net.minecraft.entity.LivingEntity; 30 | import net.minecraft.entity.player.HungerManager; 31 | import net.minecraft.entity.player.PlayerEntity; 32 | import net.minecraft.world.World; 33 | import org.spongepowered.asm.mixin.Mixin; 34 | import org.spongepowered.asm.mixin.Shadow; 35 | import org.spongepowered.asm.mixin.injection.At; 36 | import org.spongepowered.asm.mixin.injection.Inject; 37 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 38 | 39 | @Mixin(PlayerEntity.class) 40 | public abstract class MixinPlayerEntity extends LivingEntity { 41 | 42 | @Shadow protected HungerManager hungerManager; 43 | 44 | protected MixinPlayerEntity(EntityType entityType, World world) { 45 | super(entityType, world); 46 | } 47 | 48 | @Inject(method = "", at = @At("RETURN"), remap = false) 49 | private void replaceHungerManager(CallbackInfo ci) { 50 | if (this.getWorld().isClient) { 51 | this.hungerManager = ClientHungerManager.from(this.hungerManager); 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/common/quirks/MixinSampleSubscriptionTracker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.common.quirks; 26 | 27 | import net.minecraft.server.SampleSubscriptionTracker; 28 | import org.spongepowered.asm.mixin.Final; 29 | import org.spongepowered.asm.mixin.Mixin; 30 | import org.spongepowered.asm.mixin.Shadow; 31 | import org.spongepowered.asm.mixin.injection.At; 32 | import org.spongepowered.asm.mixin.injection.Inject; 33 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 34 | 35 | import java.util.Queue; 36 | 37 | @Mixin(SampleSubscriptionTracker.class) 38 | public class MixinSampleSubscriptionTracker { 39 | 40 | @Shadow @Final private Queue pendingQueue; 41 | 42 | @Inject(method = "onSubscription", at = @At("RETURN")) 43 | private void cleanQueue(CallbackInfo ci) { 44 | this.pendingQueue.clear(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/compat/fabricapi/MixinServerLoginNetworkAddon.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.compat.fabricapi; 26 | 27 | import com.ishland.raknetify.common.connection.MultiChannelingStreamingCompression; 28 | import com.ishland.raknetify.fabric.mixin.access.IClientConnection; 29 | import net.minecraft.network.ClientConnection; 30 | import net.minecraft.server.MinecraftServer; 31 | import org.spongepowered.asm.mixin.Dynamic; 32 | import org.spongepowered.asm.mixin.Final; 33 | import org.spongepowered.asm.mixin.Mixin; 34 | import org.spongepowered.asm.mixin.Pseudo; 35 | import org.spongepowered.asm.mixin.Shadow; 36 | import org.spongepowered.asm.mixin.injection.At; 37 | import org.spongepowered.asm.mixin.injection.Inject; 38 | import org.spongepowered.asm.mixin.injection.Redirect; 39 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 40 | 41 | import java.lang.reflect.Method; 42 | 43 | @Pseudo 44 | @Mixin(targets = "net.fabricmc.fabric.impl.networking.server.ServerLoginNetworkAddon") 45 | public class MixinServerLoginNetworkAddon { 46 | 47 | @Shadow 48 | @Final 49 | private ClientConnection connection; 50 | 51 | @Dynamic("Pseudo") 52 | @Redirect(method = "sendCompressionPacket()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getNetworkCompressionThreshold()I")) 53 | private int stopCompressionIfStreamingCompressionExists(MinecraftServer server) { 54 | final MultiChannelingStreamingCompression compression = ((IClientConnection) this.connection).getChannel().pipeline().get(MultiChannelingStreamingCompression.class); 55 | if (compression != null && compression.isActive()) { 56 | System.out.println("Raknetify: Preventing vanilla compression as streaming compression is enabled"); 57 | return -1; 58 | } 59 | return server.getNetworkCompressionThreshold(); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/compat/krypton/MixinServerLoginNetworkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.compat.krypton; 26 | 27 | import com.ishland.raknetify.fabric.mixin.access.IClientConnection; 28 | import io.netty.channel.ChannelHandler; 29 | import io.netty.channel.ChannelPipeline; 30 | import net.minecraft.network.ClientConnection; 31 | import net.minecraft.network.encryption.NetworkEncryptionException; 32 | import net.minecraft.network.encryption.NetworkEncryptionUtils; 33 | import net.minecraft.network.packet.c2s.login.LoginKeyC2SPacket; 34 | import net.minecraft.server.MinecraftServer; 35 | import net.minecraft.server.network.ServerLoginNetworkHandler; 36 | import network.ycc.raknet.RakNet; 37 | import org.spongepowered.asm.mixin.Final; 38 | import org.spongepowered.asm.mixin.Mixin; 39 | import org.spongepowered.asm.mixin.Shadow; 40 | import org.spongepowered.asm.mixin.injection.At; 41 | import org.spongepowered.asm.mixin.injection.Inject; 42 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 43 | 44 | import javax.crypto.Cipher; 45 | import javax.crypto.SecretKey; 46 | import java.security.PrivateKey; 47 | 48 | @Mixin(ServerLoginNetworkHandler.class) 49 | public class MixinServerLoginNetworkHandler { 50 | 51 | @Shadow 52 | @Final 53 | public ClientConnection connection; 54 | 55 | @Shadow @Final private MinecraftServer server; 56 | 57 | @Shadow @Final private byte[] nonce; 58 | 59 | @Inject(method = "onKey", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;setupEncryption(Ljavax/crypto/Cipher;Ljavax/crypto/Cipher;)V", shift = At.Shift.AFTER)) 60 | private void afterSetupEncryption(LoginKeyC2SPacket packet, CallbackInfo ci) throws NetworkEncryptionException { 61 | final ChannelPipeline pipeline = ((IClientConnection) this.connection).getChannel().pipeline(); 62 | if (((IClientConnection) this.connection).getChannel().config() instanceof RakNet.Config) { 63 | final ChannelHandler decrypt = pipeline.get("decrypt"); 64 | final ChannelHandler encrypt = pipeline.get("encrypt"); 65 | if (decrypt != null && (decrypt.getClass().getName().equals("me.steinborn.krypton.mod.shared.network.pipeline.MinecraftCipherDecoder")) && 66 | encrypt != null && (encrypt.getClass().getName().equals("me.steinborn.krypton.mod.shared.network.pipeline.MinecraftCipherEncoder"))) { 67 | System.out.println("Raknetify: Krypton detected, applying compatibility"); 68 | 69 | pipeline.remove("decrypt"); 70 | pipeline.remove("encrypt"); 71 | 72 | // TODO [VanillaCopy] 73 | PrivateKey privateKey = this.server.getKeyPair().getPrivate(); 74 | 75 | SecretKey secretKey = packet.decryptSecretKey(privateKey); 76 | Cipher cipher = NetworkEncryptionUtils.cipherFromKey(2, secretKey); 77 | Cipher cipher2 = NetworkEncryptionUtils.cipherFromKey(1, secretKey); 78 | 79 | ((IClientConnection) this.connection).setEncrypted(false); 80 | this.connection.setupEncryption(cipher, cipher2); 81 | } 82 | } 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/compat/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.compat; 26 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/compat/qsl/MixinServerLoginNetworkAddon.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.compat.qsl; 26 | 27 | import com.ishland.raknetify.common.connection.MultiChannelingStreamingCompression; 28 | import com.ishland.raknetify.fabric.mixin.access.IClientConnection; 29 | import net.minecraft.network.ClientConnection; 30 | import net.minecraft.server.MinecraftServer; 31 | import org.spongepowered.asm.mixin.Dynamic; 32 | import org.spongepowered.asm.mixin.Final; 33 | import org.spongepowered.asm.mixin.Mixin; 34 | import org.spongepowered.asm.mixin.Pseudo; 35 | import org.spongepowered.asm.mixin.Shadow; 36 | import org.spongepowered.asm.mixin.injection.At; 37 | import org.spongepowered.asm.mixin.injection.Inject; 38 | import org.spongepowered.asm.mixin.injection.Redirect; 39 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 40 | 41 | import java.lang.reflect.Method; 42 | 43 | @Pseudo 44 | @Mixin(targets = "org.quiltmc.qsl.networking.impl.server.ServerLoginNetworkAddon") 45 | public class MixinServerLoginNetworkAddon { 46 | 47 | @Shadow 48 | @Final 49 | private ClientConnection connection; 50 | 51 | @Dynamic("Pseudo") 52 | @Redirect(method = "sendCompressionPacket()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getNetworkCompressionThreshold()I")) 53 | private int stopCompressionIfStreamingCompressionExists(MinecraftServer server) { 54 | final MultiChannelingStreamingCompression compression = ((IClientConnection) this.connection).getChannel().pipeline().get(MultiChannelingStreamingCompression.class); 55 | if (compression != null && compression.isActive()) { 56 | System.out.println("Raknetify: Preventing vanilla compression as streaming compression is enabled"); 57 | return -1; 58 | } 59 | return server.getNetworkCompressionThreshold(); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin; 26 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/server/MixinPlayerManager1_20_1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.server; 26 | 27 | import com.ishland.raknetify.common.connection.RakNetSimpleMultiChannelCodec; 28 | import com.ishland.raknetify.fabric.mixin.access.IClientConnection; 29 | import io.netty.channel.Channel; 30 | import net.minecraft.network.ClientConnection; 31 | import net.minecraft.server.PlayerManager; 32 | import net.minecraft.server.network.ServerPlayerEntity; 33 | import network.ycc.raknet.RakNet; 34 | import org.spongepowered.asm.mixin.Dynamic; 35 | import org.spongepowered.asm.mixin.Mixin; 36 | import org.spongepowered.asm.mixin.injection.At; 37 | import org.spongepowered.asm.mixin.injection.Inject; 38 | import org.spongepowered.asm.mixin.injection.Surrogate; 39 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 40 | 41 | @Mixin(PlayerManager.class) 42 | public class MixinPlayerManager1_20_1 { 43 | 44 | @Dynamic 45 | @Inject(method = {"onPlayerConnect", "method_12975"}, at = @At("HEAD"), require = 0) 46 | private void onJoin(ClientConnection connection, ServerPlayerEntity player, int latency, CallbackInfo ci) { 47 | if (((IClientConnection) connection).getChannel().config() instanceof RakNet.Config config) { 48 | System.out.println(String.format("Raknetify: %s logged in via RakNet, mtu %d", player.getName().getString(), config.getMTU())); 49 | } 50 | } 51 | 52 | @Surrogate 53 | private void onJoin(ClientConnection connection, ServerPlayerEntity player, CallbackInfo ci) { 54 | if (((IClientConnection) connection).getChannel().config() instanceof RakNet.Config config) { 55 | System.out.println(String.format("Raknetify: %s logged in via RakNet, mtu %d", player.getName().getString(), config.getMTU())); 56 | } 57 | } 58 | 59 | @Dynamic 60 | @Inject(method = {"onPlayerConnect", "method_12975"}, at = @At("RETURN"), require = 0) 61 | private void postJoin(ClientConnection connection, ServerPlayerEntity player, int latency, CallbackInfo ci) { 62 | final Channel channel = ((IClientConnection) connection).getChannel(); 63 | if (channel == null) { 64 | //noinspection RedundantStringFormatCall 65 | System.err.println("Raknetify: Warning: %s don't have valid channel when logged in, not sending sync packet".formatted(this)); 66 | return; 67 | } 68 | channel.write(RakNetSimpleMultiChannelCodec.SIGNAL_START_MULTICHANNEL); 69 | } 70 | 71 | @Surrogate 72 | private void postJoin(ClientConnection connection, ServerPlayerEntity player, CallbackInfo ci) { 73 | final Channel channel = ((IClientConnection) connection).getChannel(); 74 | if (channel == null) { 75 | //noinspection RedundantStringFormatCall 76 | System.err.println("Raknetify: Warning: %s don't have valid channel when logged in, not sending sync packet".formatted(this)); 77 | return; 78 | } 79 | channel.write(RakNetSimpleMultiChannelCodec.SIGNAL_START_MULTICHANNEL); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/server/MixinPlayerManager1_20_2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.server; 26 | 27 | import com.ishland.raknetify.common.connection.RakNetSimpleMultiChannelCodec; 28 | import com.ishland.raknetify.fabric.mixin.access.IClientConnection; 29 | import io.netty.channel.Channel; 30 | import net.minecraft.network.ClientConnection; 31 | import net.minecraft.server.PlayerManager; 32 | import net.minecraft.server.network.ConnectedClientData; 33 | import net.minecraft.server.network.ServerPlayerEntity; 34 | import network.ycc.raknet.RakNet; 35 | import org.spongepowered.asm.mixin.Dynamic; 36 | import org.spongepowered.asm.mixin.Mixin; 37 | import org.spongepowered.asm.mixin.injection.At; 38 | import org.spongepowered.asm.mixin.injection.Inject; 39 | import org.spongepowered.asm.mixin.injection.Surrogate; 40 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 41 | 42 | @Mixin(PlayerManager.class) 43 | public class MixinPlayerManager1_20_2 { 44 | 45 | @Inject(method = "onPlayerConnect", at = @At("HEAD")) 46 | private void onJoin(ClientConnection connection, ServerPlayerEntity player, ConnectedClientData clientData, CallbackInfo ci) { 47 | if (((IClientConnection) connection).getChannel().config() instanceof RakNet.Config config) { 48 | System.out.println(String.format("Raknetify: %s logged in via RakNet, mtu %d", player.getName().getString(), config.getMTU())); 49 | } 50 | } 51 | 52 | @Inject(method = "onPlayerConnect", at = @At("RETURN")) 53 | private void postJoin(ClientConnection connection, ServerPlayerEntity player, ConnectedClientData clientData, CallbackInfo ci) { 54 | final Channel channel = ((IClientConnection) connection).getChannel(); 55 | if (channel == null) { 56 | //noinspection RedundantStringFormatCall 57 | System.err.println("Raknetify: Warning: %s don't have valid channel when logged in, not sending sync packet".formatted(this)); 58 | return; 59 | } 60 | channel.write(RakNetSimpleMultiChannelCodec.SIGNAL_START_MULTICHANNEL); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/server/MixinServerCommonNetworkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.server; 26 | 27 | import com.ishland.raknetify.fabric.common.util.MultiVersionUtil; 28 | import com.ishland.raknetify.fabric.mixin.access.IClientConnection; 29 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue; 30 | import com.llamalad7.mixinextras.injector.WrapWithCondition; 31 | import io.netty.channel.Channel; 32 | import net.minecraft.network.ClientConnection; 33 | import net.minecraft.network.listener.ServerCommonPacketListener; 34 | import net.minecraft.server.network.ServerCommonNetworkHandler; 35 | import net.minecraft.server.network.ServerPlayNetworkHandler; 36 | import net.minecraft.text.Text; 37 | import net.minecraft.util.Util; 38 | import network.ycc.raknet.RakNet; 39 | import org.objectweb.asm.Opcodes; 40 | import org.spongepowered.asm.mixin.Final; 41 | import org.spongepowered.asm.mixin.Mixin; 42 | import org.spongepowered.asm.mixin.Shadow; 43 | import org.spongepowered.asm.mixin.injection.At; 44 | import org.spongepowered.asm.mixin.injection.Inject; 45 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 46 | 47 | @Mixin(ServerCommonNetworkHandler.class) 48 | public abstract class MixinServerCommonNetworkHandler implements ServerCommonPacketListener { 49 | 50 | @Shadow @Final protected ClientConnection connection; 51 | 52 | @Shadow private int latency; 53 | 54 | @ModifyExpressionValue(method = "baseTick", at = @At(value = "FIELD", target = "Lnet/minecraft/server/network/ServerCommonNetworkHandler;lastKeepAliveTime:J", opcode = Opcodes.GETFIELD)) 55 | private long disableKeepAlive(long original) { 56 | if (!(((IClientConnection) this.connection).getChannel().config() instanceof RakNet.Config)) { 57 | return original; 58 | } 59 | return Util.getMeasuringTimeMs(); 60 | } 61 | 62 | @WrapWithCondition(method = "onKeepAlive", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerCommonNetworkHandler;disconnect(Lnet/minecraft/text/Text;)V")) 63 | private boolean stopTimeoutPlayersOnKeepAlive(ServerCommonNetworkHandler instance, Text reason) { 64 | return !(((IClientConnection) MultiVersionUtil.ServerPlayNetworkHandler$connection.get((ServerCommonNetworkHandler) (Object) this)).getChannel().config() instanceof RakNet.Config); 65 | } 66 | 67 | @WrapWithCondition(method = "onKeepAlive", at = @At(value = "FIELD", target = "Lnet/minecraft/server/network/ServerCommonNetworkHandler;latency:I", opcode = Opcodes.PUTFIELD)) 68 | private boolean redirectPingStoring(ServerCommonNetworkHandler instance, int value) { 69 | return !(((IClientConnection) MultiVersionUtil.ServerPlayNetworkHandler$connection.get((ServerCommonNetworkHandler) (Object) this)).getChannel().config() instanceof RakNet.Config); 70 | } 71 | 72 | @Inject(method = "baseTick", at = @At("HEAD")) 73 | private void onTick(CallbackInfo ci) { 74 | final Channel channel = ((IClientConnection) MultiVersionUtil.ServerPlayNetworkHandler$connection.get((ServerCommonNetworkHandler) (Object) this)).getChannel(); 75 | if (channel != null && channel.config() instanceof RakNet.Config config) { 76 | this.latency = (int) ((config.getRTTNanos() + config.getRTTStdDevNanos()) / 1_000_000); 77 | } 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/server/MixinServerLoginNetworkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.server; 26 | 27 | import com.ishland.raknetify.common.connection.MultiChannelingStreamingCompression; 28 | import com.ishland.raknetify.fabric.mixin.access.IClientConnection; 29 | import net.minecraft.network.ClientConnection; 30 | import net.minecraft.server.MinecraftServer; 31 | import net.minecraft.server.network.ServerLoginNetworkHandler; 32 | import org.spongepowered.asm.mixin.Dynamic; 33 | import org.spongepowered.asm.mixin.Final; 34 | import org.spongepowered.asm.mixin.Mixin; 35 | import org.spongepowered.asm.mixin.Shadow; 36 | import org.spongepowered.asm.mixin.injection.At; 37 | import org.spongepowered.asm.mixin.injection.Inject; 38 | import org.spongepowered.asm.mixin.injection.Redirect; 39 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 40 | 41 | import java.lang.reflect.Method; 42 | 43 | @Mixin(value = ServerLoginNetworkHandler.class, priority = 900) 44 | public class MixinServerLoginNetworkHandler { 45 | 46 | @Shadow @Final public ClientConnection connection; 47 | 48 | @Shadow @Final private MinecraftServer server; 49 | 50 | @Dynamic 51 | @Redirect(method = {"method_14384()V", "tickVerify"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getNetworkCompressionThreshold()I"), require = 1) 52 | private int stopCompressionIfStreamingCompressionExists(MinecraftServer server) { 53 | final MultiChannelingStreamingCompression compression = ((IClientConnection) this.connection).getChannel().pipeline().get(MultiChannelingStreamingCompression.class); 54 | if (compression != null && compression.isActive()) { 55 | System.out.println("Raknetify: Preventing vanilla compression as streaming compression is enabled"); 56 | return -1; 57 | } 58 | return server.getNetworkCompressionThreshold(); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/server/MixinServerNetworkIo1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.server; 26 | 27 | import com.ishland.raknetify.fabric.common.connection.RakNetFabricConnectionUtil; 28 | import io.netty.channel.Channel; 29 | import io.netty.channel.ChannelInitializer; 30 | import org.spongepowered.asm.mixin.Mixin; 31 | import org.spongepowered.asm.mixin.injection.At; 32 | import org.spongepowered.asm.mixin.injection.Inject; 33 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 34 | 35 | @Mixin(targets = "net/minecraft/server/ServerNetworkIo$1") 36 | public abstract class MixinServerNetworkIo1 extends ChannelInitializer { 37 | 38 | @Inject(method = "initChannel(Lio/netty/channel/Channel;)V", at = @At("HEAD")) 39 | private void onChannelInit(Channel channel, CallbackInfo ci) { 40 | RakNetFabricConnectionUtil.initChannel(channel); 41 | } 42 | 43 | @Inject(method = "initChannel(Lio/netty/channel/Channel;)V", at = @At("RETURN")) 44 | private void postChannelInit(Channel channel, CallbackInfo ci) { 45 | RakNetFabricConnectionUtil.postInitChannel(channel, false); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /fabric/src/main/java/com/ishland/raknetify/fabric/mixin/server/MixinServerPlayNetworkHandler1_20_1.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Raknetify project, licensed under MIT. 3 | * 4 | * Copyright (c) 2022-2025 ishland 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.ishland.raknetify.fabric.mixin.server; 26 | 27 | import com.ishland.raknetify.fabric.common.util.MultiVersionUtil; 28 | import com.ishland.raknetify.fabric.mixin.access.IClientConnection; 29 | import com.llamalad7.mixinextras.injector.ModifyExpressionValue; 30 | import com.llamalad7.mixinextras.injector.WrapWithCondition; 31 | import io.netty.channel.Channel; 32 | import net.minecraft.server.network.ServerCommonNetworkHandler; 33 | import net.minecraft.server.network.ServerPlayNetworkHandler; 34 | import net.minecraft.server.network.ServerPlayerEntity; 35 | import net.minecraft.text.Text; 36 | import net.minecraft.util.Util; 37 | import network.ycc.raknet.RakNet; 38 | import org.objectweb.asm.Opcodes; 39 | import org.spongepowered.asm.mixin.Dynamic; 40 | import org.spongepowered.asm.mixin.Mixin; 41 | import org.spongepowered.asm.mixin.Shadow; 42 | import org.spongepowered.asm.mixin.injection.At; 43 | import org.spongepowered.asm.mixin.injection.Inject; 44 | import org.spongepowered.asm.mixin.injection.Redirect; 45 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 46 | 47 | @Mixin(ServerPlayNetworkHandler.class) 48 | public class MixinServerPlayNetworkHandler1_20_1 { 49 | 50 | @Shadow public ServerPlayerEntity player; 51 | 52 | @Dynamic 53 | @ModifyExpressionValue(method = "tick", at = @At(value = "FIELD", target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;field_14136:J", opcode = Opcodes.GETFIELD)) 54 | private long disableKeepAlive(long original) { 55 | if (!(((IClientConnection) MultiVersionUtil.ServerPlayNetworkHandler$connection.get((ServerPlayNetworkHandler) (Object) this)).getChannel().config() instanceof RakNet.Config)) { 56 | return original; 57 | } 58 | return Util.getMeasuringTimeMs(); 59 | } 60 | 61 | @Dynamic 62 | @WrapWithCondition(method = "method_12082", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;method_14367(Lnet/minecraft/text/Text;)V")) 63 | private boolean stopTimeoutPlayersOnKeepAlive(ServerPlayNetworkHandler instance, Text reason) { 64 | return !(((IClientConnection) MultiVersionUtil.ServerPlayNetworkHandler$connection.get((ServerPlayNetworkHandler) (Object) this)).getChannel().config() instanceof RakNet.Config); 65 | } 66 | 67 | @Dynamic 68 | @WrapWithCondition(method = "method_12082", at = @At(value = "FIELD", target = "Lnet/minecraft/server/network/ServerPlayerEntity;field_13967:I", opcode = Opcodes.PUTFIELD)) 69 | private boolean redirectPingStoring(ServerPlayerEntity instance, int value) { 70 | return !(((IClientConnection) MultiVersionUtil.ServerPlayNetworkHandler$connection.get((ServerPlayNetworkHandler) (Object) this)).getChannel().config() instanceof RakNet.Config); 71 | } 72 | 73 | @Inject(method = "tick", at = @At("HEAD")) 74 | private void onTick(CallbackInfo ci) { 75 | final Channel channel = ((IClientConnection) MultiVersionUtil.ServerPlayNetworkHandler$connection.get((ServerPlayNetworkHandler) (Object) this)).getChannel(); 76 | if (channel != null && channel.config() instanceof RakNet.Config config) { 77 | assert MultiVersionUtil.ServerPlayerEntity$pingMillis1_20_1 != null; 78 | MultiVersionUtil.ServerPlayerEntity$pingMillis1_20_1.set(this.player, (int) ((config.getRTTNanos() + config.getRTTStdDevNanos()) / 1_000_000)); 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /fabric/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "raknetify", 4 | "version": "${version}", 5 | 6 | "name": "Raknetify (Fabric)", 7 | "description": "A Fabric mod that allows using RakNet as Minecraft networking backend. ", 8 | "authors": [ 9 | "ishland" 10 | ], 11 | "contact": { 12 | }, 13 | 14 | "license": "MIT", 15 | 16 | "environment": "*", 17 | "entrypoints": { 18 | "main": [ 19 | "com.ishland.raknetify.fabric.RaknetifyFabric" 20 | ], 21 | "preLaunch": [ 22 | "com.ishland.raknetify.fabric.RaknetifyFabric" 23 | ] 24 | }, 25 | 26 | "accessWidener" : "raknetify-fabric.accesswidener", 27 | 28 | "mixins": [ 29 | "raknetify-fabric.mixins.json" 30 | ], 31 | 32 | "depends": { 33 | "fabricloader": ">=0.15.2", 34 | "java": ">=17" 35 | }, 36 | "suggests": { 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /fabric/src/main/resources/raknetify-fabric.accesswidener: -------------------------------------------------------------------------------- 1 | accessWidener v1 named 2 | 3 | accessible class net/minecraft/network/handler/PacketCodecDispatcher$PacketType 4 | 5 | accessible method net/minecraft/network/encryption/PacketEncryptionManager (Ljavax/crypto/Cipher;)V 6 | accessible method net/minecraft/client/network/MultiplayerServerListPinger createPlayerCountText (II)Lnet/minecraft/text/Text; 7 | -------------------------------------------------------------------------------- /fabric/src/main/resources/raknetify-fabric.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "com.ishland.raknetify.fabric.mixin", 5 | "plugin": "com.ishland.raknetify.fabric.mixin.RaknetifyFabricMixinPlugin", 6 | "compatibilityLevel": "JAVA_16", 7 | "mixinPriority": 1010, 8 | "mixins": [ 9 | "access.IClientConnection", 10 | "access.INetworkState1_20_4", 11 | "access.INetworkStateInternalPacketHandler", 12 | "access.IPacketCodecDispatcher", 13 | "access.IPacketCodecDispatcherPacketType", 14 | "access.IPacketEncryptionManager", 15 | "access.IServerPlayNetworkHandler", 16 | "client.MixinClientPlayNetworkHandler", 17 | "client.MixinConnectionScreen1", 18 | "client.MixinMultiplayerServerListPinger", 19 | "client.MixinMultiplayerServerListPinger1", 20 | "client.hud.MixinDebugHud", 21 | "common.MixinCCConnect", 22 | "common.MixinClientConnection", 23 | "common.MixinClientConnection1", 24 | "common.MixinClientConnection1_20_2", 25 | "common.encryption.MixinClientConnection", 26 | "common.encryption.MixinPacketDecryptor", 27 | "common.encryption.MixinPacketEncryptionManager", 28 | "common.encryption.MixinPacketEncryptor", 29 | "common.quirks.MixinPlayerEntity", 30 | "common.quirks.MixinSampleSubscriptionTracker", 31 | "compat.fabricapi.MixinServerLoginNetworkAddon", 32 | "compat.krypton.MixinServerLoginNetworkHandler", 33 | "compat.qsl.MixinServerLoginNetworkAddon", 34 | "server.MixinPlayerManager1_20_1", 35 | "server.MixinPlayerManager1_20_2", 36 | "server.MixinServerCommonNetworkHandler", 37 | "server.MixinServerLoginNetworkHandler", 38 | "server.MixinServerNetworkIo", 39 | "server.MixinServerNetworkIo1", 40 | "server.MixinServerPlayNetworkHandler1_20_1" 41 | ], 42 | "injectors": { 43 | "defaultRequire": 1 44 | }, 45 | "client": [ 46 | "access.IClientPlayNetworkHandler", 47 | "client.MixinMultiplayerServerListPinger1_20_2", 48 | "client.MixinMultiplayerServerListPinger1_20_5", 49 | "common.MixinServerAddress" 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /genMappings.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | loader_version=0.16.5 4 | installer_version=1.0.1 5 | 6 | #declare -a vers 7 | if [[ -z "$@" ]]; then 8 | vers="1.17 1.17.1 1.18.1 1.18.2 1.19 1.19.2 1.19.3 1.19.4 23w13a_or_b 1.20.1 1.20.2 1.20.4 1.20.6 1.21.1 1.21.3 1.21.4 1.21.5" 9 | else 10 | vers=$@ 11 | fi 12 | 13 | echo $vers 14 | 15 | ./gradlew clean build || exit 1 16 | 17 | mkdir run-mappingsGen || true 18 | cd run-mappingsGen || exit 1 19 | rm -r mods 20 | mkdir mods 21 | cp ../fabric/build/libs/raknetify-*-all.jar mods/ 22 | rm channelMappings.json || true 23 | if [[ -z "${MAPPINGS_GEN_FRESH}" ]]; then 24 | cp ../common/src/main/resources/raknetify-channel-mappings.json channelMappings.json 25 | fi 26 | 27 | for version in $vers 28 | do 29 | if [ -e fabric-server-mc"$version".jar ]; then 30 | echo "Using existing fabric-server-mc$version.jar" 31 | else 32 | wget -O fabric-server-mc"$version".jar https://meta.fabricmc.net/v2/versions/loader/"$version"/$loader_version/$installer_version/server/jar || exit 1 33 | fi 34 | 35 | sleep 1 36 | 37 | java -Draknetify.saveChannelMappings=true -Draknetify.saveChannelMappings.exit=true -jar fabric-server-mc"$version".jar || exit 1 38 | done 39 | 40 | cp channelMappings.json ../common/src/main/resources/raknetify-channel-mappings.json 41 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx4G 3 | org.gradle.parallel=true 4 | 5 | # Fabric Properties 6 | # check these on https://fabricmc.net/develop 7 | # 8 | # Also don't forget to gen mappings in genMappings.sh 9 | minecraft_version=1.21.5 10 | yarn_mappings=1.21.5+build.1 11 | loader_version=0.16.10 12 | 13 | # Mod Properties 14 | mod_version = 0.1.0+alpha.5 15 | maven_group = com.ishland.raknetify 16 | archives_base_name = raknetify 17 | 18 | # Dependencies 19 | #fabric_version=0.44.0+1.18 20 | #mixinextras_version=0.1.1 21 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RelativityMC/raknetify/75478a1d454efabba7749ff620cec7292b48f737/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RelativityMC/raknetify/75478a1d454efabba7749ff620cec7292b48f737/gradlew -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | before_install: 2 | - source "$HOME/.sdkman/bin/sdkman-init.sh" 3 | - sdk update 4 | - sdk install java 17.0.2-zulu 5 | - sdk use java 17.0.2-zulu 6 | -------------------------------------------------------------------------------- /modrinth_license.txt: -------------------------------------------------------------------------------- 1 | Licensing 2 | 3 | Raknetify for fabric and BungeeCord is licensed under the MIT license, 4 | you can find the license in the LICENSE file 5 | 6 | Raknetify for Velocity is licensed under the GNU General Public License v3.0, 7 | you can find the license in the velocity/LICENSE file 8 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } 11 | 12 | rootProject.name = "raknetify" 13 | 14 | includeBuild('netty-raknet') { 15 | dependencySubstitution { 16 | substitute module("com.github.RelativityMC.netty-raknet:netty-raknet-common") using project(":netty-raknet-common") 17 | substitute module("com.github.RelativityMC.netty-raknet:netty-raknet-client") using project(":netty-raknet-client") 18 | substitute module("com.github.RelativityMC.netty-raknet:netty-raknet-server") using project(":netty-raknet-server") 19 | } 20 | } 21 | 22 | include "fabric" 23 | include "velocity" 24 | include "bungee" 25 | include "common" 26 | -------------------------------------------------------------------------------- /velocity/HEADER.txt: -------------------------------------------------------------------------------- 1 | This file is a part of the Velocity implementation of the Raknetify 2 | project, licensed under GPLv3. 3 | 4 | Copyright (c) 2022-2025 ishland 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | -------------------------------------------------------------------------------- /velocity/build.gradle: -------------------------------------------------------------------------------- 1 | import java.nio.file.Files 2 | import java.nio.file.Paths 3 | import java.nio.file.StandardCopyOption 4 | 5 | evaluationDependsOn(":") 6 | 7 | apply plugin: 'com.github.johnrengelman.shadow' 8 | apply plugin: 'com.modrinth.minotaur' 9 | 10 | afterEvaluate { 11 | license { 12 | header = project.file('HEADER.txt') 13 | } 14 | } 15 | 16 | archivesBaseName = project.archives_base_name + "-velocity" 17 | group = project.maven_group + ".velocity" 18 | 19 | repositories { 20 | maven { 21 | name 'papermc' 22 | url 'https://repo.papermc.io/repository/maven-public/' 23 | } 24 | ivy { 25 | url 'https://api.papermc.io/v2/projects/' 26 | patternLayout { 27 | artifact "[organization]/versions/[module]/builds/[revision]/downloads/[organization]-[module]-[revision](.[ext])" 28 | } 29 | metadataSources { 30 | it.artifact() 31 | } 32 | } 33 | } 34 | 35 | configurations { 36 | shadowInclude 37 | } 38 | 39 | dependencies { 40 | // api 'com.velocitypowered:velocity-api:3.1.1' 41 | // annotationProcessor 'com.velocitypowered:velocity-api:3.1.1' 42 | 43 | implementation 'velocity:3.4.0-SNAPSHOT:496' 44 | // annotationProcessor 'velocity:3.1.2-SNAPSHOT:139' 45 | 46 | shadowInclude implementation(project(":common")) 47 | 48 | // copied here to workaround incomplete fastutil in velocity 49 | api("com.github.RelativityMC.netty-raknet:netty-raknet-common") { 50 | transitive = false 51 | } 52 | api("com.github.RelativityMC.netty-raknet:netty-raknet-client") 53 | api("com.github.RelativityMC.netty-raknet:netty-raknet-server") 54 | } 55 | 56 | processResources { 57 | inputs.property "version", project.version 58 | 59 | filesMatching("velocity-plugin.json") { 60 | expand "version": project.version 61 | } 62 | } 63 | 64 | jar { 65 | exclude "META-INF/LICENSE.txt" 66 | exclude "META-INF/NOTICE.txt" 67 | from "LICENSE" 68 | } 69 | 70 | shadowJar { 71 | dependencies { 72 | // exclude(dependency('it.unimi.dsi:fastutil')) 73 | } 74 | exclude "META-INF/LICENSE.txt" 75 | exclude "META-INF/NOTICE.txt" 76 | minimize() 77 | archiveClassifier = "all" 78 | configurations = [ project.configurations.shadowInclude ] 79 | from "LICENSE" 80 | } 81 | 82 | assemble.dependsOn(shadowJar) 83 | 84 | tasks.withType(AbstractArchiveTask) { 85 | preserveFileTimestamps = false 86 | reproducibleFileOrder = true 87 | } 88 | 89 | modrinth { 90 | versionNumber = project.version + "+velocity" 91 | versionName = project.version + " devbuild for Velocity" 92 | uploadFile = shadowJar 93 | loaders = ["velocity"] 94 | } 95 | 96 | task("prepareRunVelocity", dependsOn: shadowJar) { 97 | doFirst { 98 | Files.createDirectories(rootProject.projectDir.toPath().resolve("run-velocity").resolve("plugins")) 99 | Files.copy(shadowJar.archiveFile.getAsFile().get().toPath(), rootProject.projectDir.toPath().resolve("run-velocity").resolve("plugins").resolve("raknetify-velocity-devlaunch.jar"), StandardCopyOption.REPLACE_EXISTING) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /velocity/src/main/java/com/ishland/raknetify/velocity/RaknetifyVelocityLaunchWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Velocity implementation of the Raknetify 3 | * project, licensed under GPLv3. 4 | * 5 | * Copyright (c) 2022-2025 ishland 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | package com.ishland.raknetify.velocity; 22 | 23 | import com.ishland.raknetify.common.data.ProtocolMultiChannelMappings; 24 | import com.ishland.raknetify.velocity.connection.RakNetVelocityConnectionUtil; 25 | import com.ishland.raknetify.velocity.init.VelocityPacketRegistryInjector; 26 | import com.ishland.raknetify.velocity.init.VelocityRaknetifyServer; 27 | import com.velocitypowered.api.event.PostOrder; 28 | import com.velocitypowered.api.event.connection.LoginEvent; 29 | import com.velocitypowered.api.event.player.ServerPostConnectEvent; 30 | import com.velocitypowered.api.event.proxy.ListenerBoundEvent; 31 | import com.velocitypowered.api.event.proxy.ListenerCloseEvent; 32 | 33 | import static com.ishland.raknetify.velocity.RaknetifyVelocityPlugin.INSTANCE; 34 | import static com.ishland.raknetify.velocity.RaknetifyVelocityPlugin.LOGGER; 35 | import static com.ishland.raknetify.velocity.RaknetifyVelocityPlugin.PROXY; 36 | 37 | public class RaknetifyVelocityLaunchWrapper { 38 | 39 | public static void launch() { 40 | if (!isCompatible()) { 41 | Runnable runnable = () -> { 42 | LOGGER.error("This version of Raknetify is NOT compatible with your version of Velocity"); 43 | LOGGER.error("Please update your Velocity at https://papermc.io/downloads#Velocity"); 44 | }; 45 | runnable.run(); 46 | PROXY.getEventManager().register(INSTANCE, ListenerBoundEvent.class, PostOrder.LAST, ignored -> runnable.run()); 47 | return; 48 | } 49 | 50 | ProtocolMultiChannelMappings.init(); 51 | VelocityPacketRegistryInjector.inject(); 52 | 53 | PROXY.getEventManager().register(INSTANCE, LoginEvent.class, PostOrder.LAST, RakNetVelocityConnectionUtil::onPlayerLogin); 54 | PROXY.getEventManager().register(INSTANCE, ListenerBoundEvent.class, PostOrder.LAST, VelocityRaknetifyServer::start); 55 | PROXY.getEventManager().register(INSTANCE, ListenerCloseEvent.class, PostOrder.LAST, VelocityRaknetifyServer::stop); 56 | PROXY.getEventManager().register(INSTANCE, ServerPostConnectEvent.class, PostOrder.LAST, RakNetVelocityConnectionUtil::onServerSwitch); 57 | } 58 | 59 | private static boolean isCompatible() { 60 | try { 61 | Class.forName("com.velocitypowered.proxy.crypto.EncryptionUtils"); 62 | Class.forName("com.velocitypowered.proxy.protocol.packet.PluginMessagePacket"); 63 | return true; 64 | } catch (ClassNotFoundException e) { 65 | return false; 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /velocity/src/main/java/com/ishland/raknetify/velocity/connection/RakNetVelocityServerChannelEventListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Velocity implementation of the Raknetify 3 | * project, licensed under GPLv3. 4 | * 5 | * Copyright (c) 2022-2025 ishland 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | package com.ishland.raknetify.velocity.connection; 22 | 23 | import com.google.common.base.Preconditions; 24 | import com.ishland.raknetify.common.Constants; 25 | import com.ishland.raknetify.velocity.RaknetifyVelocityPlugin; 26 | import com.velocitypowered.proxy.protocol.packet.KeepAlivePacket; 27 | import io.netty.channel.Channel; 28 | import io.netty.channel.ChannelDuplexHandler; 29 | import io.netty.channel.ChannelHandler; 30 | import io.netty.channel.ChannelHandlerContext; 31 | import network.ycc.raknet.RakNet; 32 | 33 | import java.util.Map; 34 | import java.util.concurrent.TimeUnit; 35 | 36 | public class RakNetVelocityServerChannelEventListener extends ChannelDuplexHandler { 37 | 38 | public static final String NAME = "raknetify-bungee-downstream-event-listener"; 39 | 40 | private final Channel clientChannel; 41 | 42 | public RakNetVelocityServerChannelEventListener(Channel clientChannel) { 43 | Preconditions.checkArgument(clientChannel.config() instanceof RakNet.Config); 44 | this.clientChannel = clientChannel; 45 | } 46 | 47 | @Override 48 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 49 | if (msg instanceof KeepAlivePacket) { 50 | if (Constants.DEBUG) RaknetifyVelocityPlugin.LOGGER.info("Received downstream keepalive, swallowing it"); 51 | final long rttNanos = RakNet.config(clientChannel).getRTTNanos(); 52 | // RaknetifyVelocityPlugin.PROXY.getScheduler().buildTask(RaknetifyVelocityPlugin.INSTANCE, () -> ctx.write(msg)) 53 | // .delay(Math.max(rttNanos - 4_000_000, 0), TimeUnit.NANOSECONDS) // reduce delay to aid scheduling overhead 54 | // .clearRepeat() 55 | // .schedule(); 56 | ctx.channel().eventLoop().schedule(() -> ctx.writeAndFlush(msg), Math.max(rttNanos - 4_000_000, 0), TimeUnit.NANOSECONDS); // reduce delay to aid scheduling overhead 57 | return; // prevent keepalive from being sent to clients 58 | } 59 | super.channelRead(ctx, msg); 60 | } 61 | 62 | @Override 63 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 64 | super.exceptionCaught(ctx, cause); 65 | cause.printStackTrace(); 66 | for (Map.Entry entry : ctx.channel().pipeline().toMap().entrySet()) { 67 | System.out.println("%s: %s".formatted(entry.getKey(), entry.getValue().getClass().getName())); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /velocity/src/main/java/com/ishland/raknetify/velocity/init/VelocityPacketRegistryInjector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is a part of the Velocity implementation of the Raknetify 3 | * project, licensed under GPLv3. 4 | * 5 | * Copyright (c) 2022-2025 ishland 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | package com.ishland.raknetify.velocity.init; 22 | 23 | import com.velocitypowered.api.network.ProtocolVersion; 24 | import com.velocitypowered.proxy.protocol.MinecraftPacket; 25 | import com.velocitypowered.proxy.protocol.StateRegistry; 26 | import com.velocitypowered.proxy.protocol.packet.RespawnPacket; 27 | import io.netty.util.collection.IntObjectMap; 28 | import it.unimi.dsi.fastutil.objects.Object2IntMap; 29 | 30 | import java.util.Map; 31 | import java.util.function.Supplier; 32 | 33 | import static com.ishland.raknetify.common.util.ReflectionUtil.accessible; 34 | 35 | public class VelocityPacketRegistryInjector { 36 | 37 | public static void inject() { 38 | try { 39 | final StateRegistry.PacketRegistry registry = (StateRegistry.PacketRegistry) 40 | accessible(StateRegistry.class.getDeclaredField("clientbound")).get(StateRegistry.PLAY); 41 | final var versions = (Map) 42 | accessible(StateRegistry.PacketRegistry.class.getDeclaredField("versions")).get(registry); 43 | for (StateRegistry.PacketRegistry.ProtocolRegistry value : versions.values()) { 44 | final var packetClassToId = (Object2IntMap>) 45 | accessible(StateRegistry.PacketRegistry.ProtocolRegistry.class.getDeclaredField("packetClassToId")).get(value); 46 | final var packetIdToSupplier = (IntObjectMap>) 47 | accessible(StateRegistry.PacketRegistry.ProtocolRegistry.class.getDeclaredField("packetIdToSupplier")).get(value); 48 | if (packetClassToId.containsKey(RespawnPacket.class)) { 49 | final int packetId = packetClassToId.getInt(RespawnPacket.class); 50 | if (!packetIdToSupplier.containsKey(packetId)) { 51 | packetIdToSupplier.put(packetId, RespawnPacket::new); // make respawn packet no longer encodeOnly 52 | } 53 | } 54 | } 55 | } catch (Throwable t) { 56 | throw new RuntimeException("Failed to inject velocity packet registry", t); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /velocity/src/main/resources/velocity-plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "raknetify", 3 | "name": "Raknetify (Velocity)", 4 | "version": "${version}", 5 | "description": "A Velocity plugin that allows using RakNet as Minecraft networking backend. ", 6 | "authors": ["ishland"], 7 | "dependencies": [], 8 | "main": "com.ishland.raknetify.velocity.RaknetifyVelocityPlugin" 9 | } --------------------------------------------------------------------------------