diff --git a/PROVIDER.md b/PROVIDER.md index 0bc5944..2c07aad 100644 --- a/PROVIDER.md +++ b/PROVIDER.md @@ -126,3 +126,23 @@ Examples cover [anonymous NXS](examples/provider-local.yml), The [NXS contract](https://github.com/teamziax/NetworkCompatible/blob/nxs-dev/docs/external-signalling/README.md) and [native build instructions](docs/native-admission.md) describe the maintained source chain. Native/fixture readiness does not establish stock-client gameplay. + +## Warden shared fleet registration and runtime counts + +The Warden connection wizard can generate `examples/provider-console.yml` and a +separate token file. Save the token in the extension data directory. Each live +replica needs its own persistent directory; preserving `provider-state` across +restarts preserves its runtime identity. + +Warden organisation API keys select initial Signal Servers through enrolment +configuration. One Game Server can attach to several Signal Servers. The host's +`region` and `pool` data fields select that configuration; a Pool is not a separate +operator resource. Fleet completion can omit `publicAddress` and `serviceId`. +The extension logs the runtime identity and directs operators to the attached +Signal Servers for public addresses, without treating that response as a failure. + +Heartbeat player telemetry samples Geyser's actual session-manager count and +sample time independently of server-list status. Counts can exceed a lowered +admission capacity; only the legacy load fraction is bounded to one. Public +status overrides never replace this actual-player sample. This consumer requires +the exact NetworkCompatible revision in `registration-network.properties`. diff --git a/examples/provider-console.yml b/examples/provider-console.yml new file mode 100644 index 0000000..ffc4e08 --- /dev/null +++ b/examples/provider-console.yml @@ -0,0 +1,8 @@ +signalling: nxs +nxs: + advertise-addresses: [] + token: "file:warden-enrolment.token" + endpoint: "https://agent.warden.cloud" + data: + region: "EU" + pool: "lobby" diff --git a/registration-network.properties b/registration-network.properties index cceb2e7..5145953 100644 --- a/registration-network.properties +++ b/registration-network.properties @@ -1,3 +1,3 @@ repository=teamziax/NetworkCompatible -commit=f34c0b0a37cd5933ac7f5d46febc3a92a6aad381 -branch=nxs-dev +commit=5d0063699be6e037dda8013cf3d7962338a2edc2 +branch=codex/fleet-control-plane diff --git a/src/main/java/org/geyser/extension/nethernet/NetherNetExtension.java b/src/main/java/org/geyser/extension/nethernet/NetherNetExtension.java index c9ac917..f262c9f 100644 --- a/src/main/java/org/geyser/extension/nethernet/NetherNetExtension.java +++ b/src/main/java/org/geyser/extension/nethernet/NetherNetExtension.java @@ -156,7 +156,7 @@ private void startProvider() { initializingTransport = transport; transport = new GameOutcomeTransport(transport, gameOutcomes); ProviderClient client = new ProviderClient(runtime.clientConfiguration(), store, transport, - () -> providerStatusSupplier.get(), () -> new ProviderClient.Health(true, runtime.capacity(), Math.min(1, (double) GeyserImpl.getInstance().getSessionManager().size() / Math.max(1, runtime.capacity())), "nethernet", description().version()), message -> logger().warning(message)); + () -> providerStatusSupplier.get(), () -> ProviderRuntimeObservations.health(GeyserImpl.getInstance().getSessionManager().size(), runtime.capacity(), System.currentTimeMillis(), description().version()), message -> logger().warning(message)); store = null; // ProviderClient now owns its lifetime. initializingTransport = null; synchronized (providerLifecycle) { @@ -168,7 +168,7 @@ private void startProvider() { } client.start().whenComplete((registration, failure) -> { if (failure != null) { logger().error("Provider startup failed: " + providerFailure(failure)); stopProvider(); return; } - logger().info("Provider address: " + registration.get("publicAddress").getAsString() + " (instance " + registration.get("instanceId").getAsString() + ")"); + logger().info(ProviderRuntimeObservations.registrationMessage(registration)); WardenClaimAdapter claim = wardenClaim; if (claim != null) claim.current().thenAccept(action -> action.ifPresent(value -> logger().info(value.message()))); }); diff --git a/src/main/java/org/geyser/extension/nethernet/provider/ProviderRuntimeObservations.java b/src/main/java/org/geyser/extension/nethernet/provider/ProviderRuntimeObservations.java new file mode 100644 index 0000000..89e87e5 --- /dev/null +++ b/src/main/java/org/geyser/extension/nethernet/provider/ProviderRuntimeObservations.java @@ -0,0 +1,23 @@ +package org.geyser.extension.nethernet.provider; + +import com.google.gson.JsonObject; +import org.cloudburstmc.netty.signalling.ProviderClient; + +/** Host observations are independent of the publicly advertised server-list status. */ +public final class ProviderRuntimeObservations { + private ProviderRuntimeObservations() {} + + public static ProviderClient.Health health(int connectedPlayers, int capacity, long sampledAt, String build) { + return new ProviderClient.Health(true, capacity, + Math.min(1, (double) connectedPlayers / Math.max(1, capacity)), "nethernet", build, + new ProviderClient.PlayerCount(connectedPlayers, sampledAt)); + } + + public static String registrationMessage(JsonObject registration) { + String instanceId = registration.get("instanceId").getAsString(); + var address = registration.get("publicAddress"); + return address != null && !address.isJsonNull() + ? "Provider address: " + address.getAsString() + " (instance " + instanceId + ")" + : "Provider instance registered: " + instanceId + "; public addresses are managed on its attached Signal Servers"; + } +} diff --git a/src/test/java/org/geyser/extension/nethernet/provider/ProviderConfigurationTest.java b/src/test/java/org/geyser/extension/nethernet/provider/ProviderConfigurationTest.java index fa42df5..4c030af 100644 --- a/src/test/java/org/geyser/extension/nethernet/provider/ProviderConfigurationTest.java +++ b/src/test/java/org/geyser/extension/nethernet/provider/ProviderConfigurationTest.java @@ -16,6 +16,18 @@ private ProviderRuntimeConfiguration runtime(Path dir, String yaml, Map