Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions libraries/networking/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ and snake case for the identifier.
public static final NamespacedIdentifier COOKIE_CHANNEL = ChannelIdentifiers.from("example", "cookie");
```

In 1.13-pre2 and below, the game did not validate channel names, so Minecraft itself used names like `MC|Brand`. If you require a channel name with this convention, you can use the `fromLegacy` factory methods instead.

```java
ChannelIdentifiers.from("example", "cookie"); // -> "example:cookie"
ChannelIdentifiers.fromLegacy("EXAMPLE", "Cookie"); // -> "EXAMPLE|Cookie"
```

You are expected to register your channels through the `ChannelRegistry`.

```java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import net.ornithemc.osl.core.api.util.NamespacedIdentifiers;
import net.ornithemc.osl.core.impl.util.NamespacedIdentifierException;
import net.ornithemc.osl.networking.impl.ChannelIdentifierException;
import net.ornithemc.osl.networking.impl.LegacyChannelIdentifierImpl;

/**
* Utility methods for creating and validating channel identifiers.
Expand Down Expand Up @@ -45,6 +46,24 @@ public static NamespacedIdentifier from(String namespace, String identifier) {
);
}

/**
* Construct a legacy channel identifier with the given identifier.
*
* @see LegacyChannelIdentifier
*/
public static LegacyChannelIdentifier fromLegacy(String identifier) {
return fromLegacy("", identifier);
}

/**
* Construct a legacy channel identifier with the given namespace and identifier.
*
* @see LegacyChannelIdentifier
*/
public static LegacyChannelIdentifier fromLegacy(String namespace, String identifier) {
return new LegacyChannelIdentifierImpl(namespace, identifier);
}

/**
* Check whether the given channel identifier is valid, or throw an exception.
*/
Expand All @@ -54,7 +73,7 @@ public static NamespacedIdentifier validate(NamespacedIdentifier id) {
validateIdentifier(id.identifier());

return id;
} catch (ChannelIdentifierException e) {
} catch (ChannelIdentifierException | NamespacedIdentifierException e) {
throw ChannelIdentifierException.invalid(id, e);
}
}
Expand All @@ -63,15 +82,9 @@ public static NamespacedIdentifier validate(NamespacedIdentifier id) {
* Check that the given namespace is valid for a channel identifier.
*/
public static String validateNamespace(String namespace) {
if (namespace == null || namespace.isEmpty()) {
throw ChannelIdentifierException.invalidNamespace(namespace, "null or empty");
}
if (namespace.length() > MAX_LENGTH_NAMESPACE) {
throw ChannelIdentifierException.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 >= '0' && chr <= '9'))) {
throw ChannelIdentifierException.invalidNamespace(namespace, "contains illegal characters - only [a-z0-9-._] are allowed");
}

return NamespacedIdentifiers.validateNamespace(namespace);
}
Expand All @@ -80,15 +93,9 @@ public static String validateNamespace(String namespace) {
* Check that the given identifier is valid for a channel identifier.
*/
public static String validateIdentifier(String identifier) {
if (identifier == null || identifier.isEmpty()) {
throw ChannelIdentifierException.invalidIdentifier(identifier, "null or empty");
}
if (identifier.length() > MAX_LENGTH_IDENTIFIER) {
throw ChannelIdentifierException.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 >= '0' && chr <= '9'))) {
throw ChannelIdentifierException.invalidIdentifier(identifier, "contains illegal characters - only [a-z0-9-._/] are allowed");
}

