Skip to content
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
2 changes: 1 addition & 1 deletion crates/chunk-build/src/codegen/java/configurations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub(super) fn sources(
let provider = names::type_name(session, &provider_scope.path);
provider_scope.declare(&provider, session)?;
provider_scope.declarations.push(format!(
"public interface {provider} extends com.chunkzero.chunk.multistom.ConfiguredSessionProvider<{}> {{\n@Override default JsonType<{}> configurationType() {{ return {}.TYPE; }}\n}}",
"public interface {provider}<S> extends com.chunkzero.chunk.runtime.ConfiguredSessionProvider<{}, S> {{\n@Override default JsonType<{}> configurationType() {{ return {}.TYPE; }}\n}}",
config.ty, config.ty, scope.path.join(".")
));
metadata.push(json!({
Expand Down
4 changes: 3 additions & 1 deletion crates/chunk-build/src/codegen/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,9 @@ fn session_configuration_providers_are_scoped_to_their_app_and_detect_java_colli
let output = root.path().join("generated");
generate(&fixture(), &output, GenerationTarget::Java { package: "example" }).unwrap();
let provider = fs::read_to_string(output.join("java-session/duels/example/DuelsSessionProviders.java")).unwrap();
assert!(provider.contains("ConfiguredSessionProvider<SessionConfigs.Duels.Default.Config>"));
assert!(provider.contains(
"public interface Default<S> extends com.chunkzero.chunk.runtime.ConfiguredSessionProvider<SessionConfigs.Duels.Default.Config, S>"
));
assert!(provider.contains("return SessionConfigs.Duels.Default.TYPE;"));
let models = fs::read_to_string(output.join("java/example/SessionConfigs.java")).unwrap();
assert!(!models.contains("com.chunkzero.chunk.runtime"));
Expand Down
2 changes: 1 addition & 1 deletion crates/chunk-build/src/release/session_configurations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub(super) fn validate(
{
return Ok(None);
}
let registration = read_registration(archive, "com.chunkzero.chunk.multistom.SessionProvider")?;
let registration = read_registration(archive, "com.chunkzero.chunk.runtime.SessionProvider")?;
if registration.len() > 65_536 || !registration.lines().any(|line| line.trim() == configuration.provider) {
return Err(io::Error::other("unregistered configured session provider"));
}
Expand Down
2 changes: 1 addition & 1 deletion crates/chunk-build/src/release/session_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub(super) fn validate(
if actual.is_empty() {
return Ok(());
}
let registration = read_registration(archive, "com.chunkzero.chunk.multistom.SessionMethodProvider")?;
let registration = read_registration(archive, "com.chunkzero.chunk.runtime.SessionMethodProvider")?;
let providers: Vec<_> = registration.lines().filter(|line| !line.trim().is_empty()).collect();
if registration.len() > 65_536
|| providers.len() != 1
Expand Down
4 changes: 2 additions & 2 deletions crates/chunk-build/src/release/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ fn session_methods_publish_with_the_runtime_contract_and_reject_stale_jars() {
("sample/lobby/Provider.class", class(25, 1)),
("sample/Method.class", class(25, 1)),
(
"META-INF/services/com.chunkzero.chunk.multistom.SessionMethodProvider",
"META-INF/services/com.chunkzero.chunk.runtime.SessionMethodProvider",
b"sample.lobby.Provider\n".to_vec(),
),
(
Expand Down Expand Up @@ -460,7 +460,7 @@ fn session_configurations_require_matching_packaged_schemas_and_registered_provi
("META-INF/MANIFEST.MF", b"Manifest-Version: 1.0\r\nMain-Class: sample.lobby.Provider\r\n\r\n".to_vec()),
("sample/lobby/Provider.class", class(25, 1)),
("sample/ConfigProvider.class", class(25, 1)),
("META-INF/services/com.chunkzero.chunk.multistom.SessionProvider", provider.as_bytes().to_vec()),
("META-INF/services/com.chunkzero.chunk.runtime.SessionProvider", provider.as_bytes().to_vec()),
(
"META-INF/chunk/session-configurations.json",
serde_json::to_vec(&json!({"version":1,"app":"lobby","configurations":[configuration]})).unwrap(),
Expand Down
4 changes: 2 additions & 2 deletions crates/chunk-cli/templates/java/Lobby.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
import com.chunkzero.chunk.generated.BackendTypes.Shared.Greetings.MessageResult;
import com.chunkzero.chunk.multistom.ChunkMinestom;
import com.chunkzero.chunk.multistom.Session;
import com.chunkzero.chunk.multistom.SessionProvider;
import com.chunkzero.chunk.multistom.SessionScope;
import com.chunkzero.chunk.runtime.ChunkProcess;
import com.chunkzero.chunk.runtime.SessionProvider;
import com.chunkzero.chunk.runtime.SessionType;

import net.kyori.adventure.text.Component;
Expand All @@ -20,7 +20,7 @@
import java.util.concurrent.CompletionStage;

@SessionType("default")
public final class Lobby implements SessionProvider {
public final class Lobby implements SessionProvider<Session> {
public static void main(String[] args) throws Exception {
try (var chunk = ChunkProcess.connect();
var minestom = ChunkMinestom.attach(chunk, ServerProcess.create())) {
Expand Down
4 changes: 2 additions & 2 deletions crates/chunk-cli/templates/kotlin/Lobby.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ import com.chunkzero.chunk.generated.CoroutineBackendClient
import com.chunkzero.chunk.multistom.ChunkMinestom
import com.chunkzero.chunk.multistom.CoroutineSession
import com.chunkzero.chunk.multistom.Session
import com.chunkzero.chunk.multistom.SessionProvider
import com.chunkzero.chunk.multistom.SessionScope
import com.chunkzero.chunk.multistom.coroutines
import com.chunkzero.chunk.runtime.ChunkProcess
import com.chunkzero.chunk.runtime.SessionProvider
import com.chunkzero.chunk.runtime.SessionType
import net.kyori.adventure.text.Component
import net.minestom.server.ServerProcess
import net.minestom.server.entity.Player
import net.minestom.server.instance.block.Block

@SessionType("default")
class Lobby : SessionProvider {
class Lobby : SessionProvider<Session> {
override fun create(): Session = GreetingSession()
}

Expand Down
4 changes: 2 additions & 2 deletions examples/arena/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ In the arena, `/match` shows the score and `/lobby` leaves the match. Stats pers

- [`Lobby.java`](apps/lobby/src/main/java/example/lobby/Lobby.java) and
[`Arena.java`](apps/arena/src/main/java/example/arena/Arena.java) are each app's `main` and session provider. The
arena implements the generated `ArenaSessionProviders.Koth` interface to receive the destination's config, and its
[`ArenaSession`](apps/arena/src/main/java/example/arena/ArenaSession.java) implements the generated
arena implements the generated `ArenaSessionProviders.Koth<ArenaSession>` interface to receive the destination's
config, and its [`ArenaSession`](apps/arena/src/main/java/example/arena/ArenaSession.java) implements the generated
`SessionMethods.Arena.Koth.Status`.
- [`LobbyComponents`](apps/lobby/src/main/java/example/lobby/LobbyComponents.java) and
[`ArenaComponents`](apps/arena/src/main/java/example/arena/ArenaComponents.java) declare a `SESSION` component for the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
import com.chunkzero.chunk.generated.ArenaSessionProviders;
import com.chunkzero.chunk.generated.SessionConfigs;
import com.chunkzero.chunk.multistom.ChunkMinestom;
import com.chunkzero.chunk.multistom.SessionCreation;
import com.chunkzero.chunk.runtime.ChunkProcess;
import com.chunkzero.chunk.runtime.SessionCreation;
import com.chunkzero.chunk.runtime.SessionType;

import net.minestom.server.ServerProcess;

@SessionType("koth")
public final class Arena implements ArenaSessionProviders.Koth {
public final class Arena implements ArenaSessionProviders.Koth<ArenaSession> {
public static void main(String[] args) throws Exception {
try (var chunk = ChunkProcess.connect();
var minestom = ChunkMinestom.attach(chunk, ServerProcess.create())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package example.lobby;

import com.chunkzero.chunk.multistom.ChunkMinestom;
import com.chunkzero.chunk.multistom.SessionProvider;
import com.chunkzero.chunk.runtime.ChunkProcess;
import com.chunkzero.chunk.runtime.SessionProvider;
import com.chunkzero.chunk.runtime.SessionType;

import net.minestom.server.ServerProcess;

@SessionType("default")
public final class Lobby implements SessionProvider {
public final class Lobby implements SessionProvider<LobbySession> {
public static void main(String[] args) throws Exception {
try (var chunk = ChunkProcess.connect();
var minestom = ChunkMinestom.attach(chunk, ServerProcess.create())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import com.chunkzero.chunk.example.load.generated.BackendTypes
import com.chunkzero.chunk.example.load.generated.CoroutineBackendClient
import com.chunkzero.chunk.multistom.ChunkMinestom
import com.chunkzero.chunk.multistom.CoroutineSession
import com.chunkzero.chunk.multistom.SessionProvider
import com.chunkzero.chunk.multistom.SessionScope
import com.chunkzero.chunk.multistom.coroutines
import com.chunkzero.chunk.multistom.own
import com.chunkzero.chunk.runtime.ChunkProcess
import com.chunkzero.chunk.runtime.SessionProvider
import com.chunkzero.chunk.runtime.SessionType
import kotlinx.coroutines.launch
import net.minestom.server.ServerProcess
Expand All @@ -23,7 +23,7 @@ private const val SAVE_SECONDS = 60L
private const val TICKS_PER_LOG = 200

@SessionType("default")
class LobbySessions : SessionProvider {
class LobbySessions : SessionProvider<LobbySession> {
override fun create() = LobbySession()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import com.chunkzero.chunk.example.ExampleSessions
import com.chunkzero.chunk.example.generated.ArenaSessionProviders
import com.chunkzero.chunk.example.generated.SessionConfigs
import com.chunkzero.chunk.multistom.ChunkMinestom
import com.chunkzero.chunk.multistom.SessionCreation
import com.chunkzero.chunk.multistom.Session
import com.chunkzero.chunk.runtime.ChunkProcess
import com.chunkzero.chunk.runtime.SessionCreation
import com.chunkzero.chunk.runtime.SessionType
import net.minestom.server.ServerProcess

@SessionType("default")
class ArenaSessions : ArenaSessionProviders.Default {
class ArenaSessions : ArenaSessionProviders.Default<Session> {
override fun create(creation: SessionCreation<SessionConfigs.Arena.Default.Config>) =
ExampleSessions.arena("${creation.config().label()} (${creation.maxPlayers()} slots)")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package com.chunkzero.chunk.example.lobby

import com.chunkzero.chunk.example.ExampleSessions
import com.chunkzero.chunk.example.LobbySession
import com.chunkzero.chunk.multistom.ChunkMinestom
import com.chunkzero.chunk.multistom.SessionProvider
import com.chunkzero.chunk.runtime.ChunkProcess
import com.chunkzero.chunk.runtime.SessionProvider
import com.chunkzero.chunk.runtime.SessionType
import net.minestom.server.ServerProcess

@SessionType("default")
class LobbySessions : SessionProvider {
class LobbySessions : SessionProvider<LobbySession> {
override fun create() = ExampleSessions.lobby()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,11 @@ public void subscribe(
new SessionManager(
process,
ticks,
Map.of(
Map.<String, Supplier<Session>>of(
"lobby",
new SessionRegistration(
"lobby", ExampleSessions.INSTANCE::lobby),
ExampleSessions.INSTANCE::lobby,
"arena",
new SessionRegistration(
"arena",
() -> ExampleSessions.INSTANCE.arena("Arena"))),
Map.of());
() -> ExampleSessions.INSTANCE.arena("Arena")));
var host =
TestHosts.detached(
manager,
Expand Down
30 changes: 19 additions & 11 deletions jvm/gradle-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,26 +113,27 @@ run as. The plugin runs that CLI; it never builds Rust tools or installs Node pa
## Session types

The app's compiled classes are scanned for `@SessionType("id")`. Each annotated class must be public, concrete, have a
public no-argument constructor and implement `SessionProvider`; an app has 1 to 128 of them, with distinct IDs, and its
main class needs a `public static void main(String[])`. `generateChunkSessionRegistry` writes
`META-INF/services/com.chunkzero.chunk.multistom.SessionProvider`, from which the runtime loads the providers, and a
public no-argument constructor and implement `com.chunkzero.chunk.runtime.SessionProvider`; an app has 1 to 128 of them,
with distinct IDs, and its main class needs a `public static void main(String[])`. `generateChunkSessionRegistry` writes
`META-INF/services/com.chunkzero.chunk.runtime.SessionProvider`, from which the runtime loads the providers, and a
catalog of the session type IDs for release assembly. Packaging fails unless those IDs exactly match the app's
`implementations` in `app.ts` (by default just `default`).

An implementation with a `config` validator must implement its generated interface, for example
`LobbySessionProviders.Default`, and receives the validated configuration in `create(SessionCreation<Config>)`; one
without must implement plain `SessionProvider`.
`LobbySessionProviders.Default<LobbySession>`, and receives the validated configuration in
`create(SessionCreation<Config>)`; one without must implement plain `SessionProvider<LobbySession>`. The type argument
is the session class; the plugin only checks the contracts, while the engine decides which session classes it accepts.

## Session methods

For each `sessionMethod` declared in TypeScript (see the [SDK](../../crates/chunk-build/sdk/README.md#session-methods)),
the generated `SessionMethods` class has a single-method interface with `Args` and result types. The session class
implements it, and the provider's `create` must declare that concrete class as its return type. From the
implements it, and the provider's `create` must declare that public concrete class as its return type. From the
[arena example](../../examples/arena/apps/arena/src/main/java/example/arena/Arena.java):

```java
@SessionType("koth")
public final class Arena implements ArenaSessionProviders.Koth {
public final class Arena implements ArenaSessionProviders.Koth<ArenaSession> {
@Override
public ArenaSession create(SessionCreation<SessionConfigs.Arena.Koth.Config> creation) {
var config = creation.config();
Expand All @@ -154,16 +155,23 @@ public final class ArenaSession extends Session implements SessionMethods.Arena.

The signature is synchronous: futures and Kotlin `suspend` functions cannot implement it. Implementing a method that
belongs to another app or session type is a build error. `generateChunkSessionRegistry` checks the implementations and
writes `META-INF/chunk/session-methods.json` and a method provider service; `compileChunkSessionMethods` compiles
direct-call adapters into the app, which the runtime loads without scanning the classpath.
writes `META-INF/chunk/session-methods.json` and a `com.chunkzero.chunk.runtime.SessionMethodProvider` service;
`compileChunkSessionMethods` compiles typed direct-call adapters into the app, such as
`new SessionMethodBinding<>(Status.REF, ArenaSession.class, (session, args) -> session.status(args))`, which the runtime
loads without scanning the classpath.

## Components

Every module applying a Chunk plugin indexes its public static `@Component` factories after compilation
(`generateChunkComponentIndex`). Each app then reads its own index and those in its dependencies' JARs, checks the graph
for missing or duplicate providers, cycles and process components that depend on session ones
(`generateChunkComponentBindings`), and compiles one provider that calls the factories directly
(`compileChunkComponents`). See the [Minestom runtime](../multistom/README.md#components) for writing components.
(`generateChunkComponentBindings`), and compiles one `com.chunkzero.chunk.runtime.ComponentProvider` that calls the
factories directly (`compileChunkComponents`). See the [Minestom runtime](../multistom/README.md#components) for writing
components.

The host supplies some types to session-scoped factories itself: `BackendSession`, and any class on the app's runtime
classpath annotated `@Component.Supplied`, such as an engine's session handle. A factory may take them only if it is
session-scoped, and no factory may provide them.

## Testing

Expand Down
Loading
Loading