Skip to content

Commit

Permalink
fix: resource location parsing for config (#290)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ingrim4 authored Jun 2, 2023
1 parent 23a2af2 commit 3f664ec
Show file tree
Hide file tree
Showing 25 changed files with 326 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@

public class BlockProperties {

public static Builder builder(String name) {
return new Builder(name);
public static Builder builder(NamespacedKey key) {
return new Builder(key);
}

private final String name;
private final NamespacedKey key;
private final BlockStateProperties defaultBlockState;
private final ImmutableList<BlockStateProperties> possibleBlockStates;

private BlockProperties(Builder builder) {
this.name = builder.name;
this.key = builder.key;
this.defaultBlockState = builder.defaultBlockState;
this.possibleBlockStates = builder.possibleBlockStates;
}

public String getName() {
return name;
public NamespacedKey getKey() {
return key;
}

public BlockStateProperties getDefaultBlockState() {
Expand All @@ -34,7 +34,7 @@ public ImmutableList<BlockStateProperties> getPossibleBlockStates() {

@Override
public int hashCode() {
return this.name.hashCode();
return this.key.hashCode();
}

@Override
Expand All @@ -46,24 +46,24 @@ public boolean equals(Object obj) {
return false;
}
BlockProperties other = (BlockProperties) obj;
return Objects.equals(name, other.name);
return Objects.equals(key, other.key);
}

@Override
public String toString() {
return "BlockProperties [name=" + name + ", defaultBlockState=" + defaultBlockState + ", possibleBlockStates="
return "BlockProperties [key=" + key + ", defaultBlockState=" + defaultBlockState + ", possibleBlockStates="
+ possibleBlockStates + "]";
}

public static class Builder {

private final String name;
private final NamespacedKey key;

private BlockStateProperties defaultBlockState;
private ImmutableList<BlockStateProperties> possibleBlockStates;

private Builder(String name) {
this.name = name;
private Builder(NamespacedKey key) {
this.key = key;
}

public Builder withDefaultBlockState(BlockStateProperties defaultBlockState) {
Expand All @@ -77,8 +77,8 @@ public Builder withPossibleBlockStates(ImmutableList<BlockStateProperties> possi
}

public BlockProperties build() {
Objects.requireNonNull(this.defaultBlockState, "missing default block state for " + this.name);
Objects.requireNonNull(this.possibleBlockStates, "missing possible block states for " + this.name);
Objects.requireNonNull(this.defaultBlockState, "missing default block state for " + this.key);
Objects.requireNonNull(this.possibleBlockStates, "missing possible block states for " + this.key);

return new BlockProperties(this);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
package net.imprex.orebfuscator.util;

import java.util.Locale;
import java.util.UUID;

import org.bukkit.plugin.Plugin;

import com.google.common.base.Preconditions;

/**
* Represents a String based key which consists of two components - a namespace
* and a key.
*
* Namespaces may only contain lowercase alphanumeric characters, periods,
* underscores, and hyphens.
* <p>
* Keys may only contain lowercase alphanumeric characters, periods,
* underscores, hyphens, and forward slashes.
*
* @author org.bukkit.NamespacedKey from 1.19.4
*
*/
public final class NamespacedKey {

/**
* The namespace representing all inbuilt keys.
*/
public static final String MINECRAFT = "minecraft";
/**
* The namespace representing all keys generated by Bukkit for backwards
* compatibility measures.
*/
public static final String BUKKIT = "bukkit";
//
private final String namespace;
private final String key;

private static boolean isValidNamespaceChar(char c) {
return (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '-';
}

private static boolean isValidKeyChar(char c) {
return isValidNamespaceChar(c) || c == '/';
}

private static boolean isValidNamespace(String namespace) {
int len = namespace.length();
if (len == 0) {
return false;
}

for (int i = 0; i < len; i++) {
if (!isValidNamespaceChar(namespace.charAt(i))) {
return false;
}
}

return true;
}

private static boolean isValidKey(String key) {
int len = key.length();
if (len == 0) {
return false;
}

for (int i = 0; i < len; i++) {
if (!isValidKeyChar(key.charAt(i))) {
return false;
}
}

return true;
}

/**
* Create a key in a specific namespace.
*
* @param namespace namespace
* @param key key
* @deprecated should never be used by plugins, for internal use only!!
*/
@Deprecated
public NamespacedKey(String namespace, String key) {
Preconditions.checkArgument(namespace != null && isValidNamespace(namespace),
"Invalid namespace. Must be [a-z0-9._-]: %s", namespace);
Preconditions.checkArgument(key != null && isValidKey(key), "Invalid key. Must be [a-z0-9/._-]: %s", key);

this.namespace = namespace;
this.key = key;

String string = toString();
Preconditions.checkArgument(string.length() < 256, "NamespacedKey must be less than 256 characters", string);
}

/**
* Create a key in the plugin's namespace.
* <p>
* Namespaces may only contain lowercase alphanumeric characters, periods,
* underscores, and hyphens.
* <p>
* Keys may only contain lowercase alphanumeric characters, periods,
* underscores, hyphens, and forward slashes.
*
* @param plugin the plugin to use for the namespace
* @param key the key to create
*/
public NamespacedKey(Plugin plugin, String key) {
Preconditions.checkArgument(plugin != null, "Plugin cannot be null");
Preconditions.checkArgument(key != null, "Key cannot be null");

this.namespace = plugin.getName().toLowerCase(Locale.ROOT);
this.key = key.toLowerCase(Locale.ROOT);

// Check validity after normalization
Preconditions.checkArgument(isValidNamespace(this.namespace), "Invalid namespace. Must be [a-z0-9._-]: %s",
this.namespace);
Preconditions.checkArgument(isValidKey(this.key), "Invalid key. Must be [a-z0-9/._-]: %s", this.key);

String string = toString();
Preconditions.checkArgument(string.length() < 256, "NamespacedKey must be less than 256 characters (%s)",
string);
}

public String getNamespace() {
return namespace;
}

public String getKey() {
return key;
}

@Override
public int hashCode() {
int hash = 5;
hash = 47 * hash + this.namespace.hashCode();
hash = 47 * hash + this.key.hashCode();
return hash;
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final NamespacedKey other = (NamespacedKey) obj;
return this.namespace.equals(other.namespace) && this.key.equals(other.key);
}

@Override
public String toString() {
return this.namespace + ":" + this.key;
}

/**
* Return a new random key in the {@link #BUKKIT} namespace.
*
* @return new key
* @deprecated should never be used by plugins, for internal use only!!
*/
@Deprecated
public static NamespacedKey randomKey() {
return new NamespacedKey(BUKKIT, UUID.randomUUID().toString());
}

/**
* Get a key in the Minecraft namespace.
*
* @param key the key to use
* @return new key in the Minecraft namespace
*/
public static NamespacedKey minecraft(String key) {
return new NamespacedKey(MINECRAFT, key);
}

/**
* Get a NamespacedKey from the supplied string with a default namespace if a
* namespace is not defined. This is a utility method meant to fetch a
* NamespacedKey from user input. Please note that casing does matter and any
* instance of uppercase characters will be considered invalid. The input
* contract is as follows:
*
* <pre>
* fromString("foo", plugin) -{@literal >} "plugin:foo"
* fromString("foo:bar", plugin) -{@literal >} "foo:bar"
* fromString(":foo", null) -{@literal >} "minecraft:foo"
* fromString("foo", null) -{@literal >} "minecraft:foo"
* fromString("Foo", plugin) -{@literal >} null
* fromString(":Foo", plugin) -{@literal >} null
* fromString("foo:bar:bazz", plugin) -{@literal >} null
* fromString("", plugin) -{@literal >} null
* </pre>
*
* @param string the string to convert to a NamespacedKey
* @param defaultNamespace the default namespace to use if none was supplied. If
* null, the {@code minecraft} namespace
* ({@link #minecraft(String)}) will be used
* @return the created NamespacedKey. null if invalid key
* @see #fromString(String)
*/
public static NamespacedKey fromString(String string, Plugin defaultNamespace) {
Preconditions.checkArgument(string != null && !string.isEmpty(), "Input string must not be empty or null");

String[] components = string.split(":", 3);
if (components.length > 2) {
return null;
}

String key = (components.length == 2) ? components[1] : "";
if (components.length == 1) {
String value = components[0];
if (value.isEmpty() || !isValidKey(value)) {
return null;
}

return (defaultNamespace != null) ? new NamespacedKey(defaultNamespace, value) : minecraft(value);
} else if (components.length == 2 && !isValidKey(key)) {
return null;
}

String namespace = components[0];
if (namespace.isEmpty()) {
return (defaultNamespace != null) ? new NamespacedKey(defaultNamespace, key) : minecraft(key);
}

if (!isValidNamespace(namespace)) {
return null;
}

return new NamespacedKey(namespace, key);
}

/**
* Get a NamespacedKey from the supplied string.
*
* The default namespace will be Minecraft's (i.e. {@link #minecraft(String)}).
*
* @param key the key to convert to a NamespacedKey
* @return the created NamespacedKey. null if invalid
* @see #fromString(String, Plugin)
*/
public static NamespacedKey fromString(String key) {
return fromString(key, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
import net.imprex.orebfuscator.config.Config;
import net.imprex.orebfuscator.util.BlockProperties;
import net.imprex.orebfuscator.util.BlockStateProperties;
import net.imprex.orebfuscator.util.NamespacedKey;

public abstract class AbstractNmsManager implements NmsManager {

private final AbstractRegionFileCache<?> regionFileCache;

private final BlockStateProperties[] blockStates = new BlockStateProperties[getTotalBlockCount()];
private final Map<String, BlockProperties> blocks = new HashMap<>();
private final Map<NamespacedKey, BlockProperties> blocks = new HashMap<>();

public AbstractNmsManager(Config config) {
this.regionFileCache = this.createRegionFileCache(config.cache());
Expand All @@ -26,7 +27,7 @@ protected final void registerBlockStateProperties(BlockStateProperties propertie
}

protected final void registerBlockProperties(BlockProperties properties) {
this.blocks.put(properties.getName(), properties);
this.blocks.put(properties.getKey(), properties);
}

protected final BlockStateProperties getBlockStateProperties(int id) {
Expand All @@ -39,7 +40,7 @@ public final AbstractRegionFileCache<?> getRegionFileCache() {
}

@Override
public final BlockProperties getBlockByName(String key) {
public final BlockProperties getBlockByName(NamespacedKey key) {
return this.blocks.get(key);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.bukkit.entity.Player;

import net.imprex.orebfuscator.util.BlockProperties;
import net.imprex.orebfuscator.util.NamespacedKey;

public interface NmsManager {

Expand All @@ -13,7 +14,7 @@ public interface NmsManager {

int getTotalBlockCount();

BlockProperties getBlockByName(String key);
BlockProperties getBlockByName(NamespacedKey key);

boolean isAir(int blockId);

Expand Down
Loading

0 comments on commit 3f664ec

Please sign in to comment.