Merge branch 'dev/7.0-2' into dev/layered-generator

This commit is contained in:
Zoë Gidiere
2025-06-03 13:44:03 -06:00
798 changed files with 11273 additions and 10014 deletions

View File

@@ -51,6 +51,7 @@ import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.addon.bootstrap.BootstrapAddonClassLoader;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.MetaPack;
import com.dfsek.terra.api.config.PluginConfig;
import com.dfsek.terra.api.event.EventManager;
import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent;
@@ -72,6 +73,8 @@ import com.dfsek.terra.registry.CheckedRegistryImpl;
import com.dfsek.terra.registry.LockedRegistryImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
import com.dfsek.terra.registry.master.ConfigRegistry;
import com.dfsek.terra.registry.master.ConfigRegistry.PackLoadFailuresException;
import com.dfsek.terra.registry.master.MetaConfigRegistry;
/**
@@ -85,9 +88,12 @@ public abstract class AbstractPlatform implements Platform {
private static final MutableBoolean LOADED = new MutableBoolean(false);
private final EventManager eventManager = new EventManagerImpl();
private final ConfigRegistry configRegistry = new ConfigRegistry();
private final MetaConfigRegistry metaConfigRegistry = new MetaConfigRegistry();
private final CheckedRegistry<ConfigPack> checkedConfigRegistry = new CheckedRegistryImpl<>(configRegistry);
private final CheckedRegistry<MetaPack> checkedMetaConfigRegistry = new CheckedRegistryImpl<>(metaConfigRegistry);
private final Profiler profiler = new ProfilerImpl();
private final GenericLoaders loaders = new GenericLoaders(this);
@@ -102,6 +108,10 @@ public abstract class AbstractPlatform implements Platform {
return configRegistry;
}
public MetaConfigRegistry getRawMetaConfigRegistry() {
return metaConfigRegistry;
}
protected Iterable<BaseAddon> platformAddon() {
return Collections.emptySet();
}
@@ -133,11 +143,8 @@ public abstract class AbstractPlatform implements Platform {
config.load(this); // load config.yml
if(config.dumpDefaultConfig()) {
dumpResources();
} else {
logger.info("Skipping resource dumping.");
}
dumpResources(config.getIgnoredResources());
if(config.isDebugProfiler()) { // if debug.profiler is enabled, start profiling
profiler.start();
@@ -147,11 +154,12 @@ public abstract class AbstractPlatform implements Platform {
eventManager.getHandler(FunctionalEventHandler.class)
.register(internalAddon, PlatformInitializationEvent.class)
.then(event -> {
logger.info("Loading config packs...");
configRegistry.loadAll(this);
logger.info("Loaded packs.");
})
.then(event -> loadConfigPacks())
.global();
eventManager.getHandler(FunctionalEventHandler.class)
.register(internalAddon, PlatformInitializationEvent.class)
.then(event -> loadMetaConfigPacks())
.global();
@@ -159,6 +167,38 @@ public abstract class AbstractPlatform implements Platform {
logger.info("Finished initialization.");
}
protected boolean loadConfigPacks() {
logger.info("Loading config packs...");
ConfigRegistry configRegistry = getRawConfigRegistry();
configRegistry.clear();
try {
configRegistry.loadAll(this);
} catch(IOException e) {
logger.error("Failed to load config packs", e);
return false;
} catch(PackLoadFailuresException e) {
e.getExceptions().forEach(ex -> logger.error("Failed to load config pack", ex));
return false;
}
return true;
}
protected boolean loadMetaConfigPacks() {
logger.info("Loading meta config packs...");
MetaConfigRegistry metaConfigRegistry = getRawMetaConfigRegistry();
metaConfigRegistry.clear();
try {
metaConfigRegistry.loadAll(this, configRegistry);
} catch(IOException e) {
logger.error("Failed to load meta config packs", e);
return false;
} catch(PackLoadFailuresException e) {
e.getExceptions().forEach(ex -> logger.error("Failed to meta load config pack", ex));
return false;
}
return true;
}
protected InternalAddon loadAddons() {
List<BaseAddon> addonList = new ArrayList<>();
@@ -216,7 +256,7 @@ public abstract class AbstractPlatform implements Platform {
return internalAddon;
}
protected void dumpResources() {
protected void dumpResources(List<String> ignoredResources) {
try(InputStream resourcesConfig = getClass().getResourceAsStream("/resources.yml")) {
if(resourcesConfig == null) {
logger.info("No resources config found. Skipping resource dumping.");
@@ -258,51 +298,55 @@ public abstract class AbstractPlatform implements Platform {
Map<String, List<String>> resources = new Yaml().load(resourceYaml);
resources.forEach((dir, entries) -> entries.forEach(entry -> {
String resourceClassPath = dir + "/" + entry;
String resourcePath = resourceClassPath.replace('/', File.separatorChar);
File resource = new File(getDataFolder(), resourcePath);
if(resource.exists())
return; // dont overwrite
if(ignoredResources.contains(dir) || ignoredResources.contains(entry) || ignoredResources.contains(resourceClassPath)) {
logger.info("Not dumping resource {} because it is ignored.", resourceClassPath);
} else {
String resourcePath = resourceClassPath.replace('/', File.separatorChar);
File resource = new File(getDataFolder(), resourcePath);
if(resource.exists())
return; // dont overwrite
try(InputStream is = getClass().getResourceAsStream("/" + resourceClassPath)) {
if(is == null) {
logger.error("Resource {} doesn't exist on the classpath!", resourcePath);
return;
try(InputStream is = getClass().getResourceAsStream("/" + resourceClassPath)) {
if(is == null) {
logger.error("Resource {} doesn't exist on the classpath!", resourcePath);
return;
}
paths
.stream()
.filter(Pair.testRight(resourcePath::startsWith))
.forEach(Pair.consumeLeft(path -> {
logger.info("Removing outdated resource {}, replacing with {}", path, resourcePath);
try {
Files.delete(path);
} catch(IOException e) {
throw new UncheckedIOException(e);
}
}));
if(pathsNoMajor
.stream()
.anyMatch(resourcePath::startsWith) && // if any share name
paths
.stream()
.map(Pair.unwrapRight())
.noneMatch(resourcePath::startsWith)) { // but dont share major version
logger.warn(
"Addon {} has a new major version available. It will not be automatically updated; you will need to " +
"ensure " +
"compatibility and update manually.",
resourcePath);
}
logger.info("Dumping resource {}.", resource.getAbsolutePath());
resource.getParentFile().mkdirs();
resource.createNewFile();
try(OutputStream os = new FileOutputStream(resource)) {
IOUtils.copy(is, os);
}
} catch(IOException e) {
throw new UncheckedIOException(e);
}
paths
.stream()
.filter(Pair.testRight(resourcePath::startsWith))
.forEach(Pair.consumeLeft(path -> {
logger.info("Removing outdated resource {}, replacing with {}", path, resourcePath);
try {
Files.delete(path);
} catch(IOException e) {
throw new UncheckedIOException(e);
}
}));
if(pathsNoMajor
.stream()
.anyMatch(resourcePath::startsWith) && // if any share name
paths
.stream()
.map(Pair.unwrapRight())
.noneMatch(resourcePath::startsWith)) { // but dont share major version
logger.warn(
"Addon {} has a new major version available. It will not be automatically updated; you will need to " +
"ensure " +
"compatibility and update manually.",
resourcePath);
}
logger.info("Dumping resource {}...", resource.getAbsolutePath());
resource.getParentFile().mkdirs();
resource.createNewFile();
try(OutputStream os = new FileOutputStream(resource)) {
IOUtils.copy(is, os);
}
} catch(IOException e) {
throw new UncheckedIOException(e);
}
}));
} catch(IOException e) {
@@ -310,6 +354,24 @@ public abstract class AbstractPlatform implements Platform {
}
}
public static int getGenerationThreadsWithReflection(String className, String fieldName, String project) {
try {
Class aClass = Class.forName(className);
int threads = aClass.getField(fieldName).getInt(null);
logger.info("{} found, setting {} generation threads.", project, threads);
return threads;
} catch(ClassNotFoundException e) {
logger.info("{} not found.", project);
} catch(NoSuchFieldException e) {
logger.warn("{} found, but {} field not found this probably means {0} has changed its code and " +
"Terra has not updated to reflect that.", project, fieldName);
} catch(IllegalAccessException e) {
logger.error("Failed to access {} field in {}, assuming 1 generation thread.", fieldName, project, e);
}
return 0;
}
@Override
public void register(TypeRegistry registry) {
loaders.register(registry);
@@ -325,6 +387,12 @@ public abstract class AbstractPlatform implements Platform {
return checkedConfigRegistry;
}
@Override
public @NotNull CheckedRegistry<MetaPack> getMetaConfigRegistry() {
return checkedMetaConfigRegistry;
}
@Override
public @NotNull Registry<BaseAddon> getAddons() {
return lockedAddonRegistry;
@@ -339,4 +407,9 @@ public abstract class AbstractPlatform implements Platform {
public @NotNull Profiler getProfiler() {
return profiler;
}
@Override
public int getGenerationThreads() {
return 1;
}
}

View File

@@ -19,6 +19,7 @@ package com.dfsek.terra.config;
import ca.solostudios.strata.version.Version;
import ca.solostudios.strata.version.VersionRange;
import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.tectonic.api.TypeRegistry;
import java.util.LinkedHashMap;
@@ -28,11 +29,10 @@ import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.tectonic.LoaderRegistrar;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.util.range.Range;
import com.dfsek.terra.api.util.collection.MaterialSet;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.util.vector.Vector3Int;
import com.dfsek.terra.config.loaders.ExpressionParserOptionsTemplate;
import com.dfsek.terra.config.loaders.LinkedHashMapLoader;
import com.dfsek.terra.config.loaders.MaterialSetLoader;
import com.dfsek.terra.config.loaders.ProbabilityCollectionLoader;
@@ -53,14 +53,15 @@ public class GenericLoaders implements LoaderRegistrar {
@Override
public void register(TypeRegistry registry) {
registry.registerLoader(ProbabilityCollection.class, new ProbabilityCollectionLoader())
.registerLoader(Range.class, new RangeLoader())
.registerLoader(Version.class, new VersionLoader())
.registerLoader(MaterialSet.class, new MaterialSetLoader())
.registerLoader(VersionRange.class, new VersionRangeLoader())
.registerLoader(LinkedHashMap.class, new LinkedHashMapLoader())
.registerLoader(Range.class, new RangeLoader())
.registerLoader(Version.class, new VersionLoader())
.registerLoader(MaterialSet.class, new MaterialSetLoader())
.registerLoader(VersionRange.class, new VersionRangeLoader())
.registerLoader(LinkedHashMap.class, new LinkedHashMapLoader())
.registerLoader(ParseOptions.class, ExpressionParserOptionsTemplate::new);
.registerLoader(Vector3.class, new Vector3Loader())
.registerLoader(Vector3Int.class, new Vector3IntLoader());
if(platform != null) {
registry.registerLoader(BaseAddon.class, platform.getAddons())
.registerLoader(BlockType.class, (type, object, configLoader, depthTracker) -> platform

View File

@@ -30,6 +30,8 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Collections;
import java.util.List;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.PluginConfig;
@@ -71,9 +73,9 @@ public class PluginConfigImpl implements ConfigTemplate, PluginConfig {
@Default
private int providerCache = 32;
@Value("dump-default")
@Value("ignored-resources")
@Default
private boolean dumpDefaultData = true;
private List<String> ignoredResources = Collections.emptyList();
@Value("script.max-recursion")
@Default
@@ -99,11 +101,6 @@ public class PluginConfigImpl implements ConfigTemplate, PluginConfig {
logger.info("Debug logging enabled.");
}
@Override
public boolean dumpDefaultConfig() {
return dumpDefaultData;
}
@Override
public boolean isDebugCommands() {
return debugCommands;
@@ -139,6 +136,11 @@ public class PluginConfigImpl implements ConfigTemplate, PluginConfig {
return samplerCache;
}
@Override
public List<String> getIgnoredResources() {
return ignoredResources;
}
@Override
public int getMaxRecursion() {
return maxRecursion;

View File

@@ -1,66 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.config.fileloaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
/**
* Load all {@code *.yml} files from a {@link java.nio.file.Path}.
*/
public class FolderLoader extends LoaderImpl {
private static final Logger logger = LoggerFactory.getLogger(FolderLoader.class);
private final Path path;
public FolderLoader(Path path) {
this.path = path;
}
@Override
public InputStream get(String singleFile) throws IOException {
return new FileInputStream(new File(path.toFile(), singleFile));
}
protected void load(String directory, String extension) {
File newPath = new File(path.toFile(), directory);
newPath.mkdirs();
try(Stream<Path> paths = Files.walk(newPath.toPath())) {
paths.filter(Files::isRegularFile).filter(file -> file.toString().toLowerCase().endsWith(extension)).forEach(file -> {
try {
String rel = newPath.toPath().relativize(file).toString();
streams.put(rel, new FileInputStream(file.toFile()));
} catch(FileNotFoundException e) {
logger.error("Could not find file to load", e);
}
});
} catch(IOException e) {
logger.error("Error while loading files", e);
}
}
}

