mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-02-16 10:30:42 +00:00
implement namespaced registries
This commit is contained in:
@@ -209,7 +209,7 @@ public abstract class AbstractPlatform implements Platform {
|
||||
platformInjector.inject(addon);
|
||||
addon.initialize();
|
||||
if(!(addon instanceof EphemeralAddon)) { // ephemeral addons exist only for version checking
|
||||
addonRegistry.register(addon.getID(), addon);
|
||||
addonRegistry.register(addon.getKey(addon.getID()), addon);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ import java.util.function.Supplier;
|
||||
|
||||
import com.dfsek.terra.api.registry.Registry;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public class GenericTemplateSupplierLoader<T> implements TypeLoader<T> {
|
||||
private final Registry<Supplier<ObjectTemplate<T>>> registry;
|
||||
@@ -40,12 +42,11 @@ public class GenericTemplateSupplierLoader<T> implements TypeLoader<T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T load(AnnotatedType t, Object c, ConfigLoader loader) throws LoadException {
|
||||
public T load(@NotNull AnnotatedType t, @NotNull Object c, ConfigLoader loader) throws LoadException {
|
||||
Map<String, Object> map = (Map<String, Object>) c;
|
||||
try {
|
||||
return loader
|
||||
.load(registry
|
||||
.get(((String) map.get("type")))
|
||||
.load(registry.tryGet(((String) map.get("type")))
|
||||
.orElseThrow(() -> new LoadException("No such entry: " + map.get("type")))
|
||||
.get(), new MapConfiguration(map)).get();
|
||||
} catch(ConfigException e) {
|
||||
|
||||
@@ -27,6 +27,9 @@ import com.dfsek.tectonic.api.loader.AbstractConfigLoader;
|
||||
import com.dfsek.tectonic.api.loader.ConfigLoader;
|
||||
import com.dfsek.tectonic.api.loader.type.TypeLoader;
|
||||
import com.dfsek.tectonic.yaml.YamlConfiguration;
|
||||
|
||||
import com.dfsek.terra.api.registry.key.RegistryKey;
|
||||
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -115,10 +118,9 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
private final Map<Type, ShortcutHolder<?>> shortcuts = new HashMap<>();
|
||||
|
||||
private final OpenRegistry<ConfigType<?, ?>> configTypeRegistry;
|
||||
private final TreeMap<Integer, List<Pair<String, ConfigType<?, ?>>>> configTypes = new TreeMap<>();
|
||||
private final TreeMap<Integer, List<Pair<RegistryKey, ConfigType<?, ?>>>> configTypes = new TreeMap<>();
|
||||
|
||||
private final String namespace;
|
||||
private final String id;
|
||||
private final RegistryKey key;
|
||||
|
||||
public ConfigPackImpl(File folder, Platform platform) {
|
||||
this(new FolderLoader(folder.toPath()), Construct.construct(() -> {
|
||||
@@ -175,14 +177,18 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
|
||||
selfLoader.load(template, packManifest);
|
||||
|
||||
String namespace;
|
||||
String id;
|
||||
if(template.getID().contains(":")) {
|
||||
this.namespace = template.getID().substring(0, template.getID().indexOf(":"));
|
||||
this.id = template.getID().substring(template.getID().indexOf(":") + 1);
|
||||
namespace = template.getID().substring(0, template.getID().indexOf(":"));
|
||||
id = template.getID().substring(template.getID().indexOf(":") + 1);
|
||||
} else {
|
||||
this.id = template.getID();
|
||||
this.namespace = template.getID();
|
||||
id = template.getID();
|
||||
namespace = template.getID();
|
||||
}
|
||||
|
||||
this.key = RegistryKey.of(namespace, id);
|
||||
|
||||
logger.info("Loading config pack \"{}:{}\"", id, namespace);
|
||||
|
||||
configTypes.values().forEach(list -> list.forEach(pair -> configTypeRegistry.register(pair.getLeft(), pair.getRight())));
|
||||
@@ -214,7 +220,7 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
return Pair.of(configuration.getID(), loaded);
|
||||
})
|
||||
.toList()
|
||||
.forEach(pair -> registry.register(pair.getLeft(), pair.getRight()));
|
||||
.forEach(pair -> registry.register(getKey(pair.getLeft()), pair.getRight()));
|
||||
platform.getEventManager().callEvent(new ConfigTypePostLoadEvent(configType, registry, this));
|
||||
});
|
||||
|
||||
@@ -282,13 +288,13 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigPack registerConfigType(ConfigType<?, ?> type, String id, int priority) {
|
||||
Set<String> contained = new HashSet<>();
|
||||
public ConfigPack registerConfigType(ConfigType<?, ?> type, RegistryKey key, int priority) {
|
||||
Set<RegistryKey> contained = new HashSet<>();
|
||||
configTypes.forEach((p, configs) -> configs.forEach(pair -> {
|
||||
if(contained.contains(pair.getLeft())) throw new IllegalArgumentException("Duplicate config ID: " + id);
|
||||
contained.add(id);
|
||||
if(contained.contains(pair.getLeft())) throw new IllegalArgumentException("Duplicate config key: " + key);
|
||||
contained.add(key);
|
||||
}));
|
||||
configTypes.computeIfAbsent(priority, p -> new ArrayList<>()).add(Pair.of(id, type));
|
||||
configTypes.computeIfAbsent(priority, p -> new ArrayList<>()).add(Pair.of(key, type));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -374,7 +380,7 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
private OpenRegistry<ConfigType<?, ?>> createConfigRegistry() {
|
||||
return new OpenRegistryImpl<>(new LinkedHashMap<>(), CONFIG_TYPE_TYPE_KEY) {
|
||||
@Override
|
||||
public boolean register(@NotNull String identifier, @NotNull ConfigType<?, ?> value) {
|
||||
public boolean register(@NotNull RegistryKey key, @NotNull ConfigType<?, ?> value) {
|
||||
if(!registryMap
|
||||
.containsKey(value.getTypeKey()
|
||||
.getType())) {
|
||||
@@ -383,7 +389,7 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
abstractConfigLoader.registerLoader(value.getTypeKey().getType(), openRegistry);
|
||||
registryMap.put(value.getTypeKey().getType(), new CheckedRegistryImpl<>(openRegistry));
|
||||
}
|
||||
return super.register(identifier, value);
|
||||
return super.register(key, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -411,12 +417,7 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
public RegistryKey getRegistryKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.dfsek.terra.registry;
|
||||
import com.dfsek.tectonic.api.exception.LoadException;
|
||||
import com.dfsek.tectonic.api.loader.ConfigLoader;
|
||||
|
||||
import com.dfsek.terra.api.registry.key.RegistryKey;
|
||||
import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus.Internal;
|
||||
@@ -27,6 +28,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
@@ -55,18 +57,18 @@ public class CheckedRegistryImpl<T> implements CheckedRegistry<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(@NotNull String identifier, @NotNull T value) throws DuplicateEntryException {
|
||||
public void register(@NotNull RegistryKey identifier, @NotNull T value) throws DuplicateEntryException {
|
||||
registry.registerChecked(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<T> get(@NotNull String identifier) {
|
||||
return registry.get(identifier);
|
||||
public Optional<T> get(@NotNull RegistryKey key) {
|
||||
return registry.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@NotNull String identifier) {
|
||||
return registry.contains(identifier);
|
||||
public boolean contains(@NotNull RegistryKey key) {
|
||||
return registry.contains(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,7 +77,7 @@ public class CheckedRegistryImpl<T> implements CheckedRegistry<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(@NotNull BiConsumer<String, T> consumer) {
|
||||
public void forEach(@NotNull BiConsumer<RegistryKey, T> consumer) {
|
||||
registry.forEach(consumer);
|
||||
}
|
||||
|
||||
@@ -85,7 +87,7 @@ public class CheckedRegistryImpl<T> implements CheckedRegistry<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Set<String> keys() {
|
||||
public @NotNull Set<RegistryKey> keys() {
|
||||
return registry.keys();
|
||||
}
|
||||
|
||||
@@ -94,6 +96,11 @@ public class CheckedRegistryImpl<T> implements CheckedRegistry<T> {
|
||||
return registry.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<RegistryKey, T> get(String id) {
|
||||
return registry.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader) throws LoadException {
|
||||
return registry.load(t, c, loader);
|
||||
|
||||
@@ -20,12 +20,14 @@ package com.dfsek.terra.registry;
|
||||
import com.dfsek.tectonic.api.exception.LoadException;
|
||||
import com.dfsek.tectonic.api.loader.ConfigLoader;
|
||||
|
||||
import com.dfsek.terra.api.registry.key.RegistryKey;
|
||||
import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
@@ -47,13 +49,13 @@ public class LockedRegistryImpl<T> implements Registry<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<T> get(@NotNull String identifier) {
|
||||
return registry.get(identifier);
|
||||
public Optional<T> get(@NotNull RegistryKey key) {
|
||||
return registry.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@NotNull String identifier) {
|
||||
return registry.contains(identifier);
|
||||
public boolean contains(@NotNull RegistryKey key) {
|
||||
return registry.contains(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,7 +64,7 @@ public class LockedRegistryImpl<T> implements Registry<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(@NotNull BiConsumer<String, T> consumer) {
|
||||
public void forEach(@NotNull BiConsumer<RegistryKey, T> consumer) {
|
||||
registry.forEach(consumer);
|
||||
}
|
||||
|
||||
@@ -72,7 +74,7 @@ public class LockedRegistryImpl<T> implements Registry<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Set<String> keys() {
|
||||
public @NotNull Set<RegistryKey> keys() {
|
||||
return registry.keys();
|
||||
}
|
||||
|
||||
@@ -81,6 +83,11 @@ public class LockedRegistryImpl<T> implements Registry<T> {
|
||||
return registry.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<RegistryKey, T> get(String id) {
|
||||
return registry.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader) throws LoadException {
|
||||
return registry.load(t, c, loader);
|
||||
|
||||
@@ -20,20 +20,25 @@ package com.dfsek.terra.registry;
|
||||
import com.dfsek.tectonic.api.exception.LoadException;
|
||||
import com.dfsek.tectonic.api.loader.ConfigLoader;
|
||||
|
||||
import com.dfsek.terra.api.registry.key.RegistryKey;
|
||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.dfsek.terra.api.registry.OpenRegistry;
|
||||
@@ -47,36 +52,45 @@ import com.dfsek.terra.api.registry.exception.DuplicateEntryException;
|
||||
*/
|
||||
public class OpenRegistryImpl<T> implements OpenRegistry<T> {
|
||||
private static final Entry<?> NULL = new Entry<>(null);
|
||||
private static final Pattern ID_PATTERN = Pattern.compile("^[a-zA-Z0-9_-]*$");
|
||||
private final Map<String, Entry<T>> objects;
|
||||
private final Map<RegistryKey, Entry<T>> objects;
|
||||
private final ListMultimap<String, Pair<RegistryKey, Entry<T>>> objectIDs = Multimaps.newListMultimap(new HashMap<>(), ArrayList::new);
|
||||
private final TypeKey<T> typeKey;
|
||||
|
||||
public OpenRegistryImpl(TypeKey<T> typeKey) {
|
||||
this(new HashMap<>(), typeKey);
|
||||
}
|
||||
|
||||
protected OpenRegistryImpl(Map<String, Entry<T>> init, TypeKey<T> typeKey) {
|
||||
protected OpenRegistryImpl(Map<RegistryKey, Entry<T>> init, TypeKey<T> typeKey) {
|
||||
this.objects = init;
|
||||
this.typeKey = typeKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T load(@NotNull AnnotatedType type, @NotNull Object o, @NotNull ConfigLoader configLoader) throws LoadException {
|
||||
return get((String) o).orElseThrow(() -> {
|
||||
String list = objects.keySet().stream().sorted().reduce("", (a, b) -> a + "\n - " + b);
|
||||
if(objects.isEmpty()) list = "[ ]";
|
||||
return new LoadException("No such " + type.getType().getTypeName() + " matching \"" + o +
|
||||
"\" was found in this registry. Registry contains items: " + list);
|
||||
});
|
||||
return tryGet((String) o).orElseThrow(() -> new LoadException("No such " + type.getType().getTypeName() + " matching \"" + o +
|
||||
"\" was found in this registry. Registry contains items: " +
|
||||
getItemsFormatted()));
|
||||
}
|
||||
|
||||
private String getItemsFormatted() {
|
||||
if(objects.isEmpty()) {
|
||||
return "[ ]";
|
||||
}
|
||||
return objects
|
||||
.keySet()
|
||||
.stream()
|
||||
.map(RegistryKey::toString)
|
||||
.sorted()
|
||||
.reduce("", (a, b) -> a + "\n - " + b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean register(@NotNull String identifier, @NotNull T value) {
|
||||
public boolean register(@NotNull RegistryKey identifier, @NotNull T value) {
|
||||
return register(identifier, new Entry<>(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerChecked(@NotNull String identifier, @NotNull T value) throws DuplicateEntryException {
|
||||
public void registerChecked(@NotNull RegistryKey identifier, @NotNull T value) throws DuplicateEntryException {
|
||||
if(objects.containsKey(identifier))
|
||||
throw new DuplicateEntryException("Value with identifier \"" + identifier + "\" is already defined in registry.");
|
||||
register(identifier, value);
|
||||
@@ -87,25 +101,22 @@ public class OpenRegistryImpl<T> implements OpenRegistry<T> {
|
||||
objects.clear();
|
||||
}
|
||||
|
||||
public boolean register(String identifier, Entry<T> value) {
|
||||
if(!ID_PATTERN.matcher(identifier).matches())
|
||||
throw new IllegalArgumentException(
|
||||
"Registry ID must only contain alphanumeric characters, hyphens, and underscores. \"" + identifier +
|
||||
"\" is not a valid ID.");
|
||||
private boolean register(RegistryKey identifier, Entry<T> value) {
|
||||
boolean exists = objects.containsKey(identifier);
|
||||
objects.put(identifier, value);
|
||||
objectIDs.put(identifier.getID(), Pair.of(identifier, value));
|
||||
return exists;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Optional<T> get(@NotNull String identifier) {
|
||||
return Optional.ofNullable(objects.getOrDefault(identifier, (Entry<T>) NULL).getValue());
|
||||
public Optional<T> get(@NotNull RegistryKey key) {
|
||||
return Optional.ofNullable(objects.getOrDefault(key, (Entry<T>) NULL).getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@NotNull String identifier) {
|
||||
return objects.containsKey(identifier);
|
||||
public boolean contains(@NotNull RegistryKey key) {
|
||||
return objects.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,7 +125,7 @@ public class OpenRegistryImpl<T> implements OpenRegistry<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(@NotNull BiConsumer<String, T> consumer) {
|
||||
public void forEach(@NotNull BiConsumer<RegistryKey, T> consumer) {
|
||||
objects.forEach((id, entry) -> consumer.accept(id, entry.getRaw()));
|
||||
}
|
||||
|
||||
@@ -124,7 +135,7 @@ public class OpenRegistryImpl<T> implements OpenRegistry<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Set<String> keys() {
|
||||
public @NotNull Set<RegistryKey> keys() {
|
||||
return objects.keySet();
|
||||
}
|
||||
|
||||
@@ -133,8 +144,16 @@ public class OpenRegistryImpl<T> implements OpenRegistry<T> {
|
||||
return typeKey;
|
||||
}
|
||||
|
||||
public Map<String, T> getDeadEntries() {
|
||||
Map<String, T> dead = new HashMap<>();
|
||||
@Override
|
||||
public Map<RegistryKey, T> get(String id) {
|
||||
return objectIDs
|
||||
.get(id)
|
||||
.stream()
|
||||
.collect(HashMap::new, (map, pair) -> map.put(pair.getLeft(), pair.getRight().getValue()), Map::putAll);
|
||||
}
|
||||
|
||||
public Map<RegistryKey, T> getDeadEntries() {
|
||||
Map<RegistryKey, T> dead = new HashMap<>();
|
||||
objects.forEach((id, entry) -> {
|
||||
if(entry.dead()) dead.put(id, entry.value); // dont increment value here.
|
||||
});
|
||||
@@ -142,7 +161,7 @@ public class OpenRegistryImpl<T> implements OpenRegistry<T> {
|
||||
}
|
||||
|
||||
|
||||
protected static final class Entry<T> {
|
||||
private static final class Entry<T> {
|
||||
private final T value;
|
||||
private final AtomicInteger access = new AtomicInteger(0);
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import com.dfsek.terra.api.Platform;
|
||||
@@ -46,14 +47,14 @@ public class ConfigRegistry extends OpenRegistryImpl<ConfigPack> {
|
||||
|
||||
public void load(File folder, Platform platform) throws ConfigException {
|
||||
ConfigPack pack = new ConfigPackImpl(folder, platform);
|
||||
register(pack.getID(), pack);
|
||||
register(pack.getRegistryKey(), pack);
|
||||
}
|
||||
|
||||
public boolean loadAll(Platform platform) {
|
||||
boolean valid = true;
|
||||
File packsFolder = new File(platform.getDataFolder(), "packs");
|
||||
packsFolder.mkdirs();
|
||||
for(File dir : packsFolder.listFiles(File::isDirectory)) {
|
||||
for(File dir : Objects.requireNonNull(packsFolder.listFiles(File::isDirectory))) {
|
||||
try {
|
||||
load(dir, platform);
|
||||
} catch(ConfigException e) {
|
||||
@@ -61,7 +62,8 @@ public class ConfigRegistry extends OpenRegistryImpl<ConfigPack> {
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
for(File zip : packsFolder.listFiles(file -> file.getName().endsWith(".zip") || file.getName().endsWith(".terra"))) {
|
||||
for(File zip : Objects.requireNonNull(
|
||||
packsFolder.listFiles(file -> file.getName().endsWith(".zip") || file.getName().endsWith(".terra")))) {
|
||||
try {
|
||||
logger.info("Loading ZIP archive: {}", zip.getName());
|
||||
load(new ZipFile(zip), platform);
|
||||
@@ -75,6 +77,6 @@ public class ConfigRegistry extends OpenRegistryImpl<ConfigPack> {
|
||||
|
||||
public void load(ZipFile file, Platform platform) throws ConfigException {
|
||||
ConfigPackImpl pack = new ConfigPackImpl(file, platform);
|
||||
register(pack.getTemplate().getID(), pack);
|
||||
register(pack.getRegistryKey(), pack);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user