WIP meta pack system

This commit is contained in:
Zoë Gidiere
2023-12-11 16:25:13 -07:00
parent d48fa96ec7
commit b039629b2d
8 changed files with 348 additions and 3 deletions

View File

@@ -7,6 +7,8 @@
package com.dfsek.terra.api;
import com.dfsek.terra.api.config.MetaPack;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
@@ -61,6 +63,10 @@ public interface Platform extends LoaderRegistrar {
@Contract(pure = true)
CheckedRegistry<ConfigPack> getConfigRegistry();
@NotNull
@Contract(pure = true)
CheckedRegistry<MetaPack> getMetaConfigRegistry();
@NotNull
@Contract(pure = true)
Registry<BaseAddon> getAddons();

View File

@@ -2,10 +2,23 @@ package com.dfsek.terra.api.config;
import ca.solostudios.strata.version.Version;
import com.dfsek.terra.api.properties.PropertyHolder;
import com.dfsek.terra.api.registry.key.Keyed;
import com.dfsek.terra.api.registry.meta.CheckedRegistryHolder;
import com.dfsek.terra.api.registry.meta.RegistryProvider;
import com.dfsek.terra.api.tectonic.ConfigLoadingDelegate;
import com.dfsek.terra.api.tectonic.LoaderRegistrar;
import java.util.Map;
public interface MetaPack {
public interface MetaPack extends LoaderRegistrar,
ConfigLoadingDelegate,
CheckedRegistryHolder,
RegistryProvider,
Keyed<MetaPack>,
PropertyHolder {
Map<String, ConfigPack> packs();
String getAuthor();

View File

@@ -18,6 +18,10 @@
package com.dfsek.terra;
import com.dfsek.tectonic.api.TypeRegistry;
import com.dfsek.terra.api.config.MetaPack;
import com.dfsek.terra.registry.master.MetaConfigRegistry;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.jetbrains.annotations.NotNull;
@@ -86,9 +90,12 @@ public abstract class AbstractPlatform implements Platform {
private static final MutableBoolean LOADED = new MutableBoolean(false);
private final EventManager eventManager = new EventManagerImpl();
private final ConfigRegistry configRegistry = new ConfigRegistry();
private final MetaConfigRegistry metaConfigRegistry = new MetaConfigRegistry();
private final CheckedRegistry<ConfigPack> checkedConfigRegistry = new CheckedRegistryImpl<>(configRegistry);
private final CheckedRegistry<MetaPack> checkedMetaConfigRegistry = new CheckedRegistryImpl<>(metaConfigRegistry);
private final Profiler profiler = new ProfilerImpl();
private final GenericLoaders loaders = new GenericLoaders(this);
@@ -103,6 +110,10 @@ public abstract class AbstractPlatform implements Platform {
return configRegistry;
}
public MetaConfigRegistry getRawMetaConfigRegistry() {
return metaConfigRegistry;
}
protected Iterable<BaseAddon> platformAddon() {
return Collections.emptySet();
}
@@ -151,6 +162,13 @@ public abstract class AbstractPlatform implements Platform {
.then(event -> loadConfigPacks())
.global();
eventManager.getHandler(FunctionalEventHandler.class)
.register(internalAddon, PlatformInitializationEvent.class)
.then(event -> loadMetaConfigPacks())
.global();
logger.info("Terra addons successfully loaded.");
logger.info("Finished initialization.");
}
@@ -171,6 +189,22 @@ public abstract class AbstractPlatform implements Platform {
return true;
}
protected boolean loadMetaConfigPacks() {
logger.info("Loading meta config packs...");
MetaConfigRegistry metaConfigRegistry = getRawMetaConfigRegistry();
metaConfigRegistry.clear();
try {
metaConfigRegistry.loadAll(this);
} catch(IOException e) {
logger.error("Failed to load meta config packs", e);
return false;
} catch(PackLoadFailuresException e) {
e.getExceptions().forEach(ex -> logger.error("Failed to meta load config pack", ex));
return false;
}
return true;
}
protected InternalAddon loadAddons() {
List<BaseAddon> addonList = new ArrayList<>();
@@ -337,6 +371,12 @@ public abstract class AbstractPlatform implements Platform {
return checkedConfigRegistry;
}
@Override
public @NotNull CheckedRegistry<MetaPack> getMetaConfigRegistry() {
return checkedMetaConfigRegistry;
}
@Override
public @NotNull Registry<BaseAddon> getAddons() {
return lockedAddonRegistry;

View File

@@ -2,18 +2,110 @@ package com.dfsek.terra.config.pack;
import ca.solostudios.strata.version.Version;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import com.dfsek.tectonic.api.TypeRegistry;
import com.dfsek.tectonic.api.config.Configuration;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import com.dfsek.tectonic.api.loader.AbstractConfigLoader;
import com.dfsek.tectonic.api.loader.ConfigLoader;
import com.dfsek.tectonic.api.loader.type.TypeLoader;
import com.dfsek.tectonic.yaml.YamlConfiguration;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.ConfigType;
import com.dfsek.terra.api.config.MetaPack;
import com.dfsek.terra.api.properties.Context;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.tectonic.ConfigLoadingDelegate;
import com.dfsek.terra.api.util.reflection.ReflectionUtil;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.config.loaders.GenericTemplateSupplierLoader;
import com.dfsek.terra.config.loaders.config.BufferedImageLoader;
import com.dfsek.terra.registry.CheckedRegistryImpl;
import com.dfsek.terra.registry.OpenRegistryImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MetaPackImpl implements MetaPack {
private final Platform platform;
private final MetaPackTemplate template = new MetaPackTemplate();
private final Platform platform;
private final Path rootPath;
private final Map<String, ConfigPack> packs = new HashMap<>();
private final ConfigLoader selfLoader = new ConfigLoader();
private final Context context = new Context();
private final RegistryKey key;
private final Map<Type, CheckedRegistryImpl<?>> registryMap = new HashMap<>();
private static final Logger logger = LoggerFactory.getLogger(MetaPackImpl.class);
private final AbstractConfigLoader abstractConfigLoader = new AbstractConfigLoader();
public MetaPackImpl(Path path, Platform platform) throws IOException {
this.rootPath = path;
this.platform = platform;
Path packManifestPath = rootPath.resolve("metapack.yml");
if(Files.notExists(packManifestPath)) throw new IOException("No metapack.yml found in " + path);
Configuration packManifest = new YamlConfiguration(Files.newInputStream(packManifestPath),
packManifestPath.getFileName().toString());
register(selfLoader);
platform.register(selfLoader);
register(abstractConfigLoader);
platform.register(abstractConfigLoader);
selfLoader.load(template, packManifest);
String namespace;
String id;
if(template.getID().contains(":")) {
namespace = template.getID().substring(0, template.getID().indexOf(":"));
id = template.getID().substring(template.getID().indexOf(":") + 1);
} else {
id = template.getID();
namespace = template.getID();
}
this.key = RegistryKey.of(namespace, id);
try {
template.getPacks().forEach((k, v) -> {
try {
packs.put(k, new ConfigPackImpl(rootPath.resolve(v), platform));
} catch(IOException e) {
throw new RuntimeException(e);
}
});
} catch(RuntimeException e) {
throw new IOException(e);
}
}
@Override
public String getAuthor() {
return template.getAuthor();
@@ -26,6 +118,78 @@ public class MetaPackImpl implements MetaPack {
@Override
public Map<String, ConfigPack> packs() {
return null;
return packs;
}
@Override
public Context getContext() {
return context;
}
@Override
public RegistryKey getRegistryKey() {
return key;
}
@Override
public <T> CheckedRegistry<T> getRegistry(Type type) {
return (CheckedRegistry<T>) registryMap.get(type);
}
@Override
public <T> CheckedRegistry<T> getCheckedRegistry(Type type) throws IllegalStateException {
return (CheckedRegistry<T>) registryMap.get(type);
}
@Override
public <T> CheckedRegistry<T> getOrCreateRegistry(TypeKey<T> typeKey) {
return (CheckedRegistry<T>) registryMap.computeIfAbsent(typeKey.getType(), c -> {
OpenRegistry<T> registry = new OpenRegistryImpl<>(typeKey);
selfLoader.registerLoader(c, registry);
abstractConfigLoader.registerLoader(c, registry);
logger.debug("Registered loader for registry of class {}", ReflectionUtil.typeToString(c));
if(typeKey.getType() instanceof ParameterizedType param) {
Type base = param.getRawType();
if(base instanceof Class // should always be true but we'll check anyways
&& Supplier.class.isAssignableFrom((Class<?>) base)) { // If it's a supplier
Type supplied = param.getActualTypeArguments()[0]; // Grab the supplied type
if(supplied instanceof ParameterizedType suppliedParam) {
Type suppliedBase = suppliedParam.getRawType();
if(suppliedBase instanceof Class // should always be true but we'll check anyways
&& ObjectTemplate.class.isAssignableFrom((Class<?>) suppliedBase)) {
Type templateType = suppliedParam.getActualTypeArguments()[0];
GenericTemplateSupplierLoader<?> loader = new GenericTemplateSupplierLoader<>(
(Registry<Supplier<ObjectTemplate<Supplier<ObjectTemplate<?>>>>>) registry);
selfLoader.registerLoader(templateType, loader);
abstractConfigLoader.registerLoader(templateType, loader);
logger.debug("Registered template loader for registry of class {}", ReflectionUtil.typeToString(templateType));
}
}
}
}
return new CheckedRegistryImpl<>(registry);
});
}
@Override
public <T> MetaPackImpl applyLoader(Type type, TypeLoader<T> loader) {
abstractConfigLoader.registerLoader(type, loader);
selfLoader.registerLoader(type, loader);
return this;
}
@Override
public <T> MetaPackImpl applyLoader(Type type, Supplier<ObjectTemplate<T>> loader) {
abstractConfigLoader.registerLoader(type, loader);
selfLoader.registerLoader(type, loader);
return this;
}
@Override
public void register(TypeRegistry registry) {
registryMap.forEach(registry::registerLoader);
}
}

View File

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

View File

@@ -62,6 +62,7 @@ public abstract class ModPlatform extends AbstractPlatform {
public void registerWorldTypes(BiConsumer<Identifier, WorldPreset> registerFunction) {
getRawConfigRegistry()
.forEach(pack -> PresetUtil.createDefault(pack, this).apply(registerFunction));
getRawMetaConfigRegistry().forEach(pack -> PresetUtil.createMetaPack(pack, this).apply(registerFunction));
}
@Override

View File

@@ -1,5 +1,7 @@
package com.dfsek.terra.mod.util;
import com.dfsek.terra.api.config.MetaPack;
import net.minecraft.registry.Registry;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.util.Identifier;
@@ -75,6 +77,54 @@ public class PresetUtil {
return Pair.of(generatorID, preset);
}
public static Pair<Identifier, WorldPreset> createMetaPack(MetaPack pack, ModPlatform platform) {
Registry<DimensionType> dimensionTypeRegistry = platform.dimensionTypeRegistry();
Registry<ChunkGeneratorSettings> chunkGeneratorSettingsRegistry = platform.chunkGeneratorSettingsRegistry();
Registry<MultiNoiseBiomeSourceParameterList> multiNoiseBiomeSourceParameterLists =
platform.multiNoiseBiomeSourceParameterListRegistry();
RegistryEntry<DimensionType> overworldDimensionType = dimensionTypeRegistry.getEntry(DimensionTypes.OVERWORLD).orElseThrow();
RegistryEntry<ChunkGeneratorSettings> overworld = chunkGeneratorSettingsRegistry.getEntry(ChunkGeneratorSettings.OVERWORLD)
.orElseThrow();
Identifier generatorID = Identifier.of("terra", pack.getID().toLowerCase(Locale.ROOT) + "/" + pack.getNamespace().toLowerCase(
Locale.ROOT));
PRESETS.add(generatorID);
RegistryEntry<DimensionType> registryEntry = dimensionTypeRegistry.getEntry(DimensionTypes.THE_NETHER).orElseThrow();
RegistryEntry.Reference<MultiNoiseBiomeSourceParameterList> reference = multiNoiseBiomeSourceParameterLists.getEntry(
MultiNoiseBiomeSourceParameterLists.NETHER).orElseThrow();
RegistryEntry<ChunkGeneratorSettings> registryEntry2 = chunkGeneratorSettingsRegistry.getEntry(ChunkGeneratorSettings.NETHER)
.orElseThrow();
RegistryEntry<DimensionType> registryEntry3 = dimensionTypeRegistry.getEntry(DimensionTypes.THE_END).orElseThrow();
RegistryEntry<ChunkGeneratorSettings> registryEntry4 = chunkGeneratorSettingsRegistry.getEntry(ChunkGeneratorSettings.END)
.orElseThrow();
ConfigPack overWorldPack = pack.packs().get("minecraft:overworld");
TerraBiomeSource owBiomeSource = new TerraBiomeSource(overWorldPack);
ChunkGenerator owGenerator = new MinecraftChunkGeneratorWrapper(owBiomeSource, overWorldPack, overworld);
ConfigPack netherPack = pack.packs().get("minecraft:nether");
TerraBiomeSource neBiomeSource = new TerraBiomeSource(netherPack);
ChunkGenerator neGenerator = new MinecraftChunkGeneratorWrapper(neBiomeSource, netherPack, registryEntry2);
ConfigPack endPack = pack.packs().get("minecraft:the_end");
TerraBiomeSource endBiomeSource = new TerraBiomeSource(netherPack);
ChunkGenerator endGenerator = new MinecraftChunkGeneratorWrapper(endBiomeSource, endPack, registryEntry4);
DimensionOptions dimensionOptions = new DimensionOptions(overworldDimensionType, owGenerator);
DimensionOptions netherDimensionOptions = new DimensionOptions(registryEntry, neGenerator);
DimensionOptions endDimensionOptions = new DimensionOptions(registryEntry3, endGenerator);
WorldPreset preset = createPreset(dimensionOptions, netherDimensionOptions, endDimensionOptions);
LOGGER.info("Created world type \"{}\"", generatorID);
return Pair.of(generatorID, preset);
}
private static WorldPreset createPreset(DimensionOptions dimensionOptions, DimensionOptions netherDimensionOptions,
DimensionOptions endDimensionOptions) {
return new WorldPreset(

View File

@@ -35,6 +35,12 @@ public final class BiomeUtil {
pack.getCheckedRegistry(Biome.class)
.forEach((id, biome) -> registerBiome(biome, pack, id, biomeRegistry));
});
CommonPlatform.get().getMetaConfigRegistry().forEach(metaPack -> { // Register all Terra biomes.
metaPack.packs().forEach((k, pack) -> {
pack.getCheckedRegistry(Biome.class)
.forEach((id, biome) -> registerBiome(biome, pack, id, biomeRegistry));
});
});
logger.info("Terra biomes registered.");
}