begin work on WorldConfig stuff

This doesn't compile right now. A lot of work needs to be done.
This commit is contained in:
dfsek 2021-03-01 09:58:18 -07:00
parent 7f988dcf26
commit 5a6b7ac4c1
32 changed files with 377 additions and 152 deletions

View File

@ -1,13 +1,15 @@
package com.dfsek.terra.api.event.events.world;
import com.dfsek.terra.api.event.events.Event;
import com.dfsek.terra.api.event.events.PackEvent;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.world.TerraWorld;
/**
* Called upon initialization of a TerraWorld.
*/
public class TerraWorldLoadEvent implements PackEvent {
public class TerraWorldLoadEvent implements Event {
private final TerraWorld world;
public TerraWorldLoadEvent(TerraWorld world) {
@ -18,8 +20,7 @@ public class TerraWorldLoadEvent implements PackEvent {
return world;
}
@Override
public ConfigPack getPack() {
public WorldConfig getPack() {
return world.getConfig();
}
}

View File

@ -15,9 +15,9 @@ import java.util.function.Consumer;
* @param <T> Type in registry
*/
public class LockedRegistry<T> implements Registry<T> {
private final OpenRegistry<T> registry;
private final Registry<T> registry;
public LockedRegistry(OpenRegistry<T> registry) {
public LockedRegistry(Registry<T> registry) {
this.registry = registry;
}

View File

@ -31,7 +31,6 @@ import com.dfsek.terra.api.structures.structure.buffer.StructureBuffer;
import com.dfsek.terra.registry.config.FunctionRegistry;
import com.dfsek.terra.registry.config.LootRegistry;
import com.dfsek.terra.registry.config.ScriptRegistry;
import com.dfsek.terra.world.generation.math.SamplerCache;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import net.jafama.FastMath;
@ -49,7 +48,7 @@ public class StructureScript {
private final TerraPlugin main;
private String tempID;
public StructureScript(InputStream inputStream, TerraPlugin main, ScriptRegistry registry, LootRegistry lootRegistry, SamplerCache cache, FunctionRegistry functionRegistry) throws ParseException {
public StructureScript(InputStream inputStream, TerraPlugin main, ScriptRegistry registry, LootRegistry lootRegistry, FunctionRegistry functionRegistry) throws ParseException {
Parser parser;
try {
parser = new Parser(IOUtils.toString(inputStream));
@ -60,7 +59,7 @@ public class StructureScript {
functionRegistry.forEach(parser::registerFunction); // Register registry functions.
parser.registerFunction("block", new BlockFunctionBuilder(main))
.registerFunction("check", new CheckFunctionBuilder(main, cache))
.registerFunction("check", new CheckFunctionBuilder(main))
.registerFunction("structure", new StructureFunctionBuilder(registry, main))
.registerFunction("randomInt", new RandomFunctionBuilder())
.registerFunction("recursions", new RecursionsFunctionBuilder())

View File

@ -12,17 +12,15 @@ import java.util.List;
public class CheckFunctionBuilder implements FunctionBuilder<CheckFunction> {
private final TerraPlugin main;
private final SamplerCache cache;
public CheckFunctionBuilder(TerraPlugin main, SamplerCache cache) {
public CheckFunctionBuilder(TerraPlugin main) {
this.main = main;
this.cache = cache;
}
@SuppressWarnings("unchecked")
@Override
public CheckFunction build(List<Returnable<?>> argumentList, Position position) throws ParseException {
return new CheckFunction(main, (Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1), (Returnable<Number>) argumentList.get(2), cache, position);
return new CheckFunction(main, (Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1), (Returnable<Number>) argumentList.get(2), position);
}
@Override

View File

@ -25,22 +25,23 @@ public class CheckFunction implements Function<String> {
private final TerraPlugin main;
private final Returnable<Number> x, y, z;
private final Position position;
private final SamplerCache cache;
public CheckFunction(TerraPlugin main, Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, SamplerCache cache, Position position) {
public CheckFunction(TerraPlugin main, Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Position position) {
this.main = main;
this.x = x;
this.y = y;
this.z = z;
this.position = position;
this.cache = cache;
}
@Override
public String apply(ImplementationArguments implementationArguments, Map<String, Variable<?>> variableMap) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = new Vector2(x.apply(implementationArguments, variableMap).doubleValue(), z.apply(implementationArguments, variableMap).doubleValue());
RotationUtil.rotateVector(xz, arguments.getRotation());
@ -52,7 +53,8 @@ public class CheckFunction implements Function<String> {
private String apply(Location vector, World world) {
TerraWorld tw = main.getWorld(world);
double comp = sample(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ(), world);
SamplerCache cache = tw.getConfig().getSamplerCache();
double comp = sample(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ(), cache);
if(comp > 0) return "LAND"; // If noise val is greater than zero, location will always be land.
@ -64,10 +66,10 @@ public class CheckFunction implements Function<String> {
return "OCEAN"; // Below sea level
}
private double sample(int x, int y, int z, World w) {
private double sample(int x, int y, int z, SamplerCache cache) {
int cx = FastMath.floorDiv(x, 16);
int cz = FastMath.floorDiv(z, 16);
return cache.get(w, x, z).sample(x - (cx << 4), y, z - (cz << 4));
return cache.get(x, z).sample(x - (cx << 4), y, z - (cz << 4));
}
@Override

View File

@ -5,6 +5,7 @@ import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.config.builder.GeneratorBuilder;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.world.generation.WorldGenerator;
import java.util.HashSet;
import java.util.Set;
@ -13,7 +14,7 @@ import java.util.Set;
* Class representing a config-defined biome
*/
public class UserDefinedBiome implements TerraBiome {
private final GeneratorBuilder gen;
private final WorldGenerator gen;
private final ProbabilityCollection<Biome> vanilla;
private final String id;
private final BiomeTemplate config;
@ -21,13 +22,13 @@ public class UserDefinedBiome implements TerraBiome {
private final Set<String> tags;
public UserDefinedBiome(ProbabilityCollection<Biome> vanilla, GeneratorBuilder gen, BiomeTemplate config) {
public UserDefinedBiome(ProbabilityCollection<Biome> vanilla, WorldGenerator gen, BiomeTemplate config) {
this.vanilla = vanilla;
this.gen = gen;
this.id = config.getID();
this.config = config;
this.color = config.getColor();
this.tags = config.getTags() == null ? new HashSet<>() : config.getTags();
this.tags = config.getTags();
tags.add("BIOME:" + id);
}
@ -52,7 +53,7 @@ public class UserDefinedBiome implements TerraBiome {
@Override
public Generator getGenerator(World w) {
return gen.build(w.getSeed());
return gen;
}
@Override

View File

@ -1,5 +1,6 @@
package com.dfsek.terra.api.world.biome.provider;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.registry.OpenRegistry;
import net.jafama.FastMath;
@ -15,7 +16,7 @@ public class ImageBiomeProvider implements BiomeProvider, BiomeProvider.BiomePro
private final int resolution;
private final Align align;
public ImageBiomeProvider(OpenRegistry<TerraBiome> registry, BufferedImage image, int resolution, Align align) {
public ImageBiomeProvider(Registry<TerraBiome> registry, BufferedImage image, int resolution, Align align) {
this.image = image;
this.resolution = resolution;
this.align = align;

View File

@ -0,0 +1,57 @@
package com.dfsek.terra.config.builder;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.noise.samplers.ExpressionSampler;
import com.dfsek.terra.api.math.noise.samplers.noise.ConstantSampler;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.generation.WorldGenerator;
import java.util.HashMap;
import java.util.Map;
public class BiomeBuilder implements ConfigBuilder<TerraBiome> {
private final BiomeTemplate template;
private final ConfigPack pack;
public BiomeBuilder(BiomeTemplate template, ConfigPack pack) {
this.template = template;
this.pack = pack;
}
@Override
public TerraBiome build(TerraWorld world, TerraPlugin main) {
NoiseSampler noise;
NoiseSampler elevation;
NoiseSampler carving;
Scope varScope = new Scope().withParent(pack.getVarScope());
template.getVariables().forEach(varScope::create);
Map<String, NoiseSeeded> noiseBuilderMap = pack.getTemplate().getNoiseBuilderMap();
Map<String, FunctionTemplate> functionTemplateMap = new HashMap<>(template.getFunctions());
functionTemplateMap.putAll(template.getFunctions());
long seed = world.getWorld().getSeed();
try {
noise = new ExpressionSampler(template.getNoiseEquation(), varScope, seed, noiseBuilderMap, functionTemplateMap);
elevation = template.getElevationEquation() == null ? new ConstantSampler(0) : new ExpressionSampler(template.getElevationEquation(), varScope, seed, noiseBuilderMap, functionTemplateMap);
carving = new ExpressionSampler(template.getCarvingEquation(), varScope, seed, noiseBuilderMap, functionTemplateMap);
} catch(ParseException e) {
throw new RuntimeException(e);
}
WorldGenerator generator = new WorldGenerator(template.getPalette(), template.getSlantPalette(), noise, elevation, carving, template.getBiomeNoise().apply(seed), template.getElevationWeight(),
template.getBlendDistance(), template.getBlendStep(), template.getBlendWeight());
return new UserDefinedBiome(template.getVanilla(), generator, template);
}
}

View File

@ -0,0 +1,8 @@
package com.dfsek.terra.config.builder;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.world.TerraWorld;
public interface ConfigBuilder<O> {
O build(TerraWorld world, TerraPlugin main);
}

View File

@ -0,0 +1,12 @@
package com.dfsek.terra.config.builder;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.world.TerraWorld;
public class ScriptBuilder implements ConfigBuilder<StructureScript> {
@Override
public StructureScript build(TerraWorld world, TerraPlugin main) {
return null;
}
}

View File

@ -0,0 +1,79 @@
package com.dfsek.terra.config.dummy;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
import java.io.File;
import java.util.UUID;
public class DummyWorld implements World {
@Override
public Object getHandle() {
throw new UnsupportedOperationException("Cannot get handle of DummyWorld");
}
@Override
public long getSeed() {
return 2403L;
}
@Override
public int getMaxHeight() {
return 155;
}
@Override
public ChunkGenerator getGenerator() {
throw new UnsupportedOperationException("Cannot get generator of DummyWorld");
}
@Override
public String getName() {
return "DUMMY";
}
@Override
public UUID getUID() {
return UUID.randomUUID();
}
@Override
public boolean isChunkGenerated(int x, int z) {
return false;
}
@Override
public Chunk getChunkAt(int x, int z) {
throw new UnsupportedOperationException("Cannot get chunk in DummyWorld");
}
@Override
public File getWorldFolder() {
throw new UnsupportedOperationException("Cannot get folder of DummyWorld");
}
@Override
public Block getBlockAt(int x, int y, int z) {
throw new UnsupportedOperationException("Cannot get block in DummyWorld");
}
@Override
public Block getBlockAt(Location l) {
throw new UnsupportedOperationException("Cannot get block in DummyWorld");
}
@Override
public Entity spawnEntity(Location location, EntityType entityType) {
throw new UnsupportedOperationException("Cannot spawn entity in DummyWorld");
}
@Override
public int getMinHeight() {
return 0;
}
}

View File

@ -1,18 +1,13 @@
package com.dfsek.terra.config.factories;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.config.builder.GeneratorBuilder;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import com.dfsek.terra.config.builder.BiomeBuilder;
import com.dfsek.terra.config.builder.ConfigBuilder;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.BiomeTemplate;
import java.util.LinkedHashMap;
import java.util.Map;
public class BiomeFactory implements TerraFactory<BiomeTemplate, TerraBiome> {
public class BiomeFactory implements ConfigFactory<BiomeTemplate, ConfigBuilder<TerraBiome>> {
private final ConfigPack pack;
public BiomeFactory(ConfigPack pack) {
@ -20,32 +15,7 @@ public class BiomeFactory implements TerraFactory<BiomeTemplate, TerraBiome> {
}
@Override
public UserDefinedBiome build(BiomeTemplate template, TerraPlugin main) {
GeneratorBuilder generatorBuilder = new GeneratorBuilder();
generatorBuilder.setElevationEquation(template.getElevationEquation());
generatorBuilder.setNoiseEquation(template.getNoiseEquation());
generatorBuilder.setCarvingEquation(template.getCarvingEquation());
generatorBuilder.setNoiseBuilderMap(pack.getTemplate().getNoiseBuilderMap());
Map<String, FunctionTemplate> functions = new LinkedHashMap<>(pack.getTemplate().getFunctions()); // linked map to preserve order.
functions.putAll(template.getFunctions());
generatorBuilder.setFunctionTemplateMap(functions);
generatorBuilder.setPalettes(template.getPalette());
generatorBuilder.setSlantPalettes(template.getSlantPalette());
Scope vars = new Scope().withParent(pack.getVarScope());
template.getVariables().forEach(vars::create);
generatorBuilder.setVarScope(vars);
generatorBuilder.setInterpolateElevation(template.interpolateElevation());
generatorBuilder.setElevationWeight(template.getElevationWeight());
generatorBuilder.setBiomeNoise(template.getBiomeNoise());
generatorBuilder.setBlendDistance(template.getBlendDistance());
generatorBuilder.setBlendStep(template.getBlendStep());
generatorBuilder.setBlendWeight(template.getBlendWeight());
return new UserDefinedBiome(template.getVanilla(), generatorBuilder, template);
public BiomeBuilder build(BiomeTemplate template, TerraPlugin main) {
return new BiomeBuilder(template, pack);
}
}

View File

@ -11,7 +11,7 @@ import com.dfsek.terra.config.templates.CarverTemplate;
import java.util.Arrays;
import java.util.List;
public class CarverFactory implements TerraFactory<CarverTemplate, UserDefinedCarver> {
public class CarverFactory implements ConfigFactory<CarverTemplate, UserDefinedCarver> {
private final ConfigPack pack;
public CarverFactory(ConfigPack pack) {

View File

@ -4,6 +4,6 @@ import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.terra.api.TerraPlugin;
public interface TerraFactory<C extends ConfigTemplate, O> {
public interface ConfigFactory<C extends ConfigTemplate, O> {
O build(C config, TerraPlugin main) throws LoadException;
}

View File

@ -10,7 +10,7 @@ import com.dfsek.terra.api.world.palette.holder.PaletteLayerHolder;
import com.dfsek.terra.config.templates.FloraTemplate;
import com.dfsek.terra.world.population.items.flora.TerraFlora;
public class FloraFactory implements TerraFactory<FloraTemplate, Flora> {
public class FloraFactory implements ConfigFactory<FloraTemplate, Flora> {
@Override
public TerraFlora build(FloraTemplate config, TerraPlugin main) {
Palette<BlockData> palette = new NoisePalette<>(new WhiteNoiseSampler(2403), false);

View File

@ -7,7 +7,7 @@ import com.dfsek.terra.world.population.items.ores.DeformedSphereOre;
import com.dfsek.terra.world.population.items.ores.Ore;
import com.dfsek.terra.world.population.items.ores.VanillaOre;
public class OreFactory implements TerraFactory<OreTemplate, Ore> {
public class OreFactory implements ConfigFactory<OreTemplate, Ore> {
@Override
public Ore build(OreTemplate config, TerraPlugin main) {
BlockData m = config.getMaterial();

View File

@ -7,7 +7,7 @@ import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.palette.holder.PaletteLayerHolder;
import com.dfsek.terra.config.templates.PaletteTemplate;
public class PaletteFactory implements TerraFactory<PaletteTemplate, Palette<BlockData>> {
public class PaletteFactory implements ConfigFactory<PaletteTemplate, Palette<BlockData>> {
@Override
public Palette<BlockData> build(PaletteTemplate config, TerraPlugin main) {
NoisePalette<BlockData> palette = new NoisePalette<>(config.getNoise().apply(2403L), config.getNoise().getDimensions() == 2);

View File

@ -4,7 +4,7 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.config.templates.StructureTemplate;
import com.dfsek.terra.world.population.items.TerraStructure;
public class StructureFactory implements TerraFactory<StructureTemplate, TerraStructure> {
public class StructureFactory implements ConfigFactory<StructureTemplate, TerraStructure> {
@Override
public TerraStructure build(StructureTemplate config, TerraPlugin main) {
return new TerraStructure(config.getStructures(), config.getY(), config.getSpawn(), config);

View File

@ -5,7 +5,7 @@ import com.dfsek.terra.api.world.tree.Tree;
import com.dfsek.terra.config.templates.TreeTemplate;
import com.dfsek.terra.world.population.items.tree.TerraTree;
public class TreeFactory implements TerraFactory<TreeTemplate, Tree> {
public class TreeFactory implements ConfigFactory<TreeTemplate, Tree> {
@Override
public Tree build(TreeTemplate config, TerraPlugin main) {
return new TerraTree(config.getSpawnable(), config.getyOffset(), config.getStructures());

View File

@ -5,12 +5,14 @@ import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.noise.samplers.noise.ConstantSampler;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.registry.config.BiomeRegistry;
public abstract class BiomeProviderTemplate implements ObjectTemplate<BiomeProvider.BiomeProviderBuilder>, BiomeProvider.BiomeProviderBuilder {
protected final BiomeRegistry registry;
protected final Registry<TerraBiome> registry;
@Value("resolution")
@Default
protected int resolution = 1;
@ -33,7 +35,7 @@ public abstract class BiomeProviderTemplate implements ObjectTemplate<BiomeProvi
@Value("type")
BiomeProvider.Type type;
protected BiomeProviderTemplate(BiomeRegistry registry) {
protected BiomeProviderTemplate(Registry<TerraBiome> registry) {
this.registry = registry;
}

View File

@ -1,6 +1,8 @@
package com.dfsek.terra.config.loaders.config.biome.templates.source;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.biome.provider.ImageBiomeProvider;
import com.dfsek.terra.registry.config.BiomeRegistry;
@ -14,7 +16,7 @@ public class ImageProviderTemplate extends BiomeProviderTemplate {
@Value("image.align")
private ImageBiomeProvider.Align align;
public ImageProviderTemplate(BiomeRegistry registry) {
public ImageProviderTemplate(Registry<TerraBiome> registry) {
super(registry);
}

View File

@ -23,13 +23,15 @@ import com.dfsek.terra.api.world.flora.Flora;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.tree.Tree;
import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.config.builder.ConfigBuilder;
import com.dfsek.terra.config.dummy.DummyWorld;
import com.dfsek.terra.config.factories.BiomeFactory;
import com.dfsek.terra.config.factories.CarverFactory;
import com.dfsek.terra.config.factories.FloraFactory;
import com.dfsek.terra.config.factories.OreFactory;
import com.dfsek.terra.config.factories.PaletteFactory;
import com.dfsek.terra.config.factories.StructureFactory;
import com.dfsek.terra.config.factories.TerraFactory;
import com.dfsek.terra.config.factories.ConfigFactory;
import com.dfsek.terra.config.factories.TreeFactory;
import com.dfsek.terra.config.fileloaders.FolderLoader;
import com.dfsek.terra.config.fileloaders.Loader;
@ -60,7 +62,7 @@ import com.dfsek.terra.registry.config.PaletteRegistry;
import com.dfsek.terra.registry.config.ScriptRegistry;
import com.dfsek.terra.registry.config.StructureRegistry;
import com.dfsek.terra.registry.config.TreeRegistry;
import com.dfsek.terra.world.generation.math.SamplerCache;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.population.items.TerraStructure;
import com.dfsek.terra.world.population.items.ores.Ore;
import org.apache.commons.io.IOUtils;
@ -106,8 +108,6 @@ public class ConfigPack implements LoaderRegistrar {
private final ConfigLoader selfLoader = new ConfigLoader();
private final Scope varScope = new Scope();
private final SamplerCache samplerCache;
private final TerraPlugin main;
private final Loader loader;
@ -119,7 +119,6 @@ public class ConfigPack implements LoaderRegistrar {
this.loader = new FolderLoader(folder.toPath());
this.main = main;
long l = System.nanoTime();
this.samplerCache = new SamplerCache(main);
floraRegistry = new FloraRegistry(main);
paletteRegistry = new PaletteRegistry(main);
treeRegistry = new TreeRegistry(main);
@ -148,6 +147,7 @@ public class ConfigPack implements LoaderRegistrar {
main.logger().severe("Failed to load config pack from folder \"" + folder.getAbsolutePath() + "\"");
throw e;
}
toWorldConfig(new TerraWorld(new DummyWorld(), this, main)); // Build now to catch any errors immediately.
}
public ConfigPack(ZipFile file, TerraPlugin main) throws ConfigException {
@ -155,7 +155,6 @@ public class ConfigPack implements LoaderRegistrar {
this.loader = new ZIPLoader(file);
this.main = main;
long l = System.nanoTime();
this.samplerCache = new SamplerCache(main);
floraRegistry = new FloraRegistry(main);
paletteRegistry = new PaletteRegistry(main);
treeRegistry = new TreeRegistry(main);
@ -192,9 +191,11 @@ public class ConfigPack implements LoaderRegistrar {
main.logger().severe("Failed to load config pack from ZIP archive \"" + file.getName() + "\"");
throw e;
}
toWorldConfig(new TerraWorld(new DummyWorld(), this, main)); // Build now to catch any errors immediately.
}
public static <C extends AbstractableTemplate, O> void buildAll(TerraFactory<C, O> factory, OpenRegistry<O> registry, List<C> configTemplates, TerraPlugin main) throws LoadException {
public static <C extends AbstractableTemplate, O> void buildAll(ConfigFactory<C, O> factory, OpenRegistry<O> registry, List<C> configTemplates, TerraPlugin main) throws LoadException {
for(C template : configTemplates) registry.add(template.getID(), factory.build(template, main));
}
@ -207,10 +208,10 @@ public class ConfigPack implements LoaderRegistrar {
loader.open("structures/data", ".tesf").thenEntries(entries -> {
for(Map.Entry<String, InputStream> entry : entries) {
try {
StructureScript structureScript = new StructureScript(entry.getValue(), main, scriptRegistry, lootRegistry, samplerCache, functionRegistry);
try(InputStream stream = entry.getValue()) {
StructureScript structureScript = new StructureScript(stream, main, scriptRegistry, lootRegistry, functionRegistry);
scriptRegistry.add(structureScript.getId(), structureScript);
} catch(com.dfsek.terra.api.structures.parser.exceptions.ParseException e) {
} catch(com.dfsek.terra.api.structures.parser.exceptions.ParseException | IOException e) {
throw new LoadException("Unable to load script \"" + entry.getKey() + "\"", e);
}
}
@ -237,14 +238,6 @@ public class ConfigPack implements LoaderRegistrar {
main.logger().info("Loaded config pack \"" + template.getID() + "\" v" + template.getVersion() + " by " + template.getAuthor() + " in " + (System.nanoTime() - start) / 1000000D + "ms.");
}
public TerraBiome getBiome(String id) {
return biomeRegistry.get(id);
}
public List<String> getBiomeIDs() {
return biomeRegistry.entries().stream().map(TerraBiome::getID).collect(Collectors.toList());
}
public TerraStructure getStructure(String id) {
return structureRegistry.get(id);
}
@ -285,10 +278,6 @@ public class ConfigPack implements LoaderRegistrar {
.registerLoader(ImageSamplerTemplate.class, () -> new ImageProviderTemplate(biomeRegistry));
}
public SamplerCache getSamplerCache() {
return samplerCache;
}
public Set<UserDefinedCarver> getCarvers() {
return carverRegistry.entries();
}
@ -301,7 +290,7 @@ public class ConfigPack implements LoaderRegistrar {
return new CheckedRegistry<>(scriptRegistry);
}
public CheckedRegistry<TerraBiome> getBiomeRegistry() {
public CheckedRegistry<ConfigBuilder<TerraBiome>> getBiomeRegistry() {
return new CheckedRegistry<>(biomeRegistry);
}
@ -340,4 +329,8 @@ public class ConfigPack implements LoaderRegistrar {
public CheckedRegistry<TerraStructure> getStructureRegistry() {
return new CheckedRegistry<>(structureRegistry);
}
public WorldConfig toWorldConfig(TerraWorld world){
return new WorldConfig(world, this, main);
}
}

View File

@ -0,0 +1,124 @@
package com.dfsek.terra.config.pack;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.registry.LockedRegistry;
import com.dfsek.terra.api.structures.loot.LootTable;
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.flora.Flora;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.tree.Tree;
import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.registry.OpenRegistry;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.generation.math.SamplerCache;
import com.dfsek.terra.world.population.items.TerraStructure;
import com.dfsek.terra.world.population.items.ores.Ore;
import java.util.Set;
import java.util.function.Supplier;
public class WorldConfig {
private final LockedRegistry<StructureScript> scriptRegistry;
private final LockedRegistry<TerraBiome> biomeRegistry;
private final SamplerCache samplerCache;
private final LockedRegistry<UserDefinedCarver> carverRegistry;
private final LockedRegistry<Tree> treeRegistry;
private final LockedRegistry<Flora> floraRegistry;
private final LockedRegistry<LootTable> lootRegistry;
private final LockedRegistry<Ore> oreRegistry;
private final LockedRegistry<Palette<BlockData>> paletteRegistry;
private final LockedRegistry<TerraStructure> structureRegistry;
private final BiomeProvider provider;
private final TerraWorld world;
private final ConfigPack pack;
public WorldConfig(TerraWorld world, ConfigPack pack, TerraPlugin main) {
this.world = world;
this.pack = pack;
this.samplerCache = new SamplerCache(main, world);
this.scriptRegistry = new LockedRegistry<>(pack.getScriptRegistry());
OpenRegistry<TerraBiome> biomeOpenRegistry = new OpenRegistry<>();
pack.getBiomeRegistry().forEach((id, biome) -> biomeOpenRegistry.add(id, biome.build(world, main)));
this.biomeRegistry = new LockedRegistry<>(biomeOpenRegistry);
this.carverRegistry = new LockedRegistry<>(pack.getCarverRegistry());
this.treeRegistry = new LockedRegistry<>(pack.getTreeRegistry());
this.floraRegistry = new LockedRegistry<>(pack.getFloraRegistry());
this.lootRegistry = new LockedRegistry<>(pack.getLootRegistry());
this.oreRegistry = new LockedRegistry<>(pack.getOreRegistry());
this.paletteRegistry = new LockedRegistry<>(pack.getPaletteRegistry());
this.structureRegistry = new LockedRegistry<>(pack.getStructureRegistry());
this.provider = pack.getBiomeProviderBuilder().build(world.getWorld().getSeed());
}
public TerraWorld getWorld() {
return world;
}
public SamplerCache getSamplerCache() {
return samplerCache;
}
public Set<UserDefinedCarver> getCarvers() {
return carverRegistry.entries();
}
public LockedRegistry<StructureScript> getScriptRegistry() {
return scriptRegistry;
}
public LockedRegistry<TerraBiome> getBiomeRegistry() {
return biomeRegistry;
}
public LockedRegistry<Tree> getTreeRegistry() {
return treeRegistry;
}
public LockedRegistry<UserDefinedCarver> getCarverRegistry() {
return carverRegistry;
}
public LockedRegistry<Flora> getFloraRegistry() {
return floraRegistry;
}
public LockedRegistry<LootTable> getLootRegistry() {
return lootRegistry;
}
public LockedRegistry<Ore> getOreRegistry() {
return oreRegistry;
}
public LockedRegistry<Palette<BlockData>> getPaletteRegistry() {
return paletteRegistry;
}
public LockedRegistry<TerraStructure> getStructureRegistry() {
return structureRegistry;
}
public BiomeProvider getProvider() {
return provider;
}
public Set<TerraStructure> getStructures() {
return structureRegistry.entries();
}
public ConfigPackTemplate getTemplate() {
return pack.getTemplate();
}
}

View File

@ -31,6 +31,7 @@ import com.dfsek.terra.world.population.items.ores.OreHolder;
import com.dfsek.terra.world.population.items.tree.TreeLayer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -182,7 +183,7 @@ public class BiomeTemplate extends AbstractableTemplate implements ValidatedConf
@Value("tags")
@Default
@Abstractable
private Set<String> tags;
private Set<String> tags = new HashSet<>();
@Value("carving")
@Abstractable

View File

@ -17,7 +17,7 @@ import java.util.function.Consumer;
* Registry implementation with read/write access. For internal use only.
* @param <T>
*/
public abstract class OpenRegistry<T> implements Registry<T> {
public class OpenRegistry<T> implements Registry<T> {
private final Map<String, T> objects = new HashMap<>();
@Override

View File

@ -3,15 +3,16 @@ package com.dfsek.terra.registry.config;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.config.builder.ConfigBuilder;
import com.dfsek.terra.registry.OpenRegistry;
import java.lang.reflect.Type;
public class BiomeRegistry extends OpenRegistry<TerraBiome> {
public class BiomeRegistry extends OpenRegistry<ConfigBuilder<TerraBiome>> {
@Override
public TerraBiome load(Type type, Object o, ConfigLoader configLoader) throws LoadException {
public ConfigBuilder<TerraBiome> load(Type type, Object o, ConfigLoader configLoader) throws LoadException {
if(o.equals("SELF")) return null;
TerraBiome biome = get((String) o);
ConfigBuilder<TerraBiome> biome = get((String) o);
if(biome == null)
throw new LoadException("No such " + type.getTypeName() + " matching \"" + o + "\" was found in this registry.");
return biome;

View File

@ -12,13 +12,14 @@ import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.profiler.WorldProfiler;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import net.jafama.FastMath;
public class TerraWorld {
private final BiomeProvider provider;
private final ConfigPack config;
private final WorldConfig config;
private final boolean safe;
private final WorldProfiler profiler;
private final World world;
@ -27,10 +28,9 @@ public class TerraWorld {
public TerraWorld(World w, ConfigPack c, TerraPlugin main) {
if(!isTerraWorld(w)) throw new IllegalArgumentException("World " + w + " is not a Terra World!");
c.getBiomeRegistry().forEach(biome -> biome.getGenerator(w)); // Load all gens to cache
config = c;
config = c.toWorldConfig(this);
profiler = new WorldProfiler(w);
this.provider = config.getBiomeProviderBuilder().build(w.getSeed());
this.provider = config.getProvider();
this.world = w;
air = main.getWorldHandle().createBlockData("minecraft:air");
main.getEventManager().callEvent(new TerraWorldLoadEvent(this));
@ -53,7 +53,7 @@ public class TerraWorld {
return provider;
}
public ConfigPack getConfig() {
public WorldConfig getConfig() {
return config;
}
@ -76,7 +76,7 @@ public class TerraWorld {
public BlockData getUngeneratedBlock(int x, int y, int z) {
UserDefinedBiome biome = (UserDefinedBiome) provider.getBiome(x, z);
Palette<BlockData> palette = biome.getGenerator(world).getPalette(y);
Sampler sampler = config.getSamplerCache().get(world, x, z);
Sampler sampler = config.getSamplerCache().get(x, z);
int fdX = FastMath.floorMod(x, 16);
int fdZ = FastMath.floorMod(z, 16);
double noise = sampler.sample(fdX, y, fdZ);

View File

@ -86,7 +86,7 @@ public class DefaultChunkGenerator2D implements TerraChunkGenerator {
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
Sampler sampler = cache.getChunk(world, chunkX, chunkZ);
Sampler sampler = cache.getChunk(chunkX, chunkZ);
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {

View File

@ -99,7 +99,7 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
Sampler sampler = cache.getChunk(world, chunkX, chunkZ);
Sampler sampler = cache.getChunk(chunkX, chunkZ);
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {

View File

@ -16,56 +16,28 @@ import java.util.HashMap;
import java.util.Map;
public class SamplerCache {
private final Map<Long, Container> containerMap;
private final TerraPlugin main;
private final LoadingCache<Long, Sampler> cache;
public SamplerCache(TerraPlugin main) {
containerMap = Collections.synchronizedMap(new HashMap<>());
this.main = main;
public SamplerCache(TerraPlugin main, TerraWorld world) {
cache = CacheBuilder.newBuilder().maximumSize(main.getTerraConfig().getSamplerCache())
.build(new CacheLoader<Long, Sampler>() {
@Override
public Sampler load(@NotNull Long key) {
int cx = (int) (key >> 32);
int cz = (int) key.longValue();
return world.getGenerator().createSampler(cx, cz, world.getBiomeProvider(), world.getWorld(), world.getConfig().getTemplate().getElevationBlend());
}
});
}
public Sampler get(World world, int x, int z) {
synchronized(containerMap) {
return containerMap.computeIfAbsent(world.getSeed(), seed -> new Container(world)).get(x, z);
}
public Sampler get(int x, int z) {
int cx = FastMath.floorDiv(x, 16);
int cz = FastMath.floorDiv(z, 16);
return getChunk(cx, cz);
}
public Sampler getChunk(World world, int chunkX, int chunkZ) {
synchronized(containerMap) {
return containerMap.computeIfAbsent(world.getSeed(), seed -> new Container(world)).getChunk(chunkX, chunkZ);
}
}
public void clear() {
containerMap.clear();
}
private final class Container {
private final TerraWorld terraWorld;
private final LoadingCache<Long, Sampler> cache;
private Container(World world) {
cache = CacheBuilder.newBuilder().maximumSize(main.getTerraConfig().getSamplerCache())
.build(new CacheLoader<Long, Sampler>() {
@Override
public Sampler load(@NotNull Long key) {
int cx = (int) (key >> 32);
int cz = (int) key.longValue();
return terraWorld.getGenerator().createSampler(cx, cz, terraWorld.getBiomeProvider(), world, terraWorld.getConfig().getTemplate().getElevationBlend());
}
});
terraWorld = main.getWorld(world);
}
public Sampler get(int x, int z) {
int cx = FastMath.floorDiv(x, 16);
int cz = FastMath.floorDiv(z, 16);
return getChunk(cx, cz);
}
public Sampler getChunk(int cx, int cz) {
long key = MathUtil.squash(cx, cz);
return cache.getUnchecked(key);
}
public Sampler getChunk(int cx, int cz) {
long key = MathUtil.squash(cx, cz);
return cache.getUnchecked(key);
}
}

View File

@ -12,6 +12,7 @@ import com.dfsek.terra.api.util.world.PopulationUtil;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.config.templates.CarverTemplate;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.world.TerraWorld;
@ -40,7 +41,7 @@ public class CavePopulator implements TerraBlockPopulator {
try(ProfileFuture ignored = tw.getProfiler().measure("CaveTime")) {
Random random = PopulationUtil.getRandom(chunk);
if(!tw.isSafe()) return;
ConfigPack config = tw.getConfig();
WorldConfig config = tw.getConfig();
for(UserDefinedCarver c : config.getCarvers()) {
CarverTemplate template = c.getConfig();

View File

@ -11,6 +11,7 @@ import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.population.items.TerraStructure;
@ -35,7 +36,7 @@ public class StructurePopulator implements TerraBlockPopulator {
int cz = (chunk.getZ() << 4);
if(!tw.isSafe()) return;
BiomeProvider provider = tw.getBiomeProvider();
ConfigPack config = tw.getConfig();
WorldConfig config = tw.getConfig();
for(TerraStructure conf : config.getStructures()) {
Location spawn = conf.getSpawn().getNearestSpawn(cx + 8, cz + 8, world.getSeed()).toLocation(world);