return NamespacedIdentifiers.validateIdentifier(identifier);
}
Expand All @@ -99,7 +106,7 @@ public static Set<NamespacedIdentifier> dropInvalid(Set<NamespacedIdentifier> ch
.filter(channel -> {
try {
return ChannelIdentifiers.validate(channel) != null;
} catch (ChannelIdentifierException | NamespacedIdentifierException e) {
} catch (ChannelIdentifierException e) {
return false;
}
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package net.ornithemc.osl.networking.api;

import net.ornithemc.osl.core.api.util.NamespacedIdentifier;

/**
* A {@linkplain NamespacedIdentifier} implementation that represents a packet
* channel in the legacy format used in 1.13-pre2 and below. The legacy format
* uses the vertical bar character ({@code '|'}) as the separator, but that is
* only by convention, as no format is strictly enforced, and any character in
* the UTF-8 character set is allowed. As such, strings like {@code "MC|Brand"}
* and {@code "REGISTER"} are valid channel identifiers in the legacy format.
*/
public interface LegacyChannelIdentifier extends NamespacedIdentifier {

char SEPARATOR = '|';

@Override
LegacyChannelIdentifier prefixed(String prefix);

@Override
LegacyChannelIdentifier suffixed(String suffix);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import net.ornithemc.osl.core.api.util.NamespacedIdentifier;
import net.ornithemc.osl.core.impl.util.NamespacedIdentifierImpl;
import net.ornithemc.osl.networking.impl.ChannelIdentifierException;
import net.ornithemc.osl.networking.impl.ChannelIdentifierParseException;
import net.ornithemc.osl.networking.impl.LegacyChannelIdentifierImpl;

/**
* Utility methods for converting channel identifiers from and to {@link String}s.
Expand All @@ -23,15 +23,20 @@ public final class StringChannelIdentifierParser {
* which may or may not be a valid identifier.
*/
public static NamespacedIdentifier fromString(String s) {
int i = s.indexOf('|');
int i = s.indexOf(LegacyChannelIdentifier.SEPARATOR);

if (i < 1) {
// allow null namespaces to support channel ids that do not conform
// to OSL spec - MC did not enforce a strict spec before 1.13
return new NamespacedIdentifierImpl("", s);
} else {
return new NamespacedIdentifierImpl(s.substring(0, i), s.substring(i + 1));
if (i > 0) {
return new LegacyChannelIdentifierImpl(s.substring(0, i), s.substring(i + 1));
}

i = s.indexOf(NamespacedIdentifier.SEPARATOR);

if (i < 0) {
// allow empty namespaces since MC did not enforce a strict spec before 1.13
return new LegacyChannelIdentifierImpl("", s);
}

return new NamespacedIdentifierImpl(s.substring(0, i), s.substring(i + 1));
}

/**
Expand All @@ -45,27 +50,26 @@ public static NamespacedIdentifier fromString(String s) {
* if no valid channel identifier can be parsed from the given {@code String}.
*/
public static NamespacedIdentifier fromStringOrThrow(String s) {
int i = s.indexOf('|');
int i = s.indexOf(LegacyChannelIdentifier.SEPARATOR);

try {
if (i < 0) {
return ChannelIdentifiers.from(s);
} else if (i > 0) {
return ChannelIdentifiers.from(s.substring(0, i), s.substring(i + 1));
} else {
throw ChannelIdentifierParseException.invalid(s, "badly formatted");
}
} catch (ChannelIdentifierException e) {
throw ChannelIdentifierParseException.invalid(s, e);
if (i > 0) {
return new LegacyChannelIdentifierImpl(s.substring(0, i), s.substring(i + 1));
}

i = s.indexOf(NamespacedIdentifier.SEPARATOR);

if (i < 0) {
// allow empty namespaces since MC did not enforce a strict spec before 1.13
return new LegacyChannelIdentifierImpl("", s);
}

return ChannelIdentifiers.from(s.substring(0, i), s.substring(i + 1));
}

/**
* Convert the given {@code NamespacedIdentifier} to its {@code String} representation.
*/
public static String toString(NamespacedIdentifier id) {
return id.namespace().isEmpty()
? id.identifier()
: id.namespace() + "|" + id.identifier();
return id.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package net.ornithemc.osl.networking.impl;

import net.ornithemc.osl.core.api.util.NamespacedIdentifier;
import net.ornithemc.osl.core.api.util.NamespacedIdentifiers;
import net.ornithemc.osl.networking.api.LegacyChannelIdentifier;

public final class LegacyChannelIdentifierImpl implements LegacyChannelIdentifier {

private final String namespace;
private final String identifier;

public LegacyChannelIdentifierImpl(String namespace, String identifier) {
this.namespace = namespace;
this.identifier = identifier;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof LegacyChannelIdentifier)) {
return false;
}
return NamespacedIdentifiers.equals(this, (LegacyChannelIdentifier) o);
}

@Override
public int hashCode() {
return 31 * namespace.hashCode() + identifier.hashCode();
}

@Override
public String toString() {
return namespace.isEmpty() ? identifier : (namespace + SEPARATOR + identifier);
}

@Override
public String namespace() {
return namespace;
}

@Override
public String identifier() {
return identifier;
}

@Override
public LegacyChannelIdentifier prefixed(String prefix) {
return new LegacyChannelIdentifierImpl(namespace, prefix + identifier);
}

@Override
public LegacyChannelIdentifier suffixed(String suffix) {
return new LegacyChannelIdentifierImpl(namespace, identifier + suffix);
}
}
Loading