Merge remote-tracking branch 'upstream/ver/6.0.0' into architecture/slf4j-logging

# Conflicts:
#	common/api/core/src/main/java/com/dfsek/terra/api/Logger.java
This commit is contained in:
solonovamax 2021-09-24 13:50:21 -04:00
commit b03c8b4a11
No known key found for this signature in database
GPG Key ID: ED0FC2D44CD76482
271 changed files with 123 additions and 3977 deletions

View File

@ -10,9 +10,6 @@ your specifications, with no knowledge of Java required.
etc): [SpigotMC](https://www.spigotmc.org/resources/85151/)
* Fabric: [Modrinth](https://modrinth.com/mod/terra)
/ [CurseForge](https://www.curseforge.com/minecraft/mc-mods/terra-world-generator)
* Forge **(ALPHA - NOT
PRODUCTION-READY)**: [Modrinth](https://modrinth.com/mod/terra)
/ [CurseForge](https://www.curseforge.com/minecraft/mc-mods/terra-world-generator)
## Building and Running Terra
@ -23,7 +20,6 @@ will build all platforms, and produce JARs in `platforms/<platform>/build/libs`
* Bukkit: `Terra-<version>-shaded.jar`
* Fabric: `Terra-<version>-shaded-mapped.jar`
* Forge: `Terra-<version>-shaded.jar`
### Building a Specific Platform
@ -47,9 +43,7 @@ To run Minecraft with Terra in the IDE (for testing) use the following tasks:
* Fabric
* `runClient` - Run a Minecraft Fabric client with Terra installed.
* `runServer` - Run a Minecraft Fabric server with Terra installed.
* Forge
* `runClient` - Run a Minecraft Forge client with Terra installed.
* `runServer` - Run a Minecraft Forge server with Terra installed.
## Contributing

View File

@ -41,8 +41,8 @@ fun Project.configureDependencies() {
if (project(":common:addons").subprojects.contains(this)) { // If this is an addon project, depend on the API.
dependencies {
"compileOnly"(project(":common:api"))
"testImplementation"(project(":common:api"))
"compileOnly"(project(":common:api:core"))
"testImplementation"(project(":common:api:core"))
}
}
}

View File

@ -1,10 +0,0 @@
# api-features
Contains the API for feature generation.
This API implemented in:
* `config-feature`
* `generation-stage-feature`
* `config-locators`
* `config-distributors`

View File

@ -16,7 +16,7 @@ public class ImageProviderTemplate implements ObjectTemplate<BiomeProvider> {
private final Registry<TerraBiome> biomes;
@Value("resolution")
@Default
private final int resolution = 1;
private int resolution = 1;
@Value("image.name")
private BufferedImage image;
@Value("image.align")

View File

@ -1,28 +0,0 @@
package com.dfsek.terra.addons.biome;
import com.dfsek.paralithic.functions.dynamic.DynamicFunction;
public class BlankFunction implements DynamicFunction {
private final int args;
public BlankFunction(int args) {
this.args = args;
}
@Override
public double eval(double... d) {
return 0;
}
@Override
public int getArgNumber() {
return args;
}
@Override
public boolean isStateless() {
return true;
}
}

View File

@ -13,7 +13,7 @@ import com.dfsek.terra.api.structure.feature.Distributor;
public class NoiseDistributorTemplate implements ObjectTemplate<Distributor> {
@Value("threshold")
@Default
private final @Meta double threshold = 0;
private @Meta double threshold = 0;
@Value("distribution")
private @Meta NoiseSampler noise;

View File

@ -22,7 +22,7 @@ public class FeatureAddon extends TerraAddon {
main.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
.then(event -> event.getPack().registerConfigType(new FeatureConfigType(), "FEATURE", 2))
.then(event -> event.getPack().registerConfigType(new FeatureConfigType(), "FEATURE", 3))
.failThrough();
}
}

View File

@ -7,17 +7,18 @@ import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.config.ConfigType;
import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.structure.Structure;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.Flora;
public class FloraConfigType implements ConfigType<FloraTemplate, Flora> {
public static final TypeKey<Flora> FLORA_TYPE_TOKEN = new TypeKey<>() {
public class FloraConfigType implements ConfigType<FloraTemplate, Structure> {
public static final TypeKey<Structure> FLORA_TYPE_TOKEN = new TypeKey<>() {
};
private final FloraFactory factory = new FloraFactory();
@Override
public Supplier<OpenRegistry<Flora>> registrySupplier(ConfigPack pack) {
public Supplier<OpenRegistry<Structure>> registrySupplier(ConfigPack pack) {
return pack.getRegistryFactory()::create;
}
@ -27,12 +28,12 @@ public class FloraConfigType implements ConfigType<FloraTemplate, Flora> {
}
@Override
public ConfigFactory<FloraTemplate, Flora> getFactory() {
public ConfigFactory<FloraTemplate, Structure> getFactory() {
return factory;
}
@Override
public TypeKey<Flora> getTypeKey() {
public TypeKey<Structure> getTypeKey() {
return FLORA_TYPE_TOKEN;
}
}

View File

@ -3,14 +3,14 @@ package com.dfsek.terra.addons.flora;
import com.dfsek.terra.addons.flora.flora.gen.TerraFlora;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.world.Flora;
import com.dfsek.terra.api.structure.Structure;
public class FloraFactory implements ConfigFactory<FloraTemplate, Flora> {
public class FloraFactory implements ConfigFactory<FloraTemplate, Structure> {
@Override
public TerraFlora build(FloraTemplate config, TerraPlugin main) {
return new TerraFlora(config.getLayers(), config.doPhysics(), config.isCeiling(), config.getIrrigable(), config.getSpawnable(),
config.getReplaceable(), config.getRotatable(), config.getMaxPlacements(), config.getSearch(),
config.isSpawnBlacklist(), config.getIrrigableOffset(), main, config.getNoiseDistribution());
return new TerraFlora(config.getLayers(), config.doPhysics(), config.isCeiling(),
config.getRotatable(),
config.getNoiseDistribution(), config.getID());
}
}

View File

@ -19,23 +19,6 @@ public class FloraTemplate implements AbstractableTemplate {
@Value("id")
@Final
private String id;
@Value("spawnable")
private @Meta MaterialSet spawnable;
@Value("spawn-blacklist")
@Default
private @Meta boolean spawnBlacklist = false;
@Value("replaceable")
@Default
private @Meta MaterialSet replaceable = MaterialSet.empty();
@Value("irrigable")
@Default
private @Meta MaterialSet irrigable;
@Value("rotatable")
@Default
private @Meta MaterialSet rotatable = MaterialSet.empty();
@ -48,18 +31,6 @@ public class FloraTemplate implements AbstractableTemplate {
@Default
private @Meta boolean ceiling = false;
@Value("search")
@Default
private TerraFlora.@Meta Search search = TerraFlora.Search.UP;
@Value("max-placements")
@Default
private @Meta int maxPlacements = -1;
@Value("irrigable-offset")
@Default
private @Meta int irrigableOffset;
@Value("layers")
private @Meta List<@Meta BlockLayer> layers;
@ -78,30 +49,6 @@ public class FloraTemplate implements AbstractableTemplate {
return layers;
}
public int getIrrigableOffset() {
return irrigableOffset;
}
public TerraFlora.Search getSearch() {
return search;
}
public int getMaxPlacements() {
return maxPlacements;
}
public MaterialSet getReplaceable() {
return replaceable;
}
public MaterialSet getSpawnable() {
return spawnable;
}
public MaterialSet getIrrigable() {
return irrigable;
}
public String getID() {
return id;
}
@ -110,10 +57,6 @@ public class FloraTemplate implements AbstractableTemplate {
return ceiling;
}
public boolean isSpawnBlacklist() {
return spawnBlacklist;
}
public MaterialSet getRotatable() {
return rotatable;
}

View File

@ -7,60 +7,40 @@ import java.util.EnumSet;
import java.util.List;
import java.util.Random;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.block.state.properties.base.Properties;
import com.dfsek.terra.api.block.state.properties.enums.Direction;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.structure.Structure;
import com.dfsek.terra.api.structure.buffer.Buffer;
import com.dfsek.terra.api.structure.rotation.Rotation;
import com.dfsek.terra.api.util.collection.MaterialSet;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.Chunk;
import com.dfsek.terra.api.world.Flora;
import com.dfsek.terra.api.world.World;
public class TerraFlora implements Flora {
public class TerraFlora implements Structure {
private final List<ProbabilityCollection<BlockState>> layers;
private final boolean physics;
private final boolean ceiling;
private final MaterialSet irrigable;
private final MaterialSet spawnable;
private final MaterialSet replaceable;
private final MaterialSet testRotation;
private final int maxPlacements;
private final Search search;
private final boolean spawnBlacklist;
private final int irrigableOffset;
private final TerraPlugin main;
private final NoiseSampler distribution;
public TerraFlora(List<BlockLayer> layers, boolean physics, boolean ceiling, MaterialSet irrigable, MaterialSet spawnable,
MaterialSet replaceable, MaterialSet testRotation, int maxPlacements, Search search, boolean spawnBlacklist,
int irrigableOffset, TerraPlugin main, NoiseSampler distribution) {
private final String id;
public TerraFlora(List<BlockLayer> layers, boolean physics, boolean ceiling,
MaterialSet testRotation,
NoiseSampler distribution, String id) {
this.physics = physics;
this.testRotation = testRotation;
this.spawnBlacklist = spawnBlacklist;
this.ceiling = ceiling;
this.irrigable = irrigable;
this.spawnable = spawnable;
this.replaceable = replaceable;
this.maxPlacements = maxPlacements;
this.search = search;
this.irrigableOffset = irrigableOffset;
this.main = main;
this.distribution = distribution;
this.id = id;
this.layers = new ArrayList<>();
layers.forEach(layer -> {
for(int i = 0; i < layer.getLayers(); i++) {
@ -69,78 +49,12 @@ public class TerraFlora implements Flora {
});
}
@Override
public boolean plant(Vector3 location, World world) {
boolean doRotation = testRotation.size() > 0;
int size = layers.size();
int c = ceiling ? -1 : 1;
EnumSet<Direction> faces = doRotation ? getFaces(location.clone().add(0, c, 0), world) : EnumSet.noneOf(Direction.class);
if(doRotation && faces.size() == 0) return false; // Don't plant if no faces are valid.
for(int i = 0; FastMath.abs(i) < size; i += c) { // Down if ceiling, up if floor
int lvl = (FastMath.abs(i));
BlockState data = getStateCollection((ceiling ? lvl : size - lvl - 1)).get(distribution, location.getX(), location.getY(),
location.getZ(), world.getSeed()).clone();
if(doRotation) {
Direction oneFace = new ArrayList<>(faces).get(
new Random(location.getBlockX() ^ location.getBlockZ()).nextInt(faces.size())); // Get random face.
data.setIfPresent(Properties.DIRECTION, oneFace.opposite())
.setIfPresent(Properties.NORTH, faces.contains(Direction.NORTH))
.setIfPresent(Properties.SOUTH, faces.contains(Direction.SOUTH))
.setIfPresent(Properties.EAST, faces.contains(Direction.EAST))
.setIfPresent(Properties.WEST, faces.contains(Direction.WEST));
}
world.setBlockData(location.clone().add(0, i + c, 0), data, physics);
}
return true;
}
@Override
public List<Vector3> getValidSpawnsAt(Chunk chunk, int x, int z, Range range) {
int size = layers.size();
Vector3 current = new Vector3(x, search.equals(Search.UP) ? range.getMin() : range.getMax(), z);
List<Vector3> blocks = new ArrayList<>();
int cx = chunk.getX() << 4;
int cz = chunk.getZ() << 4;
for(int y : range) {
if(y > 255 || y < 0) continue;
current = current.add(0, search.equals(Search.UP) ? 1 : -1, 0);
if((spawnBlacklist != spawnable.contains(
chunk.getBlock(current.getBlockX(), current.getBlockY(), current.getBlockZ()).getBlockType())) && isIrrigated(
current.clone().add(cx, irrigableOffset, cz), chunk.getWorld()) && valid(size, current.clone().add(cx, 0, cz),
chunk.getWorld())) {
blocks.add(current.clone());
if(maxPlacements > 0 && blocks.size() >= maxPlacements) break;
}
}
return blocks;
}
private boolean valid(int size, Vector3 block, World world) {
for(int i = 0; i < size; i++) { // Down if ceiling, up if floor
if(block.getY() + 1 > 255 || block.getY() < 0) return false;
block.add(0, ceiling ? -1 : 1, 0);
if(!replaceable.contains(world.getBlockData(block).getBlockType())) return false;
}
return true;
}
private void test(EnumSet<Direction> faces, Direction f, Vector3 b, World world) {
if(testRotation.contains(
world.getBlockData(b.getBlockX() + f.getModX(), b.getBlockY() + f.getModY(), b.getBlockZ() + f.getModZ()).getBlockType()))
faces.add(f);
}
private boolean isIrrigated(Vector3 b, World world) {
if(irrigable == null) return true;
return irrigable.contains(world.getBlockData(b.getBlockX() + 1, b.getBlockY(), b.getBlockZ()).getBlockType())
|| irrigable.contains(world.getBlockData(b.getBlockX() - 1, b.getBlockY(), b.getBlockZ()).getBlockType())
|| irrigable.contains(world.getBlockData(b.getBlockX(), b.getBlockY(), b.getBlockZ() + 1).getBlockType())
|| irrigable.contains(world.getBlockData(b.getBlockX(), b.getBlockY(), b.getBlockZ() - 1).getBlockType());
}
private ProbabilityCollection<BlockState> getStateCollection(int layer) {
return layers.get(FastMath.max(FastMath.min(layer, layers.size() - 1), 0));
}
@ -154,8 +68,46 @@ public class TerraFlora implements Flora {
return faces;
}
public enum Search {
UP,
DOWN
@Override
public String getID() {
return id;
}
@Override
public boolean generate(Vector3 location, World world, Chunk chunk, Random random, Rotation rotation) {
return generate(location, world, random, rotation);
}
@Override
public boolean generate(Buffer buffer, World world, Random random, Rotation rotation, int recursions) {
return generate(buffer.getOrigin(), world, random, rotation);
}
@Override
public boolean generate(Vector3 location, World world, Random random, Rotation rotation) {
boolean doRotation = testRotation.size() > 0;
int size = layers.size();
int c = ceiling ? -1 : 1;
EnumSet<Direction> faces = doRotation ? getFaces(location.clone().add(0, c, 0), world) : EnumSet.noneOf(Direction.class);
if(doRotation && faces.size() == 0) return false; // Don't plant if no faces are valid.
for(int i = 0; FastMath.abs(i) < size; i += c) { // Down if ceiling, up if floor
int lvl = (FastMath.abs(i));
BlockState data = getStateCollection((ceiling ? lvl : size - lvl - 1)).get(distribution, location.getX(), location.getY(),
location.getZ(), world.getSeed()).clone();
if(doRotation) {
Direction oneFace = new ArrayList<>(faces).get(
new Random(location.getBlockX() ^ location.getBlockZ()).nextInt(faces.size())); // Get random face.
data.setIfPresent(Properties.DIRECTION, oneFace.opposite())
.setIfPresent(Properties.NORTH, faces.contains(Direction.NORTH))
.setIfPresent(Properties.SOUTH, faces.contains(Direction.SOUTH))
.setIfPresent(Properties.EAST, faces.contains(Direction.EAST))
.setIfPresent(Properties.WEST, faces.contains(Direction.WEST));
}
world.setBlockData(location.clone().add(0, i + c, 0), data, physics);
}
return true;
}
}

View File

@ -11,23 +11,23 @@ import com.dfsek.terra.api.noise.NoiseSampler;
public class GaborNoiseTemplate extends NoiseTemplate<GaborNoiseSampler> {
@Value("rotation")
@Default
private final @Meta double rotation = 0.25;
private @Meta double rotation = 0.25;
@Value("isotropic")
@Default
private final @Meta boolean isotropic = true;
private @Meta boolean isotropic = true;
@Value("deviation")
@Default
private final @Meta double deviation = 1.0;
private @Meta double deviation = 1.0;
@Value("impulses")
@Default
private final @Meta double impulses = 64d;
private @Meta double impulses = 64d;
@Value("frequency_0")
@Default
private final @Meta double f0 = 0.625;
private @Meta double f0 = 0.625;
@Override
public NoiseSampler get() {

View File

@ -7,6 +7,8 @@ import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.paralithic.functions.dynamic.Context;
import com.dfsek.paralithic.functions.dynamic.DynamicFunction;
import com.dfsek.paralithic.node.Statefulness;
import com.dfsek.terra.addons.noise.config.templates.FunctionTemplate;
@ -44,7 +46,7 @@ public class UserDefinedFunction implements DynamicFunction {
}
@Override
public boolean isStateless() {
return true;
public Statefulness statefulness() {
return Statefulness.STATELESS;
}
}

View File

@ -3,6 +3,8 @@ package com.dfsek.terra.addons.noise.paralithic.noise;
import com.dfsek.paralithic.functions.dynamic.Context;
import com.dfsek.paralithic.functions.dynamic.DynamicFunction;
import com.dfsek.paralithic.node.Statefulness;
import com.dfsek.terra.api.noise.NoiseSampler;
@ -29,7 +31,7 @@ public class NoiseFunction2 implements DynamicFunction {
}
@Override
public boolean isStateless() {
return false;
public Statefulness statefulness() {
return Statefulness.CONTEXTUAL;
}
}

View File

@ -3,6 +3,8 @@ package com.dfsek.terra.addons.noise.paralithic.noise;
import com.dfsek.paralithic.functions.dynamic.Context;
import com.dfsek.paralithic.functions.dynamic.DynamicFunction;
import com.dfsek.paralithic.node.Statefulness;
import com.dfsek.terra.api.noise.NoiseSampler;
@ -29,7 +31,7 @@ public class NoiseFunction3 implements DynamicFunction {
}
@Override
public boolean isStateless() {
return false;
public Statefulness statefulness() {
return Statefulness.CONTEXTUAL;
}
}

View File

@ -14,7 +14,7 @@ import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
public class BiomeStructuresTemplate implements ObjectTemplate<BiomeStructures> {
@Value("structures")
@Default
private final @Meta Set<@Meta ConfiguredStructure> structures = Collections.emptySet();
private @Meta Set<@Meta ConfiguredStructure> structures = Collections.emptySet();
@Override
public BiomeStructures get() {

View File

@ -14,7 +14,7 @@ import com.dfsek.terra.api.structure.feature.Feature;
public class BiomeFeaturesTemplate implements ObjectTemplate<BiomeFeatures> {
@Value("features")
@Default
private final @Meta List<@Meta Feature> features = Collections.emptyList();
private @Meta List<@Meta Feature> features = Collections.emptyList();
@Override
public BiomeFeatures get() {

View File

@ -1,18 +0,0 @@
package com.dfsek.terra.addons.generation.flora;
import java.util.List;
import com.dfsek.terra.api.properties.Properties;
public class BiomeFlora implements Properties {
private final List<FloraLayer> layers;
public BiomeFlora(List<FloraLayer> layers) {
this.layers = layers;
}
public List<FloraLayer> getLayers() {
return layers;
}
}

View File

@ -1,22 +0,0 @@
package com.dfsek.terra.addons.generation.flora;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.Collections;
import java.util.List;
import com.dfsek.terra.api.config.meta.Meta;
public class BiomeFloraTemplate implements ObjectTemplate<BiomeFlora> {
@Value("flora")
@Default
private final @Meta List<@Meta FloraLayer> flora = Collections.emptyList();
@Override
public BiomeFlora get() {
return new BiomeFlora(flora);
}
}

View File

@ -1,46 +0,0 @@
package com.dfsek.terra.addons.generation.flora;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon;
import com.dfsek.terra.api.addon.annotations.Author;
import com.dfsek.terra.api.addon.annotations.Version;
import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.generator.GenerationStageProvider;
@Addon("generation-stage-flora")
@Version("1.0.0")
@Author("Terra")
public class FloraGenerationAddon extends TerraAddon {
@Inject
private TerraPlugin main;
@Override
public void initialize() {
main.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
.then(event -> {
event.getPack().applyLoader(FloraLayer.class, FloraLayerLoader::new);
event.getPack().getOrCreateRegistry(GenerationStageProvider.class).register("FLORA",
pack -> new FloraGenerationStage(main));
})
.failThrough();
main.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(this, ConfigurationLoadEvent.class)
.then(event -> {
if(event.is(TerraBiome.class)) {
event.getLoadedObject(TerraBiome.class).getContext().put(event.load(new BiomeFloraTemplate()).get());
}
})
.failThrough();
}
}

View File

@ -1,65 +0,0 @@
package com.dfsek.terra.addons.generation.flora;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.profiler.ProfileFrame;
import com.dfsek.terra.api.util.PopulationUtil;
import com.dfsek.terra.api.vector.Vector2;
import com.dfsek.terra.api.world.Chunk;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.generator.GenerationStage;
/**
* Populates Flora
*/
public class FloraGenerationStage implements GenerationStage {
private final TerraPlugin main;
public FloraGenerationStage(TerraPlugin main) {
this.main = main;
}
@SuppressWarnings("try")
@Override
public void populate(@NotNull World world, @NotNull Chunk chunk) {
try(ProfileFrame ignore = main.getProfiler().profile("flora")) {
if(world.getConfig().disableFlora()) return;
long seed = world.getSeed();
BiomeProvider provider = world.getBiomeProvider();
Map<Vector2, List<FloraLayer>> layers = new HashMap<>();
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {
Vector2 l = new Vector2(x, z);
layers.put(l, provider.getBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z, seed)
.getContext()
.get(BiomeFlora.class)
.getLayers());
}
}
Random random = PopulationUtil.getRandom(chunk);
int iter = 0;
boolean finished = false;
while(!finished) {
finished = true;
for(Map.Entry<Vector2, List<FloraLayer>> entry : layers.entrySet()) {
if(entry.getValue().size() <= iter) continue;
finished = false;
FloraLayer layer = entry.getValue().get(iter);
if(layer.getDensity() >= random.nextDouble() * 100D) layer.place(chunk, entry.getKey());
}
iter++;
}
}
}
}

View File

@ -1,47 +0,0 @@
package com.dfsek.terra.addons.generation.flora;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.vector.Vector2;
import com.dfsek.terra.api.world.Chunk;
import com.dfsek.terra.api.world.Flora;
public class FloraLayer {
protected final double density;
protected final Range level;
protected final ProbabilityCollection<Flora> layer;
protected final NoiseSampler noise;
public FloraLayer(double density, Range level, ProbabilityCollection<Flora> layer, NoiseSampler noise) {
this.density = density;
this.level = level;
this.layer = layer;
this.noise = noise;
}
public void place(Chunk chunk, Vector2 coords) {
int cx = (chunk.getX() << 4);
int cz = (chunk.getZ() << 4);
Flora item = layer.get(noise, cx + coords.getX(), cz + coords.getZ(), chunk.getWorld().getSeed());
item.getValidSpawnsAt(chunk, (int) coords.getX(), (int) coords.getZ(), level).forEach(
block -> item.plant(block.add(cx, 0, cz), chunk.getWorld()));
}
public NoiseSampler getNoise() {
return noise;
}
public double getDensity() {
return density;
}
public Range getLevel() {
return level;
}
public ProbabilityCollection<Flora> getLayer() {
return layer;
}
}

View File

@ -1,31 +0,0 @@
package com.dfsek.terra.addons.generation.flora;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.Flora;
public class FloraLayerLoader implements ObjectTemplate<FloraLayer> {
@Value("density")
private @Meta double density;
@Value("y")
private @Meta Range y;
@Value("items")
private @Meta ProbabilityCollection<@Meta Flora> items;
@Value("distribution")
private @Meta NoiseSampler distribution;
@Override
public FloraLayer get() {
return new FloraLayer(density, y, items, distribution);
}
}

View File

@ -0,0 +1,4 @@
package com.dfsek.terra.addons.manifest;
public class ManifestLoaderEntry {
}

View File

@ -0,0 +1 @@
Entry-Point: com.dfsek.terra.addons.manifest.ManifestLoaderEntry

View File

@ -1,5 +1,7 @@
dependencies {
"shadedApi"("com.dfsek:Paralithic:0.4.0")
"shadedApi"(project(":common:api:util"))
"shadedApi"("com.dfsek:Paralithic:0.5.0")
"shadedApi"("com.dfsek.tectonic:common:2.1.2")

View File

@ -0,0 +1,4 @@
package com.dfsek.terra.api.addon;
public interface Addon {
}

View File

@ -0,0 +1,13 @@
package com.dfsek.terra.api.addon;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.registry.CheckedRegistry;
public interface AddonLoader {
/**
* Load all addons.
* @param main TerraPlugin instance.
*/
void load(TerraPlugin main, CheckedRegistry<Addon> addons);
}

Some files were not shown because too many files have changed in this diff Show More