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 diff --git a/api/build.gradle.kts b/api/build.gradle.kts new file mode 100644 index 0000000..652084c --- /dev/null +++ b/api/build.gradle.kts @@ -0,0 +1,38 @@ +plugins { + id("java-convention") + `maven-publish` +} + +java { + withSourcesJar() + withJavadocJar() +} + +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" + } + } + } + } + } +} 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..786c8b6 --- /dev/null +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/Channels.java @@ -0,0 +1,16 @@ +package com.turikhay.mc.mapmodcompanion; + +/** + * Utility holder for network channel identifiers used by various map + * modifications. + */ +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..d19f954 --- /dev/null +++ b/api/src/main/java/com/turikhay/mc/mapmodcompanion/Id.java @@ -0,0 +1,92 @@ +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 { + + /** + * 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; + + /** + * 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. + *

+ * 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 + */ + 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. + *

+ * 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 + */ + 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/common/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/LevelMapProperties.java similarity index 68% 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..854a7cf 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,23 @@ import java.io.*; +/** + * Binary format used by Xaero's Minimap and World Map to communicate the + * world id. + */ public interface LevelMapProperties { + + /** + * Deserializes standard id packets. + * + *
{@code
+     * StandardId id = LevelMapProperties.Deserializer.instance().deserialize(data);
+     * }
+ */ 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 +33,36 @@ 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. + * + *
{@code
+     * byte[] data = LevelMapProperties.Serializer.instance().serialize(id);
+     * }
+ */ 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 +74,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 73% 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..373e2bb 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,62 @@ import java.nio.charset.StandardCharsets; import java.util.Objects; +/** + * 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. + *

+ * 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; 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 +68,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 +84,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 +137,25 @@ 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. + * + *
{@code
+     * byte[] data = PrefixedId.Serializer.instance().serialize(id);
+     * }
+ */ public static class Serializer implements Id.Serializer { private static Serializer INSTANCE; + /** {@inheritDoc} */ @Override public byte[] serialize(PrefixedId id) { ByteArrayOutputStream array = new ByteArrayOutputStream(); @@ -117,7 +164,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 @@ -128,6 +175,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/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/PrefixedIdRequest.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/PrefixedIdRequest.java similarity index 62% 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..7d7ffb2 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,48 @@ import static com.turikhay.mc.mapmodcompanion.Id.MAGIC_MARKER; +/** + * Description of a packet sent by VoxelMap-style clients to request the + * server's {@code world_id}. + * + *

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);
+ * 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 +59,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 +74,16 @@ public String toString() { '}'; } + /** + * 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; + * see {@link ProtocolVersion} for common constants + * @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 +109,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 <= ProtocolVersion.MINECRAFT_1_16_3) { // 1.16.3 and below // VoxelMap Forge 1.13.2 - 1.16.3 return new PrefixedIdRequest(1, false); } @@ -79,7 +118,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/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/common/src/main/java/com/turikhay/mc/mapmodcompanion/StandardId.java b/api/src/main/java/com/turikhay/mc/mapmodcompanion/StandardId.java similarity index 70% 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..6eccc01 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 used by Xaero's mods. + */ 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/spigot/src/test/java/com/turikhay/mc/mapmodcompanion/spigot/PrefixedIdRequestParserTest.java b/api/src/test/java/PrefixedIdRequestParserTest.java similarity index 93% rename from spigot/src/test/java/com/turikhay/mc/mapmodcompanion/spigot/PrefixedIdRequestParserTest.java rename to api/src/test/java/PrefixedIdRequestParserTest.java index 237bb39..d2f46be 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 { 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.*; diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 8346d7a..7f1a8b4 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -5,6 +5,10 @@ plugins { repositories { gradlePluginPortal() + maven { + name = "Fabric" + url = uri("https://maven.fabricmc.net/") + } } gradlePlugin { @@ -28,4 +32,5 @@ dependencies { implementation(libs.semver.get().toString()) implementation("com.modrinth.minotaur:Minotaur:2.+") implementation(with(libs.plugins.hangar.get()) { "io.papermc:hangar-publish-plugin:$version" }) + implementation(with(libs.plugins.fabric.loom.get()) { "net.fabricmc:fabric-loom:$version" }) } 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..13f0186 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,3 +1,8 @@ plugins { id("java-convention") } + +dependencies { + implementation(project(":api")) + compileOnly(libs.slf4j) +} 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/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/IdRegistry.java b/common/src/main/java/com/turikhay/mc/mapmodcompanion/IdRegistry.java similarity index 85% rename from spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/IdRegistry.java rename to common/src/main/java/com/turikhay/mc/mapmodcompanion/IdRegistry.java index ea3b0b0..6ddffa9 100644 --- a/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/IdRegistry.java +++ b/common/src/main/java/com/turikhay/mc/mapmodcompanion/IdRegistry.java @@ -1,9 +1,4 @@ -package com.turikhay.mc.mapmodcompanion.spigot; - -import com.turikhay.mc.mapmodcompanion.IdLookup; -import com.turikhay.mc.mapmodcompanion.PrefixLogger; -import com.turikhay.mc.mapmodcompanion.VerboseLogger; -import org.bukkit.World; +package com.turikhay.mc.mapmodcompanion; import java.util.HashMap; import java.util.Map; @@ -11,7 +6,7 @@ import java.util.logging.Logger; public interface IdRegistry { - int getId(World world); + int getId(WorldInfo world); class CacheableRegistry implements IdRegistry { private final Map cache = new HashMap<>(); @@ -22,7 +17,7 @@ public CacheableRegistry(IdRegistry delegate) { } @Override - public int getId(World world) { + public int getId(WorldInfo world) { return cache.computeIfAbsent(world.getName(), s -> delegate.getId(world)); } @@ -46,7 +41,7 @@ public ConvertingRegistry(VerboseLogger parent, IdLookup lookup, IdRegistry dele } @Override - public int getId(World world) { + public int getId(WorldInfo world) { Optional byName = lookup.findMatch(world.getName()); if (byName.isPresent()) { logger.fine("Found override: " + world.getName() + " -> " + byName.get()); @@ -77,7 +72,7 @@ public ConstantRegistry(int id) { } @Override - public int getId(World world) { + public int getId(WorldInfo world) { return id; } @@ -91,7 +86,7 @@ public String toString() { class DynamicUUIDRegistry implements IdRegistry { @Override - public int getId(World world) { + public int getId(WorldInfo world) { return world.getUID().hashCode(); } } 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/common/src/main/java/com/turikhay/mc/mapmodcompanion/Slf4jLogger.java b/common/src/main/java/com/turikhay/mc/mapmodcompanion/Slf4jLogger.java new file mode 100644 index 0000000..a82a676 --- /dev/null +++ b/common/src/main/java/com/turikhay/mc/mapmodcompanion/Slf4jLogger.java @@ -0,0 +1,31 @@ +package com.turikhay.mc.mapmodcompanion; + +import org.slf4j.Logger; + +public class Slf4jLogger implements ILogger { + private final Logger logger; + + public Slf4jLogger(Logger logger) { + this.logger = logger; + } + + @Override + public void fine(String message) { + logger.debug("{}", message); + } + + @Override + public void info(String message) { + logger.info("{}", message); + } + + @Override + public void warn(String message, Throwable t) { + logger.warn("{}", message, t); + } + + @Override + public void error(String message, Throwable t) { + logger.error("{}", message, t); + } +} diff --git a/common/src/main/java/com/turikhay/mc/mapmodcompanion/WorldInfo.java b/common/src/main/java/com/turikhay/mc/mapmodcompanion/WorldInfo.java new file mode 100644 index 0000000..cb7646a --- /dev/null +++ b/common/src/main/java/com/turikhay/mc/mapmodcompanion/WorldInfo.java @@ -0,0 +1,42 @@ +package com.turikhay.mc.mapmodcompanion; + +import java.util.Objects; +import java.util.UUID; + +public class WorldInfo { + private final UUID uuid; + private final String name; + + public WorldInfo(UUID uuid, String name) { + this.uuid = uuid; + this.name = name; + } + + public UUID getUID() { + return uuid; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + WorldInfo worldInfo = (WorldInfo) o; + return Objects.equals(uuid, worldInfo.uuid) && Objects.equals(name, worldInfo.name); + } + + @Override + public int hashCode() { + return Objects.hash(uuid, name); + } + + @Override + public String toString() { + return "WorldInfo{" + + "uuid=" + uuid + + ", name='" + name + '\'' + + '}'; + } +} diff --git a/fabric/.gitignore b/fabric/.gitignore new file mode 100644 index 0000000..7e3b24e --- /dev/null +++ b/fabric/.gitignore @@ -0,0 +1 @@ +run/ diff --git a/fabric/1.21/build.gradle.kts b/fabric/1.21/build.gradle.kts new file mode 100644 index 0000000..e8aa5ea --- /dev/null +++ b/fabric/1.21/build.gradle.kts @@ -0,0 +1,33 @@ +plugins { + id("fabric-loom") +} + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +dependencies { + implementation(project(":api")) + implementation(project(":common")) + + // To change the versions see the gradle.properties file + minecraft("com.mojang:minecraft:${properties["minecraft_version"]}") + mappings("net.fabricmc:yarn:${properties["yarn_mappings"]}:v2") + modImplementation("net.fabricmc:fabric-loader:${properties["loader_version"]}") + + // Fabric API. This is technically optional, but you probably want it anyway. + modImplementation("net.fabricmc.fabric-api:fabric-api:${properties["fabric_version"]}") +} + +loom { + accessWidenerPath = file("src/main/resources/mapmodcompanion.accesswidener") +} + +tasks { + processResources { + filesMatching("fabric.mod.json") { + expand("version" to version) + } + } +} diff --git a/fabric/1.21/gradle.properties b/fabric/1.21/gradle.properties new file mode 100644 index 0000000..eb48e44 --- /dev/null +++ b/fabric/1.21/gradle.properties @@ -0,0 +1,8 @@ +# Fabric Properties +# check these on https://fabricmc.net/develop +minecraft_version=1.21.8 +yarn_mappings=1.21.8+build.1 +loader_version=0.17.2 + +# Fabric API +fabric_version=0.131.0+1.21.8 diff --git a/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/Channels.java b/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/Channels.java new file mode 100644 index 0000000..bf9f88f --- /dev/null +++ b/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/Channels.java @@ -0,0 +1,15 @@ +package com.turikhay.mc.mapmodcompanion.fabric; + +import net.minecraft.util.Identifier; + +import static com.turikhay.mc.mapmodcompanion.Channels.*; + +public interface Channels { + Identifier WORLD_ID = of(WORLDID_CHANNEL); + Identifier XAERO_MINIMAP = of(XAERO_MINIMAP_CHANNEL); + Identifier XAERO_WORLDMAP = of(XAERO_WORLDMAP_CHANNEL); + + static Identifier of(String channel) { + return Identifier.tryParse(channel); + } +} diff --git a/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/LevelMapPropertiesPayload.java b/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/LevelMapPropertiesPayload.java new file mode 100644 index 0000000..5e453fc --- /dev/null +++ b/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/LevelMapPropertiesPayload.java @@ -0,0 +1,57 @@ +package com.turikhay.mc.mapmodcompanion.fabric; + +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; + +public class LevelMapPropertiesPayload { + + private interface LevelIdPayload extends CustomPayload { + int id(); + } + + public record Minimap(int id) implements LevelIdPayload { + public static final Id ID = new Id<>(Channels.XAERO_MINIMAP); + + @Override + public Id getId() { + return ID; + } + } + + public record WorldMap(int id) implements LevelIdPayload { + public static final Id ID = new Id<>(Channels.XAERO_WORLDMAP); + + @Override + public Id getId() { + return ID; + } + } + + public static void register() { + register(Minimap.ID); + register(WorldMap.ID); + } + + private static void register(CustomPayload.Id id) { + PayloadTypeRegistry.playS2C().register(id, new Codec<>()); + } + + public static class Codec implements PacketCodec { + + @Override + public T decode(RegistryByteBuf buf) { + throw new UnsupportedOperationException(); + } + + @Override + public void encode(RegistryByteBuf buf, T value) { + buf.writeByte(0); + buf.writeInt(value.id()); + } + } + + private LevelMapPropertiesPayload() { + } +} diff --git a/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/MapModCompanion.java b/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/MapModCompanion.java new file mode 100644 index 0000000..7c0fa8d --- /dev/null +++ b/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/MapModCompanion.java @@ -0,0 +1,84 @@ +package com.turikhay.mc.mapmodcompanion.fabric; + +import com.turikhay.mc.mapmodcompanion.IdRegistry; +import com.turikhay.mc.mapmodcompanion.WorldInfo; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; + +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.UUID; +import java.util.function.Consumer; + +public class MapModCompanion implements ModInitializer { + public static final String MOD_ID = "mapmodcompanion"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + + public static final boolean + xaeroMinimap = enableIfMissing("xaero.minimap.XaeroMinimap"), + xaeroWorldMap = enableIfMissing("xaero.map.WorldMap"); + + private static MapModCompanion INSTANCE; + + private IdRegistry registry; + + @Override + public void onInitialize() { + LevelMapPropertiesPayload.register(); + registry = new IdRegistry.DynamicUUIDRegistry(); + INSTANCE = this; + // TODO add overrides support + // then + // TODO make pre-1.20.5 support + // TODO adapt tests_e2e to also test fabric servers + } + + public void sendLevelData(ServerPlayerEntity player, ServerWorld world) { + int id = registry.getId(toWorldInfo(world)); + if (xaeroMinimap) { + ServerPlayNetworking.send(player, new LevelMapPropertiesPayload.Minimap(id)); + } + if (xaeroWorldMap) { + ServerPlayNetworking.send(player, new LevelMapPropertiesPayload.WorldMap(id)); + } + } + + public static void run(String taskDescription, Consumer task) { + MapModCompanion instance = INSTANCE; + if (instance == null) { + throw new IllegalStateException("MapModCompanion has not been initialized"); + } + try { + task.accept(instance); + } catch (Exception e) { + LOGGER.error("Error running the task: {}", taskDescription, e); + } + } + + public static WorldInfo toWorldInfo(ServerWorld world) { + UUID uuid; + try { + uuid = WorldUID.getOrCreate(world); + } catch (IOException e) { + throw new RuntimeException("Failed to read or write CraftBukkit-style uid.dat file", e); + } + return new WorldInfo(uuid, world.worldProperties.getLevelName()); + } + + private static boolean enableIfMissing(String className) { + boolean enable = false; + try { + Class.forName(className); + } catch (ClassNotFoundException e) { + enable = true; + } + if (!enable) { + LOGGER.warn("Found {} in the classpath", className); + } + return enable; + } +} diff --git a/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/WorldUID.java b/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/WorldUID.java new file mode 100644 index 0000000..44be89c --- /dev/null +++ b/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/WorldUID.java @@ -0,0 +1,50 @@ +package com.turikhay.mc.mapmodcompanion.fabric; + +import net.minecraft.server.world.ServerWorld; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.UUID; + +// CraftBukkit-style uid.dat file reader/writer +public class WorldUID { + public static UUID getOrCreate(ServerWorld world) throws IOException { + Path worldDir = getWorldDir(world); + return getOrCreate(worldDir); + } + + static Path getWorldDir(ServerWorld world) { + return world.getServer().session.getDirectory().path(); + } + + static UUID getOrCreate(Path worldDir) throws IOException { + return getOrCreate(worldDir, UUID.randomUUID()); + } + + static UUID getOrCreate(Path worldDir, UUID fallbackUid) throws IOException { + Path uidFile = getUidFile(worldDir); + if (Files.exists(uidFile)) { + return read(uidFile); + } + write(uidFile, fallbackUid); + return fallbackUid; + } + + static Path getUidFile(Path worldDir) { + return worldDir.resolve("uid.dat"); + } + + static UUID read(Path uidFile) throws IOException { + try (DataInputStream inputStream = new DataInputStream(Files.newInputStream(uidFile))) { + return new UUID(inputStream.readLong(), inputStream.readLong()); + } + } + + static void write(Path uidFile, UUID uuid) throws IOException { + try (DataOutputStream outputStream = new DataOutputStream(Files.newOutputStream(uidFile))) { + outputStream.writeLong(uuid.getMostSignificantBits()); + outputStream.writeLong(uuid.getLeastSignificantBits()); + } + } +} diff --git a/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/mixin/PlayerManagerMixin.java b/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/mixin/PlayerManagerMixin.java new file mode 100644 index 0000000..0493e4c --- /dev/null +++ b/fabric/1.21/src/main/java/com/turikhay/mc/mapmodcompanion/fabric/mixin/PlayerManagerMixin.java @@ -0,0 +1,18 @@ +package com.turikhay.mc.mapmodcompanion.fabric.mixin; + +import com.turikhay.mc.mapmodcompanion.fabric.MapModCompanion; +import net.minecraft.server.PlayerManager; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(PlayerManager.class) +public class PlayerManagerMixin { + @Inject(method = "sendWorldInfo", at = @At("HEAD")) + private void mapmodcompanion$sendWorldId(ServerPlayerEntity player, ServerWorld world, CallbackInfo ci) { + MapModCompanion.run("$sendWorldId", mmc -> mmc.sendLevelData(player, world)); + } +} diff --git a/fabric/1.21/src/main/resources/fabric.mod.json b/fabric/1.21/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..3e420bb --- /dev/null +++ b/fabric/1.21/src/main/resources/fabric.mod.json @@ -0,0 +1,22 @@ +{ + "schemaVersion": 1, + "id": "mapmodcompanion", + "version": "${version}", + "name": "MapModCompanion", + "license": "MIT", + "environment": "*", + "entrypoints": { + "main": [ + "com.turikhay.mc.mapmodcompanion.fabric.MapModCompanion" + ] + }, + "depends": { + "fabricloader": ">=0.16.14", + "minecraft": "~1.21.8", + "java": ">=21", + "fabric-api": "*" + }, + "mixins": [ + "mapmodcompanion.mixins.json" + ] +} diff --git a/fabric/1.21/src/main/resources/mapmodcompanion.accesswidener b/fabric/1.21/src/main/resources/mapmodcompanion.accesswidener new file mode 100644 index 0000000..1863376 --- /dev/null +++ b/fabric/1.21/src/main/resources/mapmodcompanion.accesswidener @@ -0,0 +1,3 @@ +accessWidener v2 named +accessible field net/minecraft/server/world/ServerWorld worldProperties Lnet/minecraft/world/level/ServerWorldProperties; +accessible field net/minecraft/server/MinecraftServer session Lnet/minecraft/world/level/storage/LevelStorage$Session; diff --git a/fabric/1.21/src/main/resources/mapmodcompanion.mixins.json b/fabric/1.21/src/main/resources/mapmodcompanion.mixins.json new file mode 100644 index 0000000..2abe692 --- /dev/null +++ b/fabric/1.21/src/main/resources/mapmodcompanion.mixins.json @@ -0,0 +1,8 @@ +{ + "required": true, + "package": "com.turikhay.mc.mapmodcompanion.fabric.mixin", + "compatibilityLevel": "JAVA_17", + "server": [ + "PlayerManagerMixin" + ] +} diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts new file mode 100644 index 0000000..9f7b6c7 --- /dev/null +++ b/fabric/build.gradle.kts @@ -0,0 +1,3 @@ +plugins { + base +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 706506b..418ad36 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,8 @@ jackson = "2.16.1" semver = "1.3.0" hangar = "0.1.3" bungeecord-api = "1.20-R0.2" +fabric-loom = "1.11-SNAPSHOT" +slf4j = "2.0.17" [libraries] spotbugs-annotations = { module = "com.github.spotbugs:spotbugs-annotations", version.ref = "spotbugs" } @@ -22,8 +24,10 @@ velocity-api = { module = "com.velocitypowered:velocity-api", version.ref = "vel jackson-core = { module = "com.fasterxml.jackson.core:jackson-core", version.ref = "jackson" } semver = { module = "net.swiftzer.semver:semver", version.ref = "semver" } bungeecord-api = { module = "net.md-5:bungeecord-api", version.ref = "bungeecord-api" } +slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } [plugins] shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } hangar = { id = "io.papermc.hangar-publish-plugin", version.ref = "hangar" } +fabric-loom = { id = "fabric-loom", version.ref = "fabric-loom" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 0200f75..afd54c9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,8 +1,10 @@ rootProject.name = "mapmodcompanion" include(":common") +include(":api") include(":bungee") include(":spigot") include(":velocity") +include(":fabric:1.21") include(":packages") include(":packages:single") 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/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/LevelIdHandler.java b/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/LevelIdHandler.java index 3d92294..61dfaee 100644 --- a/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/LevelIdHandler.java +++ b/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/LevelIdHandler.java @@ -8,6 +8,8 @@ import java.util.logging.Level; import java.util.logging.Logger; +import static com.turikhay.mc.mapmodcompanion.spigot.MapModCompanion.toWorldInfo; + public class LevelIdHandler implements Handler, PluginMessageListener { private final Logger logger; private final String channelName; @@ -35,7 +37,7 @@ public void cleanUp() { @Override public void onPluginMessageReceived(String channel, Player player, byte[] requestBytes) { Integer protocolVersion = plugin.getProtocolLib().map(lib -> lib.getProtocolVersion(player)).orElse(null); - int id = plugin.getRegistry().getId(player.getWorld()); + int id = plugin.getRegistry().getId(toWorldInfo(player.getWorld())); PrefixedIdRequest request; try { request = PrefixedIdRequest.parse(requestBytes, protocolVersion); diff --git a/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/MapModCompanion.java b/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/MapModCompanion.java index 016c2ae..b316dc4 100644 --- a/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/MapModCompanion.java +++ b/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/MapModCompanion.java @@ -210,4 +210,8 @@ void checkEnabled(String configPath) throws InitializationException { throw new InitializationException("disabled in the config"); } } + + public static WorldInfo toWorldInfo(World world) { + return new WorldInfo(world.getUID(), world.getName()); + } } 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; -} diff --git a/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/XaeroHandler.java b/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/XaeroHandler.java index 83f8c16..9a71093 100644 --- a/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/XaeroHandler.java +++ b/spigot/src/main/java/com/turikhay/mc/mapmodcompanion/spigot/XaeroHandler.java @@ -19,6 +19,8 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import static com.turikhay.mc.mapmodcompanion.spigot.MapModCompanion.toWorldInfo; + public class XaeroHandler implements Handler, Listener { private final Logger logger; private final String configPath; @@ -64,7 +66,7 @@ public void onWorldChanged(PlayerChangedWorldEvent event) { private void sendPacket(PlayerEvent event, Type type) { Player p = event.getPlayer(); World world = p.getWorld(); - int id = plugin.getRegistry().getId(world); + int id = plugin.getRegistry().getId(toWorldInfo(world)); byte[] payload = LevelMapProperties.Serializer.instance().serialize(id); SendPayloadTask task = new SendPayloadTask(logger, plugin, p.getUniqueId(), channelName, payload, world.getUID()); int repeatTimes = plugin.getConfig().getInt( 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) diff --git a/velocity/src/main/java/com/turikhay/mc/mapmodcompanion/velocity/MapModCompanion.java b/velocity/src/main/java/com/turikhay/mc/mapmodcompanion/velocity/MapModCompanion.java index d5a17b9..b46477b 100644 --- a/velocity/src/main/java/com/turikhay/mc/mapmodcompanion/velocity/MapModCompanion.java +++ b/velocity/src/main/java/com/turikhay/mc/mapmodcompanion/velocity/MapModCompanion.java @@ -171,27 +171,7 @@ private Path getConfigFile() { private static final String CONFIG_PATH = "/config_velocity.toml"; - private static ILogger ofSlf4j(Logger logger) { - return new ILogger() { - @Override - public void fine(String message) { - logger.debug("{}", message); - } - - @Override - public void info(String message) { - logger.info("{}", message); - } - - @Override - public void warn(String message, Throwable t) { - logger.warn("{}", message, t); - } - - @Override - public void error(String message, Throwable t) { - logger.error("{}", message, t); - } - }; + private static Slf4jLogger ofSlf4j(Logger logger) { + return new Slf4jLogger(logger); } }