View File

@@ -1,83 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.config.fileloaders;
import com.dfsek.tectonic.api.exception.ConfigException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import com.dfsek.terra.api.config.Loader;
public abstract class LoaderImpl implements Loader {
private static final Logger logger = LoggerFactory.getLogger(LoaderImpl.class);
protected final Map<String, InputStream> streams = new HashMap<>();
@Override
public Loader thenNames(Consumer<List<String>> consumer) throws ConfigException {
consumer.accept(new ArrayList<>(streams.keySet()));
return this;
}
@Override
public Loader thenEntries(Consumer<Set<Map.Entry<String, InputStream>>> consumer) throws ConfigException {
consumer.accept(streams.entrySet());
return this;
}
/**
* Open a subdirectory.
*
* @param directory Directory to open
* @param extension File extension
*/
@Override
public LoaderImpl open(String directory, String extension) {
if(!streams.isEmpty()) throw new IllegalStateException("Attempted to load new directory before closing existing InputStreams");
load(directory, extension);
return this;
}
/**
* Close all InputStreams opened.
*/
@Override
public Loader close() {
streams.forEach((name, input) -> {
try {
input.close();
} catch(IOException e) {
logger.error("Error occurred while loading", e);
}
});
streams.clear();
return this;
}
protected abstract void load(String directory, String extension);
}

