mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-11 10:16:15 +00:00
Merge remote-tracking branch 'origin/master' into dev/layered-generator
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
dependencies {
|
||||
api(project(":common:api"))
|
||||
api(project(":common:implementation:bootstrap-addon-loader"))
|
||||
|
||||
|
||||
testImplementation("org.slf4j", "slf4j-api", Versions.Libraries.slf4j)
|
||||
|
||||
|
||||
implementation("commons-io", "commons-io", Versions.Libraries.Internal.apacheIO)
|
||||
|
||||
|
||||
implementation("org.apache.commons", "commons-text", Versions.Libraries.Internal.apacheText)
|
||||
implementation("com.dfsek.tectonic", "yaml", Versions.Libraries.tectonic)
|
||||
|
||||
implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
|
||||
|
||||
|
||||
|
||||
|
||||
implementation("com.dfsek", "paralithic", Versions.Libraries.paralithic)
|
||||
}
|
||||
|
||||
@@ -81,41 +81,41 @@ import com.dfsek.terra.registry.master.ConfigRegistry;
|
||||
*/
|
||||
public abstract class AbstractPlatform implements Platform {
|
||||
private static final Logger logger = LoggerFactory.getLogger(AbstractPlatform.class);
|
||||
|
||||
|
||||
private static final MutableBoolean LOADED = new MutableBoolean(false);
|
||||
private final EventManager eventManager = new EventManagerImpl();
|
||||
private final ConfigRegistry configRegistry = new ConfigRegistry();
|
||||
|
||||
|
||||
private final CheckedRegistry<ConfigPack> checkedConfigRegistry = new CheckedRegistryImpl<>(configRegistry);
|
||||
|
||||
|
||||
private final Profiler profiler = new ProfilerImpl();
|
||||
|
||||
|
||||
private final GenericLoaders loaders = new GenericLoaders(this);
|
||||
|
||||
|
||||
private final PluginConfigImpl config = new PluginConfigImpl();
|
||||
|
||||
|
||||
private final CheckedRegistry<BaseAddon> addonRegistry = new CheckedRegistryImpl<>(new OpenRegistryImpl<>(TypeKey.of(BaseAddon.class)));
|
||||
|
||||
|
||||
private final Registry<BaseAddon> lockedAddonRegistry = new LockedRegistryImpl<>(addonRegistry);
|
||||
|
||||
|
||||
public ConfigRegistry getRawConfigRegistry() {
|
||||
return configRegistry;
|
||||
}
|
||||
|
||||
|
||||
protected Iterable<BaseAddon> platformAddon() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
|
||||
protected void load() {
|
||||
if(LOADED.get()) {
|
||||
throw new IllegalStateException(
|
||||
"Someone tried to initialize Terra, but Terra has already initialized. This is most likely due to a broken platform " +
|
||||
"implementation, or a misbehaving mod.");
|
||||
"Someone tried to initialize Terra, but Terra has already initialized. This is most likely due to a broken platform " +
|
||||
"implementation, or a misbehaving mod.");
|
||||
}
|
||||
LOADED.set(true);
|
||||
|
||||
|
||||
logger.info("Initializing Terra...");
|
||||
|
||||
|
||||
try(InputStream stream = getClass().getResourceAsStream("/config.yml")) {
|
||||
logger.info("Loading config.yml");
|
||||
File configFile = new File(getDataFolder(), "config.yml");
|
||||
@@ -130,79 +130,79 @@ public abstract class AbstractPlatform implements Platform {
|
||||
} catch(IOException e) {
|
||||
logger.error("Error loading config.yml resource from jar", e);
|
||||
}
|
||||
|
||||
|
||||
config.load(this); // load config.yml
|
||||
|
||||
|
||||
if(config.dumpDefaultConfig()) {
|
||||
dumpResources();
|
||||
} else {
|
||||
logger.info("Skipping resource dumping.");
|
||||
}
|
||||
|
||||
|
||||
if(config.isDebugProfiler()) { // if debug.profiler is enabled, start profiling
|
||||
profiler.start();
|
||||
}
|
||||
|
||||
|
||||
InternalAddon internalAddon = loadAddons();
|
||||
|
||||
|
||||
eventManager.getHandler(FunctionalEventHandler.class)
|
||||
.register(internalAddon, PlatformInitializationEvent.class)
|
||||
.then(event -> {
|
||||
logger.info("Loading config packs...");
|
||||
configRegistry.loadAll(this);
|
||||
logger.info("Loaded packs.");
|
||||
})
|
||||
.global();
|
||||
|
||||
|
||||
.register(internalAddon, PlatformInitializationEvent.class)
|
||||
.then(event -> {
|
||||
logger.info("Loading config packs...");
|
||||
configRegistry.loadAll(this);
|
||||
logger.info("Loaded packs.");
|
||||
})
|
||||
.global();
|
||||
|
||||
|
||||
logger.info("Terra addons successfully loaded.");
|
||||
logger.info("Finished initialization.");
|
||||
}
|
||||
|
||||
|
||||
protected InternalAddon loadAddons() {
|
||||
List<BaseAddon> addonList = new ArrayList<>();
|
||||
|
||||
|
||||
InternalAddon internalAddon = new InternalAddon();
|
||||
|
||||
|
||||
addonList.add(internalAddon);
|
||||
|
||||
|
||||
platformAddon().forEach(addonList::add);
|
||||
|
||||
|
||||
BootstrapAddonLoader bootstrapAddonLoader = new BootstrapAddonLoader();
|
||||
|
||||
|
||||
Path addonsFolder = getDataFolder().toPath().resolve("addons");
|
||||
|
||||
|
||||
Injector<Platform> platformInjector = new InjectorImpl<>(this);
|
||||
platformInjector.addExplicitTarget(Platform.class);
|
||||
|
||||
|
||||
BootstrapAddonClassLoader bootstrapAddonClassLoader = new BootstrapAddonClassLoader(new URL[]{ }, getClass().getClassLoader());
|
||||
|
||||
|
||||
bootstrapAddonLoader.loadAddons(addonsFolder, bootstrapAddonClassLoader)
|
||||
.forEach(bootstrapAddon -> {
|
||||
platformInjector.inject(bootstrapAddon);
|
||||
|
||||
bootstrapAddon.loadAddons(addonsFolder, bootstrapAddonClassLoader)
|
||||
.forEach(addonList::add);
|
||||
});
|
||||
|
||||
.forEach(bootstrapAddon -> {
|
||||
platformInjector.inject(bootstrapAddon);
|
||||
|
||||
bootstrapAddon.loadAddons(addonsFolder, bootstrapAddonClassLoader)
|
||||
.forEach(addonList::add);
|
||||
});
|
||||
|
||||
addonList.sort(Comparator.comparing(StringIdentifiable::getID));
|
||||
if(logger.isInfoEnabled()) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("Loading ")
|
||||
.append(addonList.size())
|
||||
.append(" Terra addons:");
|
||||
|
||||
.append(addonList.size())
|
||||
.append(" Terra addons:");
|
||||
|
||||
for(BaseAddon addon : addonList) {
|
||||
builder.append("\n ")
|
||||
.append("- ")
|
||||
.append(addon.getID())
|
||||
.append("@")
|
||||
.append(addon.getVersion().getFormatted());
|
||||
.append("- ")
|
||||
.append(addon.getID())
|
||||
.append("@")
|
||||
.append(addon.getVersion().getFormatted());
|
||||
}
|
||||
|
||||
|
||||
logger.info(builder.toString());
|
||||
}
|
||||
|
||||
|
||||
DependencySorter sorter = new DependencySorter();
|
||||
addonList.forEach(sorter::add);
|
||||
sorter.sort().forEach(addon -> {
|
||||
@@ -212,48 +212,48 @@ public abstract class AbstractPlatform implements Platform {
|
||||
addonRegistry.register(addon.key(addon.getID()), addon);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return internalAddon;
|
||||
}
|
||||
|
||||
|
||||
protected void dumpResources() {
|
||||
try(InputStream resourcesConfig = getClass().getResourceAsStream("/resources.yml")) {
|
||||
if(resourcesConfig == null) {
|
||||
logger.info("No resources config found. Skipping resource dumping.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Path data = getDataFolder().toPath();
|
||||
|
||||
|
||||
Path addonsPath = data.resolve("addons");
|
||||
Files.createDirectories(addonsPath);
|
||||
Set<Pair<Path, String>> paths = Files
|
||||
.walk(addonsPath)
|
||||
.map(path -> Pair.of(path, data.relativize(path).toString()))
|
||||
|
||||
.map(Pair.mapRight(s -> {
|
||||
if(s.contains("+")) { // remove commit hash
|
||||
return s.substring(0, s.lastIndexOf('+'));
|
||||
}
|
||||
return s;
|
||||
}))
|
||||
|
||||
.filter(Pair.testRight(s -> s.contains("."))) // remove patch version
|
||||
.map(Pair.mapRight(s -> s.substring(0, s.lastIndexOf('.'))))
|
||||
|
||||
.filter(Pair.testRight(s -> s.contains("."))) // remove minor version
|
||||
.map(Pair.mapRight(s -> s.substring(0, s.lastIndexOf('.'))))
|
||||
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
.walk(addonsPath)
|
||||
.map(path -> Pair.of(path, data.relativize(path).toString()))
|
||||
|
||||
.map(Pair.mapRight(s -> {
|
||||
if(s.contains("+")) { // remove commit hash
|
||||
return s.substring(0, s.lastIndexOf('+'));
|
||||
}
|
||||
return s;
|
||||
}))
|
||||
|
||||
.filter(Pair.testRight(s -> s.contains("."))) // remove patch version
|
||||
.map(Pair.mapRight(s -> s.substring(0, s.lastIndexOf('.'))))
|
||||
|
||||
.filter(Pair.testRight(s -> s.contains("."))) // remove minor version
|
||||
.map(Pair.mapRight(s -> s.substring(0, s.lastIndexOf('.'))))
|
||||
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Set<String> pathsNoMajor = paths
|
||||
.stream()
|
||||
.filter(Pair.testRight(s -> s.contains(".")))
|
||||
.map(Pair.mapRight(s -> s.substring(0, s.lastIndexOf('.')))) // remove major version
|
||||
.map(Pair.unwrapRight())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
|
||||
.stream()
|
||||
.filter(Pair.testRight(s -> s.contains(".")))
|
||||
.map(Pair.mapRight(s -> s.substring(0, s.lastIndexOf('.')))) // remove major version
|
||||
.map(Pair.unwrapRight())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
|
||||
String resourceYaml = IOUtils.toString(resourcesConfig, StandardCharsets.UTF_8);
|
||||
Map<String, List<String>> resources = new Yaml().load(resourceYaml);
|
||||
resources.forEach((dir, entries) -> entries.forEach(entry -> {
|
||||
@@ -262,39 +262,39 @@ public abstract class AbstractPlatform implements Platform {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}));
|
||||
|
||||
.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
|
||||
.stream()
|
||||
.anyMatch(resourcePath::startsWith) && // if any share name
|
||||
paths
|
||||
.stream()
|
||||
.map(Pair.unwrapRight())
|
||||
.noneMatch(resourcePath::startsWith)) { // but dont share major version
|
||||
.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);
|
||||
"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();
|
||||
@@ -309,32 +309,32 @@ public abstract class AbstractPlatform implements Platform {
|
||||
logger.error("Error while dumping resources...", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void register(TypeRegistry registry) {
|
||||
loaders.register(registry);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull PluginConfig getTerraConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull CheckedRegistry<ConfigPack> getConfigRegistry() {
|
||||
return checkedConfigRegistry;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull Registry<BaseAddon> getAddons() {
|
||||
return lockedAddonRegistry;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull EventManager getEventManager() {
|
||||
return eventManager;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull Profiler getProfiler() {
|
||||
return profiler;
|
||||
|
||||
@@ -31,35 +31,35 @@ import com.dfsek.terra.api.addon.BaseAddon;
|
||||
public class DependencySorter {
|
||||
private final Map<String, BaseAddon> addons = new HashMap<>();
|
||||
private final Map<String, Boolean> visited = new HashMap<>();
|
||||
|
||||
|
||||
private final List<BaseAddon> addonList = new ArrayList<>();
|
||||
|
||||
|
||||
public void add(BaseAddon addon) {
|
||||
addons.put(addon.getID(), addon);
|
||||
visited.put(addon.getID(), false);
|
||||
addonList.add(addon);
|
||||
}
|
||||
|
||||
|
||||
private void sortDependencies(BaseAddon addon, List<BaseAddon> sort) {
|
||||
addon.getDependencies().forEach((id, range) -> {
|
||||
BaseAddon dependency = get(id, addon);
|
||||
|
||||
|
||||
if(!range.isSatisfiedBy(dependency.getVersion())) {
|
||||
throw new DependencyVersionException(
|
||||
"Addon " + addon.getID() + " specifies dependency on " + id + ", versions " + range.getFormatted() +
|
||||
", but non-matching version " + dependency.getVersion().getFormatted() + " is installed.");
|
||||
"Addon " + addon.getID() + " specifies dependency on " + id + ", versions " + range.getFormatted() +
|
||||
", but non-matching version " + dependency.getVersion().getFormatted() + " is installed.");
|
||||
}
|
||||
|
||||
|
||||
if(!visited.get(dependency.getID())) { // if we've not visited it yet
|
||||
visited.put(dependency.getID(), true); // we've visited it now
|
||||
|
||||
|
||||
sortDependencies(dependency, sort);
|
||||
|
||||
|
||||
sort.add(dependency); // add it to the list.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private BaseAddon get(String id, BaseAddon addon) {
|
||||
if(!addons.containsKey(id)) {
|
||||
throw new DependencyException("Addon " + addon.getID() + " specifies dependency on " + id + ", versions " +
|
||||
@@ -68,38 +68,38 @@ public class DependencySorter {
|
||||
}
|
||||
return addons.get(id);
|
||||
}
|
||||
|
||||
|
||||
private void checkDependencies(BaseAddon base, BaseAddon current) {
|
||||
current.getDependencies().forEach((id, range) -> {
|
||||
BaseAddon dependency = get(id, current);
|
||||
if(dependency.getID().equals(base.getID())) {
|
||||
throw new CircularDependencyException(
|
||||
"Addon " + base.getID() + " has circular dependency beginning with " + dependency.getID());
|
||||
"Addon " + base.getID() + " has circular dependency beginning with " + dependency.getID());
|
||||
}
|
||||
checkDependencies(base, dependency);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public List<BaseAddon> sort() {
|
||||
List<BaseAddon> sorted = new ArrayList<>();
|
||||
|
||||
|
||||
for(int i = addonList.size() - 1; i >= 0; i--) {
|
||||
BaseAddon addon = addonList.get(i);
|
||||
|
||||
|
||||
checkDependencies(addon, addon);
|
||||
|
||||
|
||||
addonList.remove(i);
|
||||
|
||||
|
||||
if(!visited.get(addon.getID())) {
|
||||
sortDependencies(addon, sorted);
|
||||
}
|
||||
|
||||
|
||||
if(!visited.get(addon.getID())) {
|
||||
sorted.add(addon);
|
||||
visited.put(addon.getID(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return sorted;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,17 +8,17 @@ import com.dfsek.terra.api.addon.BaseAddon;
|
||||
public class EphemeralAddon implements BaseAddon {
|
||||
private final Version version;
|
||||
private final String id;
|
||||
|
||||
|
||||
public EphemeralAddon(Version version, String id) {
|
||||
this.version = version;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Version getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getID() {
|
||||
return id;
|
||||
|
||||
@@ -25,16 +25,16 @@ import com.dfsek.terra.api.addon.BaseAddon;
|
||||
|
||||
public class InternalAddon implements BaseAddon {
|
||||
private static final Version VERSION = Versions.getVersion(1, 0, 0);
|
||||
|
||||
|
||||
public InternalAddon() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getID() {
|
||||
return "terra";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Version getVersion() {
|
||||
return VERSION;
|
||||
|
||||
@@ -23,11 +23,11 @@ import java.io.Serial;
|
||||
public class CircularDependencyException extends DependencyException {
|
||||
@Serial
|
||||
private static final long serialVersionUID = -6098780459461482651L;
|
||||
|
||||
|
||||
public CircularDependencyException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
public CircularDependencyException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
@@ -24,11 +24,11 @@ import java.io.Serial;
|
||||
public class DependencyException extends RuntimeException {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 4864727433635612759L;
|
||||
|
||||
|
||||
public DependencyException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
public DependencyException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ import java.io.Serial;
|
||||
public class DependencyVersionException extends DependencyException {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 3564288935278878135L;
|
||||
|
||||
|
||||
public DependencyVersionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
public DependencyVersionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
@@ -45,11 +45,11 @@ import com.dfsek.terra.config.loaders.VersionRangeLoader;
|
||||
|
||||
public class GenericLoaders implements LoaderRegistrar {
|
||||
private final Platform platform;
|
||||
|
||||
|
||||
public GenericLoaders(Platform platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void register(TypeRegistry registry) {
|
||||
registry.registerLoader(ProbabilityCollection.class, new ProbabilityCollectionLoader())
|
||||
@@ -63,10 +63,10 @@ public class GenericLoaders implements LoaderRegistrar {
|
||||
|
||||
if(platform != null) {
|
||||
registry.registerLoader(BaseAddon.class, platform.getAddons())
|
||||
.registerLoader(BlockType.class, (type, object, configLoader, depthTracker) -> platform
|
||||
.getWorldHandle().createBlockState((String) object).getBlockType())
|
||||
.registerLoader(BlockState.class, (type, object, configLoader, depthTracker) -> platform
|
||||
.getWorldHandle().createBlockState((String) object));
|
||||
.registerLoader(BlockType.class, (type, object, configLoader, depthTracker) -> platform
|
||||
.getWorldHandle().createBlockState((String) object).getBlockType())
|
||||
.registerLoader(BlockState.class, (type, object, configLoader, depthTracker) -> platform
|
||||
.getWorldHandle().createBlockState((String) object));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,43 +38,47 @@ import com.dfsek.terra.api.config.PluginConfig;
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
public class PluginConfigImpl implements ConfigTemplate, PluginConfig {
|
||||
private static final Logger logger = LoggerFactory.getLogger(PluginConfigImpl.class);
|
||||
|
||||
|
||||
@Value("debug.commands")
|
||||
@Default
|
||||
private boolean debugCommands = false;
|
||||
|
||||
|
||||
@Value("debug.profiler")
|
||||
@Default
|
||||
private boolean debugProfiler = false;
|
||||
|
||||
|
||||
@Value("debug.script")
|
||||
@Default
|
||||
private boolean debugScript = false;
|
||||
|
||||
|
||||
@Value("debug.log")
|
||||
@Default
|
||||
private boolean debugLog = false;
|
||||
|
||||
@Value("biome-search-resolution")
|
||||
@Default
|
||||
private int biomeSearch = 4;
|
||||
|
||||
|
||||
@Value("cache.structure")
|
||||
@Default
|
||||
private int structureCache = 32;
|
||||
|
||||
|
||||
@Value("cache.sampler")
|
||||
@Default
|
||||
private int samplerCache = 1024;
|
||||
|
||||
|
||||
@Value("cache.biome-provider")
|
||||
@Default
|
||||
private int providerCache = 32;
|
||||
|
||||
|
||||
@Value("dump-default")
|
||||
@Default
|
||||
private boolean dumpDefaultData = true;
|
||||
|
||||
|
||||
@Value("script.max-recursion")
|
||||
@Default
|
||||
private int maxRecursion = 1000;
|
||||
|
||||
|
||||
@Override
|
||||
public void load(Platform platform) {
|
||||
logger.info("Loading config values from config.yml");
|
||||
@@ -84,55 +88,62 @@ public class PluginConfigImpl implements ConfigTemplate, PluginConfig {
|
||||
} catch(ConfigException | IOException | UncheckedIOException e) {
|
||||
logger.error("Failed to load config", e);
|
||||
}
|
||||
|
||||
|
||||
if(debugCommands)
|
||||
logger.info("Debug commands enabled.");
|
||||
if(debugProfiler)
|
||||
logger.info("Debug profiler enabled.");
|
||||
if(debugScript)
|
||||
logger.info("Script debug blocks enabled.");
|
||||
if(debugLog)
|
||||
logger.info("Debug logging enabled.");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean dumpDefaultConfig() {
|
||||
return dumpDefaultData;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isDebugCommands() {
|
||||
return debugCommands;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isDebugProfiler() {
|
||||
return debugProfiler;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isDebugScript() {
|
||||
return debugScript;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isDebugLog() {
|
||||
return debugLog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBiomeSearchResolution() {
|
||||
return biomeSearch;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getStructureCache() {
|
||||
return structureCache;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getSamplerCache() {
|
||||
return samplerCache;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getMaxRecursion() {
|
||||
return maxRecursion;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getProviderCache() {
|
||||
return providerCache;
|
||||
|
||||
@@ -35,18 +35,18 @@ import java.util.stream.Stream;
|
||||
*/
|
||||
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();
|
||||
|
||||
@@ -35,21 +35,21 @@ 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.
|
||||
*
|
||||
@@ -62,7 +62,7 @@ public abstract class LoaderImpl implements Loader {
|
||||
load(directory, extension);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close all InputStreams opened.
|
||||
*/
|
||||
@@ -78,6 +78,6 @@ public abstract class LoaderImpl implements Loader {
|
||||
streams.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
protected abstract void load(String directory, String extension);
|
||||
}
|
||||
|
||||
@@ -29,13 +29,13 @@ 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();
|
||||
@@ -45,7 +45,7 @@ public class ZIPLoader extends LoaderImpl {
|
||||
}
|
||||
throw new IllegalArgumentException("No such file: " + singleFile);
|
||||
}
|
||||
|
||||
|
||||
protected void load(String directory, String extension) {
|
||||
Enumeration<? extends ZipEntry> entries = file.entries();
|
||||
while(entries.hasMoreElements()) {
|
||||
|
||||
@@ -34,20 +34,20 @@ import com.dfsek.terra.api.registry.Registry;
|
||||
|
||||
public class GenericTemplateSupplierLoader<T> implements TypeLoader<T> {
|
||||
private final Registry<Supplier<ObjectTemplate<T>>> registry;
|
||||
|
||||
|
||||
public GenericTemplateSupplierLoader(Registry<Supplier<ObjectTemplate<T>>> registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T load(@NotNull AnnotatedType t, @NotNull Object c, ConfigLoader loader, DepthTracker depthTracker) throws LoadException {
|
||||
Map<String, Object> map = (Map<String, Object>) c;
|
||||
String type = (String) map.get("type");
|
||||
return loader
|
||||
.load(registry.getByID(type)
|
||||
.orElseThrow(() -> new LoadException("No such entry: " + map.get("type"), depthTracker))
|
||||
.get(), new MapConfiguration(map), depthTracker.intrinsic("With type \"" + type + "\"")).get();
|
||||
|
||||
.load(registry.getByID(type)
|
||||
.orElseThrow(() -> new LoadException("No such entry: " + map.get("type"), depthTracker))
|
||||
.get(), new MapConfiguration(map), depthTracker.intrinsic("With type \"" + type + "\"")).get();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,10 +41,10 @@ public class LinkedHashMapLoader implements TypeLoader<LinkedHashMap<Object, Obj
|
||||
AnnotatedType value = pType.getAnnotatedActualTypeArguments()[1];
|
||||
for(Map.Entry<String, Object> entry : config.entrySet()) {
|
||||
map.put(loader.loadType(key, entry.getKey(), depthTracker.entry(entry.getKey())),
|
||||
loader.loadType(value, entry.getValue(), depthTracker.entry(entry.getKey())));
|
||||
loader.loadType(value, entry.getValue(), depthTracker.entry(entry.getKey())));
|
||||
}
|
||||
} else throw new LoadException("Unable to load config", depthTracker);
|
||||
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,13 +36,13 @@ public class MaterialSetLoader implements TypeLoader<MaterialSet> {
|
||||
public MaterialSet load(@NotNull AnnotatedType type, @NotNull Object o, @NotNull ConfigLoader configLoader, DepthTracker depthTracker)
|
||||
throws LoadException {
|
||||
List<String> stringData = (List<String>) o;
|
||||
|
||||
|
||||
if(stringData.size() == 1) {
|
||||
return MaterialSet.singleton(configLoader.loadType(BlockType.class, stringData.get(0), depthTracker));
|
||||
}
|
||||
|
||||
|
||||
MaterialSet set = new MaterialSet();
|
||||
|
||||
|
||||
for(String string : stringData) {
|
||||
try {
|
||||
set.add(configLoader.loadType(BlockType.class, string, depthTracker));
|
||||
@@ -50,7 +50,7 @@ public class MaterialSetLoader implements TypeLoader<MaterialSet> {
|
||||
throw new LoadException("Invalid data identifier \"" + string + "\"", e, depthTracker);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return set;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,14 +38,14 @@ public class ProbabilityCollectionLoader implements TypeLoader<ProbabilityCollec
|
||||
public ProbabilityCollection<Object> load(@NotNull AnnotatedType type, @NotNull Object o, @NotNull ConfigLoader configLoader,
|
||||
DepthTracker depthTracker) throws LoadException {
|
||||
ProbabilityCollection<Object> collection = new ProbabilityCollection<>();
|
||||
|
||||
|
||||
if(type instanceof AnnotatedParameterizedType pType) {
|
||||
AnnotatedType generic = pType.getAnnotatedActualTypeArguments()[0];
|
||||
if(o instanceof Map) {
|
||||
Map<Object, Object> map = (Map<Object, Object>) o;
|
||||
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())));
|
||||
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;
|
||||
@@ -61,10 +61,10 @@ public class ProbabilityCollectionLoader implements TypeLoader<ProbabilityCollec
|
||||
Map<Object, Object> l = map.get(i);
|
||||
for(Entry<Object, Object> entry : l.entrySet()) {
|
||||
if(entry.getValue() == null) throw new LoadException("No probability defined for entry \"" + entry.getKey() + "\"",
|
||||
depthTracker);
|
||||
depthTracker);
|
||||
Object val = configLoader.loadType(generic, entry.getKey(), depthTracker.index(i).entry((String) entry.getKey()));
|
||||
collection.add(val,
|
||||
configLoader.loadType(Integer.class, entry.getValue(), depthTracker.entry((String) entry.getKey())));
|
||||
configLoader.loadType(Integer.class, entry.getValue(), depthTracker.entry((String) entry.getKey())));
|
||||
}
|
||||
}
|
||||
} else if(o instanceof String) {
|
||||
@@ -73,9 +73,9 @@ public class ProbabilityCollectionLoader implements TypeLoader<ProbabilityCollec
|
||||
throw new LoadException("Malformed Probability Collection: " + o, depthTracker);
|
||||
}
|
||||
} else throw new LoadException("Unable to load config! Could not retrieve parameterized type: " + type, depthTracker);
|
||||
|
||||
|
||||
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -23,21 +23,17 @@ 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.loader.type.TypeLoader;
|
||||
|
||||
import com.dfsek.tectonic.impl.MapConfiguration;
|
||||
|
||||
import com.dfsek.terra.api.config.meta.Meta;
|
||||
|
||||
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.ConstantRange;
|
||||
import com.dfsek.terra.api.util.Range;
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class RangeLoader implements TypeLoader<Range> {
|
||||
@Override
|
||||
public Range load(@NotNull AnnotatedType type, @NotNull Object o, @NotNull ConfigLoader configLoader, DepthTracker depthTracker)
|
||||
@@ -49,17 +45,17 @@ public class RangeLoader implements TypeLoader<Range> {
|
||||
return new ConstantRange(h, h + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Template needed so keys can be meta annotated, otherwise the loader could just grab keys directly from the object
|
||||
*/
|
||||
public static class RangeMapTemplate implements ObjectTemplate<Range> {
|
||||
private static class RangeMapTemplate implements ObjectTemplate<Range> {
|
||||
@Value("min")
|
||||
private @Meta int min;
|
||||
|
||||
|
||||
@Value("max")
|
||||
private @Meta int max;
|
||||
|
||||
|
||||
@Override
|
||||
public Range get() {
|
||||
return new ConstantRange(min, max);
|
||||
|
||||
@@ -33,22 +33,23 @@ import com.dfsek.terra.api.config.ConfigPack;
|
||||
import com.dfsek.terra.api.config.Loader;
|
||||
import com.dfsek.terra.api.properties.Properties;
|
||||
|
||||
|
||||
/*
|
||||
* @deprecated Use the Image and ImageLoader class provided by the library-image addon instead. This is subject to removal in v7.
|
||||
*/
|
||||
@Deprecated
|
||||
public class BufferedImageLoader implements TypeLoader<BufferedImage> {
|
||||
private final Loader files;
|
||||
|
||||
|
||||
private final ConfigPack pack;
|
||||
|
||||
|
||||
public BufferedImageLoader(Loader files, ConfigPack pack) {
|
||||
this.files = files;
|
||||
this.pack = pack;
|
||||
if (!pack.getContext().has(ImageCache.class))
|
||||
if(!pack.getContext().has(ImageCache.class))
|
||||
pack.getContext().put(new ImageCache(new ConcurrentHashMap<>()));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BufferedImage load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader, DepthTracker depthTracker)
|
||||
throws LoadException {
|
||||
@@ -60,7 +61,7 @@ public class BufferedImageLoader implements TypeLoader<BufferedImage> {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Cache prevents configs from loading the same image multiple times into memory
|
||||
*/
|
||||
|
||||
@@ -33,8 +33,8 @@ public class ConfigPackAddonsTemplate implements ConfigTemplate {
|
||||
@Value("addons")
|
||||
@Default
|
||||
private Map<BaseAddon, VersionRange> addons = new HashMap<>();
|
||||
|
||||
|
||||
|
||||
|
||||
public Map<BaseAddon, VersionRange> getAddons() {
|
||||
return addons;
|
||||
}
|
||||
|
||||
@@ -103,24 +103,24 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ConfigPackImpl.class);
|
||||
private final Context context = new Context();
|
||||
private final ConfigPackTemplate template = new ConfigPackTemplate();
|
||||
|
||||
|
||||
private final AbstractConfigLoader abstractConfigLoader = new AbstractConfigLoader();
|
||||
private final ConfigLoader selfLoader = new ConfigLoader();
|
||||
private final Platform platform;
|
||||
private final Loader loader;
|
||||
|
||||
|
||||
private final Map<BaseAddon, VersionRange> addons;
|
||||
|
||||
|
||||
private final BiomeProvider seededBiomeProvider;
|
||||
|
||||
|
||||
private final Map<Type, CheckedRegistryImpl<?>> registryMap = new HashMap<>();
|
||||
private final Map<Type, ShortcutHolder<?>> shortcuts = new HashMap<>();
|
||||
|
||||
|
||||
private final OpenRegistry<ConfigType<?, ?>> configTypeRegistry;
|
||||
private final TreeMap<Integer, List<Pair<RegistryKey, ConfigType<?, ?>>>> configTypes = new TreeMap<>();
|
||||
|
||||
|
||||
private final RegistryKey key;
|
||||
|
||||
|
||||
public ConfigPackImpl(File folder, Platform platform) {
|
||||
this(new FolderLoader(folder.toPath()), Construct.construct(() -> {
|
||||
try {
|
||||
@@ -130,7 +130,7 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
}
|
||||
}), platform);
|
||||
}
|
||||
|
||||
|
||||
public ConfigPackImpl(ZipFile file, Platform platform) {
|
||||
this(new ZIPLoader(file), Construct.construct(() -> {
|
||||
ZipEntry pack = null;
|
||||
@@ -139,9 +139,9 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
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) {
|
||||
@@ -149,33 +149,33 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
}
|
||||
}), platform);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private ConfigPackImpl(Loader loader, Configuration packManifest, Platform platform) {
|
||||
long start = System.nanoTime();
|
||||
|
||||
|
||||
this.loader = loader;
|
||||
this.platform = platform;
|
||||
this.configTypeRegistry = createConfigRegistry();
|
||||
|
||||
|
||||
register(selfLoader);
|
||||
platform.register(selfLoader);
|
||||
|
||||
|
||||
register(abstractConfigLoader);
|
||||
platform.register(abstractConfigLoader);
|
||||
|
||||
|
||||
ConfigPackAddonsTemplate addonsTemplate = new ConfigPackAddonsTemplate();
|
||||
selfLoader.load(addonsTemplate, packManifest);
|
||||
this.addons = addonsTemplate.getAddons();
|
||||
|
||||
|
||||
Map<String, Configuration> configurations = discoverConfigurations();
|
||||
registerMeta(configurations);
|
||||
|
||||
|
||||
platform.getEventManager().callEvent(
|
||||
new ConfigPackPreLoadEvent(this, template -> selfLoader.load(template, packManifest)));
|
||||
|
||||
new ConfigPackPreLoadEvent(this, template -> selfLoader.load(template, packManifest)));
|
||||
|
||||
selfLoader.load(template, packManifest);
|
||||
|
||||
|
||||
String namespace;
|
||||
String id;
|
||||
if(template.getID().contains(":")) {
|
||||
@@ -185,109 +185,109 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
id = template.getID();
|
||||
namespace = template.getID();
|
||||
}
|
||||
|
||||
|
||||
this.key = RegistryKey.of(namespace, id);
|
||||
|
||||
|
||||
logger.info("Loading config pack \"{}:{}\"", id, namespace);
|
||||
|
||||
|
||||
configTypes.values().forEach(list -> list.forEach(pair -> configTypeRegistry.register(pair.getLeft(), pair.getRight())));
|
||||
|
||||
|
||||
ListMultimap<ConfigType<?, ?>, Configuration> multimap = configurations.values().parallelStream().collect(
|
||||
() -> Multimaps.newListMultimap(new ConcurrentHashMap<>(), ArrayList::new), (configs, configuration) -> {
|
||||
if(configuration.contains("type")) { // Only sort configs with type key
|
||||
ProtoConfig config = new ProtoConfig();
|
||||
selfLoader.load(config, configuration);
|
||||
configs.put(config.getType(), configuration);
|
||||
}
|
||||
}, ListMultimap::putAll);
|
||||
|
||||
() -> Multimaps.newListMultimap(new ConcurrentHashMap<>(), ArrayList::new), (configs, configuration) -> {
|
||||
if(configuration.contains("type")) { // Only sort configs with type key
|
||||
ProtoConfig config = new ProtoConfig();
|
||||
selfLoader.load(config, configuration);
|
||||
configs.put(config.getType(), configuration);
|
||||
}
|
||||
}, ListMultimap::putAll);
|
||||
|
||||
configTypeRegistry.forEach(configType -> {
|
||||
CheckedRegistry registry = getCheckedRegistry(configType.getTypeKey());
|
||||
abstractConfigLoader
|
||||
.loadConfigs(multimap.get(configType))
|
||||
.stream()
|
||||
.parallel()
|
||||
.map(configuration -> {
|
||||
logger.debug("Loading abstract config {}", configuration.getID());
|
||||
Object loaded = ((ConfigFactory) configType.getFactory()).build(
|
||||
selfLoader.load(configType.getTemplate(this, platform), configuration), platform);
|
||||
platform.getEventManager().callEvent(new ConfigurationLoadEvent(this,
|
||||
configuration,
|
||||
template -> selfLoader.load(template,
|
||||
configuration),
|
||||
configType,
|
||||
loaded));
|
||||
return Pair.of(configuration.getID(), loaded);
|
||||
})
|
||||
.toList()
|
||||
.forEach(pair -> registry.register(key(pair.getLeft()), pair.getRight()));
|
||||
.loadConfigs(multimap.get(configType))
|
||||
.stream()
|
||||
.parallel()
|
||||
.map(configuration -> {
|
||||
logger.debug("Loading abstract config {}", configuration.getID());
|
||||
Object loaded = ((ConfigFactory) configType.getFactory()).build(
|
||||
selfLoader.load(configType.getTemplate(this, platform), configuration), platform);
|
||||
platform.getEventManager().callEvent(new ConfigurationLoadEvent(this,
|
||||
configuration,
|
||||
template -> selfLoader.load(template,
|
||||
configuration),
|
||||
configType,
|
||||
loaded));
|
||||
return Pair.of(configuration.getID(), loaded);
|
||||
})
|
||||
.toList()
|
||||
.forEach(pair -> registry.register(key(pair.getLeft()), pair.getRight()));
|
||||
platform.getEventManager().callEvent(new ConfigTypePostLoadEvent(configType, registry, this));
|
||||
});
|
||||
|
||||
|
||||
platform.getEventManager().callEvent(new ConfigPackPostLoadEvent(this, template -> selfLoader.load(template, packManifest)));
|
||||
logger.info("Loaded config pack \"{}:{}\" v{} by {} in {}ms.",
|
||||
namespace, id, getVersion().getFormatted(), template.getAuthor(), (System.nanoTime() - start) / 1000000.0D);
|
||||
|
||||
|
||||
namespace, id, getVersion().getFormatted(), template.getAuthor(), (System.nanoTime() - start) / 1000000.0D);
|
||||
|
||||
|
||||
ConfigPackPostTemplate packPostTemplate = new ConfigPackPostTemplate();
|
||||
selfLoader.load(packPostTemplate, packManifest);
|
||||
seededBiomeProvider =
|
||||
template.getBiomeCache() ? packPostTemplate.getProviderBuilder().caching() : packPostTemplate.getProviderBuilder();
|
||||
template.getBiomeCache() ? packPostTemplate.getProviderBuilder().caching() : packPostTemplate.getProviderBuilder();
|
||||
checkDeadEntries();
|
||||
}
|
||||
|
||||
|
||||
private Map<String, Configuration> discoverConfigurations() {
|
||||
Map<String, Configuration> configurations = new HashMap<>();
|
||||
platform.getEventManager().callEvent(new ConfigurationDiscoveryEvent(this, loader,
|
||||
(s, c) -> configurations.put(s.replace("\\", "/"),
|
||||
c))); // Create all the configs.
|
||||
(s, c) -> configurations.put(s.replace("\\", "/"),
|
||||
c))); // Create all the configs.
|
||||
return configurations;
|
||||
}
|
||||
|
||||
|
||||
private void registerMeta(Map<String, Configuration> configurations) {
|
||||
MetaStringPreprocessor stringPreprocessor = new MetaStringPreprocessor(configurations);
|
||||
selfLoader.registerPreprocessor(Meta.class, stringPreprocessor);
|
||||
abstractConfigLoader.registerPreprocessor(Meta.class, stringPreprocessor);
|
||||
|
||||
|
||||
MetaListLikePreprocessor listPreprocessor = new MetaListLikePreprocessor(configurations);
|
||||
selfLoader.registerPreprocessor(Meta.class, listPreprocessor);
|
||||
abstractConfigLoader.registerPreprocessor(Meta.class, listPreprocessor);
|
||||
|
||||
|
||||
MetaMapPreprocessor mapPreprocessor = new MetaMapPreprocessor(configurations);
|
||||
selfLoader.registerPreprocessor(Meta.class, mapPreprocessor);
|
||||
abstractConfigLoader.registerPreprocessor(Meta.class, mapPreprocessor);
|
||||
|
||||
|
||||
MetaValuePreprocessor valuePreprocessor = new MetaValuePreprocessor(configurations);
|
||||
selfLoader.registerPreprocessor(Meta.class, valuePreprocessor);
|
||||
abstractConfigLoader.registerPreprocessor(Meta.class, valuePreprocessor);
|
||||
|
||||
|
||||
MetaNumberPreprocessor numberPreprocessor = new MetaNumberPreprocessor(configurations);
|
||||
selfLoader.registerPreprocessor(Meta.class, numberPreprocessor);
|
||||
abstractConfigLoader.registerPreprocessor(Meta.class, numberPreprocessor);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> ConfigPackImpl applyLoader(Type type, TypeLoader<T> loader) {
|
||||
abstractConfigLoader.registerLoader(type, loader);
|
||||
selfLoader.registerLoader(type, loader);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> ConfigPackImpl applyLoader(Type type, Supplier<ObjectTemplate<T>> loader) {
|
||||
abstractConfigLoader.registerLoader(type, loader);
|
||||
selfLoader.registerLoader(type, loader);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void register(TypeRegistry registry) {
|
||||
registry.registerLoader(ConfigType.class, configTypeRegistry)
|
||||
.registerLoader(BufferedImage.class, new BufferedImageLoader(loader, this));
|
||||
.registerLoader(BufferedImage.class, new BufferedImageLoader(loader, this));
|
||||
registryMap.forEach(registry::registerLoader);
|
||||
shortcuts.forEach(registry::registerLoader); // overwrite with delegated shortcuts if present
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ConfigPack registerConfigType(ConfigType<?, ?> type, RegistryKey key, int priority) {
|
||||
Set<RegistryKey> contained = new HashSet<>();
|
||||
@@ -298,17 +298,17 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
configTypes.computeIfAbsent(priority, p -> new ArrayList<>()).add(Pair.of(key, type));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<BaseAddon, VersionRange> addons() {
|
||||
return addons;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BiomeProvider getBiomeProvider() {
|
||||
return seededBiomeProvider;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> CheckedRegistry<T> getOrCreateRegistry(TypeKey<T> typeKey) {
|
||||
@@ -317,7 +317,7 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
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
|
||||
@@ -329,7 +329,7 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
&& ObjectTemplate.class.isAssignableFrom((Class<?>) suppliedBase)) {
|
||||
Type templateType = suppliedParam.getActualTypeArguments()[0];
|
||||
GenericTemplateSupplierLoader<?> loader = new GenericTemplateSupplierLoader<>(
|
||||
(Registry<Supplier<ObjectTemplate<Supplier<ObjectTemplate<?>>>>>) registry);
|
||||
(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));
|
||||
@@ -337,54 +337,54 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new CheckedRegistryImpl<>(registry);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<GenerationStage> getStages() {
|
||||
return template.getStages();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Loader getLoader() {
|
||||
return loader;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getAuthor() {
|
||||
return template.getAuthor();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Version getVersion() {
|
||||
return template.getVersion();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked,rawtypes")
|
||||
@Override
|
||||
public <T> ConfigPack registerShortcut(TypeKey<T> clazz, String shortcut, ShortcutLoader<T> loader) {
|
||||
ShortcutHolder<?> holder = shortcuts
|
||||
.computeIfAbsent(clazz.getType(), c -> new ShortcutHolder<>(getOrCreateRegistry(clazz)))
|
||||
.register(shortcut, (ShortcutLoader) loader);
|
||||
.computeIfAbsent(clazz.getType(), c -> new ShortcutHolder<>(getOrCreateRegistry(clazz)))
|
||||
.register(shortcut, (ShortcutLoader) loader);
|
||||
selfLoader.registerLoader(clazz.getType(), holder);
|
||||
abstractConfigLoader.registerLoader(clazz.getType(), holder);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ChunkGeneratorProvider getGeneratorProvider() {
|
||||
return template.getGeneratorProvider();
|
||||
}
|
||||
|
||||
|
||||
private OpenRegistry<ConfigType<?, ?>> createConfigRegistry() {
|
||||
return new OpenRegistryImpl<>(new LinkedHashMap<>(), CONFIG_TYPE_TYPE_KEY) {
|
||||
@Override
|
||||
public boolean register(@NotNull RegistryKey key, @NotNull ConfigType<?, ?> value) {
|
||||
if(!registryMap
|
||||
.containsKey(value.getTypeKey()
|
||||
.getType())) {
|
||||
.containsKey(value.getTypeKey()
|
||||
.getType())) {
|
||||
OpenRegistry<?> openRegistry = new OpenRegistryImpl<>(value.getTypeKey());
|
||||
selfLoader.registerLoader(value.getTypeKey().getType(), openRegistry);
|
||||
abstractConfigLoader.registerLoader(value.getTypeKey().getType(), openRegistry);
|
||||
@@ -394,34 +394,34 @@ public class ConfigPackImpl implements ConfigPack {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private void checkDeadEntries() {
|
||||
registryMap.forEach((clazz, pair) -> ((OpenRegistryImpl<?>) pair.getRegistry())
|
||||
.getDeadEntries()
|
||||
.forEach((id, value) -> logger.debug("Dead entry in '{}' registry: '{}'", ReflectionUtil.typeToString(clazz), id)));
|
||||
.getDeadEntries()
|
||||
.forEach((id, value) -> logger.debug("Dead entry in '{}' registry: '{}'", ReflectionUtil.typeToString(clazz), id)));
|
||||
}
|
||||
|
||||
|
||||
public ConfigPackTemplate getTemplate() {
|
||||
return template;
|
||||
}
|
||||
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RegistryKey getRegistryKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Context getContext() {
|
||||
return context;
|
||||
|
||||
@@ -27,7 +27,7 @@ import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
public class ConfigPackPostTemplate implements ConfigTemplate {
|
||||
@Value("biomes")
|
||||
private @Meta BiomeProvider providerBuilder;
|
||||
|
||||
|
||||
public BiomeProvider getProviderBuilder() {
|
||||
return providerBuilder;
|
||||
}
|
||||
|
||||
@@ -36,157 +36,157 @@ import com.dfsek.terra.api.world.chunk.generation.util.provider.ChunkGeneratorPr
|
||||
public class ConfigPackTemplate implements ConfigTemplate {
|
||||
@Value("id")
|
||||
private String id;
|
||||
|
||||
|
||||
@Value("variables")
|
||||
@Default
|
||||
private @Meta Map<String, @Meta Double> variables = new HashMap<>();
|
||||
|
||||
|
||||
@Value("beta.carving")
|
||||
@Default
|
||||
private @Meta boolean betaCarvers = false;
|
||||
|
||||
|
||||
@Value("structures.locatable")
|
||||
@Default
|
||||
private @Meta Map<@Meta String, @Meta String> locatable = new HashMap<>();
|
||||
|
||||
|
||||
@Value("blend.terrain.elevation")
|
||||
@Default
|
||||
private @Meta int elevationBlend = 4;
|
||||
|
||||
|
||||
@Value("vanilla.mobs")
|
||||
@Default
|
||||
private @Meta boolean vanillaMobs = true;
|
||||
|
||||
|
||||
@Value("vanilla.caves")
|
||||
@Default
|
||||
private @Meta boolean vanillaCaves = false;
|
||||
|
||||
|
||||
@Value("vanilla.decorations")
|
||||
@Default
|
||||
private @Meta boolean vanillaDecorations = false;
|
||||
|
||||
|
||||
@Value("vanilla.structures")
|
||||
@Default
|
||||
private @Meta boolean vanillaStructures = false;
|
||||
|
||||
|
||||
@Value("author")
|
||||
@Default
|
||||
private String author = "Anon Y. Mous";
|
||||
|
||||
|
||||
@Value("disable.sapling")
|
||||
@Default
|
||||
private @Meta boolean disableSaplings = false;
|
||||
|
||||
|
||||
@Value("stages")
|
||||
@Default
|
||||
private @Meta List<@Meta GenerationStage> stages = Collections.emptyList();
|
||||
|
||||
|
||||
@Value("version")
|
||||
private Version version;
|
||||
|
||||
|
||||
@Value("disable.carvers")
|
||||
@Default
|
||||
private @Meta boolean disableCarvers = false;
|
||||
|
||||
|
||||
@Value("disable.structures")
|
||||
@Default
|
||||
private @Meta boolean disableStructures = false;
|
||||
|
||||
|
||||
@Value("disable.ores")
|
||||
@Default
|
||||
private @Meta boolean disableOres = false;
|
||||
|
||||
|
||||
@Value("disable.trees")
|
||||
@Default
|
||||
private @Meta boolean disableTrees = false;
|
||||
|
||||
|
||||
@Value("disable.flora")
|
||||
@Default
|
||||
private @Meta boolean disableFlora = false;
|
||||
|
||||
|
||||
@Value("generator")
|
||||
private @Meta ChunkGeneratorProvider generatorProvider;
|
||||
|
||||
|
||||
@Value("cache.biome.enable")
|
||||
@Default
|
||||
private boolean biomeCache = false;
|
||||
|
||||
|
||||
public boolean disableCarvers() {
|
||||
return disableCarvers;
|
||||
}
|
||||
|
||||
|
||||
public boolean disableFlora() {
|
||||
return disableFlora;
|
||||
}
|
||||
|
||||
|
||||
public boolean disableOres() {
|
||||
return disableOres;
|
||||
}
|
||||
|
||||
|
||||
public boolean disableStructures() {
|
||||
return disableStructures;
|
||||
}
|
||||
|
||||
|
||||
public boolean disableTrees() {
|
||||
return disableTrees;
|
||||
}
|
||||
|
||||
|
||||
public boolean vanillaMobs() {
|
||||
return vanillaMobs;
|
||||
}
|
||||
|
||||
|
||||
public boolean vanillaCaves() {
|
||||
return vanillaCaves;
|
||||
}
|
||||
|
||||
|
||||
public boolean vanillaDecorations() {
|
||||
return vanillaDecorations;
|
||||
}
|
||||
|
||||
|
||||
public boolean vanillaStructures() {
|
||||
return vanillaStructures;
|
||||
}
|
||||
|
||||
|
||||
public boolean doBetaCarvers() {
|
||||
return betaCarvers;
|
||||
}
|
||||
|
||||
|
||||
public ChunkGeneratorProvider getGeneratorProvider() {
|
||||
return generatorProvider;
|
||||
}
|
||||
|
||||
|
||||
public List<GenerationStage> getStages() {
|
||||
return stages;
|
||||
}
|
||||
|
||||
|
||||
public Version getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
public boolean isDisableSaplings() {
|
||||
return disableSaplings;
|
||||
}
|
||||
|
||||
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
|
||||
public Map<String, Double> getVariables() {
|
||||
return variables;
|
||||
}
|
||||
|
||||
|
||||
public int getElevationBlend() {
|
||||
return elevationBlend;
|
||||
}
|
||||
|
||||
|
||||
public Map<String, String> getLocatable() {
|
||||
return locatable;
|
||||
}
|
||||
|
||||
|
||||
public boolean getBiomeCache() {
|
||||
return biomeCache;
|
||||
}
|
||||
|
||||
@@ -41,42 +41,43 @@ public class MetaListLikePreprocessor extends MetaPreprocessor<Meta> {
|
||||
public MetaListLikePreprocessor(Map<String, Configuration> configs) {
|
||||
super(configs);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public @NotNull <T> Result<T> process(AnnotatedType t, T c, ConfigLoader loader, Meta annotation, DepthTracker depthTracker) {
|
||||
if(t.getType() instanceof ParameterizedType parameterizedType) {
|
||||
if(parameterizedType.getRawType() instanceof Class<?> baseClass) { // Should always be true but we check anyways
|
||||
|
||||
|
||||
if((List.class.isAssignableFrom(baseClass) || Set.class.isAssignableFrom(baseClass)) &&
|
||||
c instanceof List) { // List or set metaconfig
|
||||
List<Object> list = (List<Object>) c;
|
||||
|
||||
|
||||
int offset = 0;
|
||||
List<Object> newList = new ArrayList<>((List<Object>) c);
|
||||
|
||||
|
||||
for(int i = 0; i < list.size(); i++) {
|
||||
Object o = list.get(i);
|
||||
if(!(o instanceof String)) continue;
|
||||
String s = ((String) o).trim();
|
||||
if(!s.startsWith("<< ")) continue;
|
||||
String meta = s.substring(3);
|
||||
|
||||
|
||||
|
||||
|
||||
Pair<Configuration, Object> pair = getMetaValue(meta, depthTracker);
|
||||
Object metaValue = pair.getRight();
|
||||
|
||||
|
||||
if(!(metaValue instanceof List)) {
|
||||
throw new LoadException(
|
||||
"Meta list / set injection (via <<) must point to a list. '" + meta + "' points to type " + metaValue.getClass().getCanonicalName(),
|
||||
depthTracker);
|
||||
"Meta list / set injection (via <<) must point to a list. '" + meta + "' points to type " +
|
||||
metaValue.getClass().getCanonicalName(),
|
||||
depthTracker);
|
||||
}
|
||||
|
||||
|
||||
List<Object> metaList = (List<Object>) metaValue;
|
||||
|
||||
|
||||
newList.remove(i + offset); // Remove placeholder
|
||||
newList.addAll(i + offset, metaList); // Add metalist values where placeholder was
|
||||
|
||||
|
||||
int begin = i + offset;
|
||||
offset += metaList.size() - 1; // add metalist size to offset, subtract one to account for placeholder.
|
||||
int end = i + offset;
|
||||
@@ -95,12 +96,12 @@ public class MetaListLikePreprocessor extends MetaPreprocessor<Meta> {
|
||||
return Optional.empty();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return (Result<T>) Result.overwrite(newList, depthTracker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return Result.noOp();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,41 +40,41 @@ import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||
public class MetaMapPreprocessor extends MetaPreprocessor<Meta> {
|
||||
private static final TypeKey<List<String>> STRING_LIST = new TypeKey<>() {
|
||||
};
|
||||
|
||||
|
||||
public MetaMapPreprocessor(Map<String, Configuration> configs) {
|
||||
super(configs);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public @NotNull <T> Result<T> process(AnnotatedType t, T c, ConfigLoader loader, Meta annotation, DepthTracker depthTracker) {
|
||||
if(t.getType() instanceof ParameterizedType parameterizedType) {
|
||||
if(parameterizedType.getRawType() instanceof Class<?> baseClass) { // Should always be true but we check anyways
|
||||
|
||||
|
||||
if(Map.class.isAssignableFrom(baseClass) && c instanceof Map) { // Map metaconfig
|
||||
Map<Object, Object> map = (Map<Object, Object>) c;
|
||||
|
||||
|
||||
if(map.containsKey("<<")) {
|
||||
Map<Object, Object> newMap = new HashMap<>(map);
|
||||
|
||||
|
||||
List<String> keys = (List<String>) loader.loadType(STRING_LIST.getAnnotatedType(), map.get("<<"), depthTracker);
|
||||
keys.forEach(key -> {
|
||||
Pair<Configuration, Object> pair = getMetaValue(key, depthTracker);
|
||||
Object meta = pair.getRight();
|
||||
if(!(meta instanceof Map)) {
|
||||
throw new LoadException(
|
||||
"MetaMap injection candidate must be list, is type " + meta.getClass().getCanonicalName(),
|
||||
depthTracker);
|
||||
"MetaMap injection candidate must be list, is type " + meta.getClass().getCanonicalName(),
|
||||
depthTracker);
|
||||
}
|
||||
newMap.putAll((Map<?, ?>) meta);
|
||||
|
||||
|
||||
String configName;
|
||||
if(pair.getLeft().getName() == null) {
|
||||
configName = "Anonymous Configuration";
|
||||
} else {
|
||||
configName = pair.getLeft().getName();
|
||||
}
|
||||
|
||||
|
||||
depthTracker.addIntrinsicLevel(level -> {
|
||||
if(level instanceof EntryLevel entryLevel && ((Map<?, ?>) meta).containsKey(entryLevel.getName())) {
|
||||
return Optional.of("From configuration \"" + configName + "\"");
|
||||
@@ -89,7 +89,7 @@ public class MetaMapPreprocessor extends MetaPreprocessor<Meta> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return Result.noOp();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,23 +24,24 @@ 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>() {
|
||||
};
|
||||
|
||||
|
||||
public MetaNumberPreprocessor(Map<String, Configuration> configs) {
|
||||
super(configs);
|
||||
}
|
||||
|
||||
|
||||
private static boolean isNumber(Class<?> clazz) {
|
||||
return Number.class.isAssignableFrom(clazz)
|
||||
|| byte.class.equals(clazz)
|
||||
@@ -49,7 +50,7 @@ public class MetaNumberPreprocessor extends MetaPreprocessor<Meta> {
|
||||
|| float.class.equals(clazz)
|
||||
|| double.class.equals(clazz);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public @NotNull <T> Result<T> process(AnnotatedType t, T c, ConfigLoader loader, Meta annotation, DepthTracker depthTracker) {
|
||||
|
||||
@@ -30,24 +30,24 @@ import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
public abstract class MetaPreprocessor<A extends Annotation> implements ValuePreprocessor<A> {
|
||||
private final Map<String, Configuration> configs;
|
||||
|
||||
|
||||
public MetaPreprocessor(Map<String, Configuration> configs) {
|
||||
this.configs = configs;
|
||||
}
|
||||
|
||||
|
||||
protected Pair<Configuration, Object> getMetaValue(String meta, DepthTracker depthTracker) {
|
||||
int sep = meta.indexOf(':');
|
||||
String file = meta.substring(0, sep);
|
||||
String key = meta.substring(sep + 1);
|
||||
|
||||
|
||||
if(!configs.containsKey(file)) throw new LoadException("Cannot fetch metavalue: No such config: " + file, depthTracker);
|
||||
|
||||
|
||||
Configuration config = configs.get(file);
|
||||
|
||||
|
||||
if(!config.contains(key)) {
|
||||
throw new LoadException("Cannot fetch metavalue: No such key " + key + " in configuration " + config.getName(), depthTracker);
|
||||
}
|
||||
|
||||
|
||||
return Pair.of(config, config.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public class MetaStringPreprocessor extends MetaPreprocessor<Meta> {
|
||||
public MetaStringPreprocessor(Map<String, Configuration> configs) {
|
||||
super(configs);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public @NotNull <T> Result<T> process(AnnotatedType t, T c, ConfigLoader loader, Meta annotation, DepthTracker depthTracker) {
|
||||
@@ -52,6 +52,6 @@ public class MetaStringPreprocessor extends MetaPreprocessor<Meta> {
|
||||
}
|
||||
return Result.noOp();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
|
||||
public class MetaValuePreprocessor extends MetaPreprocessor<Meta> {
|
||||
|
||||
|
||||
public MetaValuePreprocessor(Map<String, Configuration> configs) {
|
||||
super(configs);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public @NotNull <T> Result<T> process(AnnotatedType t, T c, ConfigLoader configLoader, Meta annotation, DepthTracker depthTracker) {
|
||||
@@ -44,14 +44,14 @@ public class MetaValuePreprocessor extends MetaPreprocessor<Meta> {
|
||||
if(value.startsWith("$") // it's a meta value.
|
||||
&& !value.startsWith("${")) { // it's not a meta string template.
|
||||
Pair<Configuration, Object> pair = getMetaValue(value.substring(1), depthTracker);
|
||||
|
||||
|
||||
String configName;
|
||||
if(pair.getLeft().getName() == null) {
|
||||
configName = "Anonymous Configuration";
|
||||
} else {
|
||||
configName = pair.getLeft().getName();
|
||||
}
|
||||
|
||||
|
||||
return (Result<T>) Result.overwrite(pair.getRight(), depthTracker.intrinsic("From configuration \"" + configName + "\""));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,15 +26,15 @@ import com.dfsek.terra.api.config.ConfigType;
|
||||
public class ProtoConfig implements ConfigTemplate {
|
||||
@Value("id")
|
||||
private String id;
|
||||
|
||||
|
||||
@Value("type")
|
||||
private ConfigType<?, ?> type;
|
||||
|
||||
|
||||
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
public ConfigType<?, ?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -39,63 +39,63 @@ public class EventContextImpl<T extends Event> implements EventContext<T>, Compa
|
||||
private int priority;
|
||||
private boolean failThrough = false;
|
||||
private boolean global = false;
|
||||
|
||||
|
||||
public EventContextImpl(BaseAddon addon, Type eventType, FunctionalEventHandlerImpl parent) {
|
||||
this.addon = addon;
|
||||
this.eventType = eventType;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
|
||||
public void handle(T event) {
|
||||
actions.forEach(action -> action.accept(event));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public EventContext<T> then(Consumer<T> action) {
|
||||
actions.add(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public EventContext<T> priority(int priority) {
|
||||
this.priority = priority;
|
||||
parent.recomputePriorities(eventType);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public EventContext<T> failThrough() {
|
||||
if(!FailThroughEvent.class.isAssignableFrom(ReflectionUtil.getRawType(eventType))) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot fail-through on event which does not implement FailThroughEvent: " + ReflectionUtil.typeToString(eventType));
|
||||
"Cannot fail-through on event which does not implement FailThroughEvent: " + ReflectionUtil.typeToString(eventType));
|
||||
}
|
||||
this.failThrough = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public EventContext<T> global() {
|
||||
this.global = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull EventContextImpl<?> o) {
|
||||
return this.priority - o.priority;
|
||||
}
|
||||
|
||||
|
||||
public boolean isGlobal() {
|
||||
return global;
|
||||
}
|
||||
|
||||
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
|
||||
public BaseAddon getAddon() {
|
||||
return addon;
|
||||
}
|
||||
|
||||
|
||||
public boolean isFailThrough() {
|
||||
return failThrough;
|
||||
}
|
||||
|
||||
@@ -28,22 +28,22 @@ import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
|
||||
|
||||
public class EventManagerImpl implements EventManager {
|
||||
private final Map<Class<?>, EventHandler> handlers = new HashMap<>();
|
||||
|
||||
|
||||
public EventManagerImpl() {
|
||||
registerHandler(FunctionalEventHandler.class, new FunctionalEventHandlerImpl()); // default handler
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T extends Event> T callEvent(T event) {
|
||||
handlers.values().forEach(handler -> handler.handle(event));
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T extends EventHandler> void registerHandler(Class<T> clazz, T handler) {
|
||||
handlers.put(clazz, handler);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends EventHandler> T getHandler(Class<T> clazz) {
|
||||
|
||||
@@ -39,9 +39,9 @@ import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||
|
||||
public class FunctionalEventHandlerImpl implements FunctionalEventHandler {
|
||||
private static final Logger logger = LoggerFactory.getLogger(FunctionalEventHandlerImpl.class);
|
||||
|
||||
|
||||
private final Map<Type, List<EventContextImpl<?>>> contextMap = new HashMap<>();
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void handle(Event event) {
|
||||
@@ -59,25 +59,25 @@ public class FunctionalEventHandlerImpl implements FunctionalEventHandler {
|
||||
throw e; // Rethrow if it's fail-through.
|
||||
// else warn
|
||||
logger.warn("Exception occurred during event handling. Report this to the maintainers of {}@{}",
|
||||
context.getAddon().getID(), context.getAddon().getVersion().getFormatted(), e);
|
||||
context.getAddon().getID(), context.getAddon().getVersion().getFormatted(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T extends Event> EventContext<T> register(BaseAddon addon, Class<T> clazz) {
|
||||
EventContextImpl<T> eventContext = new EventContextImpl<>(addon, clazz, this);
|
||||
contextMap.computeIfAbsent(clazz, c -> new ArrayList<>()).add(eventContext);
|
||||
return eventContext;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T extends Event> EventContext<T> register(BaseAddon addon, TypeKey<T> clazz) {
|
||||
EventContextImpl<T> eventContext = new EventContextImpl<>(addon, clazz.getType(), this);
|
||||
contextMap.computeIfAbsent(clazz.getType(), c -> new ArrayList<>()).add(eventContext);
|
||||
return eventContext;
|
||||
}
|
||||
|
||||
|
||||
public void recomputePriorities(Type target) {
|
||||
contextMap.get(target).sort(Comparator.naturalOrder());
|
||||
}
|
||||
|
||||
@@ -20,21 +20,21 @@ package com.dfsek.terra.profiler;
|
||||
public class Frame {
|
||||
private final String id;
|
||||
private final long start;
|
||||
|
||||
|
||||
public Frame(String id) {
|
||||
this.id = id;
|
||||
this.start = System.nanoTime();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
public long getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ import com.dfsek.terra.profiler.exception.MalformedStackException;
|
||||
|
||||
public class ProfilerImpl implements Profiler {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProfilerImpl.class);
|
||||
|
||||
|
||||
private static final ThreadLocal<Stack<Frame>> THREAD_STACK = ThreadLocal.withInitial(Stack::new);
|
||||
private static final ThreadLocal<Map<String, List<Long>>> TIMINGS = ThreadLocal.withInitial(HashMap::new);
|
||||
private static final ThreadLocal<Boolean> SAFE = ThreadLocal.withInitial(() -> false);
|
||||
@@ -42,13 +42,13 @@ public class ProfilerImpl implements Profiler {
|
||||
private static boolean instantiated = false;
|
||||
private final List<Map<String, List<Long>>> accessibleThreadMaps = new ArrayList<>();
|
||||
private volatile boolean running = false;
|
||||
|
||||
|
||||
public ProfilerImpl() {
|
||||
if(instantiated)
|
||||
throw new IllegalStateException("Only one instance of Profiler may exist!");
|
||||
instantiated = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void push(String frame) {
|
||||
if(running) {
|
||||
@@ -59,7 +59,7 @@ public class ProfilerImpl implements Profiler {
|
||||
} else SAFE.set(false);
|
||||
} else SAFE.set(false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void pop(String frame) {
|
||||
if(running) {
|
||||
@@ -68,45 +68,45 @@ public class ProfilerImpl implements Profiler {
|
||||
if(SAFE.get()) {
|
||||
long time = System.nanoTime();
|
||||
Stack<Frame> stack = THREAD_STACK.get();
|
||||
|
||||
|
||||
Map<String, List<Long>> timingsMap = TIMINGS.get();
|
||||
|
||||
|
||||
if(timingsMap.isEmpty()) {
|
||||
synchronized(accessibleThreadMaps) {
|
||||
accessibleThreadMaps.add(timingsMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Frame top = stack.pop();
|
||||
if(!stack.isEmpty() ? !top.getId().endsWith("." + frame) : !top.getId().equals(frame))
|
||||
throw new MalformedStackException("Expected " + frame + ", found " + top);
|
||||
|
||||
|
||||
List<Long> timings = timingsMap.computeIfAbsent(top.getId(), id -> new ArrayList<>());
|
||||
|
||||
|
||||
timings.add(time - top.getStart());
|
||||
}
|
||||
if(size.get() == 0) SAFE.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
logger.info("Starting Terra profiler");
|
||||
running = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
logger.info("Stopping Terra profiler");
|
||||
running = false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
logger.info("Resetting Terra profiler");
|
||||
accessibleThreadMaps.forEach(Map::clear);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<String, Timings> getTimings() {
|
||||
Map<String, Timings> map = new HashMap<>();
|
||||
|
||||
@@ -23,15 +23,15 @@ import java.io.Serial;
|
||||
public class MalformedStackException extends ProfilerException {
|
||||
@Serial
|
||||
private static final long serialVersionUID = -3009539681021691054L;
|
||||
|
||||
|
||||
public MalformedStackException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
public MalformedStackException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
|
||||
public MalformedStackException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
@@ -23,15 +23,15 @@ import java.io.Serial;
|
||||
public class ProfilerException extends RuntimeException {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 8206737998791649002L;
|
||||
|
||||
|
||||
public ProfilerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
public ProfilerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
|
||||
public ProfilerException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
@@ -45,61 +45,61 @@ import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||
*/
|
||||
public class CheckedRegistryImpl<T> implements CheckedRegistry<T> {
|
||||
private final OpenRegistry<T> registry;
|
||||
|
||||
|
||||
public CheckedRegistryImpl(OpenRegistry<T> registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
|
||||
@Internal
|
||||
public OpenRegistry<T> getRegistry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void register(@NotNull RegistryKey identifier, @NotNull T value) throws DuplicateEntryException {
|
||||
registry.registerChecked(identifier, value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Optional<T> get(@NotNull RegistryKey key) {
|
||||
return registry.get(key);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean contains(@NotNull RegistryKey key) {
|
||||
return registry.contains(key);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void forEach(@NotNull Consumer<T> consumer) {
|
||||
registry.forEach(consumer);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void forEach(@NotNull BiConsumer<RegistryKey, T> consumer) {
|
||||
registry.forEach(consumer);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull Collection<T> entries() {
|
||||
return registry.entries();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull Set<RegistryKey> keys() {
|
||||
return registry.keys();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypeKey<T> getType() {
|
||||
return registry.getType();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<RegistryKey, T> getMatches(String id) {
|
||||
return registry.getMatches(id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public T load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader, DepthTracker depthTracker)
|
||||
throws LoadException {
|
||||
|
||||
@@ -42,51 +42,51 @@ import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||
*/
|
||||
public class LockedRegistryImpl<T> implements Registry<T> {
|
||||
private final Registry<T> registry;
|
||||
|
||||
|
||||
public LockedRegistryImpl(Registry<T> registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Optional<T> get(@NotNull RegistryKey key) {
|
||||
return registry.get(key);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean contains(@NotNull RegistryKey key) {
|
||||
return registry.contains(key);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void forEach(@NotNull Consumer<T> consumer) {
|
||||
registry.forEach(consumer);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void forEach(@NotNull BiConsumer<RegistryKey, T> consumer) {
|
||||
registry.forEach(consumer);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull Collection<T> entries() {
|
||||
return registry.entries();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull Set<RegistryKey> keys() {
|
||||
return registry.keys();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypeKey<T> getType() {
|
||||
return registry.getType();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<RegistryKey, T> getMatches(String id) {
|
||||
return registry.getMatches(id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public T load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader, DepthTracker depthTracker)
|
||||
throws LoadException {
|
||||
|
||||
@@ -53,16 +53,16 @@ public class OpenRegistryImpl<T> implements OpenRegistry<T> {
|
||||
private final Map<RegistryKey, Entry<T>> objects;
|
||||
private final ListMultimap<String, Pair<RegistryKey, Entry<T>>> objectIDs = Multimaps.newListMultimap(new HashMap<>(), ArrayList::new);
|
||||
private final TypeKey<T> typeKey;
|
||||
|
||||
|
||||
public OpenRegistryImpl(TypeKey<T> typeKey) {
|
||||
this(new HashMap<>(), typeKey);
|
||||
}
|
||||
|
||||
|
||||
protected OpenRegistryImpl(Map<RegistryKey, Entry<T>> init, TypeKey<T> typeKey) {
|
||||
this.objects = init;
|
||||
this.typeKey = typeKey;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public T load(@NotNull AnnotatedType type, @NotNull Object o, @NotNull ConfigLoader configLoader, DepthTracker depthTracker)
|
||||
throws LoadException {
|
||||
@@ -70,88 +70,88 @@ public class OpenRegistryImpl<T> implements OpenRegistry<T> {
|
||||
"\" was found in this registry. Registry contains items: " +
|
||||
getItemsFormatted(), depthTracker));
|
||||
}
|
||||
|
||||
|
||||
private String getItemsFormatted() {
|
||||
if(objects.isEmpty()) {
|
||||
return "[ ]";
|
||||
}
|
||||
return objects
|
||||
.keySet()
|
||||
.stream()
|
||||
.map(RegistryKey::toString)
|
||||
.sorted()
|
||||
.reduce("", (a, b) -> a + "\n - " + b);
|
||||
.keySet()
|
||||
.stream()
|
||||
.map(RegistryKey::toString)
|
||||
.sorted()
|
||||
.reduce("", (a, b) -> a + "\n - " + b);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean register(@NotNull RegistryKey identifier, @NotNull T value) {
|
||||
return register(identifier, new Entry<>(value));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void registerChecked(@NotNull RegistryKey identifier, @NotNull T value) throws DuplicateEntryException {
|
||||
if(objects.containsKey(identifier))
|
||||
throw new DuplicateEntryException("Value with identifier \"" + identifier + "\" is already defined in registry.");
|
||||
register(identifier, value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
objects.clear();
|
||||
objectIDs.clear();
|
||||
}
|
||||
|
||||
|
||||
private boolean register(RegistryKey identifier, Entry<T> value) {
|
||||
boolean exists = objects.containsKey(identifier);
|
||||
objects.put(identifier, value);
|
||||
objectIDs.put(identifier.getID(), Pair.of(identifier, value));
|
||||
return exists;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Optional<T> get(@NotNull RegistryKey key) {
|
||||
return Optional.ofNullable(objects.getOrDefault(key, (Entry<T>) NULL).getValue());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean contains(@NotNull RegistryKey key) {
|
||||
return objects.containsKey(key);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void forEach(@NotNull Consumer<T> consumer) {
|
||||
objects.forEach((id, obj) -> consumer.accept(obj.getRaw()));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void forEach(@NotNull BiConsumer<RegistryKey, T> consumer) {
|
||||
objects.forEach((id, entry) -> consumer.accept(id, entry.getRaw()));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull Collection<T> entries() {
|
||||
return objects.values().stream().map(Entry::getRaw).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull Set<RegistryKey> keys() {
|
||||
return objects.keySet();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypeKey<T> getType() {
|
||||
return typeKey;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<RegistryKey, T> getMatches(String id) {
|
||||
return objectIDs
|
||||
.get(id)
|
||||
.stream()
|
||||
.collect(HashMap::new, (map, pair) -> map.put(pair.getLeft(), pair.getRight().getValue()), Map::putAll);
|
||||
.get(id)
|
||||
.stream()
|
||||
.collect(HashMap::new, (map, pair) -> map.put(pair.getLeft(), pair.getRight().getValue()), Map::putAll);
|
||||
}
|
||||
|
||||
|
||||
public Map<RegistryKey, T> getDeadEntries() {
|
||||
Map<RegistryKey, T> dead = new HashMap<>();
|
||||
objects.forEach((id, entry) -> {
|
||||
@@ -159,25 +159,25 @@ public class OpenRegistryImpl<T> implements OpenRegistry<T> {
|
||||
});
|
||||
return dead;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static final class Entry<T> {
|
||||
private final T value;
|
||||
private final AtomicInteger access = new AtomicInteger(0);
|
||||
|
||||
|
||||
public Entry(T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
public boolean dead() {
|
||||
return access.get() == 0;
|
||||
}
|
||||
|
||||
|
||||
public T getValue() {
|
||||
access.incrementAndGet();
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
private T getRaw() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -17,22 +17,22 @@ import com.dfsek.terra.api.tectonic.ShortcutLoader;
|
||||
public class ShortcutHolder<T> implements TypeLoader<T> {
|
||||
private final Map<String, ShortcutLoader<T>> shortcuts = new HashMap<>();
|
||||
private final Registry<T> back;
|
||||
|
||||
|
||||
public ShortcutHolder(Registry<T> back) {
|
||||
this.back = back;
|
||||
}
|
||||
|
||||
|
||||
public ShortcutHolder<T> register(String id, ShortcutLoader<T> loader) {
|
||||
if(shortcuts.containsKey(id)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Attempted to register duplicate shortcut " + id + ", previously registered to " + shortcuts.get(id)
|
||||
.getClass()
|
||||
.getCanonicalName());
|
||||
"Attempted to register duplicate shortcut " + id + ", previously registered to " + shortcuts.get(id)
|
||||
.getClass()
|
||||
.getCanonicalName());
|
||||
}
|
||||
shortcuts.put(id, loader);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public T load(@NotNull AnnotatedType annotatedType, @NotNull Object o, @NotNull ConfigLoader configLoader, DepthTracker depthTracker)
|
||||
throws LoadException {
|
||||
@@ -41,7 +41,7 @@ public class ShortcutHolder<T> implements TypeLoader<T> {
|
||||
String shortcut = id.substring(0, id.indexOf(":"));
|
||||
if(shortcuts.containsKey(shortcut)) {
|
||||
return shortcuts.get(shortcut).load(configLoader, id.substring(id.indexOf(":") + 1),
|
||||
depthTracker.intrinsic("Using shortcut \"" + shortcut + "\""));
|
||||
depthTracker.intrinsic("Using shortcut \"" + shortcut + "\""));
|
||||
}
|
||||
throw new LoadException("Shortcut \"" + shortcut + "\" is not defined.", depthTracker);
|
||||
}
|
||||
|
||||
@@ -38,16 +38,16 @@ import com.dfsek.terra.registry.OpenRegistryImpl;
|
||||
*/
|
||||
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 boolean loadAll(Platform platform) {
|
||||
boolean valid = true;
|
||||
File packsFolder = new File(platform.getDataFolder(), "packs");
|
||||
@@ -61,7 +61,7 @@ public class ConfigRegistry extends OpenRegistryImpl<ConfigPack> {
|
||||
}
|
||||
}
|
||||
for(File zip : Objects.requireNonNull(
|
||||
packsFolder.listFiles(file -> file.getName().endsWith(".zip") || file.getName().endsWith(".terra")))) {
|
||||
packsFolder.listFiles(file -> file.getName().endsWith(".zip") || file.getName().endsWith(".terra")))) {
|
||||
try {
|
||||
logger.info("Loading ZIP archive: {}", zip.getName());
|
||||
load(new ZipFile(zip), platform);
|
||||
@@ -72,7 +72,7 @@ public class ConfigRegistry extends OpenRegistryImpl<ConfigPack> {
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
public void load(ZipFile file, Platform platform) throws ConfigException {
|
||||
ConfigPackImpl pack = new ConfigPackImpl(file, platform);
|
||||
registerChecked(pack.getRegistryKey(), pack);
|
||||
|
||||
@@ -26,25 +26,25 @@ import com.dfsek.terra.api.transform.exception.TransformException;
|
||||
|
||||
public class MapTransform<F, T> implements Transform<F, T> {
|
||||
private final Map<F, T> map;
|
||||
|
||||
|
||||
public MapTransform(Map<F, T> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
|
||||
public MapTransform() {
|
||||
this.map = new HashMap<>();
|
||||
}
|
||||
|
||||
|
||||
public MapTransform<F, T> add(F from, T to) {
|
||||
map.put(from, to);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public MapTransform<F, T> remove(F from) {
|
||||
map.remove(from);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public T transform(F input) throws TransformException {
|
||||
if(!map.containsKey(input)) throw new TransformException("No key matching " + input.toString() + " found in map.");
|
||||
|
||||
@@ -38,11 +38,11 @@ import com.dfsek.terra.api.transform.exception.TransformException;
|
||||
*/
|
||||
public class TransformerImpl<F, T> implements Transformer<F, T> {
|
||||
private final LinkedHashMap<Transform<F, T>, List<Validator<T>>> transformers;
|
||||
|
||||
|
||||
private TransformerImpl(LinkedHashMap<Transform<F, T>, List<Validator<T>>> transformer) {
|
||||
this.transformers = transformer;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public T translate(F from) {
|
||||
List<Throwable> exceptions = new ArrayList<>();
|
||||
@@ -61,7 +61,7 @@ public class TransformerImpl<F, T> implements Transformer<F, T> {
|
||||
}
|
||||
throw new AttemptsFailedException("Could not transform input; all attempts failed: " + from.toString() + "\n", exceptions);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builder pattern for building Transformers
|
||||
*
|
||||
@@ -70,14 +70,14 @@ public class TransformerImpl<F, T> implements Transformer<F, T> {
|
||||
*/
|
||||
public static final class Builder<F, T> {
|
||||
private final LinkedHashMap<Transform<F, T>, List<Validator<T>>> transforms = new LinkedHashMap<>();
|
||||
|
||||
|
||||
@SafeVarargs
|
||||
@SuppressWarnings("varargs")
|
||||
public final Builder<F, T> addTransform(Transform<F, T> transform, Validator<T>... validators) {
|
||||
transforms.put(transform, Arrays.asList(validators));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public TransformerImpl<F, T> build() {
|
||||
return new TransformerImpl<>(transforms);
|
||||
}
|
||||
|
||||
@@ -22,111 +22,111 @@ public class MetaTest {
|
||||
public void testMetaList() {
|
||||
Configuration meta = new YamlConfiguration(MetaTest.class.getResourceAsStream("/meta.yml"), "meta.yml");
|
||||
Configuration metaTarget = new YamlConfiguration(MetaTest.class.getResourceAsStream("/metaTarget.yml"), "metaTarget.yml");
|
||||
|
||||
|
||||
Map<String, Configuration> configurationMap = new HashMap<>();
|
||||
|
||||
|
||||
configurationMap.put(meta.getName(), meta);
|
||||
configurationMap.put(metaTarget.getName(), metaTarget);
|
||||
|
||||
|
||||
ConfigLoader loader = new ConfigLoader();
|
||||
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 MetaValuePreprocessor(configurationMap));
|
||||
|
||||
|
||||
loader.load(new MetaListConfig(), meta).list.forEach(System.out::println);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMetaMap() {
|
||||
Configuration meta = new YamlConfiguration(MetaTest.class.getResourceAsStream("/meta.yml"), "meta.yml");
|
||||
Configuration metaTarget = new YamlConfiguration(MetaTest.class.getResourceAsStream("/metaTarget.yml"), "metaTarget.yml");
|
||||
|
||||
|
||||
Map<String, Configuration> configurationMap = new HashMap<>();
|
||||
|
||||
|
||||
configurationMap.put(meta.getName(), meta);
|
||||
configurationMap.put(metaTarget.getName(), metaTarget);
|
||||
|
||||
|
||||
ConfigLoader loader = new ConfigLoader();
|
||||
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 MetaValuePreprocessor(configurationMap));
|
||||
|
||||
|
||||
loader.load(new MetaMapConfig(), meta).map.forEach((k, v) -> System.out.println(k + ": " + v));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMetaString() {
|
||||
Configuration meta = new YamlConfiguration(MetaTest.class.getResourceAsStream("/meta.yml"), "meta.yml");
|
||||
Configuration metaTarget = new YamlConfiguration(MetaTest.class.getResourceAsStream("/metaTarget.yml"), "metaTarget.yml");
|
||||
|
||||
|
||||
Map<String, Configuration> configurationMap = new HashMap<>();
|
||||
|
||||
|
||||
configurationMap.put(meta.getName(), meta);
|
||||
configurationMap.put(metaTarget.getName(), metaTarget);
|
||||
|
||||
|
||||
ConfigLoader loader = new ConfigLoader();
|
||||
|
||||
|
||||
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 MetaValuePreprocessor(configurationMap));
|
||||
|
||||
|
||||
System.out.println(loader.load(new MetaStringConfig(), meta).string);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMetaNumber() {
|
||||
Configuration meta = new YamlConfiguration(MetaTest.class.getResourceAsStream("/meta.yml"), "meta.yml");
|
||||
Configuration metaTarget = new YamlConfiguration(MetaTest.class.getResourceAsStream("/metaTarget.yml"), "metaTarget.yml");
|
||||
|
||||
|
||||
Map<String, Configuration> configurationMap = new HashMap<>();
|
||||
|
||||
|
||||
configurationMap.put(meta.getName(), meta);
|
||||
configurationMap.put(metaTarget.getName(), metaTarget);
|
||||
|
||||
|
||||
ConfigLoader loader = new ConfigLoader();
|
||||
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 MetaValuePreprocessor(configurationMap));
|
||||
|
||||
|
||||
System.out.println("int: " + loader.load(new MetaNumberConfig(), meta).integer);
|
||||
System.out.println("double: " + loader.load(new MetaNumberConfig(), meta).aDouble);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static final class MetaListConfig implements ConfigTemplate {
|
||||
@Value("list")
|
||||
private @Meta List<@Meta String> list;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static final class MetaMapConfig implements ConfigTemplate {
|
||||
@Value("map")
|
||||
private @Meta Map<@Meta String, @Meta String> map;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static final class MetaStringConfig implements ConfigTemplate {
|
||||
@Value("string")
|
||||
private @Meta String string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static final class MetaNumberConfig implements ConfigTemplate {
|
||||
@Value("int")
|
||||
private @Meta int integer;
|
||||
|
||||
|
||||
@Value("double")
|
||||
private @Meta double aDouble;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import com.dfsek.terra.profiler.ProfilerImpl;
|
||||
|
||||
public class ProfilerTest {
|
||||
private static final Profiler PROFILER = new ProfilerImpl();
|
||||
|
||||
|
||||
private static void doThing() throws InterruptedException {
|
||||
PROFILER.push("thing");
|
||||
Thread.sleep(1);
|
||||
@@ -33,7 +33,7 @@ public class ProfilerTest {
|
||||
thing4();
|
||||
PROFILER.pop("thing");
|
||||
}
|
||||
|
||||
|
||||
private static void doOtherThing() throws InterruptedException {
|
||||
PROFILER.push("thing2");
|
||||
Thread.sleep(2);
|
||||
@@ -41,30 +41,30 @@ public class ProfilerTest {
|
||||
thing4();
|
||||
PROFILER.pop("thing2");
|
||||
}
|
||||
|
||||
|
||||
private static void doThirdOtherThing() throws InterruptedException {
|
||||
PROFILER.push("thing3");
|
||||
Thread.sleep(2);
|
||||
PROFILER.pop("thing3");
|
||||
}
|
||||
|
||||
|
||||
private static void thing4() throws InterruptedException {
|
||||
PROFILER.push("thing4");
|
||||
Thread.sleep(2);
|
||||
PROFILER.pop("thing4");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testProfiler() throws InterruptedException {
|
||||
//PROFILER.start();
|
||||
for(int i = 0; i < 100; i++) {
|
||||
doThing();
|
||||
}
|
||||
|
||||
|
||||
for(int i = 0; i < 100; i++) {
|
||||
doThirdOtherThing();
|
||||
}
|
||||
|
||||
|
||||
for(int i = 0; i < 100; i++) {
|
||||
doOtherThing();
|
||||
}
|
||||
@@ -76,7 +76,7 @@ public class ProfilerTest {
|
||||
PROFILER.pop("thing");
|
||||
PROFILER.push("thing4");
|
||||
PROFILER.pop("thing4");
|
||||
|
||||
|
||||
PROFILER.getTimings().forEach((id, timings) -> System.out.println(id + ": " + timings.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,18 +34,18 @@ public class RegistryTest {
|
||||
@Test
|
||||
public void openRegistry() {
|
||||
OpenRegistry<String> test = new OpenRegistryImpl<>(TypeKey.of(String.class));
|
||||
|
||||
|
||||
test.register(RegistryKey.parse("test:test"), "bazinga");
|
||||
|
||||
|
||||
assertEquals(test.get(RegistryKey.parse("test:test")).orElseThrow(), "bazinga");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void openRegistryChecked() {
|
||||
OpenRegistry<String> test = new OpenRegistryImpl<>(TypeKey.of(String.class));
|
||||
|
||||
|
||||
test.registerChecked(RegistryKey.parse("test:test"), "bazinga");
|
||||
|
||||
|
||||
try {
|
||||
test.registerChecked(RegistryKey.parse("test:test"), "bazinga2");
|
||||
fail("Shouldn't be able to re-register with #registerChecked!");
|
||||
@@ -53,15 +53,15 @@ public class RegistryTest {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void checkedRegistry() {
|
||||
CheckedRegistry<String> test = new CheckedRegistryImpl<>(new OpenRegistryImpl<>(TypeKey.of(String.class)));
|
||||
|
||||
|
||||
test.register(RegistryKey.parse("test:test"), "bazinga");
|
||||
|
||||
|
||||
assertEquals(test.get(RegistryKey.parse("test:test")).orElseThrow(), "bazinga");
|
||||
|
||||
|
||||
try {
|
||||
test.register(RegistryKey.parse("test:test"), "bazinga2");
|
||||
fail("Shouldn't be able to re-register in CheckedRegistry!");
|
||||
@@ -69,23 +69,23 @@ public class RegistryTest {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getID() {
|
||||
OpenRegistry<String> test = new OpenRegistryImpl<>(TypeKey.of(String.class));
|
||||
|
||||
|
||||
test.register(RegistryKey.parse("test:test"), "bazinga");
|
||||
|
||||
|
||||
assertEquals(test.getByID("test").orElseThrow(), "bazinga");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getIDAmbiguous() {
|
||||
OpenRegistry<String> test = new OpenRegistryImpl<>(TypeKey.of(String.class));
|
||||
|
||||
|
||||
test.registerChecked(RegistryKey.parse("test:test"), "bazinga");
|
||||
test.registerChecked(RegistryKey.parse("test2:test"), "bazinga");
|
||||
|
||||
|
||||
try {
|
||||
test.getByID("test");
|
||||
fail("Shouldn't be able to get with ambiguous ID!");
|
||||
|
||||
Reference in New Issue
Block a user