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 Use this when no request payload is expected from the client.
+ * + * @paramCall {@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.
+ * + * @paramCall {@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. + * + * @paramOptionally 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 + * @paramUse 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(MSMPMethodHandlerWithoutParametersCall {@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. + * + * @paramOptionally call {@link #description(String)} before calling {@link #register()} + * to complete the registration.
+ * + * @paramInstances 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")
}
```