Skip to content
This repository was archived by the owner on Sep 11, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions .github/workflows/registration-provider.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
name: Provider extension
name: Native provider extension
on:
push:
branches: [codex/registration-provider]
branches: [codex/native-admission]
pull_request:
permissions:
contents: read
concurrency:
group: native-extension-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
jobs:
extension:
runs-on: ubuntu-latest
timeout-minutes: 20
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871
with:
path: GeyserNetherNet
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871
with:
repository: teamziax/NetworkCompatible
ref: a9b163bc5914b44399381aedbc473e16e3ce17e5
path: NetworkCompatible
- uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73
with:
distribution: temurin
java-version: '21'
java-version: |
8
17
21
- uses: gradle/actions/setup-gradle@d156388eb19639ec20ade50009f3d199ce1e2808
- run: bash gradlew build -PregistrationRevision=${{ github.sha }} --console=plain
- run: sudo apt-get update && sudo apt-get install -y cmake ninja-build g++ libssl-dev pkg-config
- run: bash scripts/build-native-development.sh
working-directory: GeyserNetherNet
- uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882
with:
name: GeyserNetherNet-registration-${{ github.sha }}
name: GeyserNetherNet-native-${{ github.sha }}
path: |
GeyserNetherNet/build/libs/*.jar
GeyserNetherNet/build/test-results/test/*.xml
Expand Down
18 changes: 8 additions & 10 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,8 @@ relocate("org.yaml.snakeyaml")
relocate("org.spongepowered.configurate")
relocate("com.google.gson")

val nativePlatforms = listOf(
"windows-x86_64",
"x86_64",
"aarch64",
"macos-x86_64",
"macos-arm64"
)
// Experimental native admission currently has a tested Linux x86_64 development classifier.
val nativePlatforms = listOf("x86_64")

val id = project.property("id") as String
val extensionName = project.property("name") as String
Expand All @@ -25,11 +20,12 @@ val version = project.version as String

val geyserVersion = "2.11.0"
val netherNetVersion = "1.8.0"
val libdatachannelVersion = "0.24.1.1"
val libdatachannelVersion = "0.24.1.1-warden.5544964002162d184bacfcd0cb8d70d86ec3f271"

val configurateVersion = "4.2.0-GeyserMC-20251111.004649-11"

repositories {
mavenLocal { content { includeGroup("dev.ziax.warden") } }
// Repo for the Geyser API artifact
maven("https://repo.opencollab.dev/main/")

Expand All @@ -53,9 +49,9 @@ dependencies {
implementation("dev.kastle.netty:netty-transport-nethernet:$netherNetVersion")

// The WebRTC library and its natives
implementation("tel.schich:libdatachannel-java:$libdatachannelVersion")
implementation("dev.ziax.warden:libdatachannel-java:$libdatachannelVersion")
nativePlatforms.forEach { platform ->
runtimeOnly("tel.schich:libdatachannel-java:$libdatachannelVersion:$platform")
runtimeOnly("dev.ziax.warden:libdatachannel-java:$libdatachannelVersion:$platform")
}

// Configurate
Expand Down Expand Up @@ -108,6 +104,8 @@ tasks {
mergeServiceFiles()
manifest.attributes["Registration-Revision"] = providers.gradleProperty("registrationRevision").getOrElse("local-development")
manifest.attributes["Registration-Network-Revision"] = "a9b163bc5914b44399381aedbc473e16e3ce17e5"
manifest.attributes["Native-Network-Revision"] = "3c346c681396e0d7743467ac816a798f331dfb71"
manifest.attributes["Native-JNI-Revision"] = "5544964002162d184bacfcd0cb8d70d86ec3f271"
dependencies {
// Exclude netty apart from the http codec
exclude {
Expand Down
37 changes: 37 additions & 0 deletions docs/native-admission.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Native provider mode (experimental)

The ServiceLoader factory binds the native Warden admission endpoint and retains
Geyser's existing NetherNet Bedrock child pipeline. It loads the pre-provisioned
DTLS identity from `host-cert.pem` and `host-key.pem` in `provider.state-directory`.
The host publishes a fresh boot incarnation, actual certificate fingerprint and
fixed UDP candidate, and installs background host-specific admission keys. Client
context arrives only in the authenticated token carried by STUN. The native
adapter rejects per-join control admission.

This draft is stacked on the WS2 provider extension PR. The two NetworkCompatible
slices are composed only in a disposable local checkout by:

```sh
bash scripts/build-native-development.sh
```

The script pins both owned source revisions, resolves only their shared Gradle
module addition, runs provider/native tests, builds the extension and verifies
the shaded factory service, sole native library and full revision manifest.
It never merges or pushes either source branch. Linux x86_64, JDK 8/17/21,
Python 3, OpenSSL CLI/development headers, CMake, Git and a C++ compiler are
required. This JNI development classifier links system OpenSSL; other native
platforms are not packaged until independently built and verified.

For a disposable game test, configure `mode: provider`, `fake-transport: false`,
an explicitly assigned `bind-address` and a `udp-port` separate from RakNet.
Wildcard `0.0.0.0` is refused: this initial profile publishes the bound interface
as its candidate. NAT/public advertised-address configuration remains a separate
profile extension. Provision the PEM key/certificate before starting the endpoint
and keep its state directory private. Do not change identity files while active.
Use the registration profile, provider URL and grant settings from the WS2 docs.

Build, factory packaging and native/Worker echo do not prove a stock Minecraft
game join. Stock-client identity, token limits, both channels into gameplay,
reconnect, two-host routing and direct-join regression must still be recorded.
No production deployment or merge is part of this draft.
57 changes: 57 additions & 0 deletions scripts/build-native-development.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
set -euo pipefail
# Disposable local composition only. Neither source branch is merged or pushed.
native_revision=3c346c681396e0d7743467ac816a798f331dfb71
provider_revision=a9b163bc5914b44399381aedbc473e16e3ce17e5
extension_root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
integration_root=$(mktemp -d "${TMPDIR:-/tmp}/geyser-native-build.XXXXXXXX")
trap 'rm -rf -- "$integration_root"' EXIT
git clone --quiet https://github.com/teamziax/NetworkCompatible.git "$integration_root/network"
git -C "$integration_root/network" checkout --quiet --detach "$native_revision"
# A source-only merge leaves HEAD at the pinned native revision; no integration commit is published.
if ! git -C "$integration_root/network" -c user.name=NativeBench -c user.email=native-bench.invalid merge --no-commit --no-ff "$provider_revision"; then
conflicts=$(git -C "$integration_root/network" diff --name-only --diff-filter=U)
if [[ "$conflicts" != 'warden-signalling/build.gradle.kts' ]]; then
echo 'Unexpected integration conflicts; refusing to invent a resolution.' >&2
exit 1
fi
python3 - "$integration_root/network" "$provider_revision" <<'PY'
import pathlib, subprocess, sys
root, provider = sys.argv[1:]
path = 'warden-signalling/build.gradle.kts'
def source(ref):
return subprocess.check_output(['git', '-C', root, 'show', ref + ':' + path], text=True)
native, registration = source('HEAD'), source(provider)
anchor = 'description = "Provider registration and Warden control client"'
version = 'version = providers.gradleProperty("wardenVersion").getOrElse("0.1.0-registration-dev")'
assert native.count(anchor) == 1 and version in registration
native = native.replace(anchor, anchor + '\n' + version)
tasks = registration[registration.index('tasks.register<JavaExec>("providerStub")'):]
pathlib.Path(root, path).write_text(native + '\n' + tasks)
PY
git -C "$integration_root/network" add warden-signalling/build.gradle.kts
fi
(
cd "$integration_root/network"
./scripts/bootstrap-native-admission.sh
./gradlew :warden-signalling:test :warden-signalling:nativeAdmissionTest :transport-nethernet:test
)
cd "$extension_root"
extension_revision=$(git rev-parse HEAD)
if [[ -n "$(git status --porcelain)" ]]; then extension_revision+="-dirty"; fi
bash gradlew build -PwardenNetworkPath="$integration_root/network" -PregistrationRevision="$extension_revision"
python3 - "$extension_root" "$native_revision" "$provider_revision" <<'PY'
import pathlib, sys, zipfile
root, native, provider = sys.argv[1:]
jars = list(pathlib.Path(root, 'build/libs').glob('*.jar'))
assert len(jars) == 1, 'Expected one shaded extension'
with zipfile.ZipFile(jars[0]) as jar:
service = 'META-INF/services/org.geyser.extension.nethernet.provider.ProviderHostFactory'
assert jar.read(service).decode().strip() == 'org.geyser.extension.nethernet.admission.NativeProviderHostFactory'
assert jar.namelist().count('native/libdatachannel-java.so') == 1
# Unfold continuation lines in the manifest before checking full SHA pins.
manifest = jar.read('META-INF/MANIFEST.MF').decode().replace('\r\n ', '')
assert 'Native-Network-Revision: ' + native in manifest
assert 'Registration-Network-Revision: ' + provider in manifest
print('Native extension packaging PASS:', jars[0])
PY
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.geyser.extension.nethernet.admission;

import dev.kastle.netty.channel.nethernet.admission.AdmissionGate;
import dev.kastle.warden.admission.NativeProviderTransport;
import io.netty.bootstrap.ServerBootstrap;
import org.geyser.extension.nethernet.provider.ProviderHostFactory;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

/** Fixed native endpoint using the extension's existing Bedrock child pipeline. */
public final class NativeProviderHostFactory implements ProviderHostFactory {
@Override public CompletionStage<Host> open(ServerBootstrap bootstrap, InetSocketAddress udpBind, Map<String,String> options) {
try {
String directory = options.get("stateDirectory");
if (directory == null || directory.isBlank()) throw new IllegalArgumentException("Provider stateDirectory required");
Path state = Path.of(directory);
return NativeProviderTransport.open(bootstrap, udpBind, state.resolve("host-cert.pem"), state.resolve("host-key.pem"), AdmissionGate.Limits.defaults())
.thenApply(transport -> new Host(transport, transport.channel()));
} catch (Exception invalid) { return CompletableFuture.failedFuture(invalid); }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.geyser.extension.nethernet.admission.NativeProviderHostFactory
Loading