View File

@@ -1,63 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.config.fileloaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class ZIPLoader extends LoaderImpl {
private static final Logger logger = LoggerFactory.getLogger(ZIPLoader.class);
private final ZipFile file;
public ZIPLoader(ZipFile file) {
this.file = file;
}
@Override
public InputStream get(String singleFile) throws IOException {
Enumeration<? extends ZipEntry> entries = file.entries();
while(entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(!entry.isDirectory() && entry.getName().equals(singleFile)) return file.getInputStream(entry);
}
throw new IllegalArgumentException("No such file: " + singleFile);
}
protected void load(String directory, String extension) {
Enumeration<? extends ZipEntry> entries = file.entries();
while(entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(!entry.isDirectory() && entry.getName().startsWith(directory) && entry.getName().endsWith(extension)) {
try {
String rel = entry.getName().substring(directory.length());
streams.put(rel, file.getInputStream(entry));
} catch(IOException e) {
logger.error("Error while loading file from zip", e);
}
}
}
}
}

View File

@@ -0,0 +1,21 @@
package com.dfsek.terra.config.loaders;
import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
public class ExpressionParserOptionsTemplate implements ObjectTemplate<ParseOptions> {
private static final ParseOptions DEFAULT_PARSE_OPTIONS = new ParseOptions();
@Value("use-let-expressions")
@Default
private boolean useLetExpressions = DEFAULT_PARSE_OPTIONS.useLetExpressions();
@Override
public ParseOptions get() {
return new ParseOptions(useLetExpressions);
}
}

View File

