From 806d2ba47b3015a2b1e6591e95aaa6e24ee09872 Mon Sep 17 00:00:00 2001 From: Mqx <62719703+Mqxx@users.noreply.github.com> Date: Sun, 14 Jun 2026 18:01:02 +0200 Subject: [PATCH 1/4] feat: new builder structure --- src/main/java/dev/loat/msmp/MSMPMethod.java | 85 +++++++++++++------ .../MSMPMethodHandlerWithoutParameters.java | 24 ++++++ .../dev/loat/msmp/builder/MethodBuilder.java | 47 ++++++++++ .../builder/MethodBuilderWithParameters.java | 34 ++++++++ .../builder/MethodBuilderWithSchemas.java | 67 +++++++++++++++ .../msmp/builder/NotificationBuilder.java | 30 +++++++ .../NotificationBuilderWithSchema.java | 46 ++++++++++ 7 files changed, 305 insertions(+), 28 deletions(-) create mode 100644 src/main/java/dev/loat/msmp/MSMPMethodHandlerWithoutParameters.java create mode 100644 src/main/java/dev/loat/msmp/builder/MethodBuilder.java create mode 100644 src/main/java/dev/loat/msmp/builder/MethodBuilderWithParameters.java create mode 100644 src/main/java/dev/loat/msmp/builder/MethodBuilderWithSchemas.java create mode 100644 src/main/java/dev/loat/msmp/builder/NotificationBuilder.java create mode 100644 src/main/java/dev/loat/msmp/builder/NotificationBuilderWithSchema.java diff --git a/src/main/java/dev/loat/msmp/MSMPMethod.java b/src/main/java/dev/loat/msmp/MSMPMethod.java index 65a2bef..84d23a6 100644 --- a/src/main/java/dev/loat/msmp/MSMPMethod.java +++ b/src/main/java/dev/loat/msmp/MSMPMethod.java @@ -6,43 +6,43 @@ import net.minecraft.server.jsonrpc.IncomingRpcMethod; import net.minecraft.server.jsonrpc.api.Schema; - /** * Represents an incoming MSMP method that can be called by connected clients. * - *

Instances are created via - * {@link MSMPNamespace#method(String, Schema, Schema, java.util.function.BiFunction)} or - * {@link MSMPNamespace#method(String, Schema, Schema, String, java.util.function.BiFunction)} + *

Instances are created via {@link dev.loat.msmp.builder.MethodBuilderWithSchemas#register(MsmpMethodHandler)} + * or {@link dev.loat.msmp.builder.MethodBuilderWithSchemas#register(MsmpParameterlessMethodHandler)} * and are registered in the MSMP registry immediately upon creation.

* *
{@code
- * msmp.namespace("my_mod")
- *     .method("get_time",
- *         VoidPayload.SCHEMA,
- *         TimePayload.SCHEMA,
- *         "Returns the current game time",
- *         (server, params) -> new TimePayload(server.getGameTime())
- *     );
+ * // With request payload:
+ * NS.method("echo")
+ *     .requestSchema(EchoPayload.SCHEMA)
+ *     .responseSchema(EchoPayload.SCHEMA)
+ *     .description("Echoes a message back to the client")
+ *     .register((server, params, client) -> params);
+ *
+ * // Without request payload:
+ * NS.method("get_time")
+ *     .responseSchema(TimePayload.SCHEMA)
+ *     .description("Returns the current game time")
+ *     .register((server, client) -> new TimePayload(server.getGameTime()));
  * }
* - * @param The type of the payload received from the client - * @param The type of the payload returned to the client + * @param the type of the payload received from the client, or {@link Void} for parameterless methods + * @param the type of the payload returned to the client */ public final class MSMPMethod { /** - * Creates and registers a new incoming method under the given namespace. - * Package-private — use - * {@link MSMPNamespace#method(String, Schema, Schema, java.util.function.BiFunction)} or - * {@link MSMPNamespace#method(String, Schema, Schema, String, java.util.function.BiFunction)}. + * Creates and registers a new incoming method with a request payload. + * Package-private — use {@link dev.loat.msmp.builder.MethodBuilderWithSchemas#register(MsmpMethodHandler)}. * - * @param namespace The namespace to register this method under (e.g. {@code "my_mod"}) - * @param name The name of this method (e.g. {@code "get_time"}), - * resulting in the identifier {@code namespace:name} - * @param paramSchema The schema describing the payload received from the client - * @param resultSchema The schema describing the payload returned to the client - * @param description A human-readable description of this method - * @param handler The function to invoke when this method is called by a client + * @param namespace the namespace to register this method under + * @param name the name of this method + * @param paramSchema the schema describing the payload received from the client + * @param resultSchema the schema describing the payload returned to the client + * @param description a human-readable description of this method + * @param handler the handler to invoke when this method is called by a client */ @SuppressWarnings("unchecked") MSMPMethod( @@ -51,15 +51,44 @@ public final class MSMPMethod { Schema paramSchema, Schema resultSchema, String description, - IncomingRpcMethod.RpcMethodFunction handler + MSMPMethodHandler handler ) { Identifier id = Identifier.fromNamespaceAndPath(namespace, name); - - ((IncomingRpcMethodBuilderAccessor) IncomingRpcMethod - .method(handler) + ((IncomingRpcMethodBuilderAccessor) + IncomingRpcMethod.method( + (api, params, client) -> handler.apply(null, params, client) + ) .description(description) .param(name, paramSchema) .response(name, resultSchema) ).invokeRegister(BuiltInRegistries.INCOMING_RPC_METHOD, id); } + + /** + * Creates and registers a new parameterless incoming method. + * Package-private — use {@link dev.loat.msmp.builder.MethodBuilderWithSchemas#register(MsmpParameterlessMethodHandler)}. + * + * @param namespace the namespace to register this method under + * @param name the name of this method + * @param resultSchema the schema describing the payload returned to the client + * @param description a human-readable description of this method + * @param handler the parameterless handler to invoke when this method is called by a client + */ + @SuppressWarnings("unchecked") + MSMPMethod( + String namespace, + String name, + Schema resultSchema, + String description, + MSMPMethodHandlerWithoutParameters handler + ) { + Identifier id = Identifier.fromNamespaceAndPath(namespace, name); + ((IncomingRpcMethodBuilderAccessor) + IncomingRpcMethod.method( + (api, client) -> handler.apply(null, client) + ) + .description(description) + .response(name, resultSchema) + ).invokeRegister(BuiltInRegistries.INCOMING_RPC_METHOD, id); + } } diff --git a/src/main/java/dev/loat/msmp/MSMPMethodHandlerWithoutParameters.java b/src/main/java/dev/loat/msmp/MSMPMethodHandlerWithoutParameters.java new file mode 100644 index 0000000..38c7471 --- /dev/null +++ b/src/main/java/dev/loat/msmp/MSMPMethodHandlerWithoutParameters.java @@ -0,0 +1,24 @@ +package dev.loat.msmp; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.jsonrpc.methods.ClientInfo; + +/** + * Functional interface for handling parameterless incoming MSMP method calls. + * + *

Use this when no request payload is expected from the client.

+ * + * @param the type of the payload returned to the client + */ +@FunctionalInterface +public interface MSMPMethodHandlerWithoutParameters { + + /** + * Handles an incoming parameterless method call from a connected client. + * + * @param server the running {@link MinecraftServer} instance + * @param client the {@link ClientInfo} of the calling client + * @return the payload to return to the client + */ + Result apply(MinecraftServer server, ClientInfo client); +} diff --git a/src/main/java/dev/loat/msmp/builder/MethodBuilder.java b/src/main/java/dev/loat/msmp/builder/MethodBuilder.java new file mode 100644 index 0000000..881eed9 --- /dev/null +++ b/src/main/java/dev/loat/msmp/builder/MethodBuilder.java @@ -0,0 +1,47 @@ +package dev.loat.msmp.builder; + +import net.minecraft.server.jsonrpc.api.Schema; + +/** + * First stage of the method builder — only the method name is known. + * + *

Call {@link #requestSchema(Schema)} to define the request payload type, + * or {@link #responseSchema(Schema)} directly for a parameterless method.

+ */ +public final class MethodBuilder { + + private final String namespace; + private final String name; + + MethodBuilder(String namespace, String name) { + this.namespace = namespace; + this.name = name; + } + + /** + * Sets the request schema for this method. + * + *

Call this if the method expects a payload from the client. + * Skip this and call {@link #responseSchema(Schema)} directly for a parameterless method.

+ * + * @param the type of the request payload + * @param schema the schema describing the request payload + * @return a {@link MethodBuilderWithParam} with the request schema set + */ + public MethodBuilderWithParameters requestSchema(Schema schema) { + return new MethodBuilderWithParameters<>(namespace, name, schema); + } + + /** + * Sets the response schema for this method, skipping the request schema. + * + *

Use this for parameterless methods that don't expect a payload from the client.

+ * + * @param the type of the response payload + * @param schema the schema describing the response payload + * @return a {@link MethodBuilderWithSchemas} with no request schema and the response schema set + */ + public MethodBuilderWithSchemas responseSchema(Schema schema) { + return new MethodBuilderWithSchemas<>(namespace, name, null, schema); + } +} diff --git a/src/main/java/dev/loat/msmp/builder/MethodBuilderWithParameters.java b/src/main/java/dev/loat/msmp/builder/MethodBuilderWithParameters.java new file mode 100644 index 0000000..3d4770c --- /dev/null +++ b/src/main/java/dev/loat/msmp/builder/MethodBuilderWithParameters.java @@ -0,0 +1,34 @@ +package dev.loat.msmp.builder; + +import net.minecraft.server.jsonrpc.api.Schema; + +/** + * Second stage of the method builder — the request schema is known. + * + *

Call {@link #responseSchema(Schema)} to define the response payload type.

+ * + * @param the type of the request payload + */ +public final class MethodBuilderWithParameters { + + private final String namespace; + private final String name; + private final Schema paramSchema; + + MethodBuilderWithParameters(String namespace, String name, Schema paramSchema) { + this.namespace = namespace; + this.name = name; + this.paramSchema = paramSchema; + } + + /** + * Sets the response schema for this method. + * + * @param the type of the response payload + * @param schema the schema describing the response payload + * @return a {@link MethodBuilderWithSchemas} with both schemas set + */ + public MethodBuilderWithSchemas responseSchema(Schema schema) { + return new MethodBuilderWithSchemas<>(namespace, name, paramSchema, schema); + } +} diff --git a/src/main/java/dev/loat/msmp/builder/MethodBuilderWithSchemas.java b/src/main/java/dev/loat/msmp/builder/MethodBuilderWithSchemas.java new file mode 100644 index 0000000..8d48ad3 --- /dev/null +++ b/src/main/java/dev/loat/msmp/builder/MethodBuilderWithSchemas.java @@ -0,0 +1,67 @@ +package dev.loat.msmp.builder; + +import dev.loat.msmp.MSMPMethod; +import dev.loat.msmp.MSMPMethodHandler; +import dev.loat.msmp.MSMPMethodHandlerWithoutParameters; +import net.minecraft.server.jsonrpc.api.Schema; + +/** + * Final stage of the method builder — both schemas are known. + * + *

Optionally call {@link #description(String)} before calling {@link #register(MsmpMethodHandler)} + * or {@link #register(MsmpParameterlessMethodHandler)} to complete the registration.

+ * + * @param the type of the request payload, or {@link Void} for parameterless methods + * @param the type of the response payload + */ +public final class MethodBuilderWithSchemas { + + private final String namespace; + private final String name; + private final Schema paramSchema; + private final Schema resultSchema; + private String description = ""; + + MethodBuilderWithSchemas(String namespace, String name, Schema paramSchema, Schema resultSchema) { + this.namespace = namespace; + this.name = name; + this.paramSchema = paramSchema; + this.resultSchema = resultSchema; + } + + /** + * Sets the description for this method. + * + * @param description a human-readable description of this method + * @return this builder + */ + public MethodBuilderWithSchemas description(String description) { + this.description = description; + return this; + } + + /** + * Registers the method with a handler that receives the request payload. + * + *

Use this when {@link MethodBuilder#requestSchema(Schema)} was called.

+ * + * @param handler the handler to invoke when this method is called by a client + * @return the registered {@link MsmpMethod} + */ + public MSMPMethod register(MSMPMethodHandler handler) { + return new MSMPMethod<>(namespace, name, paramSchema, resultSchema, description, handler); + } + + /** + * Registers the method with a parameterless handler. + * + *

Use this when {@link MethodBuilder#responseSchema(Schema)} was called directly, + * skipping {@link MethodBuilder#requestSchema(Schema)}.

+ * + * @param handler the handler to invoke when this method is called by a client + * @return the registered {@link MsmpMethod} + */ + public MSMPMethod register(MSMPMethodHandlerWithoutParameters handler) { + return new MSMPMethod<>(namespace, name, resultSchema, description, handler); + } +} diff --git a/src/main/java/dev/loat/msmp/builder/NotificationBuilder.java b/src/main/java/dev/loat/msmp/builder/NotificationBuilder.java new file mode 100644 index 0000000..310b27c --- /dev/null +++ b/src/main/java/dev/loat/msmp/builder/NotificationBuilder.java @@ -0,0 +1,30 @@ +package dev.loat.msmp.builder; + +import net.minecraft.server.jsonrpc.api.Schema; + +/** + * First stage of the notification builder — only the notification name is known. + * + *

Call {@link #responseSchema(Schema)} to define the payload type.

+ */ +public final class NotificationBuilder { + + private final String namespace; + private final String name; + + NotificationBuilder(String namespace, String name) { + this.namespace = namespace; + this.name = name; + } + + /** + * Sets the response schema for this notification. + * + * @param the type of the payload sent with this notification + * @param schema the schema describing the payload structure + * @return a {@link NotificationBuilderWithSchema} with the schema set + */ + public NotificationBuilderWithSchema responseSchema(Schema schema) { + return new NotificationBuilderWithSchema<>(namespace, name, schema); + } +} diff --git a/src/main/java/dev/loat/msmp/builder/NotificationBuilderWithSchema.java b/src/main/java/dev/loat/msmp/builder/NotificationBuilderWithSchema.java new file mode 100644 index 0000000..24ed9dd --- /dev/null +++ b/src/main/java/dev/loat/msmp/builder/NotificationBuilderWithSchema.java @@ -0,0 +1,46 @@ +package dev.loat.msmp.builder; + +import dev.loat.msmp.MSMPNotification; +import net.minecraft.server.jsonrpc.api.Schema; + +/** + * Final stage of the notification builder — the schema is known. + * + *

Optionally call {@link #description(String)} before calling {@link #register()} + * to complete the registration.

+ * + * @param the type of the payload sent with this notification + */ +public final class NotificationBuilderWithSchema { + + private final String namespace; + private final String name; + private final Schema schema; + private String description = ""; + + NotificationBuilderWithSchema(String namespace, String name, Schema schema) { + this.namespace = namespace; + this.name = name; + this.schema = schema; + } + + /** + * Sets the description for this notification. + * + * @param description a human-readable description of this notification + * @return this builder + */ + public NotificationBuilderWithSchema description(String description) { + this.description = description; + return this; + } + + /** + * Registers the notification. + * + * @return the registered {@link MsmpNotification} + */ + public MSMPNotification register() { + return new MSMPNotification<>(namespace, name, schema, description); + } +} From 5b07ee62ee109eb3955da1abf9508adfff4479ac Mon Sep 17 00:00:00 2001 From: Mqx <62719703+Mqxx@users.noreply.github.com> Date: Sun, 14 Jun 2026 18:19:54 +0200 Subject: [PATCH 2/4] fix: refactor --- .../java/dev/loat/msmp/MSMPNamespace.java | 129 +++++------------- .../dev/loat/msmp/builder/MethodBuilder.java | 36 +---- .../builder/MethodBuilderWithParameters.java | 21 +-- .../builder/MethodBuilderWithSchemas.java | 52 ++----- .../MethodBuilderWithoutParameters.java | 40 ++++++ .../msmp/builder/NotificationBuilder.java | 14 +- .../NotificationBuilderWithSchema.java | 21 +-- 7 files changed, 100 insertions(+), 213 deletions(-) create mode 100644 src/main/java/dev/loat/msmp/builder/MethodBuilderWithoutParameters.java diff --git a/src/main/java/dev/loat/msmp/MSMPNamespace.java b/src/main/java/dev/loat/msmp/MSMPNamespace.java index d90c1e7..b133ac1 100644 --- a/src/main/java/dev/loat/msmp/MSMPNamespace.java +++ b/src/main/java/dev/loat/msmp/MSMPNamespace.java @@ -1,24 +1,31 @@ package dev.loat.msmp; +import dev.loat.msmp.builder.MethodBuilder; +import dev.loat.msmp.builder.NotificationBuilder; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.jsonrpc.api.Schema; - /** * Represents a custom MSMP namespace under which methods and notifications can be registered. * - *

Instances are created directly via {@code new MSMPNamespace("my_mod")} and should be + *

Instances are created directly via {@code new MsmpNamespace("my_mod")} and should be * registered in {@code onInitialize()} before the server starts. Use {@link #attach(MinecraftServer)} * in {@code SERVER_STARTED} to bind the server instance, and {@link #detach()} in * {@code SERVER_STOPPED} to release it.

* *
{@code
- * private static final MSMPNamespace NS = new MSMPNamespace("my_mod");
+ * private static final MsmpNamespace NS = new MsmpNamespace("my_mod");
  *
  * public void onInitialize() {
- *     NS.method("echo", EchoPayload.SCHEMA, EchoPayload.SCHEMA,
- *         (server, params, client) -> params
- *     );
+ *     NS.method("echo")
+ *         .requestSchema(EchoPayload.SCHEMA)
+ *         .responseSchema(EchoPayload.SCHEMA)
+ *         .description("Echoes a message back to the client")
+ *         .register((server, params, client) -> params);
+ *
+ *     NS.notification("ping")
+ *         .responseSchema(PingPayload.SCHEMA)
+ *         .description("A ping notification")
+ *         .register();
  *
  *     ServerLifecycleEvents.SERVER_STARTED.register(server -> NS.attach(server));
  *     ServerLifecycleEvents.SERVER_STOPPED.register(server -> NS.detach());
@@ -33,7 +40,7 @@ public final class MSMPNamespace {
     /**
      * Creates a new namespace with the given identifier.
      *
-     * @param namespace The namespace identifier (e.g. {@code "my_mod"})
+     * @param namespace the namespace identifier (e.g. {@code "my_mod"})
      */
     public MSMPNamespace(String namespace) {
         this.namespace = namespace;
@@ -45,7 +52,7 @@ public MSMPNamespace(String namespace) {
      * 

Should be called in the {@code SERVER_STARTED} lifecycle event. * Required for method handlers to access the server instance.

* - * @param server The running {@link MinecraftServer} instance + * @param server the running {@link MinecraftServer} instance */ public void attach(MinecraftServer server) { this.server = server; @@ -61,104 +68,34 @@ public void detach() { } /** - * Creates and registers a new outgoing notification without a description. + * Returns the currently bound {@link MinecraftServer} instance. + * Package-private — used by builder classes to resolve the server lazily. * - * @param The type of the payload sent with this notification - * @param name The name of this notification (e.g. {@code "ping"}), - * resulting in the identifier {@code namespace:notification/name} - * @param schema The schema describing the payload structure - * - * @return The registered {@link MSMPNotification} + * @return the bound server, or {@code null} if not attached */ - public MSMPNotification notification( - String name, - Schema schema - ) { - return new MSMPNotification<>(namespace, name, schema, ""); + MinecraftServer getServer() { + return server; } /** - * Creates and registers a new outgoing notification with a description. + * Creates a new method builder for the given name. * - * @param The type of the payload sent with this notification - * @param name The name of this notification (e.g. {@code "ping"}), - * resulting in the identifier {@code namespace:notification/name} - * @param schema The schema describing the payload structure - * @param description A human-readable description of this notification - * - * @return The registered {@link MSMPNotification} + * @param name the name of this method (e.g. {@code "echo"}), + * resulting in the identifier {@code namespace:method/name} + * @return a {@link MethodBuilder} to configure and register the method */ - public MSMPNotification notification( - String name, - Schema schema, - String description - ) { - return new MSMPNotification<>(namespace, name, schema, description); + public MethodBuilder method(String name) { + return new MethodBuilder(this, namespace, name); } /** - * Creates and registers a new incoming method without a description. - * - *

The handler is invoked when a client calls this method. The {@link MinecraftServer} - * is resolved lazily at call time — {@link #attach(MinecraftServer)} must have been - * called before any client can invoke this method.

- * - * @param The type of the payload received from the client - * @param The type of the payload returned to the client - * @param name The name of this method (e.g. {@code "echo"}), - * resulting in the identifier {@code namespace:name} - * @param paramSchema The schema describing the payload received from the client - * @param resultSchema The schema describing the payload returned to the client - * @param handler The handler to invoke when this method is called by a client - * - * @return The registered {@link MSMPMethod} - */ - public MSMPMethod method( - String name, - Schema paramSchema, - Schema resultSchema, - MSMPMethodHandler handler - ) { - return new MSMPMethod<>(namespace, name, paramSchema, resultSchema, "", - (api, params, client) -> { - if (server == null) throw new IllegalStateException( - "MSMPNamespace '%s' has no server attached. Call attach(server) in SERVER_STARTED.".formatted(namespace) - ); - return handler.apply(server, params, client); - }); - } - - /** - * Creates and registers a new incoming method with a description. - * - *

The handler is invoked when a client calls this method. The {@link MinecraftServer} - * is resolved lazily at call time — {@link #attach(MinecraftServer)} must have been - * called before any client can invoke this method.

+ * Creates a new notification builder for the given name. * - * @param The type of the payload received from the client - * @param The type of the payload returned to the client - * @param name The name of this method (e.g. {@code "echo"}), - * resulting in the identifier {@code namespace:name} - * @param paramSchema The schema describing the payload received from the client - * @param resultSchema The schema describing the payload returned to the client - * @param description A human-readable description of this method - * @param handler The handler to invoke when this method is called by a client - * - * @return The registered {@link MSMPMethod} + * @param name the name of this notification (e.g. {@code "ping"}), + * resulting in the identifier {@code namespace:notification/name} + * @return a {@link NotificationBuilder} to configure and register the notification */ - public MSMPMethod method( - String name, - Schema paramSchema, - Schema resultSchema, - String description, - MSMPMethodHandler handler - ) { - return new MSMPMethod<>(namespace, name, paramSchema, resultSchema, description, - (api, params, client) -> { - if (server == null) throw new IllegalStateException( - "MSMPNamespace '%s' has no server attached. Call attach(server) in SERVER_STARTED.".formatted(namespace) - ); - return handler.apply(server, params, client); - }); + public NotificationBuilder notification(String name) { + return new NotificationBuilder(namespace, name); } } diff --git a/src/main/java/dev/loat/msmp/builder/MethodBuilder.java b/src/main/java/dev/loat/msmp/builder/MethodBuilder.java index 881eed9..ecda53a 100644 --- a/src/main/java/dev/loat/msmp/builder/MethodBuilder.java +++ b/src/main/java/dev/loat/msmp/builder/MethodBuilder.java @@ -1,47 +1,25 @@ package dev.loat.msmp.builder; +import dev.loat.msmp.MSMPNamespace; import net.minecraft.server.jsonrpc.api.Schema; -/** - * First stage of the method builder — only the method name is known. - * - *

Call {@link #requestSchema(Schema)} to define the request payload type, - * or {@link #responseSchema(Schema)} directly for a parameterless method.

- */ public final class MethodBuilder { + private final MSMPNamespace msmpNamespace; private final String namespace; private final String name; - MethodBuilder(String namespace, String name) { + public MethodBuilder(MSMPNamespace msmpNamespace, String namespace, String name) { + this.msmpNamespace = msmpNamespace; this.namespace = namespace; this.name = name; } - /** - * Sets the request schema for this method. - * - *

Call this if the method expects a payload from the client. - * Skip this and call {@link #responseSchema(Schema)} directly for a parameterless method.

- * - * @param the type of the request payload - * @param schema the schema describing the request payload - * @return a {@link MethodBuilderWithParam} with the request schema set - */ public MethodBuilderWithParameters requestSchema(Schema schema) { - return new MethodBuilderWithParameters<>(namespace, name, schema); + return new MethodBuilderWithParameters<>(msmpNamespace, namespace, name, schema); } - /** - * Sets the response schema for this method, skipping the request schema. - * - *

Use this for parameterless methods that don't expect a payload from the client.

- * - * @param the type of the response payload - * @param schema the schema describing the response payload - * @return a {@link MethodBuilderWithSchemas} with no request schema and the response schema set - */ - public MethodBuilderWithSchemas responseSchema(Schema schema) { - return new MethodBuilderWithSchemas<>(namespace, name, null, schema); + public MethodBuilderWithoutParameters responseSchema(Schema schema) { + return new MethodBuilderWithoutParameters<>(msmpNamespace, namespace, name, schema); } } diff --git a/src/main/java/dev/loat/msmp/builder/MethodBuilderWithParameters.java b/src/main/java/dev/loat/msmp/builder/MethodBuilderWithParameters.java index 3d4770c..fefaa08 100644 --- a/src/main/java/dev/loat/msmp/builder/MethodBuilderWithParameters.java +++ b/src/main/java/dev/loat/msmp/builder/MethodBuilderWithParameters.java @@ -1,34 +1,23 @@ package dev.loat.msmp.builder; +import dev.loat.msmp.MSMPNamespace; import net.minecraft.server.jsonrpc.api.Schema; -/** - * Second stage of the method builder — the request schema is known. - * - *

Call {@link #responseSchema(Schema)} to define the response payload type.

- * - * @param the type of the request payload - */ public final class MethodBuilderWithParameters { + private final MSMPNamespace msmpNamespace; private final String namespace; private final String name; private final Schema paramSchema; - MethodBuilderWithParameters(String namespace, String name, Schema paramSchema) { + MethodBuilderWithParameters(MSMPNamespace msmpNamespace, String namespace, String name, Schema paramSchema) { + this.msmpNamespace = msmpNamespace; this.namespace = namespace; this.name = name; this.paramSchema = paramSchema; } - /** - * Sets the response schema for this method. - * - * @param the type of the response payload - * @param schema the schema describing the response payload - * @return a {@link MethodBuilderWithSchemas} with both schemas set - */ public MethodBuilderWithSchemas responseSchema(Schema schema) { - return new MethodBuilderWithSchemas<>(namespace, name, paramSchema, schema); + return new MethodBuilderWithSchemas<>(msmpNamespace, namespace, name, paramSchema, schema); } } diff --git a/src/main/java/dev/loat/msmp/builder/MethodBuilderWithSchemas.java b/src/main/java/dev/loat/msmp/builder/MethodBuilderWithSchemas.java index 8d48ad3..8962b74 100644 --- a/src/main/java/dev/loat/msmp/builder/MethodBuilderWithSchemas.java +++ b/src/main/java/dev/loat/msmp/builder/MethodBuilderWithSchemas.java @@ -2,66 +2,40 @@ import dev.loat.msmp.MSMPMethod; import dev.loat.msmp.MSMPMethodHandler; -import dev.loat.msmp.MSMPMethodHandlerWithoutParameters; +import dev.loat.msmp.MSMPNamespace; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.jsonrpc.api.Schema; -/** - * Final stage of the method builder — both schemas are known. - * - *

Optionally call {@link #description(String)} before calling {@link #register(MsmpMethodHandler)} - * or {@link #register(MsmpParameterlessMethodHandler)} to complete the registration.

- * - * @param the type of the request payload, or {@link Void} for parameterless methods - * @param the type of the response payload - */ public final class MethodBuilderWithSchemas { + private final MSMPNamespace msmpNamespace; private final String namespace; private final String name; private final Schema paramSchema; private final Schema resultSchema; private String description = ""; - MethodBuilderWithSchemas(String namespace, String name, Schema paramSchema, Schema resultSchema) { + MethodBuilderWithSchemas(MSMPNamespace msmpNamespace, String namespace, String name, Schema paramSchema, Schema resultSchema) { + this.msmpNamespace = msmpNamespace; this.namespace = namespace; this.name = name; this.paramSchema = paramSchema; this.resultSchema = resultSchema; } - /** - * Sets the description for this method. - * - * @param description a human-readable description of this method - * @return this builder - */ public MethodBuilderWithSchemas description(String description) { this.description = description; return this; } - /** - * Registers the method with a handler that receives the request payload. - * - *

Use this when {@link MethodBuilder#requestSchema(Schema)} was called.

- * - * @param handler the handler to invoke when this method is called by a client - * @return the registered {@link MsmpMethod} - */ public MSMPMethod register(MSMPMethodHandler handler) { - return new MSMPMethod<>(namespace, name, paramSchema, resultSchema, description, handler); - } - - /** - * Registers the method with a parameterless handler. - * - *

Use this when {@link MethodBuilder#responseSchema(Schema)} was called directly, - * skipping {@link MethodBuilder#requestSchema(Schema)}.

- * - * @param handler the handler to invoke when this method is called by a client - * @return the registered {@link MsmpMethod} - */ - public MSMPMethod register(MSMPMethodHandlerWithoutParameters handler) { - return new MSMPMethod<>(namespace, name, resultSchema, description, handler); + return new MSMPMethod<>(namespace, name, paramSchema, resultSchema, description, + (api, params, client) -> { + MinecraftServer server = msmpNamespace.getServer(); + if (server == null) throw new IllegalStateException( + "MsmpNamespace '%s' has no server attached. Call attach(server) in SERVER_STARTED.".formatted(namespace) + ); + return handler.apply(server, params, client); + }); } } diff --git a/src/main/java/dev/loat/msmp/builder/MethodBuilderWithoutParameters.java b/src/main/java/dev/loat/msmp/builder/MethodBuilderWithoutParameters.java new file mode 100644 index 0000000..20005f5 --- /dev/null +++ b/src/main/java/dev/loat/msmp/builder/MethodBuilderWithoutParameters.java @@ -0,0 +1,40 @@ +package dev.loat.msmp.builder; + +import dev.loat.msmp.MSMPMethodHandler; +import dev.loat.msmp.MSMPMethodHandlerWithoutParameters; +import dev.loat.msmp.MSMPMethod; +import dev.loat.msmp.MSMPNamespace; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.jsonrpc.api.Schema; + +public final class MethodBuilderWithoutParameters { + + private final MSMPNamespace msmpNamespace; + private final String namespace; + private final String name; + private final Schema resultSchema; + private String description = ""; + + MethodBuilderWithoutParameters(MSMPNamespace msmpNamespace, String namespace, String name, Schema resultSchema) { + this.msmpNamespace = msmpNamespace; + this.namespace = namespace; + this.name = name; + this.resultSchema = resultSchema; + } + + public MethodBuilderWithoutParameters description(String description) { + this.description = description; + return this; + } + + public MSMPMethod register(MSMPMethodHandlerWithoutParameters handler) { + return new MSMPMethod<>(namespace, name, resultSchema, description, + (api, client) -> { + MinecraftServer server = msmpNamespace.getServer(); + if (server == null) throw new IllegalStateException( + "MsmpNamespace '%s' has no server attached. Call attach(server) in SERVER_STARTED.".formatted(namespace) + ); + return handler.apply(server, client); + }); + } +} diff --git a/src/main/java/dev/loat/msmp/builder/NotificationBuilder.java b/src/main/java/dev/loat/msmp/builder/NotificationBuilder.java index 310b27c..034e9bf 100644 --- a/src/main/java/dev/loat/msmp/builder/NotificationBuilder.java +++ b/src/main/java/dev/loat/msmp/builder/NotificationBuilder.java @@ -2,28 +2,16 @@ import net.minecraft.server.jsonrpc.api.Schema; -/** - * First stage of the notification builder — only the notification name is known. - * - *

Call {@link #responseSchema(Schema)} to define the payload type.

- */ public final class NotificationBuilder { private final String namespace; private final String name; - NotificationBuilder(String namespace, String name) { + public NotificationBuilder(String namespace, String name) { this.namespace = namespace; this.name = name; } - /** - * Sets the response schema for this notification. - * - * @param the type of the payload sent with this notification - * @param schema the schema describing the payload structure - * @return a {@link NotificationBuilderWithSchema} with the schema set - */ public NotificationBuilderWithSchema responseSchema(Schema schema) { return new NotificationBuilderWithSchema<>(namespace, name, schema); } diff --git a/src/main/java/dev/loat/msmp/builder/NotificationBuilderWithSchema.java b/src/main/java/dev/loat/msmp/builder/NotificationBuilderWithSchema.java index 24ed9dd..6d6c732 100644 --- a/src/main/java/dev/loat/msmp/builder/NotificationBuilderWithSchema.java +++ b/src/main/java/dev/loat/msmp/builder/NotificationBuilderWithSchema.java @@ -3,14 +3,6 @@ import dev.loat.msmp.MSMPNotification; import net.minecraft.server.jsonrpc.api.Schema; -/** - * Final stage of the notification builder — the schema is known. - * - *

Optionally call {@link #description(String)} before calling {@link #register()} - * to complete the registration.

- * - * @param the type of the payload sent with this notification - */ public final class NotificationBuilderWithSchema { private final String namespace; @@ -18,28 +10,17 @@ public final class NotificationBuilderWithSchema { private final Schema schema; private String description = ""; - NotificationBuilderWithSchema(String namespace, String name, Schema schema) { + public NotificationBuilderWithSchema(String namespace, String name, Schema schema) { this.namespace = namespace; this.name = name; this.schema = schema; } - /** - * Sets the description for this notification. - * - * @param description a human-readable description of this notification - * @return this builder - */ public NotificationBuilderWithSchema description(String description) { this.description = description; return this; } - /** - * Registers the notification. - * - * @return the registered {@link MsmpNotification} - */ public MSMPNotification register() { return new MSMPNotification<>(namespace, name, schema, description); } From 206bb16d72e5ca8c41c8d414216c3a553c5d9d24 Mon Sep 17 00:00:00 2001 From: Mqx <62719703+Mqxx@users.noreply.github.com> Date: Sun, 14 Jun 2026 19:05:54 +0200 Subject: [PATCH 3/4] doc: refactor --- README.md | 116 ++++++++++++------ gradle.properties | 2 +- src/main/java/dev/loat/msmp/MSMPMethod.java | 64 +++++----- .../java/dev/loat/msmp/MSMPMethodHandler.java | 4 +- .../MSMPMethodHandlerWithoutParameters.java | 10 +- .../java/dev/loat/msmp/MSMPNamespace.java | 16 +-- .../java/dev/loat/msmp/MSMPNotification.java | 17 ++- src/main/java/dev/loat/msmp/MSMPServer.java | 4 +- .../builder/MethodBuilderWithSchemas.java | 38 ++++-- .../MethodBuilderWithoutParameters.java | 40 ++++-- 10 files changed, 193 insertions(+), 118 deletions(-) diff --git a/README.md b/README.md index b240f6b..0c615a3 100644 --- a/README.md +++ b/README.md @@ -34,20 +34,20 @@ Payloads are simple records that describe the data sent and received over MSMP. Each payload needs a `Codec` for serialization and a `Schema` for MSMP discovery. ```java -public record PingPayload(String message) { +public record EchoPayload(String message) { - public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( - Codec.STRING.fieldOf("message").forGetter(PingPayload::message) - ).apply(i, PingPayload::new)); + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + Codec.STRING.fieldOf("message").forGetter(EchoPayload::message) + ).apply(i, EchoPayload::new)); - public static final Schema SCHEMA = Schema.record(CODEC) + public static final Schema SCHEMA = Schema.record(CODEC) .withField("message", Schema.STRING_SCHEMA); } ``` ### 2. Register methods and notifications -Create a `MsmpNamespace` and register methods and notifications in `onInitialize()` — +Create a `MSMPNamespace` and register methods and notifications in `onInitialize()` - before the server starts and the registry is frozen. Use `attach()` and `detach()` in the server lifecycle events to bind and release @@ -56,26 +56,34 @@ the server instance for use in method handlers. ```java public class MyMod implements ModInitializer { - private static final MsmpNamespace NS = new MsmpNamespace("my_mod"); + private static final MSMPNamespace NS = new MSMPNamespace("my_mod"); - // Registered immediately as static fields — before the server starts - private static final MsmpNotification PING = - NS.notification("ping", PingPayload.SCHEMA, "A ping notification"); + // Registered as a field - before the server starts + private static final MSMPNotification PING = + NS.notification("ping") + .responseSchema(EchoPayload.SCHEMA) + .description("A ping notification") + .register(); - private static MsmpServer msmp; + private static MSMPServer msmp; @Override public void onInitialize() { - // Methods are registered here — registry is still open - NS.method("echo", - EchoPayload.SCHEMA, - EchoPayload.SCHEMA, - "Echoes a message back to the client", - (server, params, client) -> { + // Register a method that receives a parameter + NS.method("echo") + .requestSchema(EchoPayload.SCHEMA) + .responseSchema(EchoPayload.SCHEMA) + .description("Echoes a message back to the client") + .register((server, client, params) -> { System.out.println("Called by connection: " + client.connectionId()); return params; - } - ); + }); + + // Register a method without parameters + NS.method("get_time") + .responseSchema(TimePayload.SCHEMA) + .description("Returns the current game time") + .register((server, client) -> new TimePayload(server.getGameTime())); ServerLifecycleEvents.SERVER_STARTED.register(server -> { NS.attach(server); // bind server for use in method handlers @@ -90,52 +98,84 @@ public class MyMod implements ModInitializer { // Broadcast a notification to all connected clients public static void sendPing() { - if (msmp != null) msmp.send(PING, new PingPayload("hello")); + if (msmp != null) msmp.send(PING, new EchoPayload("hello")); } } ``` +### Method types + +**Methods with request and response payload:** + +```java +NS.method("echo") + .requestSchema(EchoPayload.SCHEMA) + .responseSchema(EchoPayload.SCHEMA) + .description("Echoes a message back to the client") + .register((server, client, params) -> { + System.out.println("Received: " + params.message()); + return params; + }); +``` + +**Parameterless methods (no request payload):** + +```java +NS.method("get_time") + .responseSchema(TimePayload.SCHEMA) + .description("Returns the current game time") + .register((server, client) -> new TimePayload(server.getGameTime())); +``` + ### Handler parameters -The method handler receives three parameters: +The method handler signature depends on whether the method expects parameters: + +**With parameters:** `(server, client, params) -> result` -| Parameter | Type | Description | -|---|---|---| -| `server` | `MinecraftServer` | The running Minecraft server instance | -| `params` | `Param` | The payload received from the client | -| `client` | `ClientInfo` | Info about the calling client, including `connectionId()` | +| Parameter | Type | Description | +|-----------|-------------------|:--------------------------------------| +| `server` | `MinecraftServer` | The running Minecraft server instance | +| `client` | `ClientInfo` | Info about the calling client | +| `params` | `Param` | The payload received from the client | + +**Without parameters:** `(server, client) -> result` + +| Parameter | Type | Description | +|-----------|-------------------|:--------------------------------------| +| `server` | `MinecraftServer` | The running Minecraft server instance | +| `client` | `ClientInfo` | Info about the calling client | ### Sending notifications **Broadcast to all connected clients:** ```java -msmp.send(PING, new PingPayload("hello")); +msmp.send(PING, new EchoPayload("hello")); ``` **Send to a specific client** using the `connectionId` from a method handler: ```java -NS.method("echo", - EchoPayload.SCHEMA, - EchoPayload.SCHEMA, - "Echoes a message back to the calling client only", - (server, params, client) -> { - msmp.sendTo(client.connectionId(), PING, new PingPayload("only for you")); - return params; - } -); +NS.method("notify_client") + .requestSchema(RequestPayload.SCHEMA) + .responseSchema(ResponsePayload.SCHEMA) + .description("Sends a notification only to the calling client") + .register((server, client, params) -> { + msmp.sendTo(client.connectionId(), PING, new EchoPayload("only for you")); + return new ResponsePayload("sent"); + }); ``` ### JSON-RPC examples -**Calling a method** (`my_mod:method/echo`): +**Calling a method** (`my_mod:echo`): ```json { "jsonrpc": "2.0", "id": 1, - "method": "my_mod:method/echo", + "method": "my_mod:echo", "params": [{ "message": "hello" }] diff --git a/gradle.properties b/gradle.properties index 861c272..d1c654f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ loom_version=1.16-SNAPSHOT # check this on https://fabricmc.net/develop/ # Mod Properties -mod_version=1.4.0 +mod_version=2.0.0 maven_group=dev.loat archives_base_name=msmp-lib-mod diff --git a/src/main/java/dev/loat/msmp/MSMPMethod.java b/src/main/java/dev/loat/msmp/MSMPMethod.java index 84d23a6..01e4e5d 100644 --- a/src/main/java/dev/loat/msmp/MSMPMethod.java +++ b/src/main/java/dev/loat/msmp/MSMPMethod.java @@ -9,8 +9,8 @@ /** * Represents an incoming MSMP method that can be called by connected clients. * - *

Instances are created via {@link dev.loat.msmp.builder.MethodBuilderWithSchemas#register(MsmpMethodHandler)} - * or {@link dev.loat.msmp.builder.MethodBuilderWithSchemas#register(MsmpParameterlessMethodHandler)} + *

Instances are created via {@link dev.loat.msmp.builder.MethodBuilderWithSchemas#register(MSMPMethodHandler)} + * or {@link dev.loat.msmp.builder.MethodBuilderWithoutParameters#register(MSMPMethodHandlerWithoutParameters)} * and are registered in the MSMP registry immediately upon creation.

* *
{@code
@@ -19,7 +19,7 @@
  *     .requestSchema(EchoPayload.SCHEMA)
  *     .responseSchema(EchoPayload.SCHEMA)
  *     .description("Echoes a message back to the client")
- *     .register((server, params, client) -> params);
+ *     .register((server, client, params) -> params);
  *
  * // Without request payload:
  * NS.method("get_time")
@@ -28,67 +28,61 @@
  *     .register((server, client) -> new TimePayload(server.getGameTime()));
  * }
* - * @param the type of the payload received from the client, or {@link Void} for parameterless methods - * @param the type of the payload returned to the client + * @param The type of the payload received from the client, or {@link Void} for methods without parameters + * @param The type of the payload returned to the client */ public final class MSMPMethod { /** - * Creates and registers a new incoming method with a request payload. - * Package-private — use {@link dev.loat.msmp.builder.MethodBuilderWithSchemas#register(MsmpMethodHandler)}. + * Creates and registers a new incoming method. * - * @param namespace the namespace to register this method under - * @param name the name of this method - * @param paramSchema the schema describing the payload received from the client - * @param resultSchema the schema describing the payload returned to the client - * @param description a human-readable description of this method - * @param handler the handler to invoke when this method is called by a client + * @param namespace The namespace to register this method under + * @param name The name of this method + * @param paramSchema The schema describing the payload received from the client + * @param resultSchema The schema describing the payload returned to the client + * @param description A human-readable description of this method + * @param rpcFunction The raw RPC function to invoke when this method is called */ @SuppressWarnings("unchecked") - MSMPMethod( + public MSMPMethod( String namespace, String name, Schema paramSchema, Schema resultSchema, String description, - MSMPMethodHandler handler + IncomingRpcMethod.RpcMethodFunction rpcFunction ) { Identifier id = Identifier.fromNamespaceAndPath(namespace, name); ((IncomingRpcMethodBuilderAccessor) - IncomingRpcMethod.method( - (api, params, client) -> handler.apply(null, params, client) - ) - .description(description) - .param(name, paramSchema) - .response(name, resultSchema) + IncomingRpcMethod.method(rpcFunction) + .description(description) + .param(name, paramSchema) + .response(name, resultSchema) ).invokeRegister(BuiltInRegistries.INCOMING_RPC_METHOD, id); } /** - * Creates and registers a new parameterless incoming method. - * Package-private — use {@link dev.loat.msmp.builder.MethodBuilderWithSchemas#register(MsmpParameterlessMethodHandler)}. + * Creates and registers a new incoming method without parameters. * - * @param namespace the namespace to register this method under - * @param name the name of this method - * @param resultSchema the schema describing the payload returned to the client - * @param description a human-readable description of this method - * @param handler the parameterless handler to invoke when this method is called by a client + * @param namespace The namespace to register this method under + * @param name The name of this method + * @param resultSchema The schema describing the payload returned to the client + * @param description A human-readable description of this method + * @param rpcFunction The raw RPC function without parameters to invoke when this method is called */ @SuppressWarnings("unchecked") - MSMPMethod( + public MSMPMethod( String namespace, String name, Schema resultSchema, String description, - MSMPMethodHandlerWithoutParameters handler + IncomingRpcMethod.ParameterlessRpcMethodFunction rpcFunction ) { Identifier id = Identifier.fromNamespaceAndPath(namespace, name); ((IncomingRpcMethodBuilderAccessor) - IncomingRpcMethod.method( - (api, client) -> handler.apply(null, client) - ) - .description(description) - .response(name, resultSchema) + IncomingRpcMethod.method(rpcFunction) + .description(description) + .response(name, resultSchema) ).invokeRegister(BuiltInRegistries.INCOMING_RPC_METHOD, id); } } diff --git a/src/main/java/dev/loat/msmp/MSMPMethodHandler.java b/src/main/java/dev/loat/msmp/MSMPMethodHandler.java index 6bb75c3..f879f2d 100644 --- a/src/main/java/dev/loat/msmp/MSMPMethodHandler.java +++ b/src/main/java/dev/loat/msmp/MSMPMethodHandler.java @@ -20,10 +20,10 @@ public interface MSMPMethodHandler { * Handles an incoming method call from a connected client. * * @param server The running {@link MinecraftServer} instance - * @param params The payload received from the client * @param client The {@link ClientInfo} of the calling client, * providing access to the client's {@link ClientInfo#connectionId()} + * @param params The payload received from the client * @return The payload to return to the client */ - Result apply(MinecraftServer server, Param params, ClientInfo client); + Result apply(MinecraftServer server, ClientInfo client, Param params); } diff --git a/src/main/java/dev/loat/msmp/MSMPMethodHandlerWithoutParameters.java b/src/main/java/dev/loat/msmp/MSMPMethodHandlerWithoutParameters.java index 38c7471..ae140b5 100644 --- a/src/main/java/dev/loat/msmp/MSMPMethodHandlerWithoutParameters.java +++ b/src/main/java/dev/loat/msmp/MSMPMethodHandlerWithoutParameters.java @@ -4,20 +4,20 @@ import net.minecraft.server.jsonrpc.methods.ClientInfo; /** - * Functional interface for handling parameterless incoming MSMP method calls. + * Functional interface for handling incoming MSMP method calls without parameters. * *

Use this when no request payload is expected from the client.

* - * @param the type of the payload returned to the client + * @param The type of the payload returned to the client */ @FunctionalInterface public interface MSMPMethodHandlerWithoutParameters { /** - * Handles an incoming parameterless method call from a connected client. + * Handles an incoming method call without parameters from a connected client. * - * @param server the running {@link MinecraftServer} instance - * @param client the {@link ClientInfo} of the calling client + * @param server The running {@link MinecraftServer} instance + * @param client The {@link ClientInfo} of the calling client * @return the payload to return to the client */ Result apply(MinecraftServer server, ClientInfo client); diff --git a/src/main/java/dev/loat/msmp/MSMPNamespace.java b/src/main/java/dev/loat/msmp/MSMPNamespace.java index b133ac1..a0e1f7c 100644 --- a/src/main/java/dev/loat/msmp/MSMPNamespace.java +++ b/src/main/java/dev/loat/msmp/MSMPNamespace.java @@ -20,7 +20,7 @@ * .requestSchema(EchoPayload.SCHEMA) * .responseSchema(EchoPayload.SCHEMA) * .description("Echoes a message back to the client") - * .register((server, params, client) -> params); + * .register((server, client, params) -> params); * * NS.notification("ping") * .responseSchema(PingPayload.SCHEMA) @@ -40,7 +40,7 @@ public final class MSMPNamespace { /** * Creates a new namespace with the given identifier. * - * @param namespace the namespace identifier (e.g. {@code "my_mod"}) + * @param namespace The namespace identifier (e.g. {@code "my_mod"}) */ public MSMPNamespace(String namespace) { this.namespace = namespace; @@ -52,7 +52,7 @@ public MSMPNamespace(String namespace) { *

Should be called in the {@code SERVER_STARTED} lifecycle event. * Required for method handlers to access the server instance.

* - * @param server the running {@link MinecraftServer} instance + * @param server The running {@link MinecraftServer} instance */ public void attach(MinecraftServer server) { this.server = server; @@ -73,15 +73,15 @@ public void detach() { * * @return the bound server, or {@code null} if not attached */ - MinecraftServer getServer() { + public MinecraftServer getServer() { return server; } /** * Creates a new method builder for the given name. * - * @param name the name of this method (e.g. {@code "echo"}), - * resulting in the identifier {@code namespace:method/name} + * @param name The name of this method (e.g. {@code "echo"}), + * resulting in the identifier {@code namespace:method/name} * @return a {@link MethodBuilder} to configure and register the method */ public MethodBuilder method(String name) { @@ -91,8 +91,8 @@ public MethodBuilder method(String name) { /** * Creates a new notification builder for the given name. * - * @param name the name of this notification (e.g. {@code "ping"}), - * resulting in the identifier {@code namespace:notification/name} + * @param name The name of this notification (e.g. {@code "ping"}), + * resulting in the identifier {@code namespace:notification/name} * @return a {@link NotificationBuilder} to configure and register the notification */ public NotificationBuilder notification(String name) { diff --git a/src/main/java/dev/loat/msmp/MSMPNotification.java b/src/main/java/dev/loat/msmp/MSMPNotification.java index ab67f52..8257378 100644 --- a/src/main/java/dev/loat/msmp/MSMPNotification.java +++ b/src/main/java/dev/loat/msmp/MSMPNotification.java @@ -9,15 +9,16 @@ /** * Represents an outgoing MSMP notification that can be broadcast to all connected clients. * - *

Instances are created via {@link MSMPNamespace#notification(String, Schema)} or - * {@link MSMPNamespace#notification(String, Schema, String)} and are registered + *

Instances are created via {@link MSMPNamespace#notification(String)} and are registered * in the MSMP registry immediately upon creation.

* *

Use {@link MSMPServer#send(MSMPNotification, Object)} to broadcast this notification.

* *
{@code
- * MSMPNotification ping = msmp.namespace("my_mod")
- *     .notification("ping", PingPayload.SCHEMA, "A ping notification");
+ * MSMPNotification ping = NS.notification("ping")
+ *     .responseSchema(PingPayload.SCHEMA)
+ *     .description("A ping notification")
+ *     .register();
  *
  * msmp.send(ping, new PingPayload("hello"));
  * }
@@ -30,17 +31,15 @@ public final class MSMPNotification { /** * Creates and registers a new outgoing notification under the given namespace. - * Package-private — use {@link MSMPNamespace#notification(String, Schema)} or - * {@link MSMPNamespace#notification(String, Schema, String)}. * * @param namespace The namespace to register this notification under (e.g. {@code "my_mod"}) * @param name The name of this notification (e.g. {@code "ping"}), * resulting in the identifier {@code namespace:notification/name} * @param schema The schema describing the payload structure - * @param description A human-readable description of this notification + * @param description a human-readable description of this notification */ @SuppressWarnings("unchecked") - MSMPNotification(String namespace, String name, Schema schema, String description) { + public MSMPNotification(String namespace, String name, Schema schema, String description) { this.holder = ((OutgoingRpcMethodBuilderAccessor) OutgoingRpcMethod .notificationWithParams() .description(description) @@ -54,7 +53,7 @@ public final class MSMPNotification { *

Used internally by {@link MSMPServer#send(MSMPNotification, Object)} * to broadcast this notification to all connected clients.

* - * @return The holder reference to the registered outgoing RPC method + * @return the holder reference to the registered outgoing RPC method */ Holder.Reference> holder() { return holder; diff --git a/src/main/java/dev/loat/msmp/MSMPServer.java b/src/main/java/dev/loat/msmp/MSMPServer.java index 3349775..53acf95 100644 --- a/src/main/java/dev/loat/msmp/MSMPServer.java +++ b/src/main/java/dev/loat/msmp/MSMPServer.java @@ -42,7 +42,7 @@ public final class MSMPServer { *

The {@link ManagementServer} is located via reflection since it is not * publicly accessible on {@link MinecraftServer}.

* - * @param server the running {@link MinecraftServer} instance + * @param server The running {@link MinecraftServer} instance */ public MSMPServer(MinecraftServer server) { this.managementServer = findManagementServer(server); @@ -96,7 +96,7 @@ public void sendTo( * Finds the {@link ManagementServer} instance held by the given {@link MinecraftServer} * by traversing its class hierarchy via reflection. * - * @param server the running {@link MinecraftServer} instance + * @param server The running {@link MinecraftServer} instance * * @return the {@link ManagementServer} instance, or {@code null} if not found */ diff --git a/src/main/java/dev/loat/msmp/builder/MethodBuilderWithSchemas.java b/src/main/java/dev/loat/msmp/builder/MethodBuilderWithSchemas.java index 8962b74..3a34802 100644 --- a/src/main/java/dev/loat/msmp/builder/MethodBuilderWithSchemas.java +++ b/src/main/java/dev/loat/msmp/builder/MethodBuilderWithSchemas.java @@ -4,8 +4,18 @@ import dev.loat.msmp.MSMPMethodHandler; import dev.loat.msmp.MSMPNamespace; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.jsonrpc.IncomingRpcMethod; import net.minecraft.server.jsonrpc.api.Schema; +/** + * Final stage of the method builder — both schemas are known. + * + *

Optionally call {@link #description(String)} before calling + * {@link #register(MSMPMethodHandler)} to complete the registration.

+ * + * @param The type of the request payload + * @param The type of the response payload + */ public final class MethodBuilderWithSchemas { private final MSMPNamespace msmpNamespace; @@ -23,19 +33,31 @@ public final class MethodBuilderWithSchemas { this.resultSchema = resultSchema; } + /** + * Sets the description for this method. + * + * @param description a human-readable description of this method + * @return this builder + */ public MethodBuilderWithSchemas description(String description) { this.description = description; return this; } + /** + * Registers the method with a handler that receives the request payload. + * + * @param handler The handler to invoke when this method is called by a client + * @return the registered {@link MSMPMethod} + */ public MSMPMethod register(MSMPMethodHandler handler) { - return new MSMPMethod<>(namespace, name, paramSchema, resultSchema, description, - (api, params, client) -> { - MinecraftServer server = msmpNamespace.getServer(); - if (server == null) throw new IllegalStateException( - "MsmpNamespace '%s' has no server attached. Call attach(server) in SERVER_STARTED.".formatted(namespace) - ); - return handler.apply(server, params, client); - }); + IncomingRpcMethod.RpcMethodFunction rpcFunction = (api, params, client) -> { + MinecraftServer server = msmpNamespace.getServer(); + if (server == null) throw new IllegalStateException( + "MSMPNamespace '%s' has no server attached. Call attach(server) in SERVER_STARTED.".formatted(namespace) + ); + return handler.apply(server, client, params); + }; + return new MSMPMethod<>(namespace, name, paramSchema, resultSchema, description, rpcFunction); } } diff --git a/src/main/java/dev/loat/msmp/builder/MethodBuilderWithoutParameters.java b/src/main/java/dev/loat/msmp/builder/MethodBuilderWithoutParameters.java index 20005f5..ad43342 100644 --- a/src/main/java/dev/loat/msmp/builder/MethodBuilderWithoutParameters.java +++ b/src/main/java/dev/loat/msmp/builder/MethodBuilderWithoutParameters.java @@ -1,12 +1,20 @@ package dev.loat.msmp.builder; -import dev.loat.msmp.MSMPMethodHandler; -import dev.loat.msmp.MSMPMethodHandlerWithoutParameters; import dev.loat.msmp.MSMPMethod; +import dev.loat.msmp.MSMPMethodHandlerWithoutParameters; import dev.loat.msmp.MSMPNamespace; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.jsonrpc.IncomingRpcMethod; import net.minecraft.server.jsonrpc.api.Schema; +/** + * Final stage of the method builder for methods without parameters — the response schema is known. + * + *

Optionally call {@link #description(String)} before calling + * {@link #register(MSMPMethodHandlerWithoutParameters)} to complete the registration.

+ * + * @param The type of the response payload + */ public final class MethodBuilderWithoutParameters { private final MSMPNamespace msmpNamespace; @@ -22,19 +30,31 @@ public final class MethodBuilderWithoutParameters { this.resultSchema = resultSchema; } + /** + * Sets the description for this method. + * + * @param description a human-readable description of this method + * @return this builder + */ public MethodBuilderWithoutParameters description(String description) { this.description = description; return this; } + /** + * Registers the method without parameters. + * + * @param handler The handler to invoke when this method is called by a client + * @return the registered {@link MSMPMethod} + */ public MSMPMethod register(MSMPMethodHandlerWithoutParameters handler) { - return new MSMPMethod<>(namespace, name, resultSchema, description, - (api, client) -> { - MinecraftServer server = msmpNamespace.getServer(); - if (server == null) throw new IllegalStateException( - "MsmpNamespace '%s' has no server attached. Call attach(server) in SERVER_STARTED.".formatted(namespace) - ); - return handler.apply(server, client); - }); + IncomingRpcMethod.ParameterlessRpcMethodFunction rpcFunction = (api, client) -> { + MinecraftServer server = msmpNamespace.getServer(); + if (server == null) throw new IllegalStateException( + "MSMPNamespace '%s' has no server attached. Call attach(server) in SERVER_STARTED.".formatted(namespace) + ); + return handler.apply(server, client); + }; + return new MSMPMethod<>(namespace, name, resultSchema, description, rpcFunction); } } From 99a091821d196aad549ada5117aa2ba61a97401c Mon Sep 17 00:00:00 2001 From: Mqx <62719703+Mqxx@users.noreply.github.com> Date: Sun, 14 Jun 2026 19:07:24 +0200 Subject: [PATCH 4/4] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c615a3..1b9fe58 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ repositories { } dependencies { - implementation("com.github.YOUR_USERNAME:msmp-lib:VERSION") + implementation("com.github.MinecraftPlayground:msmp-lib-mod:VERSION") } ```