From 38d467fb95ffd697f1f59080ef0bb8f0debfb603 Mon Sep 17 00:00:00 2001 From: Artur Khusainov Date: Sat, 9 Aug 2025 01:16:28 +0300 Subject: [PATCH 01/12] docs: document API classes --- api/build.gradle.kts | 17 +++++ .../turikhay/mc/mapmodcompanion/Channels.java | 27 +++++++ .../com/turikhay/mc/mapmodcompanion/Id.java | 73 ++++++++++++++++++ .../mc/mapmodcompanion/IdBlender.java | 30 ++++++++ .../turikhay/mc/mapmodcompanion/IdLookup.java | 75 +++++++++++++++++++ .../mapmodcompanion/LevelMapProperties.java | 24 ++++++ .../mapmodcompanion/LightweightException.java | 33 ++++++++ .../MalformedPacketException.java | 28 +++++++ .../mc/mapmodcompanion/PrefixedId.java | 43 +++++++++++ .../mc/mapmodcompanion/StandardId.java | 15 ++++ .../mc/mapmodcompanion/package-info.java | 5 +- .../src/test/java/IdBlenderTest.java | 0 ...elMapPropertiesPacketDeserializerTest.java | 0 ...evelMapPropertiesPacketSerializerTest.java | 0 .../PrefixedIdPacketDeserializerTest.java | 0 bungee/build.gradle.kts | 1 + common/build.gradle.kts | 4 + .../turikhay/mc/mapmodcompanion/Channels.java | 8 -- .../com/turikhay/mc/mapmodcompanion/Id.java | 22 ------ .../mc/mapmodcompanion/IdBlender.java | 14 ---- .../turikhay/mc/mapmodcompanion/IdLookup.java | 31 -------- .../mapmodcompanion/LightweightException.java | 13 ---- .../MalformedPacketException.java | 13 ---- settings.gradle.kts | 1 + spigot/build.gradle.kts | 1 + velocity/build.gradle.kts | 1 + 26 files changed, 377 insertions(+), 102 deletions(-) create mode 100644 api/build.gradle.kts create mode 100644 api/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java create mode 100644 api/src/main/java/com/turikhay/mc/mapmodcompanion/Id.java create mode 100644 api/src/main/java/com/turikhay/mc/mapmodcompanion/IdBlender.java create mode 100644 api/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java rename {common => api}/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java (75%) create mode 100644 api/src/main/java/com/turikhay/mc/mapmodcompanion/LightweightException.java create mode 100644 api/src/main/java/com/turikhay/mc/mapmodcompanion/MalformedPacketException.java rename {common => api}/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java (77%) rename {common => api}/src/main/java/com/turikhay/mc/mapmodcompanion/StandardId.java (72%) rename {common => api}/src/main/java/com/turikhay/mc/mapmodcompanion/package-info.java (57%) rename {common => api}/src/test/java/IdBlenderTest.java (100%) rename {common => api}/src/test/java/LevelMapPropertiesPacketDeserializerTest.java (100%) rename {common => api}/src/test/java/LevelMapPropertiesPacketSerializerTest.java (100%) rename {common => api}/src/test/java/PrefixedIdPacketDeserializerTest.java (100%) delete mode 100644 common/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java delete mode 100644 common/src/main/java/com/turikhay/mc/mapmodcompanion/Id.java delete mode 100644 common/src/main/java/com/turikhay/mc/mapmodcompanion/IdBlender.java delete mode 100644 common/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java delete mode 100644 common/src/main/java/com/turikhay/mc/mapmodcompanion/LightweightException.java delete mode 100644 common/src/main/java/com/turikhay/mc/mapmodcompanion/MalformedPacketException.java diff --git a/api/build.gradle.kts b/api/build.gradle.kts new file mode 100644 index 0000000..550be84 --- /dev/null +++ b/api/build.gradle.kts @@ -0,0 +1,17 @@ +plugins { + id("java-convention") + `maven-publish` +} + +java { + withSourcesJar() + withJavadocJar() +} + +publishing { + publications { + create("mavenJava") { + from(components["java"]) + } + } +} diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java new file mode 100644 index 0000000..6f95033 --- /dev/null +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java @@ -0,0 +1,27 @@ +package com.turikhay.mc.mapmodcompanion; + +/** + * Utility holder for network channel identifiers used by various map + * modifications. + *

+ * These constants can be used with the platform specific networking API to + * register listeners or send packets. For example, registering the world id + * channel on Fabric would look like: + * + *

{@code
+ * ClientPlayNetworking.registerGlobalReceiver(
+ *         Channels.WORLDID_CHANNEL,
+ *         (client, handler, buf, responseSender) -> { /* ... *\/ }
+ * );
+ * }
+ */ +public interface Channels { + /** Plugin channel used by Xaero's Minimap. */ + String XAERO_MINIMAP_CHANNEL = "xaerominimap:main"; + /** Plugin channel used by Xaero's World Map. */ + String XAERO_WORLDMAP_CHANNEL = "xaeroworldmap:main"; + /** Official MapModCompanion channel used to query world identifiers. */ + String WORLDID_CHANNEL = "worldinfo:world_id"; + /** Legacy channel name supported for backwards compatibility. */ + String WORLDID_LEGACY_CHANNEL = "world_id"; +} diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/Id.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/Id.java new file mode 100644 index 0000000..82621cb --- /dev/null +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/Id.java @@ -0,0 +1,73 @@ +package com.turikhay.mc.mapmodcompanion; + +/** + * Represents a world identifier. + *

+ * Implementations are immutable and return a new instance when a different id + * is required. + */ +public interface Id { + + /** Magic value used in some packet formats. */ + int MAGIC_MARKER = 42; + + /** + * Returns the numeric id value. + */ + int getId(); + + /** + * Creates a copy of this id with a different numeric value. + * + * @param id new value + * @return new id instance + */ + Id withIdUnchecked(int id); + + /** + * Type-safe wrapper around {@link #withIdUnchecked(int)}. + * + *

{@code
+     * StandardId newId = existing.withId(5);
+     * }
+ * + * @param id new value + * @param concrete {@link Id} type + * @return new id instance + */ + @SuppressWarnings("unchecked") + default IdType withId(int id) { + return (IdType) withIdUnchecked(id); + } + + /** + * Converts raw packet bytes into an {@link Id} instance. + * + * @param type of id produced + */ + interface Deserializer { + /** + * Deserializes an id from raw bytes. + * + * @param data raw packet data + * @return parsed id + * @throws MalformedPacketException if the data cannot be parsed + */ + IdType deserialize(byte[] data) throws MalformedPacketException; + } + + /** + * Produces raw packet bytes from an {@link Id} instance. + * + * @param type of id to serialize + */ + interface Serializer { + /** + * Serializes the supplied id to a byte array. + * + * @param id id to encode + * @return encoded packet bytes + */ + byte[] serialize(IdType id); + } +} diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/IdBlender.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/IdBlender.java new file mode 100644 index 0000000..de087fd --- /dev/null +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/IdBlender.java @@ -0,0 +1,30 @@ +package com.turikhay.mc.mapmodcompanion; + +import java.util.Objects; + +/** + * Combines two world identifiers into a single deterministic value. + */ +public interface IdBlender { + + /** + * A simple implementation that hashes the provided ids using + * {@link Objects#hash(Object...)}. + */ + IdBlender DEFAULT = new IdBlender() { + @Override + public IdType blend(IdType id, int anotherId) { + return id.withId(Objects.hash(id.getId(), anotherId)); + } + }; + + /** + * Produces a new id based on two input ids. + * + * @param id base id + * @param anotherId id to blend with + * @param concrete {@link Id} type + * @return blended identifier + */ + IdType blend(IdType id, int anotherId); +} diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java new file mode 100644 index 0000000..83dd8f4 --- /dev/null +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java @@ -0,0 +1,75 @@ +package com.turikhay.mc.mapmodcompanion; + +import java.util.Optional; + +/** + * Performs lookup of world identifiers. + *

+ * Implementations may resolve identifiers from configuration files, network + * responses or any other data source. + */ +public interface IdLookup { + + /** + * Attempts to find a numeric world identifier for the supplied string id. + * + * @param id textual representation of the world id + * @return a numeric identifier if a mapping exists + */ + Optional findMatch(String id); + + /** + * Convenience overload accepting an integer id. + * + * @param id numeric id + * @return a numeric identifier if a mapping exists + */ + default Optional findMatch(int id) { + return findMatch(String.valueOf(id)); + } + + /** + * Configuration-backed implementation that resolves ids from an external + * configuration source. + *

+ * Mappings are read from keys starting with {@link #PATH_PREFIX} followed + * by the textual world id. + */ + class ConfigBased implements IdLookup { + /** Prefix within the configuration for override values. */ + public static final String PATH_PREFIX = "overrides."; + + private final ConfigAccessor accessor; + + /** + * Creates a new lookup using the supplied accessor. + * + * @param accessor callback used to read configuration values + */ + public ConfigBased(ConfigAccessor accessor) { + this.accessor = accessor; + } + + /** {@inheritDoc} */ + @Override + public Optional findMatch(String id) { + int value = accessor.getInt(PATH_PREFIX + id, Integer.MIN_VALUE); + return value == Integer.MIN_VALUE ? Optional.empty() : Optional.of(value); + } + + /** + * Adapter used to access configuration values. + */ + public interface ConfigAccessor { + /** + * Reads an integer from configuration or returns the default value + * if the path is not present. + * + * @param path configuration path + * @param def default value + * @return configured value or {@code def} + */ + int getInt(String path, int def); + } + } +} diff --git a/common/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java similarity index 75% rename from common/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java rename to api/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java index 826d468..e0e96e3 100644 --- a/common/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java @@ -2,10 +2,18 @@ import java.io.*; +/** + * Binary format used by VoxelMap to communicate the world id. + */ public interface LevelMapProperties { + + /** + * Deserializes standard id packets. + */ class Deserializer implements Id.Deserializer { private static Deserializer INSTANCE; + /** {@inheritDoc} */ @Override public StandardId deserialize(byte[] data) throws MalformedPacketException { DataInputStream in = new DataInputStream(new ByteArrayInputStream(data)); @@ -20,19 +28,32 @@ public StandardId deserialize(byte[] data) throws MalformedPacketException { } } + /** + * Returns a shared instance of the deserializer. + */ public static Deserializer instance() { return INSTANCE == null ? INSTANCE = new Deserializer() : INSTANCE; } } + /** + * Serializes standard ids into packet byte arrays. + */ class Serializer implements Id.Serializer { private static Serializer INSTANCE; + /** {@inheritDoc} */ @Override public byte[] serialize(StandardId id) { return serialize(id.getId()); } + /** + * Encodes the supplied id into the binary representation. + * + * @param id numeric world id + * @return encoded packet bytes + */ public byte[] serialize(int id) { ByteArrayOutputStream array = new ByteArrayOutputStream(); try(DataOutputStream out = new DataOutputStream(array)) { @@ -44,6 +65,9 @@ public byte[] serialize(int id) { return array.toByteArray(); } + /** + * Returns a shared instance of the serializer. + */ public static Serializer instance() { return INSTANCE == null ? INSTANCE = new Serializer() : INSTANCE; } diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/LightweightException.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/LightweightException.java new file mode 100644 index 0000000..67b8ce3 --- /dev/null +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/LightweightException.java @@ -0,0 +1,33 @@ +package com.turikhay.mc.mapmodcompanion; + +import javax.annotation.Nullable; + +/** + * A lightweight {@link Exception} implementation that does not populate the + * stack trace. + *

+ * This is useful when the exception is part of the regular control flow and + * the overhead of capturing a stack trace is undesirable. + */ +public class LightweightException extends Exception { + + /** + * Creates a new exception with the provided message and optional cause + * without filling in the stack trace. + * + * @param message human readable description of the problem + * @param cause underlying cause or {@code null} + */ + public LightweightException(String message, @Nullable Throwable cause) { + super(message, cause, false, false); + } + + /** + * Creates a new exception with the provided message. + * + * @param message human readable description of the problem + */ + public LightweightException(String message) { + this(message, null); + } +} diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/MalformedPacketException.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/MalformedPacketException.java new file mode 100644 index 0000000..50b5354 --- /dev/null +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/MalformedPacketException.java @@ -0,0 +1,28 @@ +package com.turikhay.mc.mapmodcompanion; + +import javax.annotation.Nullable; + +/** + * Indicates that a network packet could not be parsed. + */ +public class MalformedPacketException extends LightweightException { + + /** + * Creates a new exception with the provided message and optional cause. + * + * @param message human readable description of the problem + * @param cause underlying cause or {@code null} + */ + public MalformedPacketException(String message, @Nullable Throwable cause) { + super(message, cause); + } + + /** + * Creates a new exception with the provided message. + * + * @param message human readable description of the problem + */ + public MalformedPacketException(String message) { + super(message); + } +} diff --git a/common/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java similarity index 77% rename from common/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java rename to api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java index 568f1a5..2c7a0d7 100644 --- a/common/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java @@ -4,36 +4,59 @@ import java.nio.charset.StandardCharsets; import java.util.Objects; +/** + * Identifier encoded with a zero-prefixed length and optional magic marker. + *

+ * The format matches the one used by Xaero's minimap when responding to world + * id requests. The {@link Deserializer} and {@link Serializer} nested classes + * can be used to convert between the packet representation and this class. + */ public class PrefixedId implements Id { private final int padding; private final boolean usesMagicByte; private final int id; + /** + * Creates a new prefixed id. + * + * @param padding number of leading zero bytes before the marker + * @param usesMagicByte whether the {@link #MAGIC_MARKER} is present + * @param id numeric world id + */ public PrefixedId(int padding, boolean usesMagicByte, int id) { this.padding = padding; this.usesMagicByte = usesMagicByte; this.id = id; } + /** + * Deprecated constructor that assumes the packet uses the magic marker. + */ @Deprecated public PrefixedId(int padding, int id) { this(padding, true, id); } + /** {@inheritDoc} */ @Override public int getId() { return id; } + /** + * Number of zero bytes prepended to the packet. + */ public int getPadding() { return padding; } + /** {@inheritDoc} */ @Override public PrefixedId withIdUnchecked(int id) { return new PrefixedId(this.padding, this.usesMagicByte, id); } + /** {@inheritDoc} */ @Override public boolean equals(Object o) { if (this == o) return true; @@ -42,11 +65,13 @@ public boolean equals(Object o) { return padding == that.padding && usesMagicByte == that.usesMagicByte && id == that.id; } + /** {@inheritDoc} */ @Override public int hashCode() { return Objects.hash(padding, usesMagicByte, id); } + /** {@inheritDoc} */ @Override public String toString() { return "PrefixedId{" + @@ -56,9 +81,17 @@ public String toString() { '}'; } + /** + * Deserializes prefixed id packets. + * + *

{@code
+     * PrefixedId id = PrefixedId.Deserializer.instance().deserialize(data);
+     * }
+ */ public static class Deserializer implements Id.Deserializer { private static Deserializer INSTANCE; + /** {@inheritDoc} */ @Override public PrefixedId deserialize(byte[] data) throws MalformedPacketException { DataInputStream in = new DataInputStream(new ByteArrayInputStream(data)); @@ -101,14 +134,21 @@ public PrefixedId deserialize(byte[] data) throws MalformedPacketException { } } + /** + * Returns a shared instance of the deserializer. + */ public static Deserializer instance() { return INSTANCE == null ? INSTANCE = new Deserializer() : INSTANCE; } } + /** + * Serializes {@link PrefixedId} instances into packet byte arrays. + */ public static class Serializer implements Id.Serializer { private static Serializer INSTANCE; + /** {@inheritDoc} */ @Override public byte[] serialize(PrefixedId id) { ByteArrayOutputStream array = new ByteArrayOutputStream(); @@ -128,6 +168,9 @@ public byte[] serialize(PrefixedId id) { return array.toByteArray(); } + /** + * Returns a shared instance of the serializer. + */ public static Serializer instance() { return INSTANCE == null ? INSTANCE = new Serializer() : INSTANCE; } diff --git a/common/src/main/java/com/turikhay/mc/mapmodcompanion/StandardId.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/StandardId.java similarity index 72% rename from common/src/main/java/com/turikhay/mc/mapmodcompanion/StandardId.java rename to api/src/main/java/com/turikhay/mc/mapmodcompanion/StandardId.java index cb2ee03..0481782 100644 --- a/common/src/main/java/com/turikhay/mc/mapmodcompanion/StandardId.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/StandardId.java @@ -2,22 +2,35 @@ import java.util.Objects; +/** + * Plain numeric {@link Id} implementation. + */ public class StandardId implements Id { private final int id; + /** + * Creates a new id with the given value. + * + * @param id numeric world id + */ public StandardId(int id) { this.id = id; } + /** + * Returns the numeric world id. + */ public int getId() { return id; } + /** {@inheritDoc} */ @Override public StandardId withIdUnchecked(int id) { return new StandardId(id); } + /** {@inheritDoc} */ @Override public boolean equals(Object o) { if (this == o) return true; @@ -26,11 +39,13 @@ public boolean equals(Object o) { return id == that.id; } + /** {@inheritDoc} */ @Override public int hashCode() { return Objects.hash(id); } + /** {@inheritDoc} */ @Override public String toString() { return "StandardId{" + diff --git a/common/src/main/java/com/turikhay/mc/mapmodcompanion/package-info.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/package-info.java similarity index 57% rename from common/src/main/java/com/turikhay/mc/mapmodcompanion/package-info.java rename to api/src/main/java/com/turikhay/mc/mapmodcompanion/package-info.java index 8b192c9..bf23e44 100644 --- a/common/src/main/java/com/turikhay/mc/mapmodcompanion/package-info.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/package-info.java @@ -1,7 +1,10 @@ +/** + * Public API exposing helper classes for querying world identifiers. + */ @ParametersAreNonnullByDefault @ReturnValuesAreNonnullByDefault package com.turikhay.mc.mapmodcompanion; import edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault; -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/common/src/test/java/IdBlenderTest.java b/api/src/test/java/IdBlenderTest.java similarity index 100% rename from common/src/test/java/IdBlenderTest.java rename to api/src/test/java/IdBlenderTest.java diff --git a/common/src/test/java/LevelMapPropertiesPacketDeserializerTest.java b/api/src/test/java/LevelMapPropertiesPacketDeserializerTest.java similarity index 100% rename from common/src/test/java/LevelMapPropertiesPacketDeserializerTest.java rename to api/src/test/java/LevelMapPropertiesPacketDeserializerTest.java diff --git a/common/src/test/java/LevelMapPropertiesPacketSerializerTest.java b/api/src/test/java/LevelMapPropertiesPacketSerializerTest.java similarity index 100% rename from common/src/test/java/LevelMapPropertiesPacketSerializerTest.java rename to api/src/test/java/LevelMapPropertiesPacketSerializerTest.java diff --git a/common/src/test/java/PrefixedIdPacketDeserializerTest.java b/api/src/test/java/PrefixedIdPacketDeserializerTest.java similarity index 100% rename from common/src/test/java/PrefixedIdPacketDeserializerTest.java rename to api/src/test/java/PrefixedIdPacketDeserializerTest.java diff --git a/bungee/build.gradle.kts b/bungee/build.gradle.kts index ede6885..2be0f7d 100644 --- a/bungee/build.gradle.kts +++ b/bungee/build.gradle.kts @@ -29,6 +29,7 @@ tasks { } dependencies { + implementation(project(":api")) implementation(project(":common")) implementation(libs.bstats.bungeecord) compileOnly(libs.bungeecord.api) diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 090e9b5..d23ece7 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,3 +1,7 @@ plugins { id("java-convention") } + +dependencies { + implementation(project(":api")) +} diff --git a/common/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java b/common/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java deleted file mode 100644 index f5c2af3..0000000 --- a/common/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.turikhay.mc.mapmodcompanion; - -public interface Channels { - String XAERO_MINIMAP_CHANNEL = "xaerominimap:main"; - String XAERO_WORLDMAP_CHANNEL = "xaeroworldmap:main"; - String WORLDID_CHANNEL = "worldinfo:world_id"; - String WORLDID_LEGACY_CHANNEL = "world_id"; -} diff --git a/common/src/main/java/com/turikhay/mc/mapmodcompanion/Id.java b/common/src/main/java/com/turikhay/mc/mapmodcompanion/Id.java deleted file mode 100644 index 284318f..0000000 --- a/common/src/main/java/com/turikhay/mc/mapmodcompanion/Id.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.turikhay.mc.mapmodcompanion; - -public interface Id { - int MAGIC_MARKER = 42; - - int getId(); - - Id withIdUnchecked(int id); - - @SuppressWarnings("unchecked") - default IdType withId(int id) { - return (IdType) withIdUnchecked(id); - } - - interface Deserializer { - IdType deserialize(byte[] data) throws MalformedPacketException; - } - - interface Serializer { - byte[] serialize(IdType id); - } -} diff --git a/common/src/main/java/com/turikhay/mc/mapmodcompanion/IdBlender.java b/common/src/main/java/com/turikhay/mc/mapmodcompanion/IdBlender.java deleted file mode 100644 index e005ecd..0000000 --- a/common/src/main/java/com/turikhay/mc/mapmodcompanion/IdBlender.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.turikhay.mc.mapmodcompanion; - -import java.util.Objects; - -public interface IdBlender { - IdBlender DEFAULT = new IdBlender() { - @Override - public IdType blend(IdType id, int anotherId) { - return id.withId(Objects.hash(id.getId(), anotherId)); - } - }; - - IdType blend(IdType id, int anotherId); -} diff --git a/common/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java b/common/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java deleted file mode 100644 index c7b4e10..0000000 --- a/common/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.turikhay.mc.mapmodcompanion; - -import java.util.Optional; - -public interface IdLookup { - Optional findMatch(String id); - - default Optional findMatch(int id) { - return findMatch(String.valueOf(id)); - } - - class ConfigBased implements IdLookup { - public static final String PATH_PREFIX = "overrides."; - - private final ConfigAccessor accessor; - - public ConfigBased(ConfigAccessor accessor) { - this.accessor = accessor; - } - - @Override - public Optional findMatch(String id) { - int value = accessor.getInt(PATH_PREFIX + id, Integer.MIN_VALUE); - return value == Integer.MIN_VALUE ? Optional.empty() : Optional.of(value); - } - - public interface ConfigAccessor { - int getInt(String path, int def); - } - } -} diff --git a/common/src/main/java/com/turikhay/mc/mapmodcompanion/LightweightException.java b/common/src/main/java/com/turikhay/mc/mapmodcompanion/LightweightException.java deleted file mode 100644 index 72fbc10..0000000 --- a/common/src/main/java/com/turikhay/mc/mapmodcompanion/LightweightException.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.turikhay.mc.mapmodcompanion; - -import javax.annotation.Nullable; - -public class LightweightException extends Exception { - public LightweightException(String message, @Nullable Throwable cause) { - super(message, cause, false, false); - } - - public LightweightException(String message) { - this(message, null); - } -} diff --git a/common/src/main/java/com/turikhay/mc/mapmodcompanion/MalformedPacketException.java b/common/src/main/java/com/turikhay/mc/mapmodcompanion/MalformedPacketException.java deleted file mode 100644 index 6bdb40d..0000000 --- a/common/src/main/java/com/turikhay/mc/mapmodcompanion/MalformedPacketException.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.turikhay.mc.mapmodcompanion; - -import javax.annotation.Nullable; - -public class MalformedPacketException extends LightweightException { - public MalformedPacketException(String message, @Nullable Throwable cause) { - super(message, cause); - } - - public MalformedPacketException(String message) { - super(message); - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 0200f75..7fd9de3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,7 @@ rootProject.name = "mapmodcompanion" include(":common") +include(":api") include(":bungee") include(":spigot") include(":velocity") diff --git a/spigot/build.gradle.kts b/spigot/build.gradle.kts index bb9ed39..b2fa80b 100644 --- a/spigot/build.gradle.kts +++ b/spigot/build.gradle.kts @@ -39,6 +39,7 @@ val spigot_version: String by project val protocolLib_version: String by project dependencies { + implementation(project(":api")) implementation(project(":common")) implementation(libs.bstats.bukkit) diff --git a/velocity/build.gradle.kts b/velocity/build.gradle.kts index 2899094..1cb0ec1 100644 --- a/velocity/build.gradle.kts +++ b/velocity/build.gradle.kts @@ -15,6 +15,7 @@ repositories { } dependencies { + implementation(project(":api")) implementation(project(":common")) implementation(libs.bstats.velocity) From 913f8f12f2e03be9ab81ca530c1468319ea447f2 Mon Sep 17 00:00:00 2001 From: Artur Khusainov Date: Sat, 9 Aug 2025 01:30:17 +0300 Subject: [PATCH 02/12] refine API docs --- .../turikhay/mc/mapmodcompanion/Channels.java | 10 ++++----- .../com/turikhay/mc/mapmodcompanion/Id.java | 21 ++++++++++++++++++- .../mapmodcompanion/LevelMapProperties.java | 8 +++++++ .../mc/mapmodcompanion/PrefixedId.java | 8 ++++++- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java index 6f95033..9082ad0 100644 --- a/api/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java @@ -5,14 +5,12 @@ * modifications. *

* These constants can be used with the platform specific networking API to - * register listeners or send packets. For example, registering the world id - * channel on Fabric would look like: + * register listeners or send packets. For example: * *

{@code
- * ClientPlayNetworking.registerGlobalReceiver(
- *         Channels.WORLDID_CHANNEL,
- *         (client, handler, buf, responseSender) -> { /* ... *\/ }
- * );
+ * registerChannel(Channels.WORLDID_CHANNEL, data -> {
+ *     // ...
+ * });
  * }
*/ public interface Channels { diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/Id.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/Id.java index 82621cb..d19f954 100644 --- a/api/src/main/java/com/turikhay/mc/mapmodcompanion/Id.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/Id.java @@ -8,7 +8,12 @@ */ public interface Id { - /** Magic value used in some packet formats. */ + /** + * Flag value used by VoxelMap-style packets. + *

+ * When present at the start of a packet, the value {@code 42} signals that + * the payload follows the VoxelMap format. + */ int MAGIC_MARKER = 42; /** @@ -42,6 +47,13 @@ default IdType withId(int id) { /** * Converts raw packet bytes into an {@link Id} instance. + *

+ * Implementations are typically stateless and expose a shared + * {@code instance()} method so they can be reused: + * + *

{@code
+     * PrefixedId id = PrefixedId.Deserializer.instance().deserialize(data);
+     * }
* * @param type of id produced */ @@ -58,6 +70,13 @@ interface Deserializer { /** * Produces raw packet bytes from an {@link Id} instance. + *

+ * Like deserializers, serializers commonly provide a shared + * {@code instance()} for reuse: + * + *

{@code
+     * byte[] data = PrefixedId.Serializer.instance().serialize(id);
+     * }
* * @param type of id to serialize */ diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java index e0e96e3..3b43280 100644 --- a/api/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java @@ -9,6 +9,10 @@ public interface LevelMapProperties { /** * Deserializes standard id packets. + * + *
{@code
+     * StandardId id = LevelMapProperties.Deserializer.instance().deserialize(data);
+     * }
*/ class Deserializer implements Id.Deserializer { private static Deserializer INSTANCE; @@ -38,6 +42,10 @@ public static Deserializer instance() { /** * Serializes standard ids into packet byte arrays. + * + *
{@code
+     * byte[] data = LevelMapProperties.Serializer.instance().serialize(id);
+     * }
*/ class Serializer implements Id.Serializer { private static Serializer INSTANCE; diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java index 2c7a0d7..b886356 100644 --- a/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java @@ -6,6 +6,8 @@ /** * Identifier encoded with a zero-prefixed length and optional magic marker. + * When present, the marker has the value {@link Id#MAGIC_MARKER} (42) which + * flags a VoxelMap-style packet. *

* The format matches the one used by Xaero's minimap when responding to world * id requests. The {@link Deserializer} and {@link Serializer} nested classes @@ -144,6 +146,10 @@ public static Deserializer instance() { /** * Serializes {@link PrefixedId} instances into packet byte arrays. + * + *

{@code
+     * byte[] data = PrefixedId.Serializer.instance().serialize(id);
+     * }
*/ public static class Serializer implements Id.Serializer { private static Serializer INSTANCE; @@ -157,7 +163,7 @@ public byte[] serialize(PrefixedId id) { out.writeByte(0); // packetId, or prefix } if (id.usesMagicByte) { - out.writeByte(MAGIC_MARKER); // 42 (literally) + out.writeByte(MAGIC_MARKER); // VoxelMap-style flag (42) } byte[] data = String.valueOf(id.getId()).getBytes(StandardCharsets.UTF_8); out.write(data.length); // length From 59d5c3a1bc7afc8a192e0370256632a89726c009 Mon Sep 17 00:00:00 2001 From: Artur Khusainov Date: Sat, 9 Aug 2025 16:41:24 +0300 Subject: [PATCH 03/12] chore: clarify mod-specific id classes --- .../mapmodcompanion/LevelMapProperties.java | 3 +- .../mc/mapmodcompanion/PrefixedId.java | 9 ++-- .../mapmodcompanion}/PrefixedIdRequest.java | 43 ++++++++++++++++--- .../mc/mapmodcompanion/StandardId.java | 2 +- .../java}/PrefixedIdRequestParserTest.java | 12 +++--- .../src/test/java}/PrefixedIdRequestTest.java | 3 +- 6 files changed, 52 insertions(+), 20 deletions(-) rename {spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot => api/src/main/java/com/turikhay/mc/mapmodcompanion}/PrefixedIdRequest.java (68%) rename {spigot/src/test/java/com/turikhay/mc/mapmodcompanion/spigot => api/src/test/java}/PrefixedIdRequestParserTest.java (82%) rename {spigot/src/test/java/com/turikhay/mc/mapmodcompanion/spigot => api/src/test/java}/PrefixedIdRequestTest.java (91%) diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java index 3b43280..854a7cf 100644 --- a/api/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java @@ -3,7 +3,8 @@ import java.io.*; /** - * Binary format used by VoxelMap to communicate the world id. + * Binary format used by Xaero's Minimap and World Map to communicate the + * world id. */ public interface LevelMapProperties { diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java index b886356..373e2bb 100644 --- a/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedId.java @@ -9,10 +9,11 @@ * When present, the marker has the value {@link Id#MAGIC_MARKER} (42) which * flags a VoxelMap-style packet. *

- * The format matches the one used by Xaero's minimap when responding to world - * id requests. The {@link Deserializer} and {@link Serializer} nested classes - * can be used to convert between the packet representation and this class. - */ + * This format is used by VoxelMap and other mods that implement the same + * packet structure. The {@link Deserializer} and {@link Serializer} nested + * classes can be used to convert between the packet representation and this + * class. +*/ public class PrefixedId implements Id { private final int padding; private final boolean usesMagicByte; diff --git a/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/PrefixedIdRequest.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedIdRequest.java similarity index 68% rename from spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/PrefixedIdRequest.java rename to api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedIdRequest.java index 31fc33e..405dfde 100644 --- a/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/PrefixedIdRequest.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedIdRequest.java @@ -1,6 +1,4 @@ -package com.turikhay.mc.mapmodcompanion.spigot; - -import com.turikhay.mc.mapmodcompanion.*; +package com.turikhay.mc.mapmodcompanion; import javax.annotation.Nullable; import java.io.ByteArrayInputStream; @@ -11,19 +9,44 @@ import static com.turikhay.mc.mapmodcompanion.Id.MAGIC_MARKER; +/** + * Parsed description of a VoxelMap-style world id request packet. + * + *

Clients send such a packet to learn how the server expects the id to be + * encoded. Use {@link #parse(byte[], Integer)} to interpret the request and + * {@link #constructId(int)} to produce a {@link PrefixedId} for the response.

+ * + *
{@code
+ * PrefixedIdRequest request = PrefixedIdRequest.parse(data, protocolVersion);
+ * PrefixedId id = request.constructId(1337);
+ * }
+ */ public class PrefixedIdRequest { private final int padding; private final boolean usesMagicByte; + /** + * Creates a new request descriptor. + * + * @param padding number of leading zero bytes + * @param usesMagicByte whether the {@link Id#MAGIC_MARKER} is present + */ public PrefixedIdRequest(int padding, boolean usesMagicByte) { this.padding = padding; this.usesMagicByte = usesMagicByte; } + /** + * Constructs a {@link PrefixedId} using this request's parameters. + * + * @param id numeric world id + * @return {@link PrefixedId} matching the request + */ public PrefixedId constructId(int id) { return new PrefixedId(padding, usesMagicByte, id); } + /** {@inheritDoc} */ @Override public boolean equals(Object o) { if (this == o) return true; @@ -32,11 +55,13 @@ public boolean equals(Object o) { return padding == that.padding && usesMagicByte == that.usesMagicByte; } + /** {@inheritDoc} */ @Override public int hashCode() { return Objects.hash(padding, usesMagicByte); } + /** {@inheritDoc} */ @Override public String toString() { return "PrefixedIdRequest{" + @@ -45,6 +70,14 @@ public String toString() { '}'; } + /** + * Parses a VoxelMap-style request packet. + * + * @param payload raw packet bytes + * @param protocolVersion client's protocol version or {@code null} if unknown + * @return parsed request descriptor + * @throws MalformedPacketException if the payload cannot be parsed + */ public static PrefixedIdRequest parse(byte[] payload, @Nullable Integer protocolVersion) throws MalformedPacketException { int padding = -1; try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload))) { @@ -70,7 +103,7 @@ public static PrefixedIdRequest parse(byte[] payload, @Nullable Integer protocol } switch (padding) { case 1: - if (protocolVersion != null && protocolVersion <= ProtocolVersion.MINECRAFT_1_16_3) { + if (protocolVersion != null && protocolVersion <= 753) { // 1.16.3 and below // VoxelMap Forge 1.13.2 - 1.16.3 return new PrefixedIdRequest(1, false); } @@ -79,7 +112,7 @@ public static PrefixedIdRequest parse(byte[] payload, @Nullable Integer protocol // JourneyMap 1.16.5+ return new PrefixedIdRequest(padding, true); case 3: - // VoxelMap LiteLoader 1.18.9 - 1.12.2 + // VoxelMap LiteLoader 1.8.9 - 1.12.2 // VoxelMap Fabric 1.14.4 - 1.19.x return new PrefixedIdRequest(0, true); default: diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/StandardId.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/StandardId.java index 0481782..6eccc01 100644 --- a/api/src/main/java/com/turikhay/mc/mapmodcompanion/StandardId.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/StandardId.java @@ -3,7 +3,7 @@ import java.util.Objects; /** - * Plain numeric {@link Id} implementation. + * Plain numeric {@link Id} implementation used by Xaero's mods. */ public class StandardId implements Id { private final int id; diff --git a/spigot/src/test/java/com/turikhay/mc/mapmodcompanion/spigot/PrefixedIdRequestParserTest.java b/api/src/test/java/PrefixedIdRequestParserTest.java similarity index 82% rename from spigot/src/test/java/com/turikhay/mc/mapmodcompanion/spigot/PrefixedIdRequestParserTest.java rename to api/src/test/java/PrefixedIdRequestParserTest.java index 237bb39..752e7fc 100644 --- a/spigot/src/test/java/com/turikhay/mc/mapmodcompanion/spigot/PrefixedIdRequestParserTest.java +++ b/api/src/test/java/PrefixedIdRequestParserTest.java @@ -1,12 +1,10 @@ -package com.turikhay.mc.mapmodcompanion.spigot; - import com.turikhay.mc.mapmodcompanion.*; import org.junit.jupiter.api.Test; import java.util.Arrays; import java.util.List; -import static com.turikhay.mc.mapmodcompanion.spigot.PrefixedIdRequest.parse; +import static com.turikhay.mc.mapmodcompanion.PrefixedIdRequest.parse; import static org.junit.jupiter.api.Assertions.*; class PrefixedIdRequestParserTest { @@ -20,10 +18,10 @@ void voxelMapForge1_12_2() throws MalformedPacketException { void voxelMapForge1_13_2UpTo1_16_3() throws MalformedPacketException { test( Arrays.asList( - ProtocolVersion.MINECRAFT_1_13_2, - ProtocolVersion.MINECRAFT_1_14_4, - ProtocolVersion.MINECRAFT_1_15_2, - ProtocolVersion.MINECRAFT_1_16_3 + 404, + 498, + 578, + 753 ), new PrefixedIdRequest(1, false), new byte[] { 0, 42, 0 } diff --git a/spigot/src/test/java/com/turikhay/mc/mapmodcompanion/spigot/PrefixedIdRequestTest.java b/api/src/test/java/PrefixedIdRequestTest.java similarity index 91% rename from spigot/src/test/java/com/turikhay/mc/mapmodcompanion/spigot/PrefixedIdRequestTest.java rename to api/src/test/java/PrefixedIdRequestTest.java index a357119..1013c0b 100644 --- a/spigot/src/test/java/com/turikhay/mc/mapmodcompanion/spigot/PrefixedIdRequestTest.java +++ b/api/src/test/java/PrefixedIdRequestTest.java @@ -1,6 +1,5 @@ -package com.turikhay.mc.mapmodcompanion.spigot; - import com.turikhay.mc.mapmodcompanion.PrefixedId; +import com.turikhay.mc.mapmodcompanion.PrefixedIdRequest; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; From 1e1ea50d9d2ecadf11922efe311f0b0b9b79e390 Mon Sep 17 00:00:00 2001 From: Artur Khusainov Date: Sat, 9 Aug 2025 16:41:30 +0300 Subject: [PATCH 04/12] Move protocol constants to API --- .../mc/mapmodcompanion/PrefixedIdRequest.java | 8 +++++--- .../mc/mapmodcompanion/ProtocolVersion.java | 18 ++++++++++++++++++ .../spigot/ProtocolVersion.java | 8 -------- 3 files changed, 23 insertions(+), 11 deletions(-) create mode 100644 api/src/main/java/com/turikhay/mc/mapmodcompanion/ProtocolVersion.java delete mode 100644 spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/ProtocolVersion.java diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedIdRequest.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedIdRequest.java index 405dfde..9cfe059 100644 --- a/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedIdRequest.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedIdRequest.java @@ -10,9 +10,10 @@ import static com.turikhay.mc.mapmodcompanion.Id.MAGIC_MARKER; /** - * Parsed description of a VoxelMap-style world id request packet. + * Description of a packet sent by VoxelMap-style clients to request the + * server's {@code world_id}. * - *

Clients send such a packet to learn how the server expects the id to be + *

Clients send this packet to learn how the server expects the id to be * encoded. Use {@link #parse(byte[], Integer)} to interpret the request and * {@link #constructId(int)} to produce a {@link PrefixedId} for the response.

* @@ -74,7 +75,8 @@ public String toString() { * Parses a VoxelMap-style request packet. * * @param payload raw packet bytes - * @param protocolVersion client's protocol version or {@code null} if unknown + * @param protocolVersion client's protocol version or {@code null} if unknown; + * see {@link ProtocolVersion} for common constants * @return parsed request descriptor * @throws MalformedPacketException if the payload cannot be parsed */ diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/ProtocolVersion.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/ProtocolVersion.java new file mode 100644 index 0000000..175119a --- /dev/null +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/ProtocolVersion.java @@ -0,0 +1,18 @@ +package com.turikhay.mc.mapmodcompanion; + +/** + * Well-known Minecraft protocol version numbers. + * + *

These constants can be used to interpret version-specific nuances in + * packet formats.

+ */ +public interface ProtocolVersion { + /** Protocol version number for Minecraft 1.13.2. */ + int MINECRAFT_1_13_2 = 404; + /** Protocol version number for Minecraft 1.14.4. */ + int MINECRAFT_1_14_4 = 498; + /** Protocol version number for Minecraft 1.15.2. */ + int MINECRAFT_1_15_2 = 578; + /** Protocol version number for Minecraft 1.16.3. */ + int MINECRAFT_1_16_3 = 753; +} diff --git a/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/ProtocolVersion.java b/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/ProtocolVersion.java deleted file mode 100644 index aff3d38..0000000 --- a/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/ProtocolVersion.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.turikhay.mc.mapmodcompanion.spigot; - -public interface ProtocolVersion { - int MINECRAFT_1_13_2 = 404; - int MINECRAFT_1_14_4 = 498; - int MINECRAFT_1_15_2 = 578; - int MINECRAFT_1_16_3 = 753; -} From 7cfbc0ee2bc296deb2f78048ab3ca6c4c4e6cf14 Mon Sep 17 00:00:00 2001 From: Artur Khusainov Date: Sat, 9 Aug 2025 16:41:35 +0300 Subject: [PATCH 05/12] Clarify PrefixedIdRequest markers and use ProtocolVersion constants --- .../mc/mapmodcompanion/PrefixedIdRequest.java | 14 +++++++++----- api/src/test/java/PrefixedIdRequestParserTest.java | 8 ++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedIdRequest.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedIdRequest.java index 9cfe059..7d7ffb2 100644 --- a/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedIdRequest.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedIdRequest.java @@ -13,9 +13,12 @@ * Description of a packet sent by VoxelMap-style clients to request the * server's {@code world_id}. * - *

Clients send this packet to learn how the server expects the id to be - * encoded. Use {@link #parse(byte[], Integer)} to interpret the request and - * {@link #constructId(int)} to produce a {@link PrefixedId} for the response.

+ *

The packet itself has no internal structure that influences how the + * server responds. The {@link #parse(byte[], Integer)} method examines the raw + * bytes and sets markers such as zero-padding length and the presence of the + * magic marker {@link Id#MAGIC_MARKER}. These markers indicate which client + * family and version range issued the request, allowing the server to craft a + * matching {@link PrefixedId} via {@link #constructId(int)}.

* *
{@code
  * PrefixedIdRequest request = PrefixedIdRequest.parse(data, protocolVersion);
@@ -72,7 +75,8 @@ public String toString() {
     }
 
     /**
-     * Parses a VoxelMap-style request packet.
+     * Parses a VoxelMap-style request packet and sets markers describing the
+     * client family and version range.
      *
      * @param payload         raw packet bytes
      * @param protocolVersion client's protocol version or {@code null} if unknown;
@@ -105,7 +109,7 @@ public static PrefixedIdRequest parse(byte[] payload, @Nullable Integer protocol
         }
         switch (padding) {
             case 1:
-                if (protocolVersion != null && protocolVersion <= 753) { // 1.16.3 and below
+                if (protocolVersion != null && protocolVersion <= ProtocolVersion.MINECRAFT_1_16_3) { // 1.16.3 and below
                     // VoxelMap Forge 1.13.2 - 1.16.3
                     return new PrefixedIdRequest(1, false);
                 }
diff --git a/api/src/test/java/PrefixedIdRequestParserTest.java b/api/src/test/java/PrefixedIdRequestParserTest.java
index 752e7fc..d2f46be 100644
--- a/api/src/test/java/PrefixedIdRequestParserTest.java
+++ b/api/src/test/java/PrefixedIdRequestParserTest.java
@@ -18,10 +18,10 @@ void voxelMapForge1_12_2() throws MalformedPacketException {
     void voxelMapForge1_13_2UpTo1_16_3() throws MalformedPacketException {
         test(
                 Arrays.asList(
-                        404,
-                        498,
-                        578,
-                        753
+                        ProtocolVersion.MINECRAFT_1_13_2,
+                        ProtocolVersion.MINECRAFT_1_14_4,
+                        ProtocolVersion.MINECRAFT_1_15_2,
+                        ProtocolVersion.MINECRAFT_1_16_3
                 ),
                 new PrefixedIdRequest(1, false),
                 new byte[] { 0, 42, 0 }

From f5ee678ce57703d876dec6a2271866f16d3fac2f Mon Sep 17 00:00:00 2001
From: turikhay 
Date: Sat, 9 Aug 2025 20:34:26 +0500
Subject: [PATCH 06/12] remove hallucinated example

---
 .../java/com/turikhay/mc/mapmodcompanion/Channels.java   | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java
index 9082ad0..786c8b6 100644
--- a/api/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java
+++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java
@@ -3,15 +3,6 @@
 /**
  * Utility holder for network channel identifiers used by various map
  * modifications.
- * 

- * These constants can be used with the platform specific networking API to - * register listeners or send packets. For example: - * - *

{@code
- * registerChannel(Channels.WORLDID_CHANNEL, data -> {
- *     // ...
- * });
- * }
*/ public interface Channels { /** Plugin channel used by Xaero's Minimap. */ From 96a46aa05c81cf327ed50096be4949330f4975f1 Mon Sep 17 00:00:00 2001 From: turikhay Date: Sat, 9 Aug 2025 20:35:08 +0500 Subject: [PATCH 07/12] provide typical example for an argument --- .../main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java index 83dd8f4..6d2cdf1 100644 --- a/api/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java @@ -11,7 +11,8 @@ public interface IdLookup { /** - * Attempts to find a numeric world identifier for the supplied string id. + * Attempts to find a numeric world identifier for the supplied string id + * (typically, world UUID or its name). * * @param id textual representation of the world id * @return a numeric identifier if a mapping exists From c5a50211b54fb71dd08f8c997b34f678e2de4b34 Mon Sep 17 00:00:00 2001 From: turikhay Date: Sat, 9 Aug 2025 22:55:40 +0500 Subject: [PATCH 08/12] Move IdLookup back to common as it's not useful in the API --- .../turikhay/mc/mapmodcompanion/IdLookup.java | 76 ------------------- .../turikhay/mc/mapmodcompanion/IdLookup.java | 31 ++++++++ 2 files changed, 31 insertions(+), 76 deletions(-) delete mode 100644 api/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java create mode 100644 common/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java diff --git a/api/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java deleted file mode 100644 index 6d2cdf1..0000000 --- a/api/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.turikhay.mc.mapmodcompanion; - -import java.util.Optional; - -/** - * Performs lookup of world identifiers. - *

- * Implementations may resolve identifiers from configuration files, network - * responses or any other data source. - */ -public interface IdLookup { - - /** - * Attempts to find a numeric world identifier for the supplied string id - * (typically, world UUID or its name). - * - * @param id textual representation of the world id - * @return a numeric identifier if a mapping exists - */ - Optional findMatch(String id); - - /** - * Convenience overload accepting an integer id. - * - * @param id numeric id - * @return a numeric identifier if a mapping exists - */ - default Optional findMatch(int id) { - return findMatch(String.valueOf(id)); - } - - /** - * Configuration-backed implementation that resolves ids from an external - * configuration source. - *

- * Mappings are read from keys starting with {@link #PATH_PREFIX} followed - * by the textual world id. - */ - class ConfigBased implements IdLookup { - /** Prefix within the configuration for override values. */ - public static final String PATH_PREFIX = "overrides."; - - private final ConfigAccessor accessor; - - /** - * Creates a new lookup using the supplied accessor. - * - * @param accessor callback used to read configuration values - */ - public ConfigBased(ConfigAccessor accessor) { - this.accessor = accessor; - } - - /** {@inheritDoc} */ - @Override - public Optional findMatch(String id) { - int value = accessor.getInt(PATH_PREFIX + id, Integer.MIN_VALUE); - return value == Integer.MIN_VALUE ? Optional.empty() : Optional.of(value); - } - - /** - * Adapter used to access configuration values. - */ - public interface ConfigAccessor { - /** - * Reads an integer from configuration or returns the default value - * if the path is not present. - * - * @param path configuration path - * @param def default value - * @return configured value or {@code def} - */ - int getInt(String path, int def); - } - } -} diff --git a/common/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java b/common/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java new file mode 100644 index 0000000..c7b4e10 --- /dev/null +++ b/common/src/main/java/com/turikhay/mc/mapmodcompanion/IdLookup.java @@ -0,0 +1,31 @@ +package com.turikhay.mc.mapmodcompanion; + +import java.util.Optional; + +public interface IdLookup { + Optional findMatch(String id); + + default Optional findMatch(int id) { + return findMatch(String.valueOf(id)); + } + + class ConfigBased implements IdLookup { + public static final String PATH_PREFIX = "overrides."; + + private final ConfigAccessor accessor; + + public ConfigBased(ConfigAccessor accessor) { + this.accessor = accessor; + } + + @Override + public Optional findMatch(String id) { + int value = accessor.getInt(PATH_PREFIX + id, Integer.MIN_VALUE); + return value == Integer.MIN_VALUE ? Optional.empty() : Optional.of(value); + } + + public interface ConfigAccessor { + int getInt(String path, int def); + } + } +} From 40a66998fad5fa5294dd4a4bb7c70a879c2afa90 Mon Sep 17 00:00:00 2001 From: turikhay Date: Sat, 9 Aug 2025 23:18:41 +0500 Subject: [PATCH 09/12] Publish to GitHub packages --- api/build.gradle.kts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 550be84..652084c 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -9,9 +9,30 @@ java { } publishing { + fun env(name: String) = System.getenv(name) ?: name + repositories { + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/${env("GITHUB_REPOSITORY")}") + credentials { + username = env("GITHUB_ACTOR") + password = env("GITHUB_TOKEN") + } + } + } publications { create("mavenJava") { from(components["java"]) + pom { + name = "MapModCompanion (API)" + artifactId = "mapmodcompanion-api" + licenses { + license { + name = "MIT License" + url = "https://opensource.org/licenses/MIT" + } + } + } } } } From 34fd39446e2056d2fcda0c180e1ff29076e7bbf3 Mon Sep 17 00:00:00 2001 From: turikhay Date: Sat, 9 Aug 2025 23:18:53 +0500 Subject: [PATCH 10/12] Publish to GitHub packages when releasing to GitHub --- .github/workflows/github.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/github.yml b/.github/workflows/github.yml index 03efc1d..9d4b83e 100644 --- a/.github/workflows/github.yml +++ b/.github/workflows/github.yml @@ -18,6 +18,7 @@ jobs: uses: ./.github/workflows/build.yml with: version: ${{ needs.version.outputs.version }} + task: build publish release: name: Prepare release needs: From 538c1f63023e99064be191c49869f988cd81dcb5 Mon Sep 17 00:00:00 2001 From: turikhay Date: Sat, 9 Aug 2025 23:25:33 +0500 Subject: [PATCH 11/12] Revert "Publish to GitHub packages when releasing to GitHub" This reverts commit 34fd39446e2056d2fcda0c180e1ff29076e7bbf3. --- .github/workflows/github.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/github.yml b/.github/workflows/github.yml index 9d4b83e..03efc1d 100644 --- a/.github/workflows/github.yml +++ b/.github/workflows/github.yml @@ -18,7 +18,6 @@ jobs: uses: ./.github/workflows/build.yml with: version: ${{ needs.version.outputs.version }} - task: build publish release: name: Prepare release needs: From 02fbe4a91f9c2e8bbf6bd9c721542730e0100682 Mon Sep 17 00:00:00 2001 From: turikhay Date: Sat, 9 Aug 2025 23:26:40 +0500 Subject: [PATCH 12/12] Use separate workflow to publish to GitHub packages --- .github/workflows/github-packages.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/github-packages.yml diff --git a/.github/workflows/github-packages.yml b/.github/workflows/github-packages.yml new file mode 100644 index 0000000..3a1cd4b --- /dev/null +++ b/.github/workflows/github-packages.yml @@ -0,0 +1,21 @@ +name: GitHub release + +on: + push: + tags: + - 'v*.*.*' + +permissions: + contents: write + +jobs: + version: + name: Detect version + uses: ./.github/workflows/version.yml + publish: + name: Publish + needs: version + uses: ./.github/workflows/build.yml + with: + version: ${{ needs.version.outputs.version }} + task: publish