@@ -43,23 +43,27 @@ public class ProbabilityCollectionLoader implements TypeLoader<ProbabilityCollec
AnnotatedType generic = pType.getAnnotatedActualTypeArguments()[0];
if(o instanceof Map) {
Map<Object, Object> map = (Map<Object, Object>) o;
if (map.size() == 1) {
Object onlyKey = map.keySet().iterator().next();
return new ProbabilityCollection.Singleton<>(configLoader.loadType(generic, onlyKey, depthTracker));
}
for(Map.Entry<Object, Object> entry : map.entrySet()) {
collection.add(configLoader.loadType(generic, entry.getKey(), depthTracker.entry((String) entry.getKey())),
configLoader.loadType(Integer.class, entry.getValue(), depthTracker.entry((String) entry.getKey())));
}
} else if(o instanceof List) {
List<Map<Object, Object>> map = (List<Map<Object, Object>>) o;
if(map.size() == 1) {
Map<Object, Object> entry = map.get(0);
if(entry.size() == 1) {
for(Object value : entry.keySet()) {
List<Map<Object, Object>> list = (List<Map<Object, Object>>) o;
if(list.size() == 1) {
Map<Object, Object> map = list.getFirst();
if(map.size() == 1) {
for(Object value : map.keySet()) {
return new ProbabilityCollection.Singleton<>(configLoader.loadType(generic, value, depthTracker));
}
}
}
for(int i = 0; i < map.size(); i++) {
Map<Object, Object> l = map.get(i);
for(Entry<Object, Object> entry : l.entrySet()) {
for(int i = 0; i < list.size(); i++) {
Map<Object, Object> map = list.get(i);
for(Entry<Object, Object> entry : map.entrySet()) {
if(entry.getValue() == null) throw new LoadException("No probability defined for entry \"" + entry.getKey() + "\"",
depthTracker);
Object val = configLoader.loadType(generic, entry.getKey(), depthTracker.index(i).entry((String) entry.getKey()));

View File

@@ -30,8 +30,8 @@ import java.lang.reflect.AnnotatedType;
import java.util.Map;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.ConstantRange;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.util.range.ConstantRange;
import com.dfsek.terra.api.util.range.Range;
public class RangeLoader implements TypeLoader<Range> {

View File

@@ -27,10 +27,10 @@ import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.lang.reflect.AnnotatedType;
import java.nio.file.Files;
import java.util.concurrent.ConcurrentHashMap;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.Loader;
import com.dfsek.terra.api.properties.Properties;
@@ -39,12 +39,10 @@ import com.dfsek.terra.api.properties.Properties;
*/
@Deprecated
public class BufferedImageLoader implements TypeLoader<BufferedImage> {
private final Loader files;
private final ConfigPack pack;
public BufferedImageLoader(Loader files, ConfigPack pack) {
this.files = files;
public BufferedImageLoader(ConfigPack pack) {
this.pack = pack;
if(!pack.getContext().has(ImageCache.class))
pack.getContext().put(new ImageCache(new ConcurrentHashMap<>()));
@@ -55,7 +53,7 @@ public class BufferedImageLoader implements TypeLoader<BufferedImage> {
throws LoadException {
return pack.getContext().get(ImageCache.class).map.computeIfAbsent((String) c, s -> {
try {
return ImageIO.read(files.get(s));
return ImageIO.read(Files.newInputStream(pack.getRootPath().resolve(s)));
} catch(IOException e) {
throw new LoadException("Unable to load image", e, depthTracker);
}

View File

@@ -0,0 +1,17 @@
package com.dfsek.terra.config.pack;
import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.tectonic.api.config.template.ConfigTemplate;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;
public class ConfigPackExpressionOptionsTemplate implements ConfigTemplate {
@Value("expressions.options")
@Default
private ParseOptions parseOptions = new ParseOptions();
public ParseOptions getParseOptions() {
return parseOptions;
}
}

View File

@@ -19,6 +19,7 @@ package com.dfsek.terra.config.pack;
import ca.solostudios.strata.version.Version;
import ca.solostudios.strata.version.VersionRange;
import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.tectonic.api.TypeRegistry;
import com.dfsek.tectonic.api.config.Configuration;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
@@ -33,15 +34,15 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -51,15 +52,12 @@ import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.ConfigType;
import com.dfsek.terra.api.config.Loader;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.event.events.config.ConfigurationDiscoveryEvent;
import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent;
@@ -72,15 +70,12 @@ import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.tectonic.ShortcutLoader;
import com.dfsek.terra.api.util.generic.Construct;
import com.dfsek.terra.api.util.generic.pair.Pair;
import com.dfsek.terra.api.util.reflection.ReflectionUtil;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage;
import com.dfsek.terra.api.world.chunk.generation.util.provider.ChunkGeneratorProvider;
import com.dfsek.terra.config.fileloaders.FolderLoader;
import com.dfsek.terra.config.fileloaders.ZIPLoader;
import com.dfsek.terra.config.loaders.GenericTemplateSupplierLoader;
import com.dfsek.terra.config.loaders.config.BufferedImageLoader;
import com.dfsek.terra.config.preprocessor.MetaListLikePreprocessor;
@@ -107,7 +102,7 @@ public class ConfigPackImpl implements ConfigPack {
private final AbstractConfigLoader abstractConfigLoader = new AbstractConfigLoader();
private final ConfigLoader selfLoader = new ConfigLoader();
private final Platform platform;
private final Loader loader;
private final Path rootPath;
private final Map<BaseAddon, VersionRange> addons;
@@ -121,40 +116,31 @@ public class ConfigPackImpl implements ConfigPack {
private final RegistryKey key;
public ConfigPackImpl(File folder, Platform platform) {
this(new FolderLoader(folder.toPath()), Construct.construct(() -> {
try {
return new YamlConfiguration(new FileInputStream(new File(folder, "pack.yml")), "pack.yml");
} catch(FileNotFoundException e) {
throw new UncheckedIOException("No pack.yml file found in " + folder.getAbsolutePath(), e);
}
}), platform);
}
private final ParseOptions parseOptions;
public ConfigPackImpl(ZipFile file, Platform platform) {
this(new ZIPLoader(file), Construct.construct(() -> {
ZipEntry pack = null;
Enumeration<? extends ZipEntry> entries = file.entries();
while(entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(entry.getName().equals("pack.yml")) pack = entry;
}
if(pack == null) throw new IllegalArgumentException("No pack.yml file found in " + file.getName());
try {
return new YamlConfiguration(file.getInputStream(pack), "pack.yml");
} catch(IOException e) {
throw new UncheckedIOException("Unable to load pack.yml from ZIP file", e);
}
}), platform);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private ConfigPackImpl(Loader loader, Configuration packManifest, Platform platform) {
@SuppressWarnings({ "rawtypes" })
public ConfigPackImpl(Path path, Platform platform) throws IOException {
long start = System.nanoTime();
this.loader = loader;
if(Files.notExists(path)) throw new FileNotFoundException("Could not load config pack, " + path + " does not exist");
if(Files.isDirectory(path)) {
this.rootPath = path;
} else if(Files.isRegularFile(path)) {
if(!path.getFileName().toString().endsWith(".zip")) {
throw new IOException("Could not load config pack, file " + path + " is not a zip");
}
FileSystem zipfs = FileSystems.newFileSystem(path);
this.rootPath = zipfs.getPath("/");
} else {
throw new IOException("Could not load config pack from " + path);
}
Path packManifestPath = rootPath.resolve("pack.yml");
if(Files.notExists(packManifestPath)) throw new IOException("No pack.yml found in " + path);
Configuration packManifest = new YamlConfiguration(Files.newInputStream(packManifestPath),
packManifestPath.getFileName().toString());
this.platform = platform;
this.configTypeRegistry = createConfigRegistry();
@@ -168,6 +154,11 @@ public class ConfigPackImpl implements ConfigPack {
selfLoader.load(addonsTemplate, packManifest);
this.addons = addonsTemplate.getAddons();
ConfigPackExpressionOptionsTemplate expressionOptionsTemplate = new ConfigPackExpressionOptionsTemplate();
selfLoader.load(expressionOptionsTemplate, packManifest);
this.parseOptions = expressionOptionsTemplate.getParseOptions();
Map<String, Configuration> configurations = discoverConfigurations();
registerMeta(configurations);
@@ -232,13 +223,13 @@ public class ConfigPackImpl implements ConfigPack {
ConfigPackPostTemplate packPostTemplate = new ConfigPackPostTemplate();
selfLoader.load(packPostTemplate, packManifest);
seededBiomeProvider =
template.getBiomeCache() ? packPostTemplate.getProviderBuilder().caching() : packPostTemplate.getProviderBuilder();
template.getBiomeCache() ? packPostTemplate.getProviderBuilder().caching(platform) : packPostTemplate.getProviderBuilder();
checkDeadEntries();
}
private Map<String, Configuration> discoverConfigurations() {
Map<String, Configuration> configurations = new HashMap<>();
platform.getEventManager().callEvent(new ConfigurationDiscoveryEvent(this, loader,
platform.getEventManager().callEvent(new ConfigurationDiscoveryEvent(this,
(s, c) -> configurations.put(s.replace("\\", "/"),
c))); // Create all the configs.
return configurations;
@@ -261,7 +252,7 @@ public class ConfigPackImpl implements ConfigPack {
selfLoader.registerPreprocessor(Meta.class, valuePreprocessor);
abstractConfigLoader.registerPreprocessor(Meta.class, valuePreprocessor);
MetaNumberPreprocessor numberPreprocessor = new MetaNumberPreprocessor(configurations);
MetaNumberPreprocessor numberPreprocessor = new MetaNumberPreprocessor(configurations, parseOptions);
selfLoader.registerPreprocessor(Meta.class, numberPreprocessor);
abstractConfigLoader.registerPreprocessor(Meta.class, numberPreprocessor);
}
@@ -283,7 +274,7 @@ public class ConfigPackImpl implements ConfigPack {
@Override
public void register(TypeRegistry registry) {
registry.registerLoader(ConfigType.class, configTypeRegistry)
.registerLoader(BufferedImage.class, new BufferedImageLoader(loader, this));
.registerLoader(BufferedImage.class, new BufferedImageLoader(this));
registryMap.forEach(registry::registerLoader);
shortcuts.forEach(registry::registerLoader); // overwrite with delegated shortcuts if present
}
@@ -309,7 +300,6 @@ public class ConfigPackImpl implements ConfigPack {
return seededBiomeProvider;
}
@SuppressWarnings("unchecked")
@Override
public <T> CheckedRegistry<T> getOrCreateRegistry(TypeKey<T> typeKey) {
return (CheckedRegistry<T>) registryMap.computeIfAbsent(typeKey.getType(), c -> {
@@ -348,8 +338,8 @@ public class ConfigPackImpl implements ConfigPack {
}
@Override
public Loader getLoader() {
return loader;
public Path getRootPath() {
return rootPath;
}
@Override
@@ -362,7 +352,12 @@ public class ConfigPackImpl implements ConfigPack {
return template.getVersion();
}
@SuppressWarnings("unchecked,rawtypes")
@Override
public ParseOptions getExpressionParseOptions() {
return parseOptions;
}
@SuppressWarnings("rawtypes")
@Override
public <T> ConfigPack registerShortcut(TypeKey<T> clazz, String shortcut, ShortcutLoader<T> loader) {
ShortcutHolder<?> holder = shortcuts
@@ -406,12 +401,10 @@ public class ConfigPackImpl implements ConfigPack {
}
@Override
@SuppressWarnings("unchecked")
public <T> CheckedRegistry<T> getRegistry(Type type) {
return (CheckedRegistry<T>) registryMap.get(type);
}
@SuppressWarnings("unchecked")
@Override
public <T> CheckedRegistry<T> getCheckedRegistry(Type type) throws IllegalStateException {
return (CheckedRegistry<T>) registryMap.get(type);

View File

@@ -0,0 +1,215 @@
package com.dfsek.terra.config.pack;
import ca.solostudios.strata.version.Version;
import com.dfsek.tectonic.api.TypeRegistry;
import com.dfsek.tectonic.api.config.Configuration;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.MetaPack;
import com.dfsek.terra.api.properties.Context;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.util.reflection.ReflectionUtil;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.config.loaders.GenericTemplateSupplierLoader;
import com.dfsek.terra.registry.CheckedRegistryImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
import com.dfsek.terra.registry.master.ConfigRegistry;
public class MetaPackImpl implements MetaPack {
private static final Pattern PATTERN = Pattern.compile(", ");
private static final Logger logger = LoggerFactory.getLogger(MetaPackImpl.class);
private final MetaPackTemplate template = new MetaPackTemplate();
private final Platform platform;
private final Path rootPath;
private final Map<String, ConfigPack> packs = new HashMap<>();
private final ConfigLoader selfLoader = new ConfigLoader();
private final Context context = new Context();
private final RegistryKey key;
private final Map<Type, CheckedRegistryImpl<?>> registryMap = new HashMap<>();
private final AbstractConfigLoader abstractConfigLoader = new AbstractConfigLoader();
private final String author;
public MetaPackImpl(Path path, Platform platform, ConfigRegistry configRegistry) throws IOException {
long start = System.nanoTime();
if(Files.notExists(path)) throw new FileNotFoundException("Could not load metapack, " + path + " does not exist");
if(Files.isDirectory(path)) {
this.rootPath = path;
} else if(Files.isRegularFile(path)) {
if(!path.getFileName().toString().endsWith(".zip")) {
throw new IOException("Could not load metapack, file " + path + " is not a zip");
}
FileSystem zipfs = FileSystems.newFileSystem(path);
this.rootPath = zipfs.getPath("/");
} else {
throw new IOException("Could not load metapack from " + path);
}
Path packManifestPath = rootPath.resolve("metapack.yml");
if(Files.notExists(packManifestPath)) throw new IOException("No metapack.yml found in " + path);
Configuration packManifest = new YamlConfiguration(Files.newInputStream(packManifestPath),
packManifestPath.getFileName().toString());
this.platform = platform;
register(selfLoader);
platform.register(selfLoader);
register(abstractConfigLoader);
platform.register(abstractConfigLoader);
selfLoader.load(template, packManifest);
String namespace;
String id;
if(template.getID().contains(":")) {
namespace = template.getID().substring(0, template.getID().indexOf(":"));
id = template.getID().substring(template.getID().indexOf(":") + 1);
} else {
id = template.getID();
namespace = template.getID();
}
this.key = RegistryKey.of(namespace, id);
logger.info("Loading metapack \"{}:{}\"", id, namespace);
template.getPacks().forEach((k, v) -> {
RegistryKey registryKey = RegistryKey.parse(v);
if(configRegistry.contains(registryKey)) {
packs.put(k, configRegistry.get(registryKey).get());
logger.info("Linked config pack \"{}\" to metapack \"{}:{}\".", v, namespace, id);
} else {
logger.warn("Failed to link config pack \"{}\" to metapack \"{}:{}\".", v, namespace, id);
}
});
HashSet<String> authors = new HashSet<>();
packs.forEach((k, v) -> {
authors.addAll(Arrays.asList(PATTERN.split(v.getAuthor())));
});
authors.addAll(Arrays.asList(PATTERN.split(template.getAuthor())));
this.author = String.join(", ", authors);
logger.info("Loaded metapack \"{}:{}\" v{} by {} in {}ms.",
namespace, id, getVersion().getFormatted(), author, (System.nanoTime() - start) / 1000000.0D);
}
@Override
public String getAuthor() {
return author;
}
@Override
public Version getVersion() {
return template.getVersion();
}
@Override
public Map<String, ConfigPack> packs() {
return packs;
}
@Override
public Context getContext() {
return context;
}
@Override
public RegistryKey getRegistryKey() {
return key;
}
@Override
public <T> CheckedRegistry<T> getRegistry(Type type) {
return (CheckedRegistry<T>) registryMap.get(type);
}
@Override
public <T> CheckedRegistry<T> getCheckedRegistry(Type type) throws IllegalStateException {
return (CheckedRegistry<T>) registryMap.get(type);
}
@Override
public <T> CheckedRegistry<T> getOrCreateRegistry(TypeKey<T> typeKey) {
return (CheckedRegistry<T>) registryMap.computeIfAbsent(typeKey.getType(), c -> {
OpenRegistry<T> registry = new OpenRegistryImpl<>(typeKey);
selfLoader.registerLoader(c, registry);
abstractConfigLoader.registerLoader(c, registry);
logger.debug("Registered loader for registry of class {}", ReflectionUtil.typeToString(c));
if(typeKey.getType() instanceof ParameterizedType param) {
Type base = param.getRawType();
if(base instanceof Class // should always be true but we'll check anyways
&& Supplier.class.isAssignableFrom((Class<?>) base)) { // If it's a supplier
Type supplied = param.getActualTypeArguments()[0]; // Grab the supplied type
if(supplied instanceof ParameterizedType suppliedParam) {
Type suppliedBase = suppliedParam.getRawType();
if(suppliedBase instanceof Class // should always be true but we'll check anyways
&& ObjectTemplate.class.isAssignableFrom((Class<?>) suppliedBase)) {
Type templateType = suppliedParam.getActualTypeArguments()[0];
GenericTemplateSupplierLoader<?> loader = new GenericTemplateSupplierLoader<>(
(Registry<Supplier<ObjectTemplate<Supplier<ObjectTemplate<?>>>>>) registry);
selfLoader.registerLoader(templateType, loader);
abstractConfigLoader.registerLoader(templateType, loader);
logger.debug("Registered template loader for registry of class {}", ReflectionUtil.typeToString(templateType));
}
}
}
}
return new CheckedRegistryImpl<>(registry);
});
}
@Override
public <T> MetaPackImpl applyLoader(Type type, TypeLoader<T> loader) {
abstractConfigLoader.registerLoader(type, loader);
selfLoader.registerLoader(type, loader);
return this;
}
@Override
public <T> MetaPackImpl applyLoader(Type type, Supplier<ObjectTemplate<T>> loader) {
abstractConfigLoader.registerLoader(type, loader);
selfLoader.registerLoader(type, loader);
return this;
}
@Override
public void register(TypeRegistry registry) {
registryMap.forEach(registry::registerLoader);
}
}

View File

@@ -0,0 +1,41 @@
package com.dfsek.terra.config.pack;
import ca.solostudios.strata.version.Version;
import com.dfsek.tectonic.api.config.template.ConfigTemplate;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import java.util.Map;
@SuppressWarnings({ "unused", "FieldMayBeFinal" })
public class MetaPackTemplate implements ConfigTemplate {
@Value("id")
private String id;
@Value("author")
@Default
private String author = "Anon Y. Mous";
@Value("version")
private Version version;
@Value("packs")
private Map<String, String> packs;
public String getID() {
return id;
}
public String getAuthor() {
return author;
}
public Version getVersion() {
return version;
}
public Map<String, String> getPacks() {
return packs;
}
}

View File

@@ -18,28 +18,30 @@
package com.dfsek.terra.config.preprocessor;
import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.tectonic.api.config.Configuration;
import com.dfsek.tectonic.api.depth.DepthTracker;
import com.dfsek.tectonic.api.exception.LoadException;
import com.dfsek.tectonic.api.loader.ConfigLoader;
import com.dfsek.tectonic.api.preprocessor.Result;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.reflection.TypeKey;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.AnnotatedType;
import java.util.Map;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.reflection.TypeKey;
public class MetaNumberPreprocessor extends MetaPreprocessor<Meta> {
public static final TypeKey<String> META_STRING_KEY = new TypeKey<@Meta String>() {
};
private final ParseOptions parseOptions;
public MetaNumberPreprocessor(Map<String, Configuration> configs) {
public MetaNumberPreprocessor(Map<String, Configuration> configs, ParseOptions parseOptions) {
super(configs);
this.parseOptions = parseOptions;
}
private static boolean isNumber(Class<?> clazz) {
@@ -57,7 +59,7 @@ public class MetaNumberPreprocessor extends MetaPreprocessor<Meta> {
if(t.getType() instanceof Class && isNumber((Class<?>) t.getType()) && c instanceof String) {
String expression = (String) loader.loadType(META_STRING_KEY.getAnnotatedType(), c, depthTracker);
try {
return (Result<T>) Result.overwrite(new Parser().eval(expression), depthTracker);
return (Result<T>) Result.overwrite(new Parser(parseOptions).eval(expression), depthTracker);
} catch(ParseException e) {
throw new LoadException("Invalid expression: ", e, depthTracker);
}

View File

@@ -57,7 +57,7 @@ public class ProfilerImpl implements Profiler {
Stack<Frame> stack = THREAD_STACK.get();
stack.push(new Frame(stack.isEmpty() ? frame : stack.peek().getId() + "." + frame));
} else SAFE.set(false);
} else SAFE.set(false);
}
}
@Override
@@ -99,6 +99,7 @@ public class ProfilerImpl implements Profiler {
public void stop() {
logger.info("Stopping Terra profiler");
running = false;
SAFE.set(false);
}
@Override

View File

@@ -17,14 +17,13 @@
package com.dfsek.terra.registry.master;
import com.dfsek.tectonic.api.exception.ConfigException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.zip.ZipFile;
import java.io.Serial;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigPack;
@@ -37,44 +36,42 @@ import com.dfsek.terra.registry.OpenRegistryImpl;
* Class to hold config packs
*/
public class ConfigRegistry extends OpenRegistryImpl<ConfigPack> {
private static final Logger logger = LoggerFactory.getLogger(ConfigRegistry.class);
public ConfigRegistry() {
super(TypeKey.of(ConfigPack.class));
}
public void load(File folder, Platform platform) throws ConfigException {
ConfigPack pack = new ConfigPackImpl(folder, platform);
registerChecked(pack.getRegistryKey(), pack);
public void loadAll(Platform platform) throws IOException, PackLoadFailuresException {
Path packsDirectory = platform.getDataFolder().toPath().resolve("packs");
Files.createDirectories(packsDirectory);
List<IOException> failedLoads = new ArrayList<>();
try(Stream<Path> packs = Files.list(packsDirectory)) {
packs.forEach(path -> {
try {
ConfigPack pack = new ConfigPackImpl(path, platform);
registerChecked(pack.getRegistryKey(), pack);
} catch(IOException e) {
failedLoads.add(e);
}
});
}
if(!failedLoads.isEmpty()) {
throw new PackLoadFailuresException(failedLoads);
}
}
public boolean loadAll(Platform platform) {
boolean valid = true;
File packsFolder = new File(platform.getDataFolder(), "packs");
packsFolder.mkdirs();
for(File dir : Objects.requireNonNull(packsFolder.listFiles(File::isDirectory))) {
try {
load(dir, platform);
} catch(ConfigException e) {
logger.error("Error loading config pack {}", dir.getName(), e);
valid = false;
}
}
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);
} catch(IOException | ConfigException e) {
logger.error("Error loading config pack {}", zip.getName(), e);
valid = false;
}
}
return valid;
}
public static class PackLoadFailuresException extends Exception {
@Serial
private static final long serialVersionUID = 538998844645186306L;
public void load(ZipFile file, Platform platform) throws ConfigException {
ConfigPackImpl pack = new ConfigPackImpl(file, platform);
registerChecked(pack.getRegistryKey(), pack);
private final List<Throwable> exceptions;
public PackLoadFailuresException(List<? extends Throwable> exceptions) {
this.exceptions = (List<Throwable>) exceptions;
}
public List<Throwable> getExceptions() {
return exceptions;
}
}
}

View File

@@ -0,0 +1,62 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.registry.master;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.MetaPack;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.config.pack.MetaPackImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
import com.dfsek.terra.registry.master.ConfigRegistry.PackLoadFailuresException;
/**
* Class to hold config packs
*/
public class MetaConfigRegistry extends OpenRegistryImpl<MetaPack> {
public MetaConfigRegistry() {
super(TypeKey.of(MetaPack.class));
}
public void loadAll(Platform platform, ConfigRegistry configRegistry) throws IOException, PackLoadFailuresException {
Path packsDirectory = platform.getDataFolder().toPath().resolve("metapacks");
Files.createDirectories(packsDirectory);
List<IOException> failedLoads = new ArrayList<>();
try(Stream<Path> packs = Files.list(packsDirectory)) {
packs.forEach(path -> {
try {
MetaPack pack = new MetaPackImpl(path, platform, configRegistry);
registerChecked(pack.getRegistryKey(), pack);
} catch(IOException e) {
failedLoads.add(e);
}
});
}
if(!failedLoads.isEmpty()) {
throw new PackLoadFailuresException(failedLoads);
}
}
}

View File

@@ -10,11 +10,13 @@ debug:
log: false
profiler: false
script: false
dump-default: true
biome-search-resolution: 4
cache:
structure: 32
sampler: 128
biome-provider: 32
script:
max-recursion: 1000
max-recursion: 1000
ignored-resources:
# - "addons"
# - "packs"

View File

@@ -1,3 +1,4 @@
import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.tectonic.api.config.Configuration;
import com.dfsek.tectonic.api.config.template.ConfigTemplate;
import com.dfsek.tectonic.api.config.template.annotations.Value;
@@ -32,7 +33,7 @@ public class MetaTest {
loader.registerPreprocessor(Meta.class, new MetaStringPreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaListLikePreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaMapPreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaNumberPreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaNumberPreprocessor(configurationMap, new ParseOptions()));
loader.registerPreprocessor(Meta.class, new MetaValuePreprocessor(configurationMap));
@@ -53,7 +54,7 @@ public class MetaTest {
loader.registerPreprocessor(Meta.class, new MetaStringPreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaListLikePreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaMapPreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaNumberPreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaNumberPreprocessor(configurationMap, new ParseOptions()));
loader.registerPreprocessor(Meta.class, new MetaValuePreprocessor(configurationMap));
@@ -75,7 +76,7 @@ public class MetaTest {
loader.registerPreprocessor(Meta.class, new MetaStringPreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaListLikePreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaMapPreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaNumberPreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaNumberPreprocessor(configurationMap, new ParseOptions()));
loader.registerPreprocessor(Meta.class, new MetaValuePreprocessor(configurationMap));
@@ -96,7 +97,7 @@ public class MetaTest {
loader.registerPreprocessor(Meta.class, new MetaStringPreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaListLikePreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaMapPreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaNumberPreprocessor(configurationMap));
loader.registerPreprocessor(Meta.class, new MetaNumberPreprocessor(configurationMap, new ParseOptions()));
loader.registerPreprocessor(Meta.class, new MetaValuePreprocessor(configurationMap));

View File

@@ -17,8 +17,6 @@
package registry;
import org.junit.jupiter.api.Test;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.registry.exception.DuplicateEntryException;
@@ -27,7 +25,10 @@ import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.registry.CheckedRegistryImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
public class RegistryTest {