mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2025-07-02 16:05:29 +00:00
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:
commit
b03c8b4a11
@ -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
|
||||
|
||||
|
@ -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"))
|
||||
}
|
||||
}
|
||||
}
|
@ -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`
|
@ -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")
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package com.dfsek.terra.addons.manifest;
|
||||
|
||||
public class ManifestLoaderEntry {
|
||||
}
|
@ -0,0 +1 @@
|
||||
Entry-Point: com.dfsek.terra.addons.manifest.ManifestLoaderEntry
|
@ -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")
|
||||
|
@ -0,0 +1,4 @@
|
||||
package com.dfsek.terra.api.addon;
|
||||
|
||||
public interface Addon {
|
||||
}
|
@ -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
Loading…
x
Reference in New Issue
Block a user