mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-18 22:30:00 +00:00
Merge branch 'dev/7.0-2' into dev/layered-generator
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user