From e5513d7b7821813bb3d43973bfdf762595fdee1c Mon Sep 17 00:00:00 2001 From: Space Walker Date: Sat, 22 Nov 2025 17:59:42 +0100 Subject: [PATCH 1/5] add NamespaceIdentifier to Core API --- .../core/api/util/NamespacedIdentifier.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java diff --git a/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java new file mode 100644 index 00000000..a1f77432 --- /dev/null +++ b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java @@ -0,0 +1,52 @@ +package net.ornithemc.osl.core.api.util; + +import java.util.Objects; + +public final class NamespacedIdentifier { + + public static NamespacedIdentifier fromMinecraft(String identifier) { + return new NamespacedIdentifier("minecraft", identifier); + } + + public static NamespacedIdentifier from(String namespace, String identifier) { + return new NamespacedIdentifier(namespace, identifier); + } + + private final String namespace; + private final String identifier; + + private NamespacedIdentifier(String namespace, String identifier) { + this.namespace = namespace; + this.identifier = identifier; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof NamespacedIdentifier)) { + return false; + } + NamespacedIdentifier id = (NamespacedIdentifier) o; + return namespace.equals(id.namespace) && identifier.equals(id.identifier); + } + + @Override + public int hashCode() { + return Objects.hash(namespace, identifier); + } + + @Override + public String toString() { + return namespace + ":" + identifier; + } + + public String getNamespace() { + return namespace; + } + + public String getIdentifier() { + return identifier; + } +} From 6bebdc9d3eaa80d6e32bd25fd6210660c7e9d1e5 Mon Sep 17 00:00:00 2001 From: Space Walker Date: Sun, 23 Nov 2025 15:09:38 +0100 Subject: [PATCH 2/5] validate created identifiers --- .../core/api/util/NamespacedIdentifier.java | 12 +- .../core/api/util/NamespacedIdentifiers.java | 136 ++++++++++++++++++ .../util/NamespacedIdentifierException.java | 31 ++++ .../NamespacedIdentifierParseException.java | 21 +++ 4 files changed, 191 insertions(+), 9 deletions(-) create mode 100644 libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifiers.java create mode 100644 libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/NamespacedIdentifierException.java create mode 100644 libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/NamespacedIdentifierParseException.java diff --git a/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java index a1f77432..64cd721d 100644 --- a/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java +++ b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java @@ -4,18 +4,12 @@ public final class NamespacedIdentifier { - public static NamespacedIdentifier fromMinecraft(String identifier) { - return new NamespacedIdentifier("minecraft", identifier); - } - - public static NamespacedIdentifier from(String namespace, String identifier) { - return new NamespacedIdentifier(namespace, identifier); - } + public static final char SEPARATOR = ':'; private final String namespace; private final String identifier; - private NamespacedIdentifier(String namespace, String identifier) { + NamespacedIdentifier(String namespace, String identifier) { this.namespace = namespace; this.identifier = identifier; } @@ -39,7 +33,7 @@ public int hashCode() { @Override public String toString() { - return namespace + ":" + identifier; + return namespace + SEPARATOR + identifier; } public String getNamespace() { diff --git a/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifiers.java b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifiers.java new file mode 100644 index 00000000..13a23dd6 --- /dev/null +++ b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifiers.java @@ -0,0 +1,136 @@ +package net.ornithemc.osl.core.api.util; + +import net.ornithemc.osl.core.impl.util.NamespacedIdentifierException; +import net.ornithemc.osl.core.impl.util.NamespacedIdentifierParseException; + +/** + * Utility methods for creating and validating {@link NamespacedIdentifier}s. + */ +public final class NamespacedIdentifiers { + + /** + * The {@code minecraft} namespace is used for Vanilla resources and ids. + */ + public static final String MINECRAFT_NAMESPACE = "minecraft"; + /** + * The default namespace of {@code NamespacedIdentifier}s. + * It is recommended to use a custom namespace for your own identifiers. + */ + public static final String DEFAULT_NAMESPACE = MINECRAFT_NAMESPACE; + + /** + * The maximum length of a {@code NamespacedIdentifier}'s namespace string. + */ + public static final int MAX_LENGTH_NAMESPACE = Integer.MAX_VALUE; + /** + * The maximum length of a {@code NamespacedIdentifier} identifier string. + */ + public static final int MAX_LENGTH_IDENTIFIER = Integer.MAX_VALUE; + + /** + * Construct a {@code NamespacedIdentifier} without validating it. + * + * @deprecated use {@link #from(String, String)} instead + */ + public static NamespacedIdentifier of(String namespace, String identifier) { + return new NamespacedIdentifier(namespace, identifier); + } + + /** + * Construct and validate a {@code NamespacedIdentifier} with the default namespace and the given identifier. + * + * @return a {@code NamespacedIdentifier} with the default namespace and the given identifier. + * @throws NamespacedIdentifierException + * if the given identifier is invalid. + */ + public static NamespacedIdentifier from(String identifier) { + return from(DEFAULT_NAMESPACE, identifier); + } + + /** + * Construct and validate a {@code NamespacedIdentifier} from the given namespace and identifier. + * + * @return a {@code NamespacedIdentifier} with the given namespace and identifier. + * @throws NamespacedIdentifierException + * if the given namespace or identifier is invalid. + */ + public static NamespacedIdentifier from(String namespace, String identifier) { + return new NamespacedIdentifier( + validateNamespace(namespace), + validateIdentifier(identifier) + ); + } + + /** + * Parse a {@code NamespacedIdentifier} from the given {@code String}. + * The returned identifier is always valid. If no valid identifier can + * be parsed from the given string, an exception is thrown. + * + * @return the {@code NamespacedIdentifier}} represented by the {@code String}. + * @throws NamespacedIdentifierParseException + * if no valid {@code NamespacedIdentifier} can be parsed from the given {@code String}. + */ + public static NamespacedIdentifier parse(String s) { + int i = s.indexOf(NamespacedIdentifier.SEPARATOR); + + try { + if (i < 0) { + return from(s.substring(i + 1)); + } else if (i > 0) { + return from(s.substring(0, i), s.substring(i + 1)); + } else { + throw NamespacedIdentifierParseException.invalid(s, "badly formatted"); + } + } catch (NamespacedIdentifierException e) { + throw NamespacedIdentifierParseException.invalid(s, e); + } + } + + /** + * Check whether the given {@code NamespacedIdentifier} is valid, or throw an exception. + */ + public static NamespacedIdentifier validate(NamespacedIdentifier id) { + try { + validateNamespace(id.getNamespace()); + validateIdentifier(id.getIdentifier()); + + return id; + } catch (NamespacedIdentifierException e) { + throw NamespacedIdentifierException.invalid(id, e); + } + } + + /** + * Check that the given namespace is valid for a {@code NamespacedIdentifier}. + */ + public static String validateNamespace(String namespace) { + if (namespace == null || namespace.isEmpty()) { + throw NamespacedIdentifierException.invalidNamespace(namespace, "null or empty"); + } + if (namespace.length() > MAX_LENGTH_NAMESPACE) { + throw NamespacedIdentifierException.invalidNamespace(namespace, "length " + namespace.length() + " is greater than maximum allowed " + MAX_LENGTH_NAMESPACE); + } + if (!namespace.chars().allMatch(chr -> chr == '-' || chr == '.' || chr == '_' || (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9'))) { + throw NamespacedIdentifierException.invalidNamespace(namespace, "contains illegal characters - only [a-zA-Z0-9-._] are allowed"); + } + + return namespace; + } + + /** + * Check that the given identifier is valid for a {@code NamespacedIdentifier}. + */ + public static String validateIdentifier(String identifier) { + if (identifier == null || identifier.isEmpty()) { + throw NamespacedIdentifierException.invalidIdentifier(identifier, "null or empty"); + } + if (identifier.length() > MAX_LENGTH_IDENTIFIER) { + throw NamespacedIdentifierException.invalidIdentifier(identifier, "length " + identifier.length() + " is greater than maximum allowed " + MAX_LENGTH_IDENTIFIER); + } + if (!identifier.chars().allMatch(chr -> chr == '-' || chr == '.' || chr == '_' || chr == '/' || (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9'))) { + throw NamespacedIdentifierException.invalidIdentifier(identifier, "contains illegal characters - only [a-zA-Z0-9-._/] are allowed"); + } + + return identifier; + } +} diff --git a/libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/NamespacedIdentifierException.java b/libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/NamespacedIdentifierException.java new file mode 100644 index 00000000..505ddc66 --- /dev/null +++ b/libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/NamespacedIdentifierException.java @@ -0,0 +1,31 @@ +package net.ornithemc.osl.core.impl.util; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +@SuppressWarnings("serial") +public class NamespacedIdentifierException extends RuntimeException { + + private NamespacedIdentifierException(String message) { + super(message); + } + + private NamespacedIdentifierException(String message, Throwable cause) { + super(message, cause); + } + + public static NamespacedIdentifierException invalid(NamespacedIdentifier id, Throwable cause) { + return new NamespacedIdentifierException("\'" + id + "\' is not a valid namespaced identifier", cause); + } + + public static NamespacedIdentifierException invalid(NamespacedIdentifier id, String reason) { + return new NamespacedIdentifierException("\'" + id + "\' is not a valid namespaced identifier: " + reason); + } + + public static NamespacedIdentifierException invalidNamespace(String namespace, String reason) { + return new NamespacedIdentifierException("\'" + namespace + "\' is not a valid namespace: " + reason); + } + + public static NamespacedIdentifierException invalidIdentifier(String identifier, String reason) { + return new NamespacedIdentifierException("\'" + identifier + "\' is not a valid identifier: " + reason); + } +} diff --git a/libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/NamespacedIdentifierParseException.java b/libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/NamespacedIdentifierParseException.java new file mode 100644 index 00000000..caf35242 --- /dev/null +++ b/libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/NamespacedIdentifierParseException.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.core.impl.util; + +@SuppressWarnings("serial") +public class NamespacedIdentifierParseException extends RuntimeException { + + private NamespacedIdentifierParseException(String message) { + super(message); + } + + private NamespacedIdentifierParseException(String message, Throwable cause) { + super(message, cause); + } + + public static NamespacedIdentifierParseException invalid(String s, Throwable cause) { + return new NamespacedIdentifierParseException("unable to parse namespaced identifier from \'" + s + "\'", cause); + } + + public static NamespacedIdentifierParseException invalid(String s, String reason) { + return new NamespacedIdentifierParseException("unable to parse namespaced identifier from \'" + s + "\': " + reason); + } +} From 0696d1cb13d475135b0e79abde7d5cf18b068e23 Mon Sep 17 00:00:00 2001 From: Space Walker Date: Sun, 23 Nov 2025 19:37:38 +0100 Subject: [PATCH 3/5] add javadoc to NamespacedIdentifier --- .../core/api/util/NamespacedIdentifier.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java index 64cd721d..aff371f8 100644 --- a/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java +++ b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java @@ -2,11 +2,45 @@ import java.util.Objects; +/** + * Namespaced identifiers are two-part strings that uniquely point to content in Minecraft. + * The two parts are the namespace and the identifier. They can be combined into a single + * string representation as namespace:identifier (the namespace, followed by the identifier, + * separated by a colon). + *

+ * A namespace is a domain for content. It is used not to point to specific content, but to + * differentiate between different content sources or publishers. The use of namespaces can + * prevent conflicts between mods, resource packs, or data packs, in cases where the same + * identifier is used. + *

+ * The identifier is a unique name for content within a namespace. It should be descriptive + * to avoid naming conflicts with other content. The preferred format is snake_case. + *

+ * Namespaces may only contain alphanumeric characters [a-zA-Z0-9] and special characters + * [-._]. Identifiers may also contain the special character [/]. + *

+ * This class is essentially equivalent to Vanilla's {@code Identifier}. It was added for a + * few reasons. For one, Vanilla's {@code Identifier} was only added in 13w21a, and then was + * client-only until 14w27b. Implementation details of this class also changed a few times, + * and only since 17w43a were {@code Identifiers} validated in any way. + *
This class is available for all Minecraft versions, without any version-specific + * implementation details. + */ public final class NamespacedIdentifier { + /** + * The separator between the namespace and identifier in the {@code String} + * representation of a {@code NamespacedIdentifier}. + */ public static final char SEPARATOR = ':'; + /** + * The namespace of this {@code NamespacedIdentifier}. + */ private final String namespace; + /** + * The identifier of this {@code NamespacedIdentifier}. + */ private final String identifier; NamespacedIdentifier(String namespace, String identifier) { @@ -36,10 +70,16 @@ public String toString() { return namespace + SEPARATOR + identifier; } + /** + * @return the namespace of this {@code NamespacedIdentifier}. + */ public String getNamespace() { return namespace; } + /** + * @return the identifier of this {@code NamespacedIdentifier}. + */ public String getIdentifier() { return identifier; } From e486b000866bd44474f14beba36b906c43810f05 Mon Sep 17 00:00:00 2001 From: Space Walker Date: Sat, 6 Dec 2025 14:20:35 +0100 Subject: [PATCH 4/5] make NamespacedIdentifier an interface --- .../core/api/util/NamespacedIdentifier.java | 58 ++----------------- .../core/api/util/NamespacedIdentifiers.java | 20 +++---- .../osl/core/impl/mixin/IdentifierMixin.java | 47 +++++++++++++++ .../impl/util/NamespacedIdentifierImpl.java | 57 ++++++++++++++++++ .../core/src/main/resources/fabric.mod.json | 3 + .../src/main/resources/osl.core.mixins.json | 16 +++++ 6 files changed, 136 insertions(+), 65 deletions(-) create mode 100644 libraries/core/src/main/java/net/ornithemc/osl/core/impl/mixin/IdentifierMixin.java create mode 100644 libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/NamespacedIdentifierImpl.java create mode 100644 libraries/core/src/main/resources/osl.core.mixins.json diff --git a/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java index aff371f8..598ac994 100644 --- a/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java +++ b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifier.java @@ -1,7 +1,5 @@ package net.ornithemc.osl.core.api.util; -import java.util.Objects; - /** * Namespaced identifiers are two-part strings that uniquely point to content in Minecraft. * The two parts are the namespace and the identifier. They can be combined into a single @@ -18,69 +16,23 @@ *

* Namespaces may only contain alphanumeric characters [a-zA-Z0-9] and special characters * [-._]. Identifiers may also contain the special character [/]. - *

- * This class is essentially equivalent to Vanilla's {@code Identifier}. It was added for a - * few reasons. For one, Vanilla's {@code Identifier} was only added in 13w21a, and then was - * client-only until 14w27b. Implementation details of this class also changed a few times, - * and only since 17w43a were {@code Identifiers} validated in any way. - *
This class is available for all Minecraft versions, without any version-specific - * implementation details. */ -public final class NamespacedIdentifier { +public interface NamespacedIdentifier { /** * The separator between the namespace and identifier in the {@code String} * representation of a {@code NamespacedIdentifier}. */ - public static final char SEPARATOR = ':'; - - /** - * The namespace of this {@code NamespacedIdentifier}. - */ - private final String namespace; - /** - * The identifier of this {@code NamespacedIdentifier}. - */ - private final String identifier; - - NamespacedIdentifier(String namespace, String identifier) { - this.namespace = namespace; - this.identifier = identifier; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof NamespacedIdentifier)) { - return false; - } - NamespacedIdentifier id = (NamespacedIdentifier) o; - return namespace.equals(id.namespace) && identifier.equals(id.identifier); - } - - @Override - public int hashCode() { - return Objects.hash(namespace, identifier); - } - - @Override - public String toString() { - return namespace + SEPARATOR + identifier; - } + static char SEPARATOR = ':'; /** * @return the namespace of this {@code NamespacedIdentifier}. */ - public String getNamespace() { - return namespace; - } + String namespace(); /** * @return the identifier of this {@code NamespacedIdentifier}. */ - public String getIdentifier() { - return identifier; - } + String identifier(); + } diff --git a/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifiers.java b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifiers.java index 13a23dd6..23b59655 100644 --- a/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifiers.java +++ b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifiers.java @@ -2,6 +2,7 @@ import net.ornithemc.osl.core.impl.util.NamespacedIdentifierException; import net.ornithemc.osl.core.impl.util.NamespacedIdentifierParseException; +import net.ornithemc.osl.core.impl.util.NamespacedIdentifierImpl; /** * Utility methods for creating and validating {@link NamespacedIdentifier}s. @@ -27,15 +28,6 @@ public final class NamespacedIdentifiers { */ public static final int MAX_LENGTH_IDENTIFIER = Integer.MAX_VALUE; - /** - * Construct a {@code NamespacedIdentifier} without validating it. - * - * @deprecated use {@link #from(String, String)} instead - */ - public static NamespacedIdentifier of(String namespace, String identifier) { - return new NamespacedIdentifier(namespace, identifier); - } - /** * Construct and validate a {@code NamespacedIdentifier} with the default namespace and the given identifier. * @@ -55,7 +47,7 @@ public static NamespacedIdentifier from(String identifier) { * if the given namespace or identifier is invalid. */ public static NamespacedIdentifier from(String namespace, String identifier) { - return new NamespacedIdentifier( + return new NamespacedIdentifierImpl( validateNamespace(namespace), validateIdentifier(identifier) ); @@ -91,8 +83,8 @@ public static NamespacedIdentifier parse(String s) { */ public static NamespacedIdentifier validate(NamespacedIdentifier id) { try { - validateNamespace(id.getNamespace()); - validateIdentifier(id.getIdentifier()); + validateNamespace(id.namespace()); + validateIdentifier(id.identifier()); return id; } catch (NamespacedIdentifierException e) { @@ -133,4 +125,8 @@ public static String validateIdentifier(String identifier) { return identifier; } + + public static boolean equals(NamespacedIdentifier a, NamespacedIdentifier b) { + return a.namespace().equals(b.namespace()) && a.identifier().equals(b.identifier()); + } } diff --git a/libraries/core/src/main/java/net/ornithemc/osl/core/impl/mixin/IdentifierMixin.java b/libraries/core/src/main/java/net/ornithemc/osl/core/impl/mixin/IdentifierMixin.java new file mode 100644 index 00000000..ce6a763d --- /dev/null +++ b/libraries/core/src/main/java/net/ornithemc/osl/core/impl/mixin/IdentifierMixin.java @@ -0,0 +1,47 @@ +package net.ornithemc.osl.core.impl.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.client.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; + +@Pseudo // needed because Identifier does not exist in all versions +@Mixin(Identifier.class) +public class IdentifierMixin implements NamespacedIdentifier { // TODO: interface injection + + @Shadow + private String namespace; + @Shadow + private String path; + + @Inject( + method = "equals", + remap = false, + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$core$equalsNamespacedIdentifier(Object o, CallbackInfoReturnable cir) { + if (o instanceof NamespacedIdentifier) { + cir.setReturnValue(NamespacedIdentifiers.equals(this, (NamespacedIdentifier) o)); + } + } + + @Override + public String namespace() { + return namespace; + } + + @Override + public String identifier() { + return path; + } +} diff --git a/libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/NamespacedIdentifierImpl.java b/libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/NamespacedIdentifierImpl.java new file mode 100644 index 00000000..f373c436 --- /dev/null +++ b/libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/NamespacedIdentifierImpl.java @@ -0,0 +1,57 @@ +package net.ornithemc.osl.core.impl.util; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; + +/** + * This class is a version-agnostic implementation of {@link NamespacedIdentifier}. + *

+ * This class is essentially equivalent to Vanilla's {@code Identifier}. It was added for a + * few reasons. For one, Vanilla's {@code Identifier} was only added in 13w21a, and then was + * client-only until 14w27b. Implementation details of this class also changed a few times, + * and only since 17w43a were {@code Identifiers} validated in any way. + *
This class is available for all Minecraft versions, without any version-specific + * implementation details. + */ +public final class NamespacedIdentifierImpl implements NamespacedIdentifier { + + private final String namespace; + private final String identifier; + + public NamespacedIdentifierImpl(String namespace, String identifier) { + this.namespace = namespace; + this.identifier = identifier; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof NamespacedIdentifier)) { + return false; + } + return NamespacedIdentifiers.equals(this, (NamespacedIdentifier) o); + } + + @Override + public int hashCode() { + // this impl matches Vanilla Identifier's impl + return 31 * namespace.hashCode() + identifier.hashCode(); + } + + @Override + public String toString() { + return namespace + SEPARATOR + identifier; + } + + @Override + public String namespace() { + return namespace; + } + + @Override + public String identifier() { + return identifier; + } +} diff --git a/libraries/core/src/main/resources/fabric.mod.json b/libraries/core/src/main/resources/fabric.mod.json index f5bf5e48..b4fd2ede 100644 --- a/libraries/core/src/main/resources/fabric.mod.json +++ b/libraries/core/src/main/resources/fabric.mod.json @@ -16,6 +16,9 @@ "license": "Apache-2.0", "icon": "assets/ornithe-standard-libraries/core/icon.png", "environment": "*", + "mixins": [ + "osl.core.mixins.json" + ], "depends": { "fabricloader": ">=0.16.0" } diff --git a/libraries/core/src/main/resources/osl.core.mixins.json b/libraries/core/src/main/resources/osl.core.mixins.json new file mode 100644 index 00000000..da16fd2f --- /dev/null +++ b/libraries/core/src/main/resources/osl.core.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.ornithemc.osl.core.impl.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "IdentifierMixin" + ], + "client": [ + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} From 4b938921fc85e15987386e556357167b7289f5df Mon Sep 17 00:00:00 2001 From: Space Walker Date: Sat, 6 Dec 2025 16:22:00 +0100 Subject: [PATCH 5/5] add comparator to NamespacedIdentifiers --- .../osl/core/api/util/NamespacedIdentifiers.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifiers.java b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifiers.java index 23b59655..691ae091 100644 --- a/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifiers.java +++ b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/NamespacedIdentifiers.java @@ -1,5 +1,7 @@ package net.ornithemc.osl.core.api.util; +import java.util.Comparator; + import net.ornithemc.osl.core.impl.util.NamespacedIdentifierException; import net.ornithemc.osl.core.impl.util.NamespacedIdentifierParseException; import net.ornithemc.osl.core.impl.util.NamespacedIdentifierImpl; @@ -28,6 +30,18 @@ public final class NamespacedIdentifiers { */ public static final int MAX_LENGTH_IDENTIFIER = Integer.MAX_VALUE; + /** + * A comparator for {@code NamespacedIdentifier}s, comparing first by identifier, then by namespace. + */ + public static final Comparator COMPARATOR = (a, b) -> { + int c = a.identifier().compareTo(b.identifier()); + if (c == 0) { + c = a.namespace().compareTo(b.namespace()); + } + + return c; + }; + /** * Construct and validate a {@code NamespacedIdentifier} with the default namespace and the given identifier. *