Compare commits

..

18 Commits

Author SHA1 Message Date
dfsek be3e50411e add AutoDocShadow 2021-04-26 23:13:44 -07:00
dfsek c87d0446d3 check and warn about dead links 2021-04-26 22:55:01 -07:00
dfsek e08a105d27 intellij really doesnt like adding imports 2021-04-26 22:45:41 -07:00
dfsek 03cecfb0fd generate pages for intermediate templates 2021-04-26 22:44:10 -07:00
dfsek 502b84722e children link improvements 2021-04-26 22:21:26 -07:00
dfsek 1abaace21b fix parent links 2021-04-26 22:12:12 -07:00
dfsek 951270c147 mostly working children list 2021-04-26 22:10:53 -07:00
dfsek 29cc8e9ffb cleanup buildscript imports 2021-04-26 21:35:39 -07:00
dfsek c5bd7e7646 document pipeline stages 2021-04-26 12:13:58 -07:00
dfsek 4cdcdc0fee aliasing 2021-04-26 12:05:14 -07:00
dfsek 9d4c4e35e7 cleanup 2021-04-26 12:01:42 -07:00
dfsek 3876cbc88e AutoDocAlias magic 2021-04-25 23:24:24 -07:00
dfsek 800b8bc3a7 only use main source set 2021-04-25 22:27:37 -07:00
dfsek 73ca08cb3d more default docs. 2021-04-25 22:26:19 -07:00
dfsek 664995e6eb generic types and "primitive" docs 2021-04-25 22:19:11 -07:00
dfsek 130d9648ee document more stuff 2021-04-25 17:08:10 -07:00
dfsek 869d95f5c8 begin work on automatic config docs 2021-04-25 16:53:11 -07:00
dfsek f396e0e5eb Merge pull request #133 from PolyhedralDev/ver/5.1.4
Fix minor Fabric issues
2021-04-16 09:01:29 -07:00
52 changed files with 624 additions and 33 deletions
+212
View File
@@ -1,10 +1,25 @@
import com.dfsek.terra.configureCommon
import com.github.javaparser.StaticJavaParser
import com.github.javaparser.ast.CompilationUnit
import com.github.javaparser.ast.body.FieldDeclaration
import com.github.javaparser.ast.expr.StringLiteralExpr
import com.github.javaparser.ast.type.PrimitiveType
import com.github.javaparser.ast.type.PrimitiveType.Primitive
import com.github.javaparser.ast.type.Type
import com.github.javaparser.ast.Node
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
plugins {
`java-library`
`maven-publish`
}
buildscript {
dependencies {
classpath("com.github.javaparser:javaparser-symbol-solver-core:3.20.2")
}
}
configureCommon()
group = "com.dfsek.terra.common"
@@ -51,4 +66,201 @@ publishing {
}
}
}
}
sourceSets {
create("tectonic") {
}
}
tasks.create<SourceTask>("tectonicDocs") {
group = "terra"
println("Scanning sources...")
val docs = HashMap<String, String>()
val refactor = HashMap<String, String>()
val sources = HashMap<String, CompilationUnit>()
sourceSets.main.get().java.forEach {
sources[it.name.substring(0, it.name.length - 5)] = StaticJavaParser.parse(it)
}
sources.forEach { (name, unit) ->
unit.getClassByName(name).ifPresent { declaration ->
if (declaration.isAnnotationPresent("AutoDocAlias")) {
refactor[name] = (declaration.getAnnotationByName("AutoDocAlias").get().childNodes[1] as StringLiteralExpr).asString()
println("Refactoring $name to ${refactor[name]}.")
} else if (declaration.isAnnotationPresent("AutoDocShadow")) {
refactor[name] = (declaration.getAnnotationByName("AutoDocShadow").get().childNodes[1] as StringLiteralExpr).asString()
println("Shadowing $name to ${refactor[name]}.")
}
}
}
val children = HashMap<String, MutableList<ClassOrInterfaceDeclaration>>()
sources.forEach { (name, unit) ->
unit.getClassByName(name).ifPresent { declaration ->
if(!declaration.isAnnotationPresent("AutoDocShadow")) {
declaration.extendedTypes.forEach { classOrInterfaceType ->
val inherit = classOrInterfaceType.name.asString()
if (!children.containsKey(inherit)) children[inherit] = ArrayList()
children[inherit]!!.add(declaration)
}
}
}
}
val linksAll = HashMap<String, Set<String>>()
sources.forEach { (name, unit) ->
val doc = StringBuilder()
doc.append("# ${generify(name, refactor)}\n")
var applicable = false
val links = HashSet<String>()
unit.getClassByName(name).ifPresent { declaration ->
applicable = scanForParent(sources, declaration, "ConfigTemplate", "ValidatedConfigTemplate", "ObjectTemplate")
declaration.javadoc.ifPresent {
doc.append("${sanitizeJavadoc(it.toText())} \n")
}
declaration.extendedTypes.forEach {
if (!it.name.asString().equals("AbstractableTemplate")) {
doc.append("Inherits from ${parseTypeLink(it, refactor, links, false)} \n \n")
}
}
if (children.containsKey(name)) {
doc.append("Children:\n")
children[name]!!.forEach {
doc.append("* ${parseTypeLink(it.name, refactor, links)}\n")
}
doc.append(" \n\n")
}
doc.append("\n")
}
unit.findAll(FieldDeclaration::class.java).filter { it.isAnnotationPresent("Value") }.forEach { fieldDeclaration ->
doc.append("## ${(fieldDeclaration.getAnnotationByName("Value").get().childNodes[1] as StringLiteralExpr).asString()}\n")
if (fieldDeclaration.isAnnotationPresent("Default")) {
doc.append("* Default value: ${fieldDeclaration.variables[0]} \n")
}
val type = fieldDeclaration.commonType
doc.append("* Type: ${parseTypeLink(type, refactor, links)} \n")
doc.append("\n")
fieldDeclaration.javadoc.ifPresent {
doc.append(sanitizeJavadoc(it.toText()))
}
doc.append("\n\n")
applicable = true
}
val s = doc.toString()
if (s.isNotEmpty() && applicable) {
docs[generify(name, refactor)] = s
linksAll[name] = links
}
}
println("Done. Generated ${docs.size} files")
val docsDir = File(buildDir, "tectonic")
docsDir.mkdirs()
val files = HashSet<String>()
docs.forEach {
val save = File(docsDir, "${it.key}.md")
files.add(it.key)
if (save.exists()) save.delete()
save.createNewFile()
save.writeText(it.value)
}
sourceSets["tectonic"].resources.forEach {
files.add(it.name.substringBefore('.'))
it.copyTo(File(docsDir, it.name), true)
}
linksAll.forEach { (file, links) ->
links.forEach {
if(!files.contains(it)) println("WARNING: Dead link to \"$it\" in file \"$file\"")
}
}
}
fun scanForParent(map: HashMap<String, CompilationUnit>, current: ClassOrInterfaceDeclaration, vararg parent: String): Boolean {
for (type in current.implementedTypes) {
if(parent.contains(type.childNodes[0].toString())) return true
}
for(type in current.extendedTypes) {
val name = type.childNodes[0].toString()
if(map.containsKey(name)) {
val op = map[name]!!.getClassByName(name)
if(op.isPresent && scanForParent(map, op.get(), *parent)) {
return true
}
}
}
return false
}
fun parseTypeLink(type: Node, refactor: Map<String, String>, links: MutableSet<String>, generic: Boolean = true): String {
val st = parseType(type, refactor)
if (type is Type && type.childNodes.size > 1 && generic) {
val outer = generify(type.childNodes[0].toString(), refactor)
val builder = StringBuilder()
builder.append("[$outer](./$outer)\\<")
links.add(outer)
for (i in 1 until type.childNodes.size) {
builder.append(parseTypeLink(type.childNodes[i], refactor, links, generic))
if (i != type.childNodes.size - 1) builder.append(", ")
}
builder.append("\\>")
return builder.toString()
}
links.add(st)
return "[$st](./$st)"
}
fun parseType(type: Node, refactor: Map<String, String>): String {
if (type is PrimitiveType) {
return when (type.type) {
Primitive.BOOLEAN -> "Boolean"
Primitive.BYTE -> "Byte"
Primitive.DOUBLE -> "Double"
Primitive.INT -> "Integer"
Primitive.CHAR -> "Char"
Primitive.FLOAT -> "Float"
Primitive.SHORT -> "Short"
Primitive.LONG -> "Long"
else -> type.asString()
}
}
if(type is Type && type.childNodes.size > 1) return generify(type.childNodes[0].toString(), refactor)
return generify(type.toString(), refactor)
}
fun generify(type: String, refactor: Map<String, String>): String {
return when (type) {
"HashMap", "LinkedHashMap" -> "Map"
"ArrayList", "LinkedList", "GlueList" -> "List"
"HashSet" -> "Set"
else -> refactor.getOrDefault(type, type)
}
}
fun sanitizeJavadoc(doc: String): String {
return doc
.replace("<p>", "")
}
@@ -0,0 +1,17 @@
package com.dfsek.terra.api.docs;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* For use in Terra AutoDoc, to specify
* that references to the annotated class
* should be refactored in the documentation.
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface AutoDocAlias {
String value();
}
@@ -0,0 +1,17 @@
package com.dfsek.terra.api.docs;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* For use in Terra AutoDoc, to specify
* that references to the annotated class
* should be shadowed to the target class.
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface AutoDocShadow {
String value();
}
@@ -1,11 +1,13 @@
package com.dfsek.terra.config.builder;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.platform.world.Biome;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.SeededBuilder;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.config.templates.BiomeTemplate;
@AutoDocAlias("TerraBiome")
public interface BiomeBuilder extends SeededBuilder<TerraBiome> {
ProbabilityCollection<Biome> getVanillaBiomes();
@@ -11,16 +11,28 @@ import com.dfsek.terra.api.world.biome.provider.StandardBiomeProvider;
import java.util.List;
/**
* Configures a biome pipeline.
*/
@SuppressWarnings({"FieldMayBeFinal", "unused"})
public class BiomePipelineTemplate extends BiomeProviderTemplate {
private final TerraPlugin main;
/**
* Initial size of biome pipeline chunks.
*/
@Value("pipeline.initial-size")
@Default
private int initialSize = 2;
/**
* Mutator stages to be used in this biome pipeline.
*/
@Value("pipeline.stages")
private List<StageSeeded> stages;
/**
* Biome source to initialize the pipeline.
*/
@Value("pipeline.source")
private SourceSeeded source;
@@ -8,10 +8,21 @@ 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.provider.BiomeProvider;
/**
* Configures a biome provider.
*/
public abstract class BiomeProviderTemplate implements ObjectTemplate<BiomeProvider.BiomeProviderBuilder>, BiomeProvider.BiomeProviderBuilder {
/**
* Resolution of this provider.
* A resolution of 1 means that 1 block = 1 sample.
*/
@Value("resolution")
@Default
protected int resolution = 1;
/**
* Noise function to use for blending biomes at edges.
*/
@Value("blend.noise")
@Default
protected NoiseSeeded blend = new NoiseSeeded() {
@@ -25,11 +36,13 @@ public abstract class BiomeProviderTemplate implements ObjectTemplate<BiomeProvi
return 2;
}
};
/**
* Amplitude of edge blending, in blocks.
*/
@Value("blend.amplitude")
@Default
protected double blendAmp = 0d;
@Value("type")
BiomeProvider.Type type;
@Override
public BiomeProvider.BiomeProviderBuilder get() {
@@ -9,11 +9,21 @@ import com.dfsek.terra.config.builder.BiomeBuilder;
import java.awt.image.BufferedImage;
import java.util.stream.Collectors;
/**
* Configures an image biome provider.
*/
public class ImageProviderTemplate extends BiomeProviderTemplate {
private final Registry<BiomeBuilder> biomes;
/**
* Image to use for biome selection.
*/
@Value("image.name")
private BufferedImage image;
/**
* How the image should be aligned.
*/
@Value("image.align")
private ImageBiomeProvider.Align align;
@@ -5,7 +5,13 @@ import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.biome.provider.SingleBiomeProvider;
import com.dfsek.terra.config.builder.BiomeBuilder;
/**
* Configures a single-biome provider.
*/
public class SingleBiomeProviderTemplate extends BiomeProviderTemplate {
/**
* The biome.
*/
@Value("biome")
private BiomeBuilder biome;
@@ -1,16 +1,27 @@
package com.dfsek.terra.config.loaders.config.biome.templates.source;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.world.biome.pipeline.source.RandomSource;
import com.dfsek.terra.config.builder.BiomeBuilder;
/**
* Configures a noise-based biome source.
*/
@AutoDocAlias("NoiseSource")
public class NoiseSourceTemplate extends SourceTemplate {
/**
* Noise function to use for selecting biomes.
*/
@Value("noise")
private NoiseSeeded noise;
/**
* ProbabilityCollection of biomes to use.
*/
@Value("biomes")
private ProbabilityCollection<BiomeBuilder> biomes;
@@ -1,9 +1,11 @@
package com.dfsek.terra.config.loaders.config.biome.templates.source;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.util.seeded.SourceSeeded;
import com.dfsek.terra.api.world.biome.pipeline.source.BiomeSource;
@AutoDocAlias("SourceSeeded")
public abstract class SourceTemplate implements ObjectTemplate<SourceSeeded>, SourceSeeded {
@Override
public SourceSeeded get() {
@@ -2,12 +2,17 @@ package com.dfsek.terra.config.loaders.config.biome.templates.stage;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.util.seeded.SeededBuilder;
import com.dfsek.terra.api.util.seeded.StageSeeded;
import com.dfsek.terra.api.world.biome.pipeline.stages.Stage;
@AutoDocAlias("StageSeeded")
public abstract class StageTemplate implements ObjectTemplate<SeededBuilder<Stage>>, StageSeeded {
/**
* Noise function to use for mutating biomes in this stage.
*/
@Value("noise")
protected NoiseSeeded noise;
@@ -1,6 +1,7 @@
package com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.pipeline.mutator.BiomeMutator;
@@ -11,16 +12,30 @@ import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("unused")
@AutoDocAlias("BorderListMutator")
public class BorderListMutatorTemplate extends MutatorStageTemplate {
/**
* Tag of the biome on the external side of the border.
*/
@Value("from")
private String from;
/**
* Tag of biomes to replace when bordering biomes with
* tag "from".
*/
@Value("default-replace")
private String defaultReplace;
/**
* Default replacement biomes.
*/
@Value("default-to")
private ProbabilityCollection<BiomeBuilder> defaultTo;
/**
* Map of single biomes to their replacements.
*/
@Value("replace")
private Map<BiomeBuilder, ProbabilityCollection<BiomeBuilder>> replace;
@@ -1,19 +1,32 @@
package com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.pipeline.mutator.BiomeMutator;
import com.dfsek.terra.api.world.biome.pipeline.mutator.BorderMutator;
import com.dfsek.terra.config.builder.BiomeBuilder;
@SuppressWarnings("unused")
@AutoDocAlias("BorderMutator")
public class BorderMutatorTemplate extends MutatorStageTemplate {
/**
* Tag of the biome on the external side of the border.
*/
@Value("from")
private String from;
/**
* Tag of biomes to replace when bordering biomes
* with tag "from"
*/
@Value("replace")
private String replace;
/**
* Collection of biomes to place at borders
* of "from" and "to"
*/
@Value("to")
private ProbabilityCollection<BiomeBuilder> to;
@@ -1,10 +1,12 @@
package com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.world.biome.pipeline.mutator.BiomeMutator;
import com.dfsek.terra.api.world.biome.pipeline.stages.MutatorStage;
import com.dfsek.terra.api.world.biome.pipeline.stages.Stage;
import com.dfsek.terra.config.loaders.config.biome.templates.stage.StageTemplate;
@AutoDocAlias("MutatorStage")
public abstract class MutatorStageTemplate extends StageTemplate {
public abstract BiomeMutator build(long seed);
@@ -1,6 +1,7 @@
package com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.pipeline.mutator.BiomeMutator;
@@ -11,7 +12,11 @@ import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("unused")
@AutoDocAlias("ReplaceListMutator")
public class ReplaceListMutatorTemplate extends MutatorStageTemplate {
/**
* Default tag to replace from
*/
@Value("default-from")
private String defaultFrom;
@@ -1,16 +1,24 @@
package com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.pipeline.mutator.BiomeMutator;
import com.dfsek.terra.api.world.biome.pipeline.mutator.ReplaceMutator;
import com.dfsek.terra.config.builder.BiomeBuilder;
@SuppressWarnings("unused")
@AutoDocAlias("ReplaceMutator")
public class ReplaceMutatorTemplate extends MutatorStageTemplate {
/**
* Tag of biomes to replace.
*/
@Value("from")
private String from;
/**
* Biomes to replace with.
*/
@Value("to")
private ProbabilityCollection<BiomeBuilder> to;
@@ -1,8 +1,10 @@
package com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.world.biome.pipeline.mutator.BiomeMutator;
import com.dfsek.terra.api.world.biome.pipeline.mutator.SmoothMutator;
@AutoDocAlias("SmoothMutator")
public class SmoothMutatorTemplate extends MutatorStageTemplate {
@Override
public BiomeMutator build(long seed) {
@@ -6,6 +6,7 @@ import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.registry.config.NoiseRegistry;
@@ -14,6 +15,7 @@ import java.util.Locale;
import java.util.Map;
@SuppressWarnings("unchecked")
@AutoDocAlias("NoiseSeeded")
public class NoiseSamplerBuilderLoader implements TypeLoader<NoiseSeeded> {
private final NoiseRegistry noiseRegistry;
@@ -2,28 +2,46 @@ package com.dfsek.terra.config.loaders.config.sampler.templates;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.samplers.DomainWarpedSampler;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
/**
* Defines a domain-warped noise function.
*/
@SuppressWarnings({"unused", "FieldMayBeFinal"})
@AutoDocAlias("DomainWarpedSampler")
public class DomainWarpTemplate extends SamplerTemplate<DomainWarpedSampler> {
/**
* Noise function used to warp input function.
*/
@Value("warp")
private NoiseSeeded warp;
/**
* Input function (function to be warped)
*/
@Value("function")
private NoiseSeeded function;
/**
* Salt for both warp function and
* input function.
*/
@Value("salt")
@Default
private int salt = 0;
/**
* Amplitude of warping. Values provided by
* the warp function are multiplied by this constant.
*/
@Value("amplitude")
@Default
private double amplitude = 1;
@Override
public NoiseSampler apply(Long seed) {
public DomainWarpedSampler apply(Long seed) {
return new DomainWarpedSampler(function.apply(seed), warp.apply(seed), (int) (seed + salt), amplitude);
}
}
@@ -1,12 +1,13 @@
package com.dfsek.terra.config.loaders.config.sampler.templates;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.samplers.ImageSampler;
import java.awt.image.BufferedImage;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
@AutoDocAlias("ImageSampler")
public class ImageSamplerTemplate extends SamplerTemplate<ImageSampler> {
@Value("image")
@@ -19,7 +20,7 @@ public class ImageSamplerTemplate extends SamplerTemplate<ImageSampler> {
private ImageSampler.Channel channel;
@Override
public NoiseSampler apply(Long seed) {
public ImageSampler apply(Long seed) {
return new ImageSampler(image, channel, frequency);
}
}
@@ -4,13 +4,14 @@ import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ValidatedConfigTemplate;
import com.dfsek.tectonic.exception.ValidationException;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.samplers.KernelSampler;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import java.util.List;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
@AutoDocAlias("KernelSampler")
public class KernelTemplate extends SamplerTemplate<KernelSampler> implements ValidatedConfigTemplate {
@Value("kernel")
@@ -28,7 +29,7 @@ public class KernelTemplate extends SamplerTemplate<KernelSampler> implements Va
private double frequency = 1;
@Override
public NoiseSampler apply(Long seed) {
public KernelSampler apply(Long seed) {
double[][] k = new double[kernel.size()][kernel.get(0).size()];
for(int x = 0; x < kernel.size(); x++) {
@@ -5,11 +5,16 @@ import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ValidatedConfigTemplate;
import com.dfsek.tectonic.exception.ValidationException;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
@SuppressWarnings("FieldMayBeFinal")
@AutoDocAlias("NoiseSeeded")
public abstract class SamplerTemplate<T extends NoiseSampler> implements ValidatedConfigTemplate, ObjectTemplate<NoiseSeeded>, NoiseSeeded {
/**
* Number of dimensions for this sampler.
*/
@Value("dimensions")
@Default
private int dimensions = 2;
@@ -28,4 +33,7 @@ public abstract class SamplerTemplate<T extends NoiseSampler> implements Validat
public NoiseSeeded get() {
return this;
}
@Override
public abstract T apply(Long seed);
}
@@ -2,12 +2,14 @@ package com.dfsek.terra.config.loaders.config.sampler.templates.noise;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.noise.samplers.noise.CellularSampler;
import com.dfsek.terra.api.math.noise.samplers.noise.simplex.OpenSimplex2Sampler;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
@SuppressWarnings("FieldMayBeFinal")
@AutoDocAlias("CellularSampler")
public class CellularNoiseTemplate extends NoiseTemplate<CellularSampler> {
@Value("distance")
@Default
@@ -38,7 +40,7 @@ public class CellularNoiseTemplate extends NoiseTemplate<CellularSampler> {
};
@Override
public NoiseSampler apply(Long seed) {
public CellularSampler apply(Long seed) {
CellularSampler sampler = new CellularSampler((int) (long) seed + salt);
sampler.setNoiseLookup(lookup.apply(seed));
sampler.setFrequency(frequency);
@@ -2,18 +2,19 @@ package com.dfsek.terra.config.loaders.config.sampler.templates.noise;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.samplers.noise.ConstantSampler;
import com.dfsek.terra.config.loaders.config.sampler.templates.SamplerTemplate;
@SuppressWarnings("FieldMayBeFinal")
@AutoDocAlias("ConstantSampler")
public class ConstantNoiseTemplate extends SamplerTemplate<ConstantSampler> {
@Value("value")
@Default
private double value = 0d;
@Override
public NoiseSampler apply(Long seed) {
public ConstantSampler apply(Long seed) {
return new ConstantSampler(value);
}
}
@@ -8,9 +8,8 @@ import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ValidatedConfigTemplate;
import com.dfsek.tectonic.exception.ValidationException;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.samplers.noise.ExpressionFunction;
import com.dfsek.terra.api.math.paralithic.BlankFunction;
import com.dfsek.terra.api.math.paralithic.defined.UserDefinedFunction;
import com.dfsek.terra.api.math.paralithic.noise.NoiseFunction2;
import com.dfsek.terra.api.math.paralithic.noise.NoiseFunction3;
@@ -24,6 +23,7 @@ import java.util.Map;
@SuppressWarnings({"FieldMayBeFinal", "unused"})
@AutoDocAlias("ExpressionFunction")
public class ExpressionFunctionTemplate extends SamplerTemplate<ExpressionFunction> implements ValidatedConfigTemplate {
@Value("variables")
@Default
@@ -41,7 +41,7 @@ public class ExpressionFunctionTemplate extends SamplerTemplate<ExpressionFuncti
private LinkedHashMap<String, FunctionTemplate> expressions = new LinkedHashMap<>();
@Override
public NoiseSampler apply(Long seed) {
public ExpressionFunction apply(Long seed) {
try {
Map<String, Function> noiseFunctionMap = generateFunctions(seed);
return new ExpressionFunction(noiseFunctionMap, equation, vars);
@@ -2,18 +2,31 @@ package com.dfsek.terra.config.loaders.config.sampler.templates.noise;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.samplers.noise.GaborNoiseSampler;
/**
* Defines a Gabor noise function.
*/
@AutoDocAlias("GaborNoiseSampler")
public class GaborNoiseTemplate extends NoiseTemplate<GaborNoiseSampler> {
/**
* Rotation to apply to noise. Only has noticeable effects in anisotropic mode.
*/
@Value("rotation")
@Default
private double rotation = 0.25;
/**
* Whether to use anisotropic or isotropic algorithm.
*/
@Value("isotropic")
@Default
private boolean isotropic = true;
/**
* Standard deviation of result values.
*/
@Value("deviation")
@Default
private double deviation = 1.0;
@@ -27,7 +40,7 @@ public class GaborNoiseTemplate extends NoiseTemplate<GaborNoiseSampler> {
private double f0 = 0.625;
@Override
public NoiseSampler apply(Long seed) {
public GaborNoiseSampler apply(Long seed) {
GaborNoiseSampler gaborNoiseSampler = new GaborNoiseSampler((int) (long) seed + salt);
gaborNoiseSampler.setFrequency(frequency);
gaborNoiseSampler.setRotation(rotation);
@@ -2,10 +2,12 @@ package com.dfsek.terra.config.loaders.config.sampler.templates.noise;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.samplers.noise.NoiseFunction;
import com.dfsek.terra.config.loaders.config.sampler.templates.SamplerTemplate;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
@AutoDocAlias("NoiseFunction")
public abstract class NoiseTemplate<T extends NoiseFunction> extends SamplerTemplate<T> {
@Value("frequency")
@Default
@@ -1,10 +1,11 @@
package com.dfsek.terra.config.loaders.config.sampler.templates.noise;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.docs.AutoDocShadow;
import com.dfsek.terra.api.math.noise.samplers.noise.NoiseFunction;
import java.util.function.Function;
@AutoDocShadow("NoiseFunction")
public class SimpleNoiseTemplate extends NoiseTemplate<NoiseFunction> {
private final Function<Integer, NoiseFunction> samplerSupplier;
@@ -13,7 +14,7 @@ public class SimpleNoiseTemplate extends NoiseTemplate<NoiseFunction> {
}
@Override
public NoiseSampler apply(Long seed) {
public NoiseFunction apply(Long seed) {
NoiseFunction sampler = samplerSupplier.apply((int) (long) seed + salt);
sampler.setFrequency(frequency);
return sampler;
@@ -1,11 +1,12 @@
package com.dfsek.terra.config.loaders.config.sampler.templates.noise.fractal;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.samplers.noise.fractal.BrownianMotionSampler;
@AutoDocAlias("BrownianMotionSampler")
public class BrownianMotionTemplate extends FractalTemplate<BrownianMotionSampler> {
@Override
public NoiseSampler apply(Long seed) {
public BrownianMotionSampler apply(Long seed) {
BrownianMotionSampler sampler = new BrownianMotionSampler((int) (long) seed, function.apply(seed));
sampler.setGain(fractalGain);
sampler.setLacunarity(fractalLacunarity);
@@ -2,10 +2,12 @@ package com.dfsek.terra.config.loaders.config.sampler.templates.noise.fractal;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.samplers.noise.fractal.FractalNoiseFunction;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.config.loaders.config.sampler.templates.SamplerTemplate;
@AutoDocAlias("FractalNoiseFunction")
public abstract class FractalTemplate<T extends FractalNoiseFunction> extends SamplerTemplate<T> {
@Value("octaves")
@Default
@@ -2,16 +2,17 @@ package com.dfsek.terra.config.loaders.config.sampler.templates.noise.fractal;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.samplers.noise.fractal.PingPongSampler;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
@AutoDocAlias("PingPongSampler")
public class PingPongTemplate extends FractalTemplate<PingPongSampler> {
@Value("ping-pong")
@Default
private double pingPong = 2.0D;
@Override
public NoiseSampler apply(Long seed) {
public PingPongSampler apply(Long seed) {
PingPongSampler sampler = new PingPongSampler((int) (long) seed, function.apply(seed));
sampler.setGain(fractalGain);
sampler.setLacunarity(fractalLacunarity);
@@ -1,11 +1,12 @@
package com.dfsek.terra.config.loaders.config.sampler.templates.noise.fractal;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.samplers.noise.fractal.RidgedFractalSampler;
@AutoDocAlias("RidgedFractalSampler")
public class RidgedFractalTemplate extends FractalTemplate<RidgedFractalSampler> {
@Override
public NoiseSampler apply(Long seed) {
public RidgedFractalSampler apply(Long seed) {
RidgedFractalSampler sampler = new RidgedFractalSampler((int) (long) seed, function.apply(seed));
sampler.setGain(fractalGain);
sampler.setLacunarity(fractalLacunarity);
@@ -1,12 +1,12 @@
package com.dfsek.terra.config.loaders.config.sampler.templates.normalizer;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.normalizer.ClampNormalizer;
import com.dfsek.terra.api.math.noise.normalizer.LinearNormalizer;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
public class ClampNormalizerTemplate extends NormalizerTemplate<LinearNormalizer> {
@AutoDocAlias("ClampNormalizer")
public class ClampNormalizerTemplate extends NormalizerTemplate<ClampNormalizer> {
@Value("max")
private double max;
@@ -14,7 +14,7 @@ public class ClampNormalizerTemplate extends NormalizerTemplate<LinearNormalizer
private double min;
@Override
public NoiseSampler apply(Long seed) {
public ClampNormalizer apply(Long seed) {
return new ClampNormalizer(function.apply(seed), min, max);
}
}
@@ -1,10 +1,11 @@
package com.dfsek.terra.config.loaders.config.sampler.templates.normalizer;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.normalizer.LinearNormalizer;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
@AutoDocAlias("LinearNormalizer")
public class LinearNormalizerTemplate extends NormalizerTemplate<LinearNormalizer> {
@Value("max")
private double max;
@@ -13,7 +14,7 @@ public class LinearNormalizerTemplate extends NormalizerTemplate<LinearNormalize
private double min;
@Override
public NoiseSampler apply(Long seed) {
public LinearNormalizer apply(Long seed) {
return new LinearNormalizer(function.apply(seed), min, max);
}
}
@@ -2,10 +2,11 @@ package com.dfsek.terra.config.loaders.config.sampler.templates.normalizer;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.normalizer.NormalNormalizer;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
@AutoDocAlias("NormalNormalizer")
public class NormalNormalizerTemplate extends NormalizerTemplate<NormalNormalizer> {
@Value("mean")
private double mean;
@@ -18,7 +19,7 @@ public class NormalNormalizerTemplate extends NormalizerTemplate<NormalNormalize
private int groups = 16384;
@Override
public NoiseSampler apply(Long seed) {
public NormalNormalizer apply(Long seed) {
return new NormalNormalizer(function.apply(seed), groups, mean, stdDev);
}
}
@@ -1,10 +1,12 @@
package com.dfsek.terra.config.loaders.config.sampler.templates.normalizer;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.normalizer.Normalizer;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.config.loaders.config.sampler.templates.SamplerTemplate;
@AutoDocAlias("Normalizer")
public abstract class NormalizerTemplate<T extends Normalizer> extends SamplerTemplate<T> {
@Value("function")
protected NoiseSeeded function;
@@ -15,24 +15,52 @@ import java.util.Set;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
public class ConfigPackTemplate implements ConfigTemplate {
/**
* The ID of the config pack.
*/
@Value("id")
private String id;
/**
* Noise functions to be made available
* to noise equations in the config pack.
* <p>
* Keys are Paralithic function IDs,
* values are noise functions.
*/
@Value("noise")
private Map<String, NoiseSeeded> noiseBuilderMap;
/**
* Addons this pack depends on.
*/
@Value("addons")
@Default
private Set<TerraAddon> addons = new HashSet<>();
/**
* Variables to be made available
* to noise equations in the config pack.
* <p>
* Keys are variable IDs,
* values are variable values.
*/
@Value("variables")
@Default
private Map<String, Double> variables = new HashMap<>();
/**
* Whether to enable beta noise
* carvers.
*/
@Value("beta.carving")
@Default
private boolean betaCarvers = false;
/**
*
*/
@Value("functions")
@Default
private LinkedHashMap<String, FunctionTemplate> functions = new LinkedHashMap<>();
@@ -9,6 +9,7 @@ import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ValidatedConfigTemplate;
import com.dfsek.tectonic.exception.ValidationException;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.noise.samplers.noise.ConstantSampler;
import com.dfsek.terra.api.math.paralithic.BlankFunction;
@@ -38,6 +39,7 @@ import java.util.Map;
import java.util.Set;
@SuppressWarnings({"FieldMayBeFinal", "unused"})
@AutoDocAlias("TerraBiome")
public class BiomeTemplate extends AbstractableTemplate implements ValidatedConfigTemplate {
private final ConfigPack pack;
@@ -3,6 +3,7 @@ package com.dfsek.terra.config.templates;
import com.dfsek.tectonic.annotations.Abstractable;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.Range;
import com.dfsek.terra.api.platform.block.BlockType;
import com.dfsek.terra.api.util.collections.MaterialSet;
@@ -12,6 +13,7 @@ import java.util.HashMap;
import java.util.Map;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
@AutoDocAlias("UserDefinedCarver")
public class CarverTemplate extends AbstractableTemplate {
@Value("id")
private String id;
@@ -3,6 +3,7 @@ package com.dfsek.terra.config.templates;
import com.dfsek.tectonic.annotations.Abstractable;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.api.world.palette.holder.PaletteLayerHolder;
import com.dfsek.terra.world.population.items.flora.TerraFlora;
@@ -10,6 +11,7 @@ import com.dfsek.terra.world.population.items.flora.TerraFlora;
import java.util.List;
@SuppressWarnings({"FieldMayBeFinal", "unused"})
@AutoDocAlias("Flora")
public class FloraTemplate extends AbstractableTemplate {
@Value("id")
private String id;
@@ -32,7 +34,7 @@ public class FloraTemplate extends AbstractableTemplate {
@Value("irrigable")
@Abstractable
@Default
private MaterialSet irrigable = null;
private MaterialSet irrigable = new MaterialSet();
@Value("rotatable")
@Abstractable
@@ -3,12 +3,14 @@ package com.dfsek.terra.config.templates;
import com.dfsek.tectonic.annotations.Abstractable;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.Range;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.world.population.items.ores.Ore;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
@AutoDocAlias("Ore")
public class OreTemplate extends AbstractableTemplate {
@Value("id")
private String id;
@@ -3,6 +3,7 @@ package com.dfsek.terra.config.templates;
import com.dfsek.tectonic.annotations.Abstractable;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.noise.samplers.noise.random.WhiteNoiseSampler;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
@@ -11,6 +12,7 @@ import com.dfsek.terra.api.world.palette.holder.PaletteLayerHolder;
import java.util.List;
@SuppressWarnings({"FieldMayBeFinal", "unused"})
@AutoDocAlias("Palette")
public class PaletteTemplate extends AbstractableTemplate {
@Value("noise")
@Abstractable
@@ -4,6 +4,7 @@ import com.dfsek.tectonic.annotations.Abstractable;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.math.GridSpawn;
import com.dfsek.terra.api.math.Range;
import com.dfsek.terra.api.structures.script.StructureScript;
@@ -13,6 +14,7 @@ import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import java.util.List;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
@AutoDocAlias("TerraStructure")
public class StructureTemplate extends AbstractableTemplate implements ConfigTemplate {
@Value("id")
private String id;
@@ -3,11 +3,13 @@ package com.dfsek.terra.config.templates;
import com.dfsek.tectonic.annotations.Abstractable;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.docs.AutoDocAlias;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
@AutoDocAlias("Tree")
public class TreeTemplate extends AbstractableTemplate {
@Value("scripts")
@Abstractable
+5
View File
@@ -0,0 +1,5 @@
# Boolean
A Boolean data type represents a logical boolean value, a value which can
be either `true` or `false`.
+10
View File
@@ -0,0 +1,10 @@
# Double
A Double type represents a double-precision floating point value.
Essentially, a Double is a decimal number.
Examples:
* `5`
* `0.3`
* `-12.5`
* `100.3`
+10
View File
@@ -0,0 +1,10 @@
# Integer
An Integer data type represents a Java integer, a whole number with
a minimum value of -2^31, and a maximum value of 2^31-1.
Examples:
* `0`
* `5`
* `-20`
* `123456`
+17
View File
@@ -0,0 +1,17 @@
# List
A List is an ordered collection of objects of a specific type.
Examples:
* A List of [Strings](./String)s
```yml
- "thing"
- "thing 2"
- "thing 3"
```
* A List of [Integers](./Integer)
```yml
- 1
- 2
- 3
```
+17
View File
@@ -0,0 +1,17 @@
# Map
A map is a data structure that "maps" one type (keys) to another (values).
Examples:
* Mapping [Strings](./String) to [Strings](./String)
```yml
a: "thing"
b: "thing 2"
c: "thing 3"
```
* Mapping [Strings](./String) to [Integers](./Integer)
```yml
a: 1
b: 2
c: 3
```
@@ -0,0 +1,50 @@
# ProbabilityCollection
A Probability Collection is a representation of a weighted pool.
Example:
* `a` has a 1/5 (20%) chance, `b` and `c` both have a 2/5 (40%) chance.
```yml
- a: 1
- b: 2
- c: 2
```
# Weighted Pool
A weighted pool is a way to randomly select one of many objects from a "pool" based on "weight".
## Pools
A pool is a list of objects from which selections will be pulled.
## Weight
Weight is the *relative* probability that any object will be selected from the pool. Each object in the pool has a
weight, meaning the chance of object O being selected from pool P is `weight(O)/sum(weight(P_n))`.
## Example
Here's an example pool:
```yaml
OPTION_A: 2
OPTION_B: 1
OPTION_C: 1
```
In this YAML-based pool, the keys are the objects, and the values are the weights. If we want the probability that
`OPTION_A` will be selected, we sum all weights, and divide the weight of `OPTION_A` by that sum.
`2 + 1 + 1 = 4`
Therefore the probability that OPTION_A will be selected is `2/4`, or 50%.
## Manipulating weights to get a desired probability
What if we want Option A to have a 60% chance of being selected? This requires manipulating the weights of all objects
in the pool, since with B and C having a weight of 1, there is no integer weight that can be assigned to A that will
give it a probability of 60%. What is usually done is that the weights are given a set sum that is easy to work with.
Usually this is 100, since with a sum of 100, every object's weight is equal to the percent chance it will be selected.
By applying this to the above example, we can produce this pool that has a 60% chance of A being selected:
```yaml
OPTION_A: 60
OPTION_B: 20
OPTION_C: 20
```
## Use Cases
Sometimes, it is undesirable to have an equal probability of all objects being selected, so you may want to "weight"
some objects higher, so they are selected more often.
+17
View File
@@ -0,0 +1,17 @@
# Set
A Set is very similar to a [List](./List), except it is *unordered*.
Examples:
* A Set of [Strings](./String).
```yml
- "thing"
- "thing 2"
- "thing 3"
```
* A Set of [Integers](./Integer).
```yml
- 1
- 2
- 3
```
+13
View File
@@ -0,0 +1,13 @@
# String
A String data type represents a string of characters.
Examples:
* `"Hello, World!"`
* ```
A
Multi
Line
String
```
* `"Something"`