Compare commits

..

17 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
294 changed files with 3300 additions and 6655 deletions
+1 -1
View File
@@ -342,6 +342,6 @@ ij_json_wrap_long_lines = false
indent_size = 2
ij_yaml_keep_indents_on_empty_lines = true
ij_yaml_keep_line_breaks = true
ij_yaml_space_before_colon = false
ij_yaml_space_before_colon = true
ij_yaml_spaces_within_braces = true
ij_yaml_spaces_within_brackets = true
+10 -26
View File
@@ -7,40 +7,24 @@ to your specifications, with no knowledge of Java required.
* Paper+ servers (Paper, Tuinity, Purpur, 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
## Building and running Terra
To build, simply run `./gradlew build` (`gradlew.bat build` on Windows). This will build all platforms, and
produce JARs in `platforms/<platform>/build/libs`
To build, simply run `./gradlew build` (`gradlew.bat build` on Windows). This will produce a jar in `build/libs`
called `Terra-[CURRENT VERSION].jar`. You can put this right into your plugins dir, along with the correct Gaea version.
### Production JARs:
* Bukkit: `Terra-<version>-shaded.jar`
* Fabric: `Terra-<version>-shaded-mapped.jar`
* Forge: `Terra-<version>-shaded.jar`
If you would like to test it with a default server config, just run `./gradlew setupServer` or
`./gradlew.bat setupServer` to set up the server, then `./gradlew testWithPaper` or `gradlew.bat testWithPaper` to run the server. If you
want a clean installation of the server, re-run the `setupServer` task. This will download a default server config
from [here](https://github.com/PolyhedralDev/WorldGenTestServer)
and install the server in the `target/server` directory, along with all the needed plugins.
### Building a Specific Platform
To build a specific platform, run `gradlew :platforms:<platform>:build`.
**Note: You will need to adjust the `NAME` variable `bukkit.yml` of the test server if you are not using the default Terra config.**
JARs are produced in `platforms/<platform>/build/libs`.
### Running Minecraft in the IDE
To run Minecraft with Terra in the IDE (for testing) use the following tasks:
* Bukkit
* `installPaper` - Install a [Paper](https://github.com/PaperMC/Paper) test server. (Only needs to be run once).
* `installPurpur` - Install a [Purpur](https://github.com/pl3xgaming/Purpur) test server. (Only needs to be run once).
* `runPaper` - Run the Paper test server with Terra (`installPaper` must have been run previously).
* `runPurpur` - Run the Purpur test server with Terra (`installPurpur` must have been run previously).
* 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
Contributions are welcome! If you want to see a feature in Terra, please, open an issue, or implement it yourself and
submit a PR!
Join the discord [here](https://discord.gg/PXUEbbF) if you would like to talk more about the project!
## Beta
Terra is still in beta! While it is stable, it is not feature-complete. There is a lot to be added!
Terra is still in beta! While it is stable, it is not feature-complete. There is a lot to be added!
+1 -18
View File
@@ -1,27 +1,10 @@
import com.dfsek.terra.getGitHash
val versionObj = Version("5", "3", "3", true)
val versionObj = Version("5", "1", "3", true)
allprojects {
version = versionObj
group = "com.dfsek.terra"
tasks.withType<JavaCompile>().configureEach {
options.isFork = true
options.isIncremental = true
}
tasks.withType<Test>().configureEach {
useJUnitPlatform()
maxHeapSize = "2G"
ignoreFailures = false
failFast = true
maxParallelForks = (Runtime.getRuntime().availableProcessors() - 1).takeIf { it > 0 } ?: 1
reports.html.isEnabled = false
reports.junitXml.isEnabled = false
}
}
/**
* Version class that does version stuff.
@@ -7,11 +7,26 @@ import org.gradle.kotlin.dsl.withType
import java.io.ByteArrayOutputStream
fun Project.configureCommon() {
apply(plugin = "java-library")
apply(plugin = "maven-publish")
apply(plugin = "idea")
configureDependencies()
configureCompilation()
configureDistribution()
version = rootProject.version
tasks.withType<Test>().configureEach {
useJUnitPlatform()
maxHeapSize = "2G"
ignoreFailures = false
failFast = true
maxParallelForks = 12
}
}
fun Project.getGitHash(): String {
@@ -3,16 +3,14 @@ package com.dfsek.terra
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.kotlin.dsl.*
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.filter
import org.gradle.kotlin.dsl.withType
import org.gradle.language.jvm.tasks.ProcessResources
fun Project.configureCompilation() {
apply(plugin = "maven-publish")
apply(plugin = "idea")
configure<JavaPluginConvention> {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
@@ -21,7 +19,7 @@ fun Project.configureCompilation() {
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
doFirst {
options.compilerArgs.add("-Xlint:all")
options.compilerArgs = mutableListOf("-Xlint:all")
}
}
@@ -29,12 +27,7 @@ fun Project.configureCompilation() {
include("**/*.*")
filter<org.apache.tools.ant.filters.ReplaceTokens>(
"tokens" to mapOf(
"VERSION" to project.version.toString(),
"DESCRIPTION" to project.properties["terra.description"],
"WIKI" to project.properties["terra.wiki"],
"SOURCE" to project.properties["terra.source"],
"ISSUES" to project.properties["terra.issues"],
"LICENSE" to project.properties["terra.license"]
"VERSION" to project.version.toString()
)
)
}
@@ -42,19 +35,4 @@ fun Project.configureCompilation() {
tasks.withType<Javadoc> {
options.encoding = "UTF-8"
}
tasks.withType<Jar> {
archiveBaseName.set("Terra-${archiveBaseName.get()}")
from("../LICENSE", "../../LICENSE")
}
tasks.register<Jar>("sourcesJar") {
archiveClassifier.set("sources")
}
tasks.register<Jar>("javadocJar") {
dependsOn("javadoc")
archiveClassifier.set("javadoc")
from(tasks.getByName<Javadoc>("javadoc").destinationDir)
}
}
@@ -1,27 +1,13 @@
package com.dfsek.terra
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.invoke
import org.gradle.kotlin.dsl.repositories
fun Project.configureDependencies() {
apply(plugin = "java")
apply(plugin = "java-library")
configurations {
val shaded = create("shaded")
val shadedApi = create("shadedApi")
shaded.extendsFrom(shadedApi)
getByName("api").extendsFrom(shadedApi)
val shadedImplementation = create("shadedImplementation")
shaded.extendsFrom(shadedImplementation)
getByName("implementation").extendsFrom(shadedImplementation)
}
repositories {
maven { url = uri("https://maven.enginehub.org/repo/") }
maven { url = uri("http://maven.enginehub.org/repo/") }
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
maven { url = uri("https://maven.fabricmc.net/") }
@@ -33,6 +19,6 @@ fun Project.configureDependencies() {
dependencies {
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.7.0")
"testImplementation"("org.junit.jupiter:junit-jupiter-engine:5.7.0")
"api"("org.jetbrains:annotations:20.1.0")
"compileOnly"("org.jetbrains:annotations:20.1.0")
}
}
@@ -14,6 +14,17 @@ fun Project.configureDistribution() {
apply(plugin = "java-library")
apply(plugin = "com.github.johnrengelman.shadow")
configurations {
val shaded = create("shaded")
getByName("compile").extendsFrom(shaded)
val shadedApi = create("shadedApi")
shaded.extendsFrom(shadedApi)
getByName("api").extendsFrom(shadedApi)
val shadedImplementation = create("shadedImplementation")
shaded.extendsFrom(shadedImplementation)
getByName("implementation").extendsFrom(shadedImplementation)
}
val downloadDefaultPacks = tasks.create("downloadDefaultPacks") {
group = "terra"
doFirst {
@@ -27,6 +38,21 @@ fun Project.configureDistribution() {
}
tasks["processResources"].dependsOn(downloadDefaultPacks)
tasks.withType<Jar> {
archiveBaseName.set("Terra-${archiveBaseName.get()}")
from("../LICENSE", "../../LICENSE")
}
tasks.register<Jar>("sourcesJar") {
archiveClassifier.set("sources")
}
tasks.register<Jar>("javadocJar") {
dependsOn("javadoc")
archiveClassifier.set("javadoc")
from(tasks.getByName<Javadoc>("javadoc").destinationDir)
}
tasks.named<ShadowJar>("shadowJar") {
// Tell shadow to download the packs
dependsOn(downloadDefaultPacks)
+215 -6
View File
@@ -1,14 +1,26 @@
import com.dfsek.terra.configureCompilation
import com.dfsek.terra.configureDependencies
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`
idea
}
configureCompilation()
configureDependencies()
buildscript {
dependencies {
classpath("com.github.javaparser:javaparser-symbol-solver-core:3.20.2")
}
}
configureCommon()
group = "com.dfsek.terra.common"
@@ -17,7 +29,7 @@ dependencies {
"shadedApi"("commons-io:commons-io:2.4")
"shadedApi"("com.dfsek:Paralithic:0.3.2")
"shadedApi"("com.dfsek:Tectonic:1.3.1")
"shadedApi"("com.dfsek:Tectonic:1.2.3")
"shadedApi"("net.jafama:jafama:2.3.2")
"shadedApi"("org.yaml:snakeyaml:1.27")
"shadedApi"("org.ow2.asm:asm:9.0")
@@ -54,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>", "")
}
@@ -4,25 +4,17 @@ import com.dfsek.terra.api.addons.TerraAddon;
import com.dfsek.terra.api.event.EventManager;
import com.dfsek.terra.api.platform.handle.ItemHandle;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.modloader.Mod;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.LockedRegistry;
import com.dfsek.terra.api.util.JarUtil;
import com.dfsek.terra.api.util.logging.DebugLogger;
import com.dfsek.terra.api.util.logging.Logger;
import com.dfsek.terra.config.PluginConfig;
import com.dfsek.terra.config.lang.Language;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.profiler.Profiler;
import com.dfsek.terra.world.TerraWorld;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Set;
import java.util.jar.JarFile;
/**
* Represents a Terra mod/plugin instance.
@@ -72,14 +64,4 @@ public interface TerraPlugin extends LoaderRegistrar {
default void runPossiblyUnsafeTask(Runnable task) {
task.run();
}
Profiler getProfiler();
default JarFile getModJar() throws URISyntaxException, IOException {
return JarUtil.getJarFile();
}
default Set<Mod> getMods() {
return Collections.emptySet();
}
}
@@ -65,7 +65,7 @@ public class TerraCommandManager implements CommandManager {
return;
}
if(commandClass.isAnnotationPresent(WorldCommand.class) && (!(sender instanceof Player) || !(((Player) sender).getWorld()).isTerraWorld())) {
if(commandClass.isAnnotationPresent(WorldCommand.class) && (!(sender instanceof Player) || !TerraWorld.isTerraWorld(((Player) sender).getWorld()))) {
sender.sendMessage("Command must be executed in a Terra world.");
return;
}
@@ -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,9 +1,6 @@
package com.dfsek.terra.api.event.events.config;
import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.terra.api.event.events.PackEvent;
import com.dfsek.terra.config.fileloaders.Loader;
import com.dfsek.terra.config.pack.ConfigPack;
/**
@@ -11,34 +8,13 @@ import com.dfsek.terra.config.pack.ConfigPack;
*/
public abstract class ConfigPackLoadEvent implements PackEvent {
private final ConfigPack pack;
private final ExceptionalConsumer<ConfigTemplate> configLoader;
private final Loader loader;
public ConfigPackLoadEvent(ConfigPack pack, ExceptionalConsumer<ConfigTemplate> configLoader, Loader loader) {
public ConfigPackLoadEvent(ConfigPack pack) {
this.pack = pack;
this.configLoader = configLoader;
this.loader = loader;
}
@Override
public ConfigPack getPack() {
return pack;
}
/**
* Load a custom {@link ConfigTemplate} using the pack manifest.
*
* @param template Template to register.
*/
public void loadTemplate(ConfigTemplate template) throws ConfigException {
configLoader.accept(template);
}
public interface ExceptionalConsumer<T extends ConfigTemplate> {
void accept(T value) throws ConfigException;
}
public Loader getLoader() {
return loader;
}
}
@@ -1,14 +1,12 @@
package com.dfsek.terra.api.event.events.config;
import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.terra.config.fileloaders.Loader;
import com.dfsek.terra.config.pack.ConfigPack;
/**
* Called when a config pack has finished loading.
*/
public class ConfigPackPostLoadEvent extends ConfigPackLoadEvent {
public ConfigPackPostLoadEvent(ConfigPack pack, ExceptionalConsumer<ConfigTemplate> configTemplateLoader, Loader loader) {
super(pack, configTemplateLoader, loader);
public ConfigPackPostLoadEvent(ConfigPack pack) {
super(pack);
}
}
@@ -1,14 +1,12 @@
package com.dfsek.terra.api.event.events.config;
import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.terra.config.fileloaders.Loader;
import com.dfsek.terra.config.pack.ConfigPack;
/**
* Called before a config pack's registries are filled. At this point, the pack manifest has been loaded, and all registries are empty.
*/
public class ConfigPackPreLoadEvent extends ConfigPackLoadEvent {
public ConfigPackPreLoadEvent(ConfigPack pack, ExceptionalConsumer<ConfigTemplate> configLoader, Loader loader) {
super(pack, configLoader, loader);
public ConfigPackPreLoadEvent(ConfigPack pack) {
super(pack);
}
}
@@ -1,7 +1,6 @@
package com.dfsek.terra.api.platform.inventory;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.inventory.item.Damageable;
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
public interface ItemStack extends Handle {
@@ -14,8 +13,4 @@ public interface ItemStack extends Handle {
ItemMeta getItemMeta();
void setItemMeta(ItemMeta meta);
default boolean isDamageable() {
return getItemMeta() instanceof Damageable;
}
}
@@ -1,9 +0,0 @@
package com.dfsek.terra.api.platform.modloader;
public interface Mod {
String getID();
String getVersion();
String getName();
}
@@ -6,8 +6,6 @@ import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import java.io.File;
import java.util.UUID;
@@ -19,12 +17,20 @@ public interface World extends Handle {
ChunkGenerator getGenerator();
String getName();
UUID getUID();
boolean isChunkGenerated(int x, int z);
Chunk getChunkAt(int x, int z);
default Chunk getChunkAt(Location location) {
return getChunkAt(location.getBlockX() >> 4, location.getBlockZ() >> 4);
}
File getWorldFolder();
Block getBlockAt(int x, int y, int z);
default Block getBlockAt(Location l) {
@@ -34,12 +40,4 @@ public interface World extends Handle {
Entity spawnEntity(Location location, EntityType entityType);
int getMinHeight();
default boolean isTerraWorld() {
return getGenerator().getHandle() instanceof GeneratorWrapper;
}
default TerraChunkGenerator getTerraGenerator() {
return ((GeneratorWrapper) getGenerator().getHandle()).getHandle();
}
}
@@ -34,8 +34,8 @@ public class DamageFunction implements LootFunction {
@Override
public ItemStack apply(ItemStack original, Random r) {
if(original == null) return null;
if(!original.isDamageable()) return original;
ItemMeta meta = original.getItemMeta();
if(!(meta instanceof Damageable)) return original;
double itemDurability = (r.nextDouble() * (max - min)) + min;
Damageable damage = (Damageable) meta;
damage.setDamage((int) (original.getType().getMaxDurability() - (itemDurability / 100) * original.getType().getMaxDurability()));
@@ -29,7 +29,6 @@ import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.structure.buffer.Buffer;
import com.dfsek.terra.api.structures.structure.buffer.DirectBuffer;
import com.dfsek.terra.api.structures.structure.buffer.StructureBuffer;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.registry.config.FunctionRegistry;
import com.dfsek.terra.registry.config.LootRegistry;
import com.dfsek.terra.registry.config.ScriptRegistry;
@@ -40,7 +39,6 @@ import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Random;
import java.util.concurrent.ExecutionException;
@@ -54,7 +52,7 @@ public class StructureScript {
public StructureScript(InputStream inputStream, TerraPlugin main, ScriptRegistry registry, LootRegistry lootRegistry, FunctionRegistry functionRegistry) throws ParseException {
Parser parser;
try {
parser = new Parser(IOUtils.toString(inputStream, Charset.defaultCharset()));
parser = new Parser(IOUtils.toString(inputStream));
} catch(IOException e) {
throw new RuntimeException(e);
}
@@ -89,12 +87,6 @@ public class StructureScript {
.registerFunction("ceil", new UnaryNumberFunctionBuilder(number -> FastMath.ceil(number.doubleValue())))
.registerFunction("log", new UnaryNumberFunctionBuilder(number -> FastMath.log(number.doubleValue())))
.registerFunction("round", new UnaryNumberFunctionBuilder(number -> FastMath.round(number.doubleValue())))
.registerFunction("sin", new UnaryNumberFunctionBuilder(number -> FastMath.sin(number.doubleValue())))
.registerFunction("cos", new UnaryNumberFunctionBuilder(number -> FastMath.cos(number.doubleValue())))
.registerFunction("tan", new UnaryNumberFunctionBuilder(number -> FastMath.tan(number.doubleValue())))
.registerFunction("asin", new UnaryNumberFunctionBuilder(number -> FastMath.asin(number.doubleValue())))
.registerFunction("acos", new UnaryNumberFunctionBuilder(number -> FastMath.acos(number.doubleValue())))
.registerFunction("atan", new UnaryNumberFunctionBuilder(number -> FastMath.atan(number.doubleValue())))
.registerFunction("max", new BinaryNumberFunctionBuilder((number, number2) -> FastMath.max(number.doubleValue(), number2.doubleValue())))
.registerFunction("min", new BinaryNumberFunctionBuilder((number, number2) -> FastMath.min(number.doubleValue(), number2.doubleValue())));
@@ -112,31 +104,22 @@ public class StructureScript {
* @param rotation Rotation of structure
* @return Whether generation was successful
*/
@SuppressWarnings("try")
public boolean execute(Location location, Random random, Rotation rotation) {
try(ProfileFrame ignore = main.getProfiler().profile("terrascript:" + id)) {
StructureBuffer buffer = new StructureBuffer(location);
boolean level = applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
buffer.paste();
return level;
}
StructureBuffer buffer = new StructureBuffer(location);
boolean level = applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
buffer.paste();
return level;
}
@SuppressWarnings("try")
public boolean execute(Location location, Chunk chunk, Random random, Rotation rotation) {
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_chunk:" + id)) {
StructureBuffer buffer = computeBuffer(location, random, rotation);
buffer.paste(chunk);
return buffer.succeeded();
}
StructureBuffer buffer = computeBuffer(location, random, rotation);
buffer.paste(chunk);
return buffer.succeeded();
}
@SuppressWarnings("try")
public boolean test(Location location, Random random, Rotation rotation) {
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_test:" + id)) {
StructureBuffer buffer = computeBuffer(location, random, rotation);
return buffer.succeeded();
}
StructureBuffer buffer = computeBuffer(location, random, rotation);
return buffer.succeeded();
}
private StructureBuffer computeBuffer(Location location, Random random, Rotation rotation) {
@@ -151,19 +134,13 @@ public class StructureScript {
}
}
@SuppressWarnings("try")
public boolean executeInBuffer(Buffer buffer, Random random, Rotation rotation, int recursions) {
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_recursive:" + id)) {
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, recursions));
}
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, recursions));
}
@SuppressWarnings("try")
public boolean executeDirect(Location location, Random random, Rotation rotation) {
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_direct:" + id)) {
DirectBuffer buffer = new DirectBuffer(location);
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
}
DirectBuffer buffer = new DirectBuffer(location);
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
}
public String getId() {
@@ -19,6 +19,6 @@ public class BufferedEntity implements BufferedItem {
@Override
public void paste(Location origin) {
Entity entity = origin.clone().add(0.5, 0, 0.5).getWorld().spawnEntity(origin, type);
main.getEventManager().callEvent(new EntitySpawnEvent(entity.getWorld().getTerraGenerator().getConfigPack(), entity, entity.getLocation()));
main.getEventManager().callEvent(new EntitySpawnEvent(main.getWorld(entity.getWorld()).getGenerator().getConfigPack(), entity, entity.getLocation()));
}
}
@@ -32,7 +32,7 @@ public class BufferedLootApplication implements BufferedItem {
}
Container container = (Container) data;
LootPopulateEvent event = new LootPopulateEvent(block, container, table, block.getLocation().getWorld().getTerraGenerator().getConfigPack(), structure);
LootPopulateEvent event = new LootPopulateEvent(block, container, table, main.getWorld(block.getLocation().getWorld()).getGenerator().getConfigPack(), structure);
main.getEventManager().callEvent(event);
if(event.isCancelled()) return;
@@ -40,7 +40,7 @@ public class BufferedLootApplication implements BufferedItem {
data.update(false);
} catch(Exception e) {
main.logger().warning("Could not apply loot at " + origin + ": " + e.getMessage());
e.printStackTrace();
main.getDebugLogger().stack(e);
}
}
}
@@ -21,7 +21,7 @@ public class BufferedStateManipulator implements BufferedItem {
state.update(false);
} catch(Exception e) {
main.logger().warning("Could not apply BlockState at " + origin + ": " + e.getMessage());
e.printStackTrace();
main.getDebugLogger().stack(e);
}
}
}
@@ -0,0 +1,8 @@
package com.dfsek.terra.api.transform;
public class NotNullValidator<T> implements Validator<T> {
@Override
public boolean validate(T value) {
return !(value == null);
}
}
@@ -53,7 +53,6 @@ public class Transformer<F, T> {
private final LinkedHashMap<Transform<F, T>, List<Validator<T>>> transforms = new LinkedHashMap<>();
@SafeVarargs
@SuppressWarnings("varargs")
public final Builder<F, T> addTransform(Transform<F, T> transform, Validator<T>... validators) {
transforms.put(transform, Arrays.asList(validators));
return this;
@@ -1,12 +1,6 @@
package com.dfsek.terra.api.transform;
import java.util.Objects;
public interface Validator<T> {
boolean validate(T value) throws TransformException;
static <T> Validator<T> notNull() {
return Objects::nonNull;
}
}
@@ -1,13 +1,9 @@
package com.dfsek.terra.api.util;
import com.dfsek.terra.api.TerraPlugin;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -36,12 +32,4 @@ public class JarUtil {
}
}
}
public static JarFile getJarFile() throws URISyntaxException, IOException {
return new JarFile(new File(getJarURL().toURI()));
}
public static URL getJarURL() {
return TerraPlugin.class.getProtectionDomain().getCodeSource().getLocation();
}
}
@@ -4,10 +4,16 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileQueryCommand implements CommandTemplate {
@Inject
@@ -15,9 +21,8 @@ public class ProfileQueryCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
StringBuilder data = new StringBuilder("Terra Profiler data dump: \n");
main.getProfiler().getTimings().forEach((id, timings) -> data.append(id).append(": ").append(timings.toString()).append('\n'));
main.logger().info(data.toString());
sender.sendMessage("Profiler data dumped to console.");
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
player.sendMessage(world.getProfiler().getResultsFormatted());
}
}
@@ -4,10 +4,16 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileResetCommand implements CommandTemplate {
@Inject
@@ -15,7 +21,9 @@ public class ProfileResetCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
main.getProfiler().reset();
sender.sendMessage("Profiler reset.");
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
world.getProfiler().reset();
player.sendMessage("Profiler reset.");
}
}
@@ -4,10 +4,16 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileStartCommand implements CommandTemplate {
@Inject
@@ -15,7 +21,9 @@ public class ProfileStartCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
main.getProfiler().start();
sender.sendMessage("Profiling enabled.");
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
world.getProfiler().setProfiling(true);
player.sendMessage("Profiling enabled.");
}
}
@@ -4,10 +4,16 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileStopCommand implements CommandTemplate {
@Inject
@@ -15,7 +21,9 @@ public class ProfileStopCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
main.getProfiler().stop();
sender.sendMessage("Profiling disabled.");
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
world.getProfiler().setProfiling(false);
player.sendMessage("Profiling disabled.");
}
}
@@ -46,8 +46,6 @@ import com.dfsek.terra.config.loaders.config.sampler.templates.ImageSamplerTempl
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.ClampNormalizerTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.LinearNormalizerTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.NormalNormalizerTemplate;
import com.dfsek.terra.config.loaders.mod.ModDependentConfigSection;
import com.dfsek.terra.config.loaders.mod.ModDependentConfigSectionLoader;
import com.dfsek.terra.config.loaders.palette.CarverPaletteLoader;
import com.dfsek.terra.config.loaders.palette.PaletteHolderLoader;
import com.dfsek.terra.config.loaders.palette.PaletteLayerLoader;
@@ -110,8 +108,7 @@ public class GenericLoaders implements LoaderRegistrar {
if(main != null) {
registry.registerLoader(TerraAddon.class, main.getAddons())
.registerLoader(BlockType.class, (t, object, cf) -> main.getWorldHandle().createBlockData((String) object).getBlockType())
.registerLoader(ModDependentConfigSection.class, new ModDependentConfigSectionLoader(main));
.registerLoader(BlockType.class, (t, object, cf) -> main.getWorldHandle().createBlockData((String) object).getBlockType());
}
}
}
@@ -69,12 +69,12 @@ public class PluginConfig implements ConfigTemplate {
ConfigLoader loader = new ConfigLoader();
loader.load(this, file);
if(dumpDefaultConfig) { // Don't dump default config if already loaded.
try(JarFile jar = main.getModJar()) {
try(JarFile jar = new JarFile(new File(TerraPlugin.class.getProtectionDomain().getCodeSource().getLocation().toURI()))) {
JarUtil.copyResourcesToDirectory(jar, "packs", new File(main.getDataFolder(), "packs").toString());
} catch(IOException | URISyntaxException e) {
main.getDebugLogger().error("Failed to dump default config files!");
e.printStackTrace();
main.getDebugLogger().error("Either you're on Forge, or this is a bug. If it's the latter, report this to Terra!");
main.getDebugLogger().error("Report this to Terra!");
}
}
} catch(ConfigException | IOException e) {
@@ -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();
@@ -0,0 +1,147 @@
package com.dfsek.terra.config.builder;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.noise.samplers.ExpressionSampler;
import com.dfsek.terra.api.math.noise.samplers.noise.ConstantSampler;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.palette.holder.PaletteHolder;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import com.dfsek.terra.world.generation.WorldGenerator;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class GeneratorBuilder {
private final Map<Long, WorldGenerator> gens = Collections.synchronizedMap(new HashMap<>());
private String noiseEquation;
private String elevationEquation;
private String carvingEquation;
private Scope varScope;
private Map<String, NoiseSeeded> noiseBuilderMap;
private Map<String, FunctionTemplate> functionTemplateMap;
private PaletteHolder palettes;
private PaletteHolder slantPalettes;
private boolean preventInterpolation;
private boolean interpolateElevation;
private NoiseSeeded biomeNoise;
private double elevationWeight;
private int blendDistance;
private int blendStep;
private double blendWeight;
public WorldGenerator build(long seed) {
synchronized(gens) {
return gens.computeIfAbsent(seed, k -> {
NoiseSampler noise;
NoiseSampler elevation;
NoiseSampler carving;
try {
noise = new ExpressionSampler(noiseEquation, varScope, seed, noiseBuilderMap, functionTemplateMap);
elevation = elevationEquation == null ? new ConstantSampler(0) : new ExpressionSampler(elevationEquation, varScope, seed, noiseBuilderMap, functionTemplateMap);
carving = new ExpressionSampler(carvingEquation, varScope, seed, noiseBuilderMap, functionTemplateMap);
} catch(ParseException e) {
throw new RuntimeException(e);
}
return new WorldGenerator(palettes, slantPalettes, noise, elevation, carving, biomeNoise.apply(seed), elevationWeight, blendDistance, blendStep, blendWeight);
});
}
}
public void setBlendWeight(double blendWeight) {
this.blendWeight = blendWeight;
}
public void setFunctionTemplateMap(Map<String, FunctionTemplate> functionTemplateMap) {
this.functionTemplateMap = functionTemplateMap;
}
public void setBlendStep(int blendStep) {
this.blendStep = blendStep;
}
public void setBlendDistance(int blendDistance) {
this.blendDistance = blendDistance;
}
public void setBiomeNoise(NoiseSeeded biomeNoise) {
this.biomeNoise = biomeNoise;
}
public void setElevationWeight(double elevationWeight) {
this.elevationWeight = elevationWeight;
}
public void setNoiseEquation(String noiseEquation) {
this.noiseEquation = noiseEquation;
}
public void setElevationEquation(String elevationEquation) {
this.elevationEquation = elevationEquation;
}
public void setCarvingEquation(String carvingEquation) {
this.carvingEquation = carvingEquation;
}
public Scope getVarScope() {
return varScope;
}
public void setVarScope(Scope varScope) {
this.varScope = varScope;
}
public void setNoiseBuilderMap(Map<String, NoiseSeeded> noiseBuilderMap) {
this.noiseBuilderMap = noiseBuilderMap;
}
public PaletteHolder getPalettes() {
return palettes;
}
public void setPalettes(PaletteHolder palettes) {
this.palettes = palettes;
}
public PaletteHolder getSlantPalettes() {
return slantPalettes;
}
public void setSlantPalettes(PaletteHolder slantPalettes) {
this.slantPalettes = slantPalettes;
}
public boolean isPreventInterpolation() {
return preventInterpolation;
}
public void setPreventInterpolation(boolean preventInterpolation) {
this.preventInterpolation = preventInterpolation;
}
public void setInterpolateElevation(boolean interpolateElevation) {
this.interpolateElevation = interpolateElevation;
}
public boolean interpolateElevation() {
return interpolateElevation;
}
}
@@ -9,6 +9,9 @@ import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper;
import java.io.File;
import java.util.UUID;
public class DummyWorld implements World {
@Override
public Object getHandle() {
@@ -30,11 +33,31 @@ public class DummyWorld implements World {
return () -> (GeneratorWrapper) () -> null;
}
@Override
public String getName() {
return "DUMMY";
}
@Override
public UUID getUID() {
return UUID.randomUUID();
}
@Override
public boolean isChunkGenerated(int x, int z) {
return false;
}
@Override
public Chunk getChunkAt(int x, int z) {
throw new UnsupportedOperationException("Cannot get chunk in DummyWorld");
}
@Override
public File getWorldFolder() {
throw new UnsupportedOperationException("Cannot get folder of DummyWorld");
}
@Override
public Block getBlockAt(int x, int y, int z) {
throw new UnsupportedOperationException("Cannot get block in DummyWorld");
@@ -1,6 +1,5 @@
package com.dfsek.terra.config.fileloaders;
import com.dfsek.tectonic.config.Configuration;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.terra.api.util.GlueList;
@@ -19,12 +18,8 @@ public abstract class Loader {
*
* @param consumer Something to do with the streams.
*/
public Loader then(ExceptionalConsumer<List<Configuration>> consumer) throws ConfigException {
List<Configuration> list = new GlueList<>();
streams.forEach((id, stream) -> {
list.add(new Configuration(stream, id));
});
consumer.accept(list);
public Loader then(ExceptionalConsumer<List<InputStream>> consumer) throws ConfigException {
consumer.accept(new GlueList<>(streams.values()));
return this;
}
@@ -1,6 +1,5 @@
package com.dfsek.terra.config.fileloaders;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
@@ -21,7 +20,7 @@ public class ZIPLoader extends Loader {
ZipEntry entry = entries.nextElement();
if(!entry.isDirectory() && entry.getName().equals(singleFile)) return file.getInputStream(entry);
}
throw new FileNotFoundException("No such file: " + singleFile);
throw new IllegalArgumentException("No such file: " + singleFile);
}
@Override
@@ -17,7 +17,7 @@ public final class LangUtil {
public static void load(String langID, TerraPlugin main) {
Logger logger = main.logger();
File file = new File(main.getDataFolder(), "lang");
try(JarFile jar = main.getModJar()) {
try(JarFile jar = new JarFile(new File(TerraPlugin.class.getProtectionDomain().getCodeSource().getLocation().toURI()))) {
copyResourcesToDirectory(jar, "lang", file.toString());
} catch(IOException | URISyntaxException e) {
main.getDebugLogger().error("Failed to dump language files!");
@@ -18,7 +18,7 @@ public class OreHolderLoader implements TypeLoader<OreHolder> {
Map<String, Object> map = (Map<String, Object>) o;
for(Map.Entry<String, Object> entry : map.entrySet()) {
holder.add(configLoader.loadClass(Ore.class, entry.getKey()), configLoader.loadClass(OreConfig.class, entry.getValue()), entry.getKey());
holder.add(configLoader.loadClass(Ore.class, entry.getKey()), (OreConfig) configLoader.loadType(OreConfig.class, entry.getValue()));
}
return holder;
@@ -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;
@@ -1,46 +0,0 @@
package com.dfsek.terra.config.loaders.mod;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.platform.modloader.Mod;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class ModDependentConfigSection<T> {
private static final Object NULL = new Object(); // Null object
private final TerraPlugin main;
private final Map<String, T> results = new HashMap<>();
private final T defaultValue;
@SuppressWarnings("unchecked")
private T value = (T) NULL;
protected ModDependentConfigSection(TerraPlugin main, T defaultValue) {
this.main = main;
this.defaultValue = defaultValue;
}
public void add(String id, T value) {
results.put(id, value);
}
public static <T1> ModDependentConfigSection<T1> withDefault(T1 defaultValue) {
return new ModDependentConfigSection<>(null, defaultValue);
}
public T get() {
if(value == NULL) value = compute(); // Cache the value.
return value;
}
private T compute() {
if(main != null) {
Set<String> mods = main.getMods().stream().map(Mod::getID).collect(Collectors.toSet());
for(Map.Entry<String, T> entry : results.entrySet()) {
if(mods.contains(entry.getKey())) return entry.getValue();
}
}
return defaultValue;
}
}
@@ -1,43 +0,0 @@
package com.dfsek.terra.config.loaders.mod;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import com.dfsek.terra.api.TerraPlugin;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
public class ModDependentConfigSectionLoader implements TypeLoader<ModDependentConfigSection<?>> {
private final TerraPlugin main;
public ModDependentConfigSectionLoader(TerraPlugin main) {
this.main = main;
}
@SuppressWarnings("unchecked")
@Override
public ModDependentConfigSection<?> load(Type type, Object c, ConfigLoader loader) throws LoadException {
if(type instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) type;
Type generic = pType.getActualTypeArguments()[0];
if(c instanceof Map && ((Map<?, ?>) c).containsKey("default")) {
Map<String, ?> map = (Map<String, ?>) c;
ModDependentConfigSection<Object> configSection = new ModDependentConfigSection<>(main, loader.loadType(generic, map.get("default")));
if(map.containsKey("mods")) {
for(Map.Entry<String, ?> modEntry : ((Map<String, ?>) map.get("mods")).entrySet()) {
configSection.add(modEntry.getKey(), loader.loadType(generic, modEntry.getValue()));
}
}
return configSection;
} else {
return ModDependentConfigSection.withDefault(loader.loadType(generic, c)); // Load the original type otherwise.
}
} else throw new LoadException("Unable to load config! Could not retrieve parameterized type: " + type);
}
}
@@ -2,7 +2,6 @@ package com.dfsek.terra.config.pack;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.tectonic.abstraction.AbstractConfigLoader;
import com.dfsek.tectonic.config.Configuration;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
@@ -111,8 +110,6 @@ public class ConfigPack implements LoaderRegistrar {
private final TerraPlugin main;
private final Loader loader;
private final Configuration configuration;
private final BiomeProvider.BiomeProviderBuilder biomeProviderBuilder;
@@ -133,15 +130,11 @@ public class ConfigPack implements LoaderRegistrar {
File pack = new File(folder, "pack.yml");
try {
configuration = new Configuration(new FileInputStream(pack));
selfLoader.load(template, configuration);
selfLoader.load(template, new FileInputStream(pack));
main.logger().info("Loading config pack \"" + template.getID() + "\"");
main.getEventManager().callEvent(new ConfigPackPreLoadEvent(this, template -> selfLoader.load(template, configuration), loader));
load(l, main);
ConfigPackPostTemplate packPostTemplate = new ConfigPackPostTemplate();
selfLoader.load(packPostTemplate, new FileInputStream(pack));
biomeProviderBuilder = packPostTemplate.getProviderBuilder();
@@ -181,12 +174,9 @@ public class ConfigPack implements LoaderRegistrar {
if(pack == null) throw new LoadException("No pack.yml file found in " + file.getName());
configuration = new Configuration(file.getInputStream(pack));
selfLoader.load(template, configuration);
selfLoader.load(template, file.getInputStream(pack));
main.logger().info("Loading config pack \"" + template.getID() + "\"");
main.getEventManager().callEvent(new ConfigPackPreLoadEvent(this, template -> selfLoader.load(template, configuration), loader));
load(l, main);
ConfigPackPostTemplate packPostTemplate = new ConfigPackPostTemplate();
@@ -221,6 +211,8 @@ public class ConfigPack implements LoaderRegistrar {
private void load(long start, TerraPlugin main) throws ConfigException {
main.getEventManager().callEvent(new ConfigPackPreLoadEvent(this));
for(Map.Entry<String, Double> var : template.getVariables().entrySet()) {
varScope.create(var.getKey(), var.getValue());
}
@@ -245,15 +237,15 @@ public class ConfigPack implements LoaderRegistrar {
}).close();
loader
.open("carving", ".yml").then(configs -> buildAll(new CarverFactory(this), carverRegistry, abstractConfigLoader.loadConfigs(configs, CarverTemplate::new), main)).close()
.open("palettes", ".yml").then(configs -> buildAll(new PaletteFactory(), paletteRegistry, abstractConfigLoader.loadConfigs(configs, PaletteTemplate::new), main)).close()
.open("ores", ".yml").then(configs -> buildAll(new OreFactory(), oreRegistry, abstractConfigLoader.loadConfigs(configs, OreTemplate::new), main)).close()
.open("structures/trees", ".yml").then(configs -> buildAll(new TreeFactory(), treeRegistry, abstractConfigLoader.loadConfigs(configs, TreeTemplate::new), main)).close()
.open("structures/structures", ".yml").then(configs -> buildAll(new StructureFactory(), structureRegistry, abstractConfigLoader.loadConfigs(configs, StructureTemplate::new), main)).close()
.open("flora", ".yml").then(configs -> buildAll(new FloraFactory(), floraRegistry, abstractConfigLoader.loadConfigs(configs, FloraTemplate::new), main)).close()
.open("biomes", ".yml").then(configs -> buildAll(new BiomeFactory(this), biomeRegistry, abstractConfigLoader.loadConfigs(configs, () -> new BiomeTemplate(this, main)), main)).close();
.open("carving", ".yml").then(streams -> buildAll(new CarverFactory(this), carverRegistry, abstractConfigLoader.load(streams, CarverTemplate::new), main)).close()
.open("palettes", ".yml").then(streams -> buildAll(new PaletteFactory(), paletteRegistry, abstractConfigLoader.load(streams, PaletteTemplate::new), main)).close()
.open("ores", ".yml").then(streams -> buildAll(new OreFactory(), oreRegistry, abstractConfigLoader.load(streams, OreTemplate::new), main)).close()
.open("structures/trees", ".yml").then(streams -> buildAll(new TreeFactory(), treeRegistry, abstractConfigLoader.load(streams, TreeTemplate::new), main)).close()
.open("structures/structures", ".yml").then(streams -> buildAll(new StructureFactory(), structureRegistry, abstractConfigLoader.load(streams, StructureTemplate::new), main)).close()
.open("flora", ".yml").then(streams -> buildAll(new FloraFactory(), floraRegistry, abstractConfigLoader.load(streams, FloraTemplate::new), main)).close()
.open("biomes", ".yml").then(streams -> buildAll(new BiomeFactory(this), biomeRegistry, abstractConfigLoader.load(streams, () -> new BiomeTemplate(this, main)), main)).close();
main.getEventManager().callEvent(new ConfigPackPostLoadEvent(this, template -> selfLoader.load(template, configuration), loader));
main.getEventManager().callEvent(new ConfigPackPostLoadEvent(this));
main.logger().info("Loaded config pack \"" + template.getID() + "\" v" + template.getVersion() + " by " + template.getAuthor() + " in " + (System.nanoTime() - start) / 1000000D + "ms.");
}
@@ -6,42 +6,68 @@ import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.terra.api.addons.TerraAddon;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import com.dfsek.terra.config.loaders.mod.ModDependentConfigSection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@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<>();
@Value("structures.locatable")
@Default
private Map<String, ModDependentConfigSection<String>> locatable = new HashMap<>();
private Map<String, String> locatable = new HashMap<>();
@Value("blend.terrain.elevation")
@Default
@@ -49,19 +75,19 @@ public class ConfigPackTemplate implements ConfigTemplate {
@Value("vanilla.mobs")
@Default
private ModDependentConfigSection<Boolean> vanillaMobs = ModDependentConfigSection.withDefault(true);
private boolean vanillaMobs = true;
@Value("vanilla.caves")
@Default
private ModDependentConfigSection<Boolean> vanillaCaves = ModDependentConfigSection.withDefault(false);
private boolean vanillaCaves = false;
@Value("vanilla.decorations")
@Default
private ModDependentConfigSection<Boolean> vanillaDecorations = ModDependentConfigSection.withDefault(false);
private boolean vanillaDecorations = false;
@Value("vanilla.structures")
@Default
private ModDependentConfigSection<Boolean> vanillaStructures = ModDependentConfigSection.withDefault(false);
private boolean vanillaStructures = false;
@Value("author")
@Default
@@ -69,7 +95,7 @@ public class ConfigPackTemplate implements ConfigTemplate {
@Value("disable.sapling")
@Default
private ModDependentConfigSection<Boolean> disableSaplings = ModDependentConfigSection.withDefault(false);
private boolean disableSaplings = false;
@Value("version")
@Default
@@ -77,42 +103,42 @@ public class ConfigPackTemplate implements ConfigTemplate {
@Value("disable.carvers")
@Default
private ModDependentConfigSection<Boolean> disableCarvers = ModDependentConfigSection.withDefault(false);
private boolean disableCarvers = false;
@Value("disable.structures")
@Default
private ModDependentConfigSection<Boolean> disableStructures = ModDependentConfigSection.withDefault(false);
private boolean disableStructures = false;
@Value("disable.ores")
@Default
private ModDependentConfigSection<Boolean> disableOres = ModDependentConfigSection.withDefault(false);
private boolean disableOres = false;
@Value("disable.trees")
@Default
private ModDependentConfigSection<Boolean> disableTrees = ModDependentConfigSection.withDefault(false);
private boolean disableTrees = false;
@Value("disable.flora")
@Default
private ModDependentConfigSection<Boolean> disableFlora = ModDependentConfigSection.withDefault(false);
private boolean disableFlora = false;
public boolean disableCarvers() {
return disableCarvers.get();
return disableCarvers;
}
public boolean disableFlora() {
return disableFlora.get();
return disableFlora;
}
public boolean disableOres() {
return disableOres.get();
return disableOres;
}
public boolean disableStructures() {
return disableStructures.get();
return disableStructures;
}
public boolean disableTrees() {
return disableTrees.get();
return disableTrees;
}
public LinkedHashMap<String, FunctionTemplate> getFunctions() {
@@ -124,7 +150,7 @@ public class ConfigPackTemplate implements ConfigTemplate {
}
public boolean isDisableSaplings() {
return disableSaplings.get();
return disableSaplings;
}
public String getID() {
@@ -136,19 +162,19 @@ public class ConfigPackTemplate implements ConfigTemplate {
}
public boolean vanillaMobs() {
return vanillaMobs.get();
return vanillaMobs;
}
public boolean vanillaCaves() {
return vanillaCaves.get();
return vanillaCaves;
}
public boolean vanillaDecorations() {
return vanillaDecorations.get();
return vanillaDecorations;
}
public boolean vanillaStructures() {
return vanillaStructures.get();
return vanillaStructures;
}
public Map<String, NoiseSeeded> getNoiseBuilderMap() {
@@ -164,7 +190,7 @@ public class ConfigPackTemplate implements ConfigTemplate {
}
public Map<String, String> getLocatable() {
return locatable.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().get()));
return locatable;
}
public boolean doBetaCarvers() {
@@ -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
@@ -0,0 +1,36 @@
package com.dfsek.terra.profiler;
/**
* Class to hold a profiler data value. Contains formatting method to highlight value based on desired range.
*/
public class DataHolder {
private final long desired;
private final DataType type;
private final double desiredRangePercent;
/**
* Constructs a DataHolder with a DataType and a desired value, including a percentage around the desired value considered acceptable
*
* @param type The type of data held in this instance.
* @param desired The desired value. This should be the average value of whatever is being measured.
* @param desiredRangePercent The percentage around the desired value to be considered acceptable.
*/
public DataHolder(DataType type, long desired, double desiredRangePercent) {
this.desired = desired;
this.type = type;
this.desiredRangePercent = desiredRangePercent;
}
/**
* Returns a String, formatted with Bungee ChatColors.<br>
* GREEN if the value is better than desired and outside of acceptable range.<br>
* YELLOW if the value is better or worse than desired, and within acceptable range.<br>
* RED if the value is worse than desired and outside of acceptable range.<br>
*
* @param data The data to format.
* @return String - The formatted data.
*/
public String getFormattedData(long data) {
return type.getFormatted(data);
}
}
@@ -0,0 +1,24 @@
package com.dfsek.terra.profiler;
import net.jafama.FastMath;
public enum DataType {
PERIOD_MILLISECONDS(Desire.LOW, 1000000, "ms"), PERIOD_NANOSECONDS(Desire.LOW, 1, "ns");
private final Desire desire;
private final long divisor;
private final String unit;
DataType(Desire d, long divisor, String unit) {
this.desire = d;
this.divisor = divisor;
this.unit = unit;
}
public String getFormatted(long value) {
return (double) FastMath.round(((double) value / divisor) * 100D) / 100D + unit;
}
public Desire getDesire() {
return desire;
}
}
@@ -0,0 +1,10 @@
package com.dfsek.terra.profiler;
/**
* Enum to represent the "goal" of a value, whether it is desirable for the value to be high (e.g. Frequency), or low (e.g. Period)
*/
public enum Desire {
LOW, HIGH
}
@@ -1,24 +0,0 @@
package com.dfsek.terra.profiler;
public class Frame {
private final String id;
private final long start;
public Frame(String id) {
this.id = id;
this.start = System.nanoTime();
}
public String getId() {
return id;
}
public long getStart() {
return start;
}
@Override
public String toString() {
return id;
}
}
@@ -0,0 +1,87 @@
package com.dfsek.terra.profiler;
import com.dfsek.terra.api.math.MathUtil;
import com.dfsek.terra.api.util.GlueList;
import net.jafama.FastMath;
import java.math.BigInteger;
import java.util.LinkedList;
import java.util.List;
/**
* Class to record and hold all data for a single type of measurement performed by the profiler.
*/
public class Measurement {
private final List<Long> measurements = new LinkedList<>();
private final long desirable;
private final DataType type;
private long min = Long.MAX_VALUE;
private long max = Long.MIN_VALUE;
/**
* Constructs a new Measurement with a desired value and DataType.
*
* @param desirable The desired value of the measurement.
* @param type The type of data the measurement is holding.
*/
public Measurement(long desirable, DataType type) {
this.desirable = desirable;
this.type = type;
}
public void record(long value) {
max = FastMath.max(value, max);
min = FastMath.min(value, min);
measurements.add(value);
}
public int size() {
return measurements.size();
}
public ProfileFuture beginMeasurement() {
ProfileFuture future = new ProfileFuture();
long current = System.nanoTime();
future.thenRun(() -> record(System.nanoTime() - current));
return future;
}
public void reset() {
min = Long.MAX_VALUE;
max = Long.MIN_VALUE;
measurements.clear();
}
public DataHolder getDataHolder() {
return new DataHolder(type, desirable, 0.25);
}
public long getMin() {
if(min == Long.MAX_VALUE) return 0;
return min;
}
public long getMax() {
if(max == Long.MIN_VALUE) return 0;
return max;
}
public long average() {
BigInteger running = BigInteger.valueOf(0);
List<Long> mTemp = new GlueList<>(measurements);
for(Long l : mTemp) {
running = running.add(BigInteger.valueOf(l));
}
if(measurements.size() == 0) return 0;
return running.divide(BigInteger.valueOf(measurements.size())).longValue();
}
public double getStdDev() {
return MathUtil.standardDeviation(new GlueList<>(measurements));
}
public int entries() {
return measurements.size();
}
}
@@ -1,14 +0,0 @@
package com.dfsek.terra.profiler;
public class ProfileFrame implements AutoCloseable {
private final Runnable action;
public ProfileFrame(Runnable action) {
this.action = action;
}
@Override
public void close() {
action.run();
}
}
@@ -0,0 +1,18 @@
package com.dfsek.terra.profiler;
import java.util.concurrent.CompletableFuture;
public class ProfileFuture extends CompletableFuture<Boolean> implements AutoCloseable {
public ProfileFuture() {
super();
}
public boolean complete() {
return super.complete(true);
}
@Override
public void close() {
this.complete();
}
}
@@ -1,56 +0,0 @@
package com.dfsek.terra.profiler;
import java.util.Map;
public interface Profiler {
/**
* Push a frame to this profiler.
*
* @param frame ID of frame.
*/
void push(String frame);
/**
* Pop a frame from this profiler.
*
* @param frame ID of frame. Must match ID
* at the top of the profiler stack.
*/
void pop(String frame);
/**
* Start profiling.
*/
void start();
/**
* Stop profiling.
*/
void stop();
/**
* Get the profiler data.
*
* @return Profiler data.
*/
Map<String, Timings> getTimings();
/**
* Return a {@link AutoCloseable} implementation that
* may be used in a try-with-resources statement for
* more intuitive profiling, with auto-push/pop.
*
* @param frame ID of frame.
* @return {@link AutoCloseable} implementation for use
* in try-with-resources.
*/
default ProfileFrame profile(String frame) {
push(frame);
return new ProfileFrame(() -> pop(frame));
}
/**
* Clear the profiler data.
*/
void reset();
}
@@ -1,91 +0,0 @@
package com.dfsek.terra.profiler;
import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.profiler.exception.MalformedStackException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
public class ProfilerImpl implements Profiler {
private static final ThreadLocal<Stack<Frame>> THREAD_STACK = ThreadLocal.withInitial(Stack::new);
private static final ThreadLocal<Map<String, List<Long>>> TIMINGS = ThreadLocal.withInitial(HashMap::new);
private final List<Map<String, List<Long>>> accessibleThreadMaps = new ArrayList<>();
private volatile boolean running = false;
private static boolean instantiated = false;
private static final ThreadLocal<Boolean> SAFE = ThreadLocal.withInitial(() -> false);
private static final ThreadLocal<MutableInteger> STACK_SIZE = ThreadLocal.withInitial(() -> new MutableInteger(0));
public ProfilerImpl() {
if(instantiated) throw new IllegalStateException("Only one instance of Profiler may exist!");
instantiated = true;
}
@Override
public void push(String frame) {
STACK_SIZE.get().increment();
if(running && SAFE.get()) {
Stack<Frame> stack = THREAD_STACK.get();
stack.push(new Frame(stack.isEmpty() ? frame : stack.peek().getId() + "." + frame));
} else SAFE.set(false);
}
@Override
public void pop(String frame) {
MutableInteger size = STACK_SIZE.get();
size.decrement();
if(running && SAFE.get()) {
long time = System.nanoTime();
Stack<Frame> stack = THREAD_STACK.get();
Map<String, List<Long>> timingsMap = TIMINGS.get();
if(timingsMap.size() == 0) {
synchronized(accessibleThreadMaps) {
accessibleThreadMaps.add(timingsMap);
}
}
Frame top = stack.pop();
if((stack.size() != 0 && !top.getId().endsWith("." + frame)) || (stack.size() == 0 && !top.getId().equals(frame)))
throw new MalformedStackException("Expected " + frame + ", found " + top);
List<Long> timings = timingsMap.computeIfAbsent(top.getId(), id -> new ArrayList<>());
timings.add(time - top.getStart());
}
if(size.get() == 0) SAFE.set(true);
}
@Override
public void start() {
running = true;
}
@Override
public void stop() {
running = false;
}
@Override
public Map<String, Timings> getTimings() {
Map<String, Timings> map = new HashMap<>();
accessibleThreadMaps.forEach(smap -> smap.forEach((key, list) -> {
String[] keys = key.split("\\.");
Timings timings = map.computeIfAbsent(keys[0], id -> new Timings());
for(int i = 1; i < keys.length; i++) {
timings = timings.getSubItem(keys[i]);
}
list.forEach(timings::addTime);
}));
return map;
}
@Override
public void reset() {
accessibleThreadMaps.forEach(Map::clear);
}
}
@@ -1,73 +0,0 @@
package com.dfsek.terra.profiler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Timings {
private final Map<String, Timings> subItems = new HashMap<>();
private final List<Long> timings = new ArrayList<>();
public void addTime(long time) {
timings.add(time);
}
public List<Long> getTimings() {
return timings;
}
public double average() {
return (double) timings.stream().reduce(0L, Long::sum) / timings.size();
}
public long max() {
return timings.stream().mapToLong(Long::longValue).max().orElse(0L);
}
public long min() {
return timings.stream().mapToLong(Long::longValue).min().orElse(0L);
}
public double sum() {
return timings.stream().mapToDouble(Long::doubleValue).sum();
}
public Timings getSubItem(String id) {
return subItems.computeIfAbsent(id, s -> new Timings());
}
public String toString(int indent, Timings parent, Set<Integer> branches) {
StringBuilder builder = new StringBuilder();
builder.append((double) min() / 1000000).append("ms min / ").append(average() / 1000000).append("ms avg / ")
.append((double) max() / 1000000).append("ms max (").append(timings.size()).append(" samples, ")
.append((sum() / parent.sum()) * 100).append("% of parent)");
List<String> frames = new ArrayList<>();
Set<Integer> newBranches = new HashSet<>(branches);
newBranches.add(indent);
subItems.forEach((id, timings) -> frames.add(id + ": " + timings.toString(indent + 1, this, newBranches)));
for(int i = 0; i < frames.size(); i++) {
builder.append('\n');
for(int j = 0; j < indent; j++) {
if(branches.contains(j)) builder.append("");
else builder.append(" ");
}
if(i == frames.size() - 1 && !frames.get(i).contains("\n")) builder.append("└───");
else builder.append("├───");
builder.append(frames.get(i));
}
return builder.toString();
}
@Override
public String toString() {
return toString(1, this, Collections.emptySet());
}
}
@@ -0,0 +1,85 @@
package com.dfsek.terra.profiler;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.world.TerraWorld;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import net.jafama.FastMath;
import java.util.Map;
public class WorldProfiler {
private final BiMap<String, Measurement> measures = HashBiMap.create();
private final World world;
private boolean isProfiling;
public WorldProfiler(World w) {
if(!TerraWorld.isTerraWorld(w))
throw new IllegalArgumentException("Attempted to instantiate profiler on non-Terra managed world!");
this.addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "TotalChunkGenTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "FloraTime")
.addMeasurement(new Measurement(10000000, DataType.PERIOD_MILLISECONDS), "TreeTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "OreTime")
.addMeasurement(new Measurement(5000000, DataType.PERIOD_MILLISECONDS), "CaveTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "StructureTime");
isProfiling = false;
this.world = w;
}
public String getResultsFormatted() {
if(! isProfiling) return "Profiler is not currently running.";
StringBuilder result = new StringBuilder("Gaea World Profiler Results (Min / Avg / Max / Std Dev): \n");
for(Map.Entry<String, Measurement> e : measures.entrySet()) {
result
.append(e.getKey())
.append(": ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().getMin()))
.append(" / ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().average()))
.append(" / ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().getMax()))
.append(" / ")
.append((double) FastMath.round((e.getValue().getStdDev() / 1000000) * 100D) / 100D)
.append("ms")
.append(" (x").append(e.getValue().size()).append(")\n");
}
return result.toString();
}
public void reset() {
for(Map.Entry<String, Measurement> e : measures.entrySet()) {
e.getValue().reset();
}
}
public com.dfsek.terra.profiler.WorldProfiler addMeasurement(Measurement m, String name) {
measures.put(name, m);
return this;
}
public void setMeasurement(String id, long value) {
if(isProfiling) measures.get(id).record(value);
}
public ProfileFuture measure(String id) {
if(isProfiling) return measures.get(id).beginMeasurement();
else return null;
}
public String getID(Measurement m) {
return measures.inverse().get(m);
}
public boolean isProfiling() {
return isProfiling;
}
public void setProfiling(boolean enabled) {
this.isProfiling = enabled;
}
public World getWorld() {
return world;
}
}
@@ -1,17 +0,0 @@
package com.dfsek.terra.profiler.exception;
public class MalformedStackException extends ProfilerException {
private static final long serialVersionUID = -3009539681021691054L;
public MalformedStackException(String message) {
super(message);
}
public MalformedStackException(String message, Throwable cause) {
super(message, cause);
}
public MalformedStackException(Throwable cause) {
super(cause);
}
}
@@ -1,17 +0,0 @@
package com.dfsek.terra.profiler.exception;
public class ProfilerException extends RuntimeException {
private static final long serialVersionUID = 8206737998791649002L;
public ProfilerException(String message) {
super(message);
}
public ProfilerException(String message, Throwable cause) {
super(message, cause);
}
public ProfilerException(Throwable cause) {
super(cause);
}
}
@@ -65,9 +65,7 @@ public class OpenRegistry<T> implements Registry<T> {
@Override
public T get(String identifier) {
Entry<T> entry = objects.get(identifier);
if(entry == null) return null;
return entry.getValue();
return objects.get(identifier).getValue();
}
@Override
@@ -68,4 +68,10 @@ public class FloraRegistry extends OpenRegistry<Flora> {
private BlockData data(String s) {
return main.getWorldHandle().createBlockData(s);
}
@Override
public Flora get(String identifier) {
return super.get(identifier);
}
}
@@ -13,6 +13,7 @@ import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.profiler.WorldProfiler;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import net.jafama.FastMath;
@@ -20,25 +21,33 @@ public class TerraWorld {
private final BiomeProvider provider;
private final WorldConfig config;
private final boolean safe;
private final WorldProfiler profiler;
private final World world;
private final BlockData air;
public TerraWorld(World w, ConfigPack c, TerraPlugin main) {
if(!w.isTerraWorld()) throw new IllegalArgumentException("World " + w + " is not a Terra World!");
if(!isTerraWorld(w)) throw new IllegalArgumentException("World " + w + " is not a Terra World!");
this.world = w;
config = c.toWorldConfig(this);
this.provider = config.getProvider();
profiler = new WorldProfiler(w);
air = main.getWorldHandle().createBlockData("minecraft:air");
main.getEventManager().callEvent(new TerraWorldLoadEvent(this, c));
safe = true;
}
public static boolean isTerraWorld(World w) {
return w.getGenerator().getHandle() instanceof GeneratorWrapper;
}
public World getWorld() {
return world;
}
public TerraChunkGenerator getGenerator() {
return ((GeneratorWrapper) world.getGenerator().getHandle()).getHandle();
}
public BiomeProvider getBiomeProvider() {
return provider;
@@ -52,6 +61,9 @@ public class TerraWorld {
return safe;
}
public WorldProfiler getProfiler() {
return profiler;
}
/**
* Get a block at an ungenerated location
@@ -70,7 +82,7 @@ public class TerraWorld {
double noise = sampler.sample(fdX, y, fdZ);
if(noise > 0) {
int level = 0;
for(int yi = world.getMaxHeight()-1; yi > y; yi--) {
for(int yi = world.getMaxHeight(); yi > y; yi--) {
if(sampler.sample(fdX, yi, fdZ) > 0) level++;
else level = 0;
}
@@ -15,7 +15,7 @@ import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.world.Carver;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.carving.NoiseCarver;
@@ -94,7 +94,7 @@ public class DefaultChunkGenerator2D implements TerraChunkGenerator {
public ChunkData generateChunkData(@NotNull World world, Random random, int chunkX, int chunkZ, ChunkData chunk) {
TerraWorld tw = main.getWorld(world);
BiomeProvider grid = tw.getBiomeProvider();
try(ProfileFrame ignore = main.getProfiler().profile("chunk_base_2d")) {
try(ProfileFuture ignore = tw.getProfiler().measure("TotalChunkGenTime")) {
if(!tw.isSafe()) return chunk;
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);

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