mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-02-16 10:30:42 +00:00
Merge pull request #43 from PolyhedralDev/agnostic
Platform-agnostic engine & TerraScript structures
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -137,3 +137,9 @@ build
|
||||
|
||||
!lib/*.jar
|
||||
.idea/Terra.iml
|
||||
/run/
|
||||
.idea/**.iml
|
||||
/lang/
|
||||
/packs/
|
||||
/config.yml
|
||||
/region/
|
||||
|
||||
217
build.gradle.kts
217
build.gradle.kts
@@ -1,192 +1,11 @@
|
||||
//import java.util.zip.ZipFile
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.net.URL
|
||||
import java.nio.channels.Channels
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
import java.nio.file.StandardCopyOption
|
||||
import com.dfsek.terra.getGitHash
|
||||
|
||||
plugins {
|
||||
java
|
||||
maven
|
||||
id("com.github.johnrengelman.shadow").version("6.1.0")
|
||||
val versionObj = Version("3", "0", "0", true)
|
||||
|
||||
allprojects {
|
||||
version = versionObj
|
||||
group = "com.dfsek.terra"
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") }
|
||||
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/") }
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
val versionObj = Version("2", "1", "1", true)
|
||||
|
||||
version = versionObj
|
||||
|
||||
dependencies {
|
||||
val gaeaVersion = "1.15.0"
|
||||
compileOnly("org.polydev.gaea:Gaea:${gaeaVersion}")
|
||||
testImplementation("org.polydev.gaea:Gaea:${gaeaVersion}")
|
||||
|
||||
compileOnly("org.jetbrains:annotations:20.1.0")
|
||||
|
||||
implementation("commons-io:commons-io:2.4")
|
||||
implementation("org.apache.commons:commons-imaging:1.0-alpha2")
|
||||
|
||||
compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.2.0-SNAPSHOT")
|
||||
implementation("org.bstats:bstats-bukkit:1.7")
|
||||
|
||||
compileOnly("com.googlecode.json-simple:json-simple:1.1")
|
||||
|
||||
implementation("com.scireum:parsii:1.2.1")
|
||||
|
||||
compileOnly("org.spigotmc:spigot-api:1.16.2-R0.1-SNAPSHOT")
|
||||
implementation("io.papermc:paperlib:1.0.5")
|
||||
|
||||
implementation("net.jafama:jafama:2.3.2")
|
||||
|
||||
implementation("com.dfsek:Tectonic:1.0.3")
|
||||
|
||||
|
||||
// JUnit.
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0")
|
||||
}
|
||||
|
||||
val compileJava: JavaCompile by tasks
|
||||
val mainSourceSet: SourceSet = sourceSets["main"]
|
||||
|
||||
tasks.withType<ProcessResources> {
|
||||
include("**/*.yml")
|
||||
filter<org.apache.tools.ant.filters.ReplaceTokens>(
|
||||
"tokens" to mapOf(
|
||||
"VERSION" to project.version.toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
compileJava.apply {
|
||||
options.encoding = "UTF-8"
|
||||
doFirst {
|
||||
options.compilerArgs = mutableListOf("-Xlint:all")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
|
||||
maxHeapSize = "4G"
|
||||
ignoreFailures = false
|
||||
failFast = true
|
||||
maxParallelForks = 12
|
||||
}
|
||||
|
||||
tasks.named<ShadowJar>("shadowJar") {
|
||||
// Tell shadow to download the packs
|
||||
dependsOn(downloadDefaultPacks)
|
||||
|
||||
archiveClassifier.set("")
|
||||
archiveBaseName.set("Terra")
|
||||
setVersion(project.version)
|
||||
relocate("org.apache.commons", "com.dfsek.terra.lib.commons")
|
||||
relocate("org.bstats.bukkit", "com.dfsek.terra.lib.bstats")
|
||||
relocate("parsii", "com.dfsek.terra.lib.parsii")
|
||||
relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib")
|
||||
relocate("net.jafama", "com.dfsek.terra.lib.jafama")
|
||||
relocate("com.dfsek.tectonic", "com.dfsek.terra.lib.tectonic")
|
||||
minimize()
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
dependsOn(tasks.shadowJar)
|
||||
// dependsOn(testWithPaper)
|
||||
// testWithPaper.mustRunAfter(tasks.shadowJar)
|
||||
}
|
||||
|
||||
val testDir = "target/server/"
|
||||
|
||||
val setupServer = tasks.create("setupServer") {
|
||||
dependsOn(tasks.shadowJar)
|
||||
doFirst {
|
||||
// clean
|
||||
file("${testDir}/").deleteRecursively()
|
||||
file("${testDir}/plugins").mkdirs()
|
||||
|
||||
// Downloading latest paper jar.
|
||||
val paperUrl = URL("https://papermc.io/api/v1/paper/1.16.4/latest/download")
|
||||
val paperReadableByteChannel = Channels.newChannel(paperUrl.openStream())
|
||||
val paperFile = file("${testDir}/paper.jar")
|
||||
val paperFileOutputStream = paperFile.outputStream()
|
||||
val paperFileChannel = paperFileOutputStream.channel
|
||||
paperFileChannel.transferFrom(paperReadableByteChannel, 0, Long.MAX_VALUE)
|
||||
|
||||
// Cloning test setup.
|
||||
gitClone("https://github.com/PolyhedralDev/WorldGenTestServer")
|
||||
// Copying plugins
|
||||
Files.move(Paths.get("WorldGenTestServer/plugins"),
|
||||
Paths.get("$testDir/plugins"),
|
||||
StandardCopyOption.REPLACE_EXISTING)
|
||||
// Copying config
|
||||
val serverText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/server.properties").readText()
|
||||
file("${testDir}/server.properties").writeText(serverText)
|
||||
val bukkitText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/bukkit.yml").readText()
|
||||
file("${testDir}/bukkit.yml").writeText(bukkitText.replace("\${world}", "world").replace("\${gen}", "Terra:DEFAULT"))
|
||||
|
||||
File("${testDir}/eula.txt").writeText("eula=true")
|
||||
|
||||
// clean up
|
||||
file("WorldGenTestServer").deleteRecursively()
|
||||
}
|
||||
}
|
||||
|
||||
val downloadDefaultPacks = tasks.create("downloadDefaultPacks") {
|
||||
doFirst {
|
||||
// Downloading latest paper jar.
|
||||
// if (file("${buildDir}/resources/main/packs/default").exists() && file("${buildDir}/resources/main/packs/nether").exists())
|
||||
// return@doFirst
|
||||
// else
|
||||
file("${buildDir}/resources/main/packs/").deleteRecursively()
|
||||
|
||||
val defaultPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/default.zip")
|
||||
downloadPack(defaultPackUrl)
|
||||
val netherPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/nether.zip")
|
||||
downloadPack(netherPackUrl)
|
||||
}
|
||||
}
|
||||
|
||||
val testWithPaper = task<JavaExec>(name = "testWithPaper") {
|
||||
standardInput = System.`in`
|
||||
dependsOn(tasks.shadowJar)
|
||||
// Copy Terra into dir
|
||||
doFirst {
|
||||
copy {
|
||||
from("${buildDir}/libs/Terra-${versionObj}.jar")
|
||||
into("${testDir}/plugins/")
|
||||
}
|
||||
}
|
||||
|
||||
main = "io.papermc.paperclip.Paperclip"
|
||||
jvmArgs = listOf("-XX:+UseG1GC", "-XX:+ParallelRefProcEnabled", "-XX:MaxGCPauseMillis=200",
|
||||
"-XX:+UnlockExperimentalVMOptions", "-XX:+DisableExplicitGC", "-XX:+AlwaysPreTouch",
|
||||
"-XX:G1NewSizePercent=30", "-XX:G1MaxNewSizePercent=40", "-XX:G1HeapRegionSize=8M",
|
||||
"-XX:G1ReservePercent=20", "-XX:G1HeapWastePercent=5", "-XX:G1MixedGCCountTarget=4",
|
||||
"-XX:InitiatingHeapOccupancyPercent=15", "-XX:G1MixedGCLiveThresholdPercent=90",
|
||||
"-XX:G1RSetUpdatingPauseTimePercent=5", "-XX:SurvivorRatio=32", "-XX:+PerfDisableSharedMem",
|
||||
"-XX:MaxTenuringThreshold=1", "-Dusing.aikars.flags=https://mcflags.emc.gs",
|
||||
"-Daikars.new.flags=true", "-DIReallyKnowWhatIAmDoingISwear")
|
||||
maxHeapSize = "2G"
|
||||
args = listOf("nogui")
|
||||
workingDir = file("${testDir}/")
|
||||
classpath = files("${testDir}/paper.jar")
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Version class that does version stuff.
|
||||
*/
|
||||
@@ -199,28 +18,4 @@ class Version(val major: String, val minor: String, val revision: String, val pr
|
||||
else //Only use git hash if it's a prerelease.
|
||||
"$major.$minor.$revision-BETA+${getGitHash()}"
|
||||
}
|
||||
}
|
||||
|
||||
fun getGitHash(): String {
|
||||
val stdout = ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine = mutableListOf("git", "rev-parse", "--short", "HEAD")
|
||||
standardOutput = stdout
|
||||
}
|
||||
return stdout.toString().trim()
|
||||
}
|
||||
|
||||
fun gitClone(name: String) {
|
||||
val stdout = ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine = mutableListOf("git", "clone", name)
|
||||
standardOutput = stdout
|
||||
}
|
||||
}
|
||||
|
||||
fun downloadPack(packUrl: URL) {
|
||||
val fileName = packUrl.file.substring(packUrl.file.lastIndexOf("/"))
|
||||
val file = file("${buildDir}/resources/main/packs/${fileName}")
|
||||
file.parentFile.mkdirs()
|
||||
file.outputStream().write(packUrl.readBytes())
|
||||
}
|
||||
13
buildSrc/build.gradle.kts
Normal file
13
buildSrc/build.gradle.kts
Normal file
@@ -0,0 +1,13 @@
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
kotlin("jvm") version embeddedKotlinVersion
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
"implementation"("com.github.jengelman.gradle.plugins:shadow:+")
|
||||
}
|
||||
47
buildSrc/src/main/kotlin/com/dfsek/terra/CommonConfig.kt
Normal file
47
buildSrc/src/main/kotlin/com/dfsek/terra/CommonConfig.kt
Normal file
@@ -0,0 +1,47 @@
|
||||
package com.dfsek.terra
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.testing.Test
|
||||
import org.gradle.kotlin.dsl.apply
|
||||
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 {
|
||||
val stdout = java.io.ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine = mutableListOf("git", "rev-parse", "--short", "HEAD")
|
||||
standardOutput = stdout
|
||||
}
|
||||
return stdout.toString().trim()
|
||||
}
|
||||
|
||||
fun Project.gitClone(name: String) {
|
||||
val stdout = ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine = mutableListOf("git", "clone", name)
|
||||
standardOutput = stdout
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
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.compile.JavaCompile
|
||||
import org.gradle.api.tasks.javadoc.Javadoc
|
||||
import org.gradle.kotlin.dsl.configure
|
||||
import org.gradle.kotlin.dsl.withType
|
||||
|
||||
fun Project.configureCompilation() {
|
||||
configure<JavaPluginConvention> {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
options.encoding = "UTF-8"
|
||||
doFirst {
|
||||
options.compilerArgs = mutableListOf("-Xlint:all")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Javadoc> {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
}
|
||||
25
buildSrc/src/main/kotlin/com/dfsek/terra/DependencyConfig.kt
Normal file
25
buildSrc/src/main/kotlin/com/dfsek/terra/DependencyConfig.kt
Normal file
@@ -0,0 +1,25 @@
|
||||
package com.dfsek.terra
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.dependencies
|
||||
import org.gradle.kotlin.dsl.repositories
|
||||
|
||||
fun Project.configureDependencies() {
|
||||
|
||||
repositories {
|
||||
maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") }
|
||||
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/") }
|
||||
gradlePluginPortal()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.7.0")
|
||||
"testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.7.0")
|
||||
"compileOnly"("org.jetbrains:annotations:20.1.0")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.dfsek.terra
|
||||
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.BasePluginConvention
|
||||
import org.gradle.api.tasks.bundling.Jar
|
||||
import org.gradle.api.tasks.javadoc.Javadoc
|
||||
import org.gradle.kotlin.dsl.*
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
|
||||
fun Project.configureDistribution() {
|
||||
apply(plugin = "java-library")
|
||||
apply(plugin = "com.github.johnrengelman.shadow")
|
||||
|
||||
|
||||
// configurations.create("shaded")
|
||||
|
||||
configurations {
|
||||
val shaded = create("shaded")
|
||||
getByName("compile").extendsFrom(shaded)
|
||||
// shaded.extendsFrom(getByName("compile"))
|
||||
val shadedApi = create("shadedApi")
|
||||
shaded.extendsFrom(shadedApi)
|
||||
getByName("api").extendsFrom(shadedApi)
|
||||
val shadedImplementation = create("shadedImplementation")
|
||||
shaded.extendsFrom(shadedImplementation)
|
||||
getByName("implementation").extendsFrom(shadedImplementation)
|
||||
}
|
||||
|
||||
// tasks.withType<JavaCompile> {
|
||||
// classpath +=
|
||||
// }
|
||||
|
||||
val downloadDefaultPacks = tasks.create("downloadDefaultPacks") {
|
||||
doFirst {
|
||||
file("${buildDir}/resources/main/packs/").deleteRecursively()
|
||||
|
||||
val defaultPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/default.zip")
|
||||
downloadPack(defaultPackUrl, project)
|
||||
val netherPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/nether.zip")
|
||||
downloadPack(netherPackUrl, project)
|
||||
}
|
||||
}
|
||||
tasks["processResources"].dependsOn(downloadDefaultPacks)
|
||||
|
||||
tasks.register<Jar>("sourcesJar") {
|
||||
archiveClassifier.set("sources")
|
||||
}
|
||||
|
||||
tasks.withType<Jar> {
|
||||
from("../LICENSE", "../../LICENSE")
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
configurations = listOf(project.configurations["shaded"])
|
||||
|
||||
archiveClassifier.set("shaded")
|
||||
setVersion(project.version)
|
||||
relocate("org.apache.commons", "com.dfsek.terra.lib.commons")
|
||||
relocate("parsii", "com.dfsek.terra.lib.parsii")
|
||||
relocate("net.jafama", "com.dfsek.terra.lib.jafama")
|
||||
minimize()
|
||||
}
|
||||
convention.getPlugin<BasePluginConvention>().archivesBaseName = project.name
|
||||
|
||||
tasks.named<DefaultTask>("build") {
|
||||
dependsOn(tasks["shadowJar"])
|
||||
}
|
||||
}
|
||||
|
||||
fun downloadPack(packUrl: URL, project: Project) {
|
||||
val fileName = packUrl.file.substring(packUrl.file.lastIndexOf("/"))
|
||||
val file = File("${project.buildDir}/resources/main/packs/${fileName}")
|
||||
file.parentFile.mkdirs()
|
||||
file.outputStream().write(packUrl.readBytes())
|
||||
}
|
||||
23
common/build.gradle.kts
Normal file
23
common/build.gradle.kts
Normal file
@@ -0,0 +1,23 @@
|
||||
import com.dfsek.terra.configureCommon
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
}
|
||||
|
||||
configureCommon()
|
||||
|
||||
group = "com.dfsek.terra.common"
|
||||
|
||||
dependencies {
|
||||
"shadedApi"("org.apache.commons:commons-rng-core:1.3")
|
||||
"shadedApi"("commons-io:commons-io:2.4")
|
||||
|
||||
"shadedApi"("com.scireum:parsii:1.2.1")
|
||||
"shadedApi"("com.dfsek:Tectonic:1.1.0")
|
||||
"shadedApi"("net.jafama:jafama:2.3.2")
|
||||
"shadedApi"("org.yaml:snakeyaml:1.27")
|
||||
|
||||
"compileOnly"("com.googlecode.json-simple:json-simple:1.1")
|
||||
|
||||
"shadedApi"("com.google.guava:guava:30.0-jre")
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.dfsek.terra;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.polydev.gaea.profiler.DataType;
|
||||
import org.polydev.gaea.profiler.Measurement;
|
||||
import org.polydev.gaea.profiler.WorldProfiler;
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
import com.dfsek.terra.api.profiler.DataType;
|
||||
import com.dfsek.terra.api.profiler.Measurement;
|
||||
import com.dfsek.terra.api.profiler.WorldProfiler;
|
||||
|
||||
public class TerraProfiler extends WorldProfiler {
|
||||
public TerraProfiler(World w) {
|
||||
@@ -13,7 +13,6 @@ public class TerraProfiler extends WorldProfiler {
|
||||
.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")
|
||||
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "ElevationTime");
|
||||
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "StructureTime");
|
||||
}
|
||||
}
|
||||
55
common/src/main/java/com/dfsek/terra/TerraWorld.java
Normal file
55
common/src/main/java/com/dfsek/terra/TerraWorld.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package com.dfsek.terra;
|
||||
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.api.platform.generator.GeneratorWrapper;
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
import com.dfsek.terra.biome.BiomeZone;
|
||||
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
|
||||
import com.dfsek.terra.config.base.ConfigPack;
|
||||
|
||||
public class TerraWorld {
|
||||
private final TerraBiomeGrid grid;
|
||||
private final BiomeZone zone;
|
||||
private final ConfigPack config;
|
||||
private final boolean safe;
|
||||
private final TerraProfiler profiler;
|
||||
private final World world;
|
||||
|
||||
|
||||
public TerraWorld(World w, ConfigPack c, TerraPlugin main) {
|
||||
config = c;
|
||||
profiler = new TerraProfiler(w);
|
||||
this.grid = new TerraBiomeGrid.TerraBiomeGridBuilder(w.getSeed(), c, main).build();
|
||||
this.zone = grid.getZone();
|
||||
this.world = w;
|
||||
safe = true;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public static boolean isTerraWorld(World w) {
|
||||
return w.getGenerator().getHandle() instanceof GeneratorWrapper;
|
||||
}
|
||||
|
||||
public TerraBiomeGrid getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
public ConfigPack getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public BiomeZone getZone() {
|
||||
return zone;
|
||||
}
|
||||
|
||||
public boolean isSafe() {
|
||||
return safe;
|
||||
}
|
||||
|
||||
public TerraProfiler getProfiler() {
|
||||
return profiler;
|
||||
}
|
||||
}
|
||||
8
common/src/main/java/com/dfsek/terra/api/Entity.java
Normal file
8
common/src/main/java/com/dfsek/terra/api/Entity.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package com.dfsek.terra.api;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface Entity extends Handle {
|
||||
Location getLocation();
|
||||
}
|
||||
20
common/src/main/java/com/dfsek/terra/api/Gaea.java
Normal file
20
common/src/main/java/com/dfsek/terra/api/Gaea.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package com.dfsek.terra.api;
|
||||
|
||||
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class Gaea {
|
||||
private static boolean debug;
|
||||
|
||||
public static File getGaeaFolder(World w) {
|
||||
File f = new File(w.getWorldFolder(), "gaea");
|
||||
f.mkdirs();
|
||||
return f;
|
||||
}
|
||||
|
||||
public static boolean isDebug() {
|
||||
return debug;
|
||||
}
|
||||
}
|
||||
63
common/src/main/java/com/dfsek/terra/api/GenericLoaders.java
Normal file
63
common/src/main/java/com/dfsek/terra/api/GenericLoaders.java
Normal file
@@ -0,0 +1,63 @@
|
||||
package com.dfsek.terra.api;
|
||||
|
||||
import com.dfsek.tectonic.loading.TypeRegistry;
|
||||
import com.dfsek.terra.api.math.GridSpawn;
|
||||
import com.dfsek.terra.api.math.ProbabilityCollection;
|
||||
import com.dfsek.terra.api.math.Range;
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
|
||||
import com.dfsek.terra.biome.palette.PaletteHolder;
|
||||
import com.dfsek.terra.biome.palette.PaletteLayer;
|
||||
import com.dfsek.terra.carving.CarverPalette;
|
||||
import com.dfsek.terra.config.loaders.ImageLoaderLoader;
|
||||
import com.dfsek.terra.config.loaders.MaterialSetLoader;
|
||||
import com.dfsek.terra.config.loaders.ProbabilityCollectionLoader;
|
||||
import com.dfsek.terra.config.loaders.RangeLoader;
|
||||
import com.dfsek.terra.config.loaders.config.FloraLayerLoader;
|
||||
import com.dfsek.terra.config.loaders.config.GridSpawnLoader;
|
||||
import com.dfsek.terra.config.loaders.config.NoiseBuilderLoader;
|
||||
import com.dfsek.terra.config.loaders.config.OreConfigLoader;
|
||||
import com.dfsek.terra.config.loaders.config.OreHolderLoader;
|
||||
import com.dfsek.terra.config.loaders.config.TreeLayerLoader;
|
||||
import com.dfsek.terra.config.loaders.palette.CarverPaletteLoader;
|
||||
import com.dfsek.terra.config.loaders.palette.PaletteHolderLoader;
|
||||
import com.dfsek.terra.config.loaders.palette.PaletteLayerLoader;
|
||||
import com.dfsek.terra.generation.config.NoiseBuilder;
|
||||
import com.dfsek.terra.image.ImageLoader;
|
||||
import com.dfsek.terra.population.items.flora.FloraLayer;
|
||||
import com.dfsek.terra.population.items.flora.TerraFlora;
|
||||
import com.dfsek.terra.population.items.ores.Ore;
|
||||
import com.dfsek.terra.population.items.ores.OreConfig;
|
||||
import com.dfsek.terra.population.items.ores.OreHolder;
|
||||
import com.dfsek.terra.population.items.tree.TreeLayer;
|
||||
import com.dfsek.terra.util.MaterialSet;
|
||||
|
||||
public class GenericLoaders implements LoaderRegistrar {
|
||||
private final TerraPlugin main;
|
||||
|
||||
public GenericLoaders(TerraPlugin main) {
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(TypeRegistry registry) {
|
||||
registry.registerLoader(ProbabilityCollection.class, new ProbabilityCollectionLoader())
|
||||
.registerLoader(Range.class, new RangeLoader())
|
||||
.registerLoader(CarverPalette.class, new CarverPaletteLoader())
|
||||
.registerLoader(GridSpawn.class, new GridSpawnLoader())
|
||||
.registerLoader(PaletteHolder.class, new PaletteHolderLoader())
|
||||
.registerLoader(PaletteLayer.class, new PaletteLayerLoader())
|
||||
.registerLoader(FloraLayer.class, new FloraLayerLoader())
|
||||
.registerLoader(Ore.Type.class, (t, o, l) -> Ore.Type.valueOf((String) o))
|
||||
.registerLoader(OreConfig.class, new OreConfigLoader())
|
||||
.registerLoader(NoiseBuilder.class, new NoiseBuilderLoader())
|
||||
.registerLoader(TreeLayer.class, new TreeLayerLoader())
|
||||
.registerLoader(MaterialSet.class, new MaterialSetLoader())
|
||||
.registerLoader(OreHolder.class, new OreHolderLoader())
|
||||
.registerLoader(ImageLoader.class, new ImageLoaderLoader())
|
||||
.registerLoader(TerraBiomeGrid.Type.class, (t, o, l) -> TerraBiomeGrid.Type.valueOf((String) o))
|
||||
.registerLoader(ImageLoader.Channel.class, (t, o, l) -> ImageLoader.Channel.valueOf((String) o))
|
||||
.registerLoader(ImageLoader.Align.class, (t, o, l) -> ImageLoader.Align.valueOf((String) o))
|
||||
.registerLoader(TerraFlora.Search.class, (t, o, l) -> TerraFlora.Search.valueOf((String) o));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.dfsek.terra.api;
|
||||
|
||||
import com.dfsek.tectonic.loading.TypeRegistry;
|
||||
|
||||
public interface LoaderRegistrar {
|
||||
void register(TypeRegistry registry);
|
||||
}
|
||||
4
common/src/main/java/com/dfsek/terra/api/Player.java
Normal file
4
common/src/main/java/com/dfsek/terra/api/Player.java
Normal file
@@ -0,0 +1,4 @@
|
||||
package com.dfsek.terra.api;
|
||||
|
||||
public interface Player extends Entity {
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.dfsek.terra.api.language;
|
||||
|
||||
|
||||
import com.dfsek.tectonic.config.Configuration;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class Language {
|
||||
private final Configuration configuration;
|
||||
public Language(File file) throws IOException {
|
||||
configuration = new Configuration(new FileInputStream(file));
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
public Message getMessage(String id) {
|
||||
Message temp = null;
|
||||
if(configuration.contains(id)) {
|
||||
Object m = configuration.get(id);
|
||||
|
||||
if(m instanceof List) {
|
||||
temp = new MultiLineMessage((List<String>) m);
|
||||
} else if(m instanceof String) {
|
||||
temp = new SingleLineMessage((String) m);
|
||||
} else return new SingleLineMessage("message:" + id + ":translation_undefined");
|
||||
}
|
||||
if(temp == null || temp.isEmpty()) return new SingleLineMessage("message:" + id + ":translation_undefined");
|
||||
return temp;
|
||||
}
|
||||
public void log(String messageID, Level level, Logger logger, String... args) {
|
||||
getMessage(messageID).log(logger, level, args);
|
||||
}
|
||||
public void send(String messageID, CommandSender sender, String... args) {
|
||||
getMessage(messageID).send(sender, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.dfsek.terra.api.language;
|
||||
|
||||
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public interface Message {
|
||||
void log(Logger logger, Level level, String... args);
|
||||
void send(CommandSender sender, String... args);
|
||||
boolean isEmpty();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.dfsek.terra.api.language;
|
||||
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class MultiLineMessage implements Message {
|
||||
private final List<String> message;
|
||||
public MultiLineMessage(List<String> message) {
|
||||
this.message = message;
|
||||
}
|
||||
@Override
|
||||
public void log(Logger logger, Level level, String... args) {
|
||||
for(String line: message) {
|
||||
logger.log(level, String.format(line, Arrays.asList(args).toArray()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(CommandSender sender, String... args) {
|
||||
for(String line: message) {
|
||||
sender.sendMessage(String.format(line, Arrays.asList(args).toArray()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return message == null || message.isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.dfsek.terra.api.language;
|
||||
|
||||
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class SingleLineMessage implements Message {
|
||||
private final String message;
|
||||
public SingleLineMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
@Override
|
||||
public void log(Logger logger, Level level, String... args) {
|
||||
logger.log(level, String.format(message, Arrays.asList(args).toArray()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(CommandSender sender, String... args) {
|
||||
sender.sendMessage(String.format(message, Arrays.asList(args).toArray()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return message == null || message.equals("");
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
package com.dfsek.terra.procgen;
|
||||
package com.dfsek.terra.api.math;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
import org.polydev.gaea.math.MathUtil;
|
||||
import org.polydev.gaea.util.FastRandom;
|
||||
import org.polydev.gaea.util.GlueList;
|
||||
import com.dfsek.terra.api.math.vector.Vector3;
|
||||
import com.dfsek.terra.api.util.FastRandom;
|
||||
import com.dfsek.terra.api.util.GlueList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
@@ -14,12 +13,12 @@ import java.util.Random;
|
||||
public class GridSpawn {
|
||||
private final int separation;
|
||||
private final int width;
|
||||
private final int seedOffset;
|
||||
private final int salt;
|
||||
|
||||
public GridSpawn(int width, int separation, int seedOffset) {
|
||||
public GridSpawn(int width, int separation, int salt) {
|
||||
this.separation = separation;
|
||||
this.width = width;
|
||||
this.seedOffset = seedOffset;
|
||||
this.salt = salt;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,18 +29,18 @@ public class GridSpawn {
|
||||
* @param seed Seed for RNG
|
||||
* @return Vector representing nearest spawnpoint
|
||||
*/
|
||||
public Vector getNearestSpawn(int x, int z, long seed) {
|
||||
public Vector3 getNearestSpawn(int x, int z, long seed) {
|
||||
int structureChunkX = x / (width + 2 * separation);
|
||||
int structureChunkZ = z / (width + 2 * separation);
|
||||
List<Vector> zones = new GlueList<>();
|
||||
List<Vector3> zones = new GlueList<>();
|
||||
for(int xi = structureChunkX - 1; xi <= structureChunkX + 1; xi++) {
|
||||
for(int zi = structureChunkZ - 1; zi <= structureChunkZ + 1; zi++) {
|
||||
zones.add(getChunkSpawn(xi, zi, seed + seedOffset));
|
||||
zones.add(getChunkSpawn(xi, zi, seed));
|
||||
}
|
||||
}
|
||||
Vector shortest = zones.get(0);
|
||||
Vector compare = new Vector(x, 0, z);
|
||||
for(Vector v : zones) {
|
||||
Vector3 shortest = zones.get(0);
|
||||
Vector3 compare = new Vector3(x, 0, z);
|
||||
for(Vector3 v : zones) {
|
||||
if(compare.distanceSquared(shortest) > compare.distanceSquared(v)) shortest = v.clone();
|
||||
}
|
||||
return shortest;
|
||||
@@ -55,13 +54,13 @@ public class GridSpawn {
|
||||
* @param seed Seed for RNG
|
||||
* @return Vector representing spawnpoint
|
||||
*/
|
||||
public Vector getChunkSpawn(int structureChunkX, int structureChunkZ, long seed) {
|
||||
Random r = new FastRandom(MathUtil.getCarverChunkSeed(structureChunkX, structureChunkZ, seed + seedOffset));
|
||||
public Vector3 getChunkSpawn(int structureChunkX, int structureChunkZ, long seed) {
|
||||
Random r = new FastRandom(MathUtil.getCarverChunkSeed(structureChunkX, structureChunkZ, seed + salt));
|
||||
int offsetX = r.nextInt(width);
|
||||
int offsetZ = r.nextInt(width);
|
||||
int sx = structureChunkX * (width + 2 * separation) + offsetX;
|
||||
int sz = structureChunkZ * (width + 2 * separation) + offsetZ;
|
||||
return new Vector(sx, 0, sz);
|
||||
return new Vector3(sx, 0, sz);
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
97
common/src/main/java/com/dfsek/terra/api/math/MathUtil.java
Normal file
97
common/src/main/java/com/dfsek/terra/api/math/MathUtil.java
Normal file
@@ -0,0 +1,97 @@
|
||||
package com.dfsek.terra.api.math;
|
||||
|
||||
import com.dfsek.terra.api.util.FastRandom;
|
||||
import com.dfsek.terra.generation.math.Sampler;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Utility class for mathematical functions.
|
||||
*/
|
||||
public final class MathUtil {
|
||||
/**
|
||||
* Epsilon for fuzzy floating point comparisons.
|
||||
*/
|
||||
public static final double EPSILON = 1.0E-5;
|
||||
/**
|
||||
* Derivative constant.
|
||||
*/
|
||||
private static final double DERIVATIVE_DIST = 0.55;
|
||||
|
||||
/**
|
||||
* Gets the standard deviation of an array of doubles.
|
||||
*
|
||||
* @param numArray The array of numbers to calculate the standard deviation of.
|
||||
* @return double - The standard deviation.
|
||||
*/
|
||||
public static double standardDeviation(List<Number> numArray) {
|
||||
double sum = 0.0, standardDeviation = 0.0;
|
||||
int length = numArray.size();
|
||||
|
||||
for(Number num : numArray) {
|
||||
sum += num.doubleValue();
|
||||
}
|
||||
|
||||
double mean = sum / length;
|
||||
|
||||
for(Number num : numArray) {
|
||||
standardDeviation += FastMath.pow2(num.doubleValue() - mean);
|
||||
}
|
||||
|
||||
return FastMath.sqrt(standardDeviation / length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the carver seed for a chunk.
|
||||
*
|
||||
* @param chunkX Chunk's X coordinate
|
||||
* @param chunkZ Chunk's Z coordinate
|
||||
* @param seed World seed
|
||||
* @return long - The carver seed.
|
||||
*/
|
||||
public static long getCarverChunkSeed(int chunkX, int chunkZ, long seed) {
|
||||
Random r = new FastRandom(seed);
|
||||
return chunkX * r.nextLong() ^ chunkZ * r.nextLong() ^ seed;
|
||||
}
|
||||
|
||||
public static long hashToLong(String s) {
|
||||
if(s == null) {
|
||||
return 0;
|
||||
}
|
||||
long hash = 0;
|
||||
for(char c : s.toCharArray()) {
|
||||
hash = 31L * hash + c;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare 2 floating-point values with epsilon to account for rounding errors
|
||||
*
|
||||
* @param a Value 1
|
||||
* @param b Value 2
|
||||
* @return Whether these values are equal
|
||||
*/
|
||||
public static boolean equals(double a, double b) {
|
||||
return a == b || FastMath.abs(a - b) < EPSILON;
|
||||
}
|
||||
|
||||
public static double derivative(Sampler sampler, double x, double y, double z) {
|
||||
double baseSample = sampler.sample(x, y, z);
|
||||
|
||||
double xVal1 = (sampler.sample(x + DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST;
|
||||
double xVal2 = (sampler.sample(x - DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST;
|
||||
double zVal1 = (sampler.sample(x, y, z + DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST;
|
||||
double zVal2 = (sampler.sample(x, y, z - DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST;
|
||||
double yVal1 = (sampler.sample(x, y + DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST;
|
||||
double yVal2 = (sampler.sample(x, y - DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST;
|
||||
|
||||
return Math.sqrt(((xVal2 - xVal1) * (xVal2 - xVal1)) + ((zVal2 - zVal1) * (zVal2 - zVal1)) + ((yVal2 - yVal1) * (yVal2 - yVal1)));
|
||||
}
|
||||
|
||||
public static long squash(int first, int last) {
|
||||
return (((long) first) << 32) | (last & 0xffffffffL);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.dfsek.terra.api.math;
|
||||
|
||||
import com.dfsek.terra.api.math.noise.samplers.NoiseSampler;
|
||||
import com.dfsek.terra.api.world.biome.NormalizationUtil;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class ProbabilityCollection<E> {
|
||||
private final Set<Object> cont = new HashSet<>();
|
||||
private Object[] array = new Object[0];
|
||||
private int size;
|
||||
|
||||
public com.dfsek.terra.api.math.ProbabilityCollection<E> add(E item, int probability) {
|
||||
if(!cont.contains(item)) size++;
|
||||
cont.add(item);
|
||||
int oldLength = array.length;
|
||||
Object[] newArray = new Object[array.length + probability];
|
||||
System.arraycopy(array, 0, newArray, 0, array.length); // Expand array.
|
||||
array = newArray;
|
||||
for(int i = oldLength; i < array.length; i++) array[i] = item;
|
||||
return this;
|
||||
}
|
||||
|
||||
public E get() {
|
||||
if(array.length == 0) return null;
|
||||
return (E) array[ThreadLocalRandom.current().nextInt(array.length)];
|
||||
}
|
||||
|
||||
public E get(Random r) {
|
||||
if(array.length == 0) return null;
|
||||
return (E) array[r.nextInt(array.length)];
|
||||
}
|
||||
|
||||
public E get(NoiseSampler n, double x, double z) {
|
||||
if(array.length == 0) return null;
|
||||
return (E) array[NormalizationUtil.normalize(n.getNoise(x, z), array.length, 1)];
|
||||
}
|
||||
|
||||
public int getTotalProbability() {
|
||||
return array.length;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
123
common/src/main/java/com/dfsek/terra/api/math/Range.java
Normal file
123
common/src/main/java/com/dfsek/terra/api/math/Range.java
Normal file
@@ -0,0 +1,123 @@
|
||||
package com.dfsek.terra.api.math;
|
||||
|
||||
import net.jafama.FastMath;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Random;
|
||||
|
||||
public class Range implements Iterable<Integer> {
|
||||
private int min;
|
||||
private int max;
|
||||
|
||||
public Range(int min, int max) {
|
||||
if(min > max) throw new IllegalArgumentException("Minimum must not be grater than maximum!");
|
||||
this.max = max;
|
||||
this.min = min;
|
||||
}
|
||||
|
||||
public boolean isInRange(int test) {
|
||||
return test >= min && test < max;
|
||||
}
|
||||
|
||||
public int getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.math.Range setMax(int max) {
|
||||
this.max = max;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.math.Range setMin(int min) {
|
||||
this.min = min;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getRange() {
|
||||
return max - min;
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.math.Range multiply(int mult) {
|
||||
min *= mult;
|
||||
max *= mult;
|
||||
return this;
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.math.Range reflect(int pt) {
|
||||
return new com.dfsek.terra.api.math.Range(2 * pt - this.getMax(), 2 * pt - this.getMin());
|
||||
}
|
||||
|
||||
public int get(Random r) {
|
||||
return r.nextInt((max - min) + 1) + min;
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.math.Range intersects(com.dfsek.terra.api.math.Range other) {
|
||||
try {
|
||||
return new com.dfsek.terra.api.math.Range(FastMath.max(this.getMin(), other.getMin()), FastMath.min(this.getMax(), other.getMax()));
|
||||
} catch(IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.math.Range add(int add) {
|
||||
this.min += add;
|
||||
this.max += add;
|
||||
return this;
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.math.Range sub(int sub) {
|
||||
this.min -= sub;
|
||||
this.max -= sub;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Min: " + getMin() + ", Max:" + getMax();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return min * 31 + max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(!(obj instanceof com.dfsek.terra.api.math.Range)) return false;
|
||||
com.dfsek.terra.api.math.Range other = (com.dfsek.terra.api.math.Range) obj;
|
||||
return other.getMin() == this.getMin() && other.getMax() == this.getMax();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<Integer> iterator() {
|
||||
return new RangeIterator(this);
|
||||
}
|
||||
|
||||
private static class RangeIterator implements Iterator<Integer> {
|
||||
private final com.dfsek.terra.api.math.Range m;
|
||||
private Integer current;
|
||||
|
||||
public RangeIterator(com.dfsek.terra.api.math.Range m) {
|
||||
this.m = m;
|
||||
current = m.getMin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return current < m.getMax();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer next() {
|
||||
current++;
|
||||
return current - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.math;
|
||||
package com.dfsek.terra.api.math.noise;
|
||||
|
||||
import parsii.eval.Function;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package com.dfsek.terra.math;
|
||||
package com.dfsek.terra.api.math.noise;
|
||||
|
||||
import com.dfsek.terra.api.math.noise.samplers.NoiseSampler;
|
||||
import com.dfsek.terra.generation.config.NoiseBuilder;
|
||||
import com.dfsek.terra.util.hash.HashMapDoubleDouble;
|
||||
import org.polydev.gaea.math.FastNoiseLite;
|
||||
import parsii.eval.Expression;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class NoiseFunction2 implements NoiseFunction {
|
||||
private final FastNoiseLite gen;
|
||||
private final NoiseSampler gen;
|
||||
private final Cache cache = new Cache();
|
||||
|
||||
public NoiseFunction2(long seed, NoiseBuilder builder) {
|
||||
@@ -44,7 +44,7 @@ public class NoiseFunction2 implements NoiseFunction {
|
||||
private static final long serialVersionUID = 8915092734723467010L;
|
||||
private static final int cacheSize = 384;
|
||||
|
||||
public double get(FastNoiseLite noise, double x, double z) {
|
||||
public double get(NoiseSampler noise, double x, double z) {
|
||||
double xx = x >= 0 ? x * 2 : x * -2 - 1;
|
||||
double zz = z >= 0 ? z * 2 : z * -2 - 1;
|
||||
double key = (xx >= zz) ? (xx * xx + xx + zz) : (zz * zz + xx);
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.dfsek.terra.math;
|
||||
package com.dfsek.terra.api.math.noise;
|
||||
|
||||
import com.dfsek.terra.api.math.noise.samplers.NoiseSampler;
|
||||
import com.dfsek.terra.generation.config.NoiseBuilder;
|
||||
import org.polydev.gaea.math.FastNoiseLite;
|
||||
import parsii.eval.Expression;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class NoiseFunction3 implements NoiseFunction {
|
||||
private final FastNoiseLite gen;
|
||||
private final NoiseSampler gen;
|
||||
|
||||
public NoiseFunction3(long seed, NoiseBuilder builder) {
|
||||
this.gen = builder.build((int) seed);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
||||
package com.dfsek.terra.api.math.noise.samplers;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Vector2;
|
||||
import com.dfsek.terra.api.math.vector.Vector3;
|
||||
|
||||
public interface NoiseSampler {
|
||||
/**
|
||||
* 2D noise at given position using current settings
|
||||
* <p>
|
||||
* Noise output bounded between -1...1
|
||||
*/
|
||||
double getNoise(/*FNLdouble*/ double x, /*FNLdouble*/ double y);
|
||||
|
||||
/**
|
||||
* 3D noise at given position using current settings
|
||||
* <p>
|
||||
* Noise output bounded between -1...1
|
||||
*/
|
||||
double getNoise(/*FNLdouble*/ double x, /*FNLdouble*/ double y, /*FNLdouble*/ double z);
|
||||
|
||||
default double getNoise(Vector3 vector3) {
|
||||
return getNoise(vector3.getX(), vector3.getY(), vector3.getZ());
|
||||
}
|
||||
|
||||
default double getNoise(Vector2 vector2) {
|
||||
return getNoise(vector2.getX(), vector2.getZ());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.dfsek.terra.api.math.noise.samplers;
|
||||
|
||||
public abstract class Normalizer implements NoiseSampler {
|
||||
private final NoiseSampler sampler;
|
||||
|
||||
protected Normalizer(NoiseSampler sampler) {
|
||||
this.sampler = sampler;
|
||||
}
|
||||
|
||||
public abstract double normalize(double in);
|
||||
|
||||
@Override
|
||||
public double getNoise(double x, double y) {
|
||||
return normalize(sampler.getNoise(x, y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getNoise(double x, double y, double z) {
|
||||
return normalize(sampler.getNoise(x, y, z));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.math;
|
||||
package com.dfsek.terra.api.math.parsii;
|
||||
|
||||
import parsii.eval.Expression;
|
||||
import parsii.eval.Function;
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.dfsek.terra.math;
|
||||
package com.dfsek.terra.api.math.parsii;
|
||||
|
||||
import org.polydev.gaea.util.FastRandom;
|
||||
import com.dfsek.terra.api.util.FastRandom;
|
||||
import parsii.eval.Expression;
|
||||
import parsii.eval.Function;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides access to a PRNG ({@link org.polydev.gaea.util.FastRandom})
|
||||
* Provides access to a PRNG ({@link com.dfsek.terra.api.util.FastRandom})
|
||||
* <p>
|
||||
* Takes 1 argument, which sets the seed
|
||||
*/
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.procgen.pixel;
|
||||
package com.dfsek.terra.api.math.pixel;
|
||||
|
||||
public class Distribution {
|
||||
public Distribution(Rectangle bound, int numPoints, double minRad) {
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.dfsek.terra.procgen.pixel;
|
||||
package com.dfsek.terra.api.math.pixel;
|
||||
|
||||
import com.dfsek.terra.procgen.math.Vector2;
|
||||
import com.dfsek.terra.api.math.vector.Vector2;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.dfsek.terra.procgen.pixel;
|
||||
package com.dfsek.terra.api.math.pixel;
|
||||
|
||||
import com.dfsek.terra.procgen.math.Vector2;
|
||||
import com.dfsek.terra.api.math.vector.Vector2;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import java.util.HashSet;
|
||||
@@ -0,0 +1,173 @@
|
||||
package com.dfsek.terra.api.math.vector;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.Block;
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Location implements Cloneable {
|
||||
private World world;
|
||||
private Vector3 vector;
|
||||
private double pitch;
|
||||
private double yaw;
|
||||
|
||||
public Location(World w, double x, double y, double z) {
|
||||
this.world = w;
|
||||
this.vector = new Vector3(x, y, z);
|
||||
}
|
||||
|
||||
public Location(World w, Vector3 vector) {
|
||||
this.world = w;
|
||||
this.vector = vector;
|
||||
}
|
||||
|
||||
public void setWorld(World world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public Vector3 getVector() {
|
||||
return vector;
|
||||
}
|
||||
|
||||
public void setVector(Vector3 vector) {
|
||||
this.vector = vector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location clone() {
|
||||
try {
|
||||
Location other = (Location) super.clone();
|
||||
other.setVector(other.getVector().clone());
|
||||
return other;
|
||||
} catch(CloneNotSupportedException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public int getBlockX() {
|
||||
return vector.getBlockX();
|
||||
}
|
||||
|
||||
public int getBlockY() {
|
||||
return vector.getBlockY();
|
||||
}
|
||||
|
||||
public int getBlockZ() {
|
||||
return vector.getBlockZ();
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return vector.getY();
|
||||
}
|
||||
|
||||
public Location setY(double y) {
|
||||
vector.setY(y);
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
return vector.getX();
|
||||
}
|
||||
|
||||
public Location setX(double x) {
|
||||
vector.setX(x);
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getZ() {
|
||||
return vector.getZ();
|
||||
}
|
||||
|
||||
public Location setZ(double z) {
|
||||
vector.setZ(z);
|
||||
return this;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public Location add(double x, double y, double z) {
|
||||
vector.add(x, y, z);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return world.getBlockAt(this);
|
||||
}
|
||||
|
||||
public Location subtract(int x, int y, int z) {
|
||||
vector.subtract(x, y, z);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Location add(Vector3 add) {
|
||||
vector.add(add);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Location add(Location add) {
|
||||
vector.add(add.toVector());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(!(obj instanceof Location)) {
|
||||
return false;
|
||||
}
|
||||
final Location other = (Location) obj;
|
||||
|
||||
World world = this.world;
|
||||
World otherWorld = other.world;
|
||||
if(!Objects.equals(world, otherWorld)) {
|
||||
return false;
|
||||
}
|
||||
if(Double.doubleToLongBits(this.vector.getX()) != Double.doubleToLongBits(other.vector.getX())) {
|
||||
return false;
|
||||
}
|
||||
if(Double.doubleToLongBits(this.vector.getY()) != Double.doubleToLongBits(other.vector.getY())) {
|
||||
return false;
|
||||
}
|
||||
return Double.doubleToLongBits(this.vector.getZ()) == Double.doubleToLongBits(other.vector.getZ());
|
||||
}
|
||||
|
||||
public double getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public void setPitch(double pitch) {
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
public double getYaw() {
|
||||
return yaw;
|
||||
}
|
||||
|
||||
public void setYaw(double yaw) {
|
||||
this.yaw = yaw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 3;
|
||||
|
||||
World world = (this.world == null) ? null : this.world;
|
||||
hash = 19 * hash + (world != null ? world.hashCode() : 0);
|
||||
hash = 19 * hash + (int) (Double.doubleToLongBits(this.vector.getX()) ^ (Double.doubleToLongBits(this.vector.getX()) >>> 32));
|
||||
hash = 19 * hash + (int) (Double.doubleToLongBits(this.vector.getY()) ^ (Double.doubleToLongBits(this.vector.getY()) >>> 32));
|
||||
hash = 19 * hash + (int) (Double.doubleToLongBits(this.vector.getZ()) ^ (Double.doubleToLongBits(this.vector.getZ()) >>> 32));
|
||||
hash = 19 * hash + (int) (Double.doubleToLongBits(this.pitch) ^ Double.doubleToLongBits(this.pitch) >>> 32);
|
||||
hash = 19 * hash + (int) (Double.doubleToLongBits(this.yaw) ^ Double.doubleToLongBits(this.yaw) >>> 32);
|
||||
return hash;
|
||||
}
|
||||
|
||||
public Vector3 toVector() {
|
||||
return vector.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + world + ": (" + getX() + ", " + getY() + ", " + getZ() + ")]";
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.dfsek.terra.procgen.math;
|
||||
package com.dfsek.terra.api.math.vector;
|
||||
|
||||
import com.dfsek.terra.api.math.MathUtil;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
/**
|
||||
@@ -157,11 +158,9 @@ public class Vector2 implements Cloneable {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(!(obj instanceof Vector2)) {
|
||||
return false;
|
||||
}
|
||||
if(!(obj instanceof Vector2)) return false;
|
||||
Vector2 other = (Vector2) obj;
|
||||
return other.x == this.x && other.z == this.z;
|
||||
return MathUtil.equals(this.x, other.x) && MathUtil.equals(this.z, other.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -173,6 +172,12 @@ public class Vector2 implements Cloneable {
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 add(double x, double z) {
|
||||
this.x += x;
|
||||
this.z += z;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + x + ", " + z + ")";
|
||||
@@ -0,0 +1,338 @@
|
||||
package com.dfsek.terra.api.math.vector;
|
||||
|
||||
import com.dfsek.terra.api.math.MathUtil;
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
import net.jafama.FastMath;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class Vector3 implements Cloneable {
|
||||
|
||||
|
||||
private double x;
|
||||
private double y;
|
||||
private double z;
|
||||
|
||||
public Vector3(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public double getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public Vector3 setZ(double z) {
|
||||
this.z = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public Vector3 setX(double x) {
|
||||
this.x = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public Vector3 setY(double y) {
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getBlockX() {
|
||||
return FastMath.floorToInt(x);
|
||||
}
|
||||
|
||||
public int getBlockY() {
|
||||
return FastMath.floorToInt(y);
|
||||
}
|
||||
|
||||
public int getBlockZ() {
|
||||
return FastMath.floorToInt(z);
|
||||
}
|
||||
|
||||
public Vector3 multiply(double m) {
|
||||
x *= m;
|
||||
y *= m;
|
||||
z *= m;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3 add(double x, double y, double z) {
|
||||
this.x += x;
|
||||
this.y += y;
|
||||
this.z += z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3 add(Vector3 other) {
|
||||
this.x += other.getX();
|
||||
this.y += other.getY();
|
||||
this.z += other.getZ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3 add(Vector2 other) {
|
||||
this.x += other.getX();
|
||||
this.z += other.getZ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public double lengthSquared() {
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3 clone() {
|
||||
try {
|
||||
return (Vector3) super.clone();
|
||||
} catch(CloneNotSupportedException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public double length() {
|
||||
return FastMath.sqrt(lengthSquared());
|
||||
}
|
||||
|
||||
public double inverseLength() {
|
||||
return FastMath.invSqrtQuick(lengthSquared());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a vector is normalized
|
||||
*
|
||||
* @return whether the vector is normalised
|
||||
*/
|
||||
public boolean isNormalized() {
|
||||
return MathUtil.equals(this.lengthSquared(), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the vector around the x axis.
|
||||
* <p>
|
||||
* This piece of math is based on the standard rotation matrix for vectors
|
||||
* in three dimensional space. This matrix can be found here:
|
||||
* <a href="https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">Rotation
|
||||
* Matrix</a>.
|
||||
*
|
||||
* @param angle the angle to rotate the vector about. This angle is passed
|
||||
* in radians
|
||||
* @return the same vector
|
||||
*/
|
||||
@NotNull
|
||||
public Vector3 rotateAroundX(double angle) {
|
||||
double angleCos = Math.cos(angle);
|
||||
double angleSin = Math.sin(angle);
|
||||
|
||||
double y = angleCos * getY() - angleSin * getZ();
|
||||
double z = angleSin * getY() + angleCos * getZ();
|
||||
return setY(y).setZ(z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the vector around the y axis.
|
||||
* <p>
|
||||
* This piece of math is based on the standard rotation matrix for vectors
|
||||
* in three dimensional space. This matrix can be found here:
|
||||
* <a href="https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">Rotation
|
||||
* Matrix</a>.
|
||||
*
|
||||
* @param angle the angle to rotate the vector about. This angle is passed
|
||||
* in radians
|
||||
* @return the same vector
|
||||
*/
|
||||
@NotNull
|
||||
public Vector3 rotateAroundY(double angle) {
|
||||
double angleCos = Math.cos(angle);
|
||||
double angleSin = Math.sin(angle);
|
||||
|
||||
double x = angleCos * getX() + angleSin * getZ();
|
||||
double z = -angleSin * getX() + angleCos * getZ();
|
||||
return setX(x).setZ(z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the vector around the z axis
|
||||
* <p>
|
||||
* This piece of math is based on the standard rotation matrix for vectors
|
||||
* in three dimensional space. This matrix can be found here:
|
||||
* <a href="https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">Rotation
|
||||
* Matrix</a>.
|
||||
*
|
||||
* @param angle the angle to rotate the vector about. This angle is passed
|
||||
* in radians
|
||||
* @return the same vector
|
||||
*/
|
||||
@NotNull
|
||||
public Vector3 rotateAroundZ(double angle) {
|
||||
double angleCos = Math.cos(angle);
|
||||
double angleSin = Math.sin(angle);
|
||||
|
||||
double x = angleCos * getX() - angleSin * getY();
|
||||
double y = angleSin * getX() + angleCos * getY();
|
||||
return setX(x).setY(y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance between this vector and another. The value of this
|
||||
* method is not cached and uses a costly square-root function, so do not
|
||||
* repeatedly call this method to get the vector's magnitude. NaN will be
|
||||
* returned if the inner result of the sqrt() function overflows, which
|
||||
* will be caused if the distance is too long.
|
||||
*
|
||||
* @param o The other vector
|
||||
* @return the distance
|
||||
*/
|
||||
public double distance(@NotNull Vector3 o) {
|
||||
return FastMath.sqrt(FastMath.pow2(x - o.x) + FastMath.pow2(y - o.y) + FastMath.pow2(z - o.z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the squared distance between this vector and another.
|
||||
*
|
||||
* @param o The other vector
|
||||
* @return the distance
|
||||
*/
|
||||
public double distanceSquared(@NotNull Vector3 o) {
|
||||
return FastMath.pow2(x - o.x) + FastMath.pow2(y - o.y) + FastMath.pow2(z - o.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the vector around a given arbitrary axis in 3 dimensional space.
|
||||
*
|
||||
* <p>
|
||||
* Rotation will follow the general Right-Hand-Rule, which means rotation
|
||||
* will be counterclockwise when the axis is pointing towards the observer.
|
||||
* <p>
|
||||
* This method will always make sure the provided axis is a unit vector, to
|
||||
* not modify the length of the vector when rotating.
|
||||
*
|
||||
* @param axis the axis to rotate the vector around. If the passed vector is
|
||||
* not of length 1, it gets copied and normalized before using it for the
|
||||
* rotation. Please use {@link Vector3#normalize()} on the instance before
|
||||
* passing it to this method
|
||||
* @param angle the angle to rotate the vector around the axis
|
||||
* @return the same vector
|
||||
* @throws IllegalArgumentException if the provided axis vector instance is
|
||||
* null
|
||||
*/
|
||||
@NotNull
|
||||
public Vector3 rotateAroundAxis(@NotNull Vector3 axis, double angle) throws IllegalArgumentException {
|
||||
return rotateAroundNonUnitAxis(axis.isNormalized() ? axis : axis.clone().normalize(), angle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the vector around a given arbitrary axis in 3 dimensional space.
|
||||
*
|
||||
* <p>
|
||||
* Rotation will follow the general Right-Hand-Rule, which means rotation
|
||||
* will be counterclockwise when the axis is pointing towards the observer.
|
||||
* <p>
|
||||
* Note that the vector length will change accordingly to the axis vector
|
||||
* length. If the provided axis is not a unit vector, the rotated vector
|
||||
* will not have its previous length. The scaled length of the resulting
|
||||
* vector will be related to the axis vector.
|
||||
*
|
||||
* @param axis the axis to rotate the vector around.
|
||||
* @param angle the angle to rotate the vector around the axis
|
||||
* @return the same vector
|
||||
* @throws IllegalArgumentException if the provided axis vector instance is
|
||||
* null
|
||||
*/
|
||||
@NotNull
|
||||
public Vector3 rotateAroundNonUnitAxis(@NotNull Vector3 axis, double angle) throws IllegalArgumentException {
|
||||
double x = getX(), y = getY(), z = getZ();
|
||||
double x2 = axis.getX(), y2 = axis.getY(), z2 = axis.getZ();
|
||||
|
||||
double cosTheta = Math.cos(angle);
|
||||
double sinTheta = Math.sin(angle);
|
||||
double dotProduct = this.dot(axis);
|
||||
|
||||
double xPrime = x2 * dotProduct * (1d - cosTheta)
|
||||
+ x * cosTheta
|
||||
+ (-z2 * y + y2 * z) * sinTheta;
|
||||
double yPrime = y2 * dotProduct * (1d - cosTheta)
|
||||
+ y * cosTheta
|
||||
+ (z2 * x - x2 * z) * sinTheta;
|
||||
double zPrime = z2 * dotProduct * (1d - cosTheta)
|
||||
+ z * cosTheta
|
||||
+ (-y2 * x + x2 * y) * sinTheta;
|
||||
|
||||
return setX(xPrime).setY(yPrime).setZ(zPrime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the dot product of this vector with another. The dot product
|
||||
* is defined as x1*x2+y1*y2+z1*z2. The returned value is a scalar.
|
||||
*
|
||||
* @param other The other vector
|
||||
* @return dot product
|
||||
*/
|
||||
public double dot(@NotNull Vector3 other) {
|
||||
return x * other.x + y * other.y + z * other.z;
|
||||
}
|
||||
|
||||
public Location toLocation(World world) {
|
||||
return new Location(world, this.clone());
|
||||
}
|
||||
|
||||
public Vector3 normalize() {
|
||||
return this.multiply(this.inverseLength());
|
||||
}
|
||||
|
||||
public Vector3 subtract(int x, int y, int z) {
|
||||
this.x -= x;
|
||||
this.y -= y;
|
||||
this.z -= z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3 subtract(Vector3 end) {
|
||||
x -= end.x;
|
||||
y -= end.y;
|
||||
z -= end.z;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code for this vector
|
||||
*
|
||||
* @return hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
|
||||
hash = 79 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32));
|
||||
hash = 79 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32));
|
||||
hash = 79 * hash + (int) (Double.doubleToLongBits(this.z) ^ (Double.doubleToLongBits(this.z) >>> 32));
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if two objects are equal.
|
||||
* <p>
|
||||
* Only two Vectors can ever return true. This method uses a fuzzy match
|
||||
* to account for floating point errors. The epsilon can be retrieved
|
||||
* with epsilon.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(!(obj instanceof Vector3)) return false;
|
||||
Vector3 other = (Vector3) obj;
|
||||
return MathUtil.equals(x, other.x) && MathUtil.equals(y, other.y) && MathUtil.equals(x, other.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + getX() + ", " + getY() + ", " + getZ() + ")";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.dfsek.terra.api.math.voxel;
|
||||
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Vector3;
|
||||
|
||||
public class Cylinder extends VoxelGeometry {
|
||||
public Cylinder(Vector3 start, int rad, int height) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
package com.dfsek.terra.procgen.voxel;
|
||||
package com.dfsek.terra.api.math.voxel;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
import org.polydev.gaea.math.FastNoiseLite;
|
||||
import com.dfsek.terra.api.math.noise.samplers.NoiseSampler;
|
||||
import com.dfsek.terra.api.math.vector.Vector3;
|
||||
|
||||
public class DeformedSphere extends VoxelGeometry {
|
||||
public DeformedSphere(Vector start, int rad, double deform, FastNoiseLite noise) {
|
||||
public DeformedSphere(Vector3 start, int rad, double deform, NoiseSampler noise) {
|
||||
for(int x = -rad; x <= rad; x++) {
|
||||
for(int y = -rad; y <= rad; y++) {
|
||||
for(int z = -rad; z <= rad; z++) {
|
||||
Vector c = new Vector(x, y, z);
|
||||
Vector3 c = new Vector3(x, y, z);
|
||||
if(c.length() < (rad + 0.5) * ((noise.getNoise(x, y, z) + 1) * deform)) {
|
||||
addVector(c.add(start));
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.dfsek.terra.procgen.voxel;
|
||||
package com.dfsek.terra.api.math.voxel;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
import com.dfsek.terra.api.math.vector.Vector3;
|
||||
|
||||
public class Sphere extends VoxelGeometry {
|
||||
public Sphere(Vector start, int rad) {
|
||||
public Sphere(Vector3 start, int rad) {
|
||||
for(int x = -rad; x <= rad; x++) {
|
||||
for(int y = -rad; y <= rad; y++) {
|
||||
for(int z = -rad; z <= rad; z++) {
|
||||
Vector c = new Vector(x, y, z);
|
||||
Vector3 c = new Vector3(x, y, z);
|
||||
if(c.length() < rad + 0.5) {
|
||||
addVector(c.add(start));
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.dfsek.terra.api.math.voxel;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Vector3;
|
||||
|
||||
public class Tube extends VoxelGeometry {
|
||||
public Tube(Vector3 start, Vector3 end, int radius) {
|
||||
Vector3 step = start.clone().subtract(end).normalize();
|
||||
Vector3 run = start.clone();
|
||||
int steps = (int) start.distance(end);
|
||||
for(int i = 0; i < steps; i++) {
|
||||
merge(new Sphere(run, radius));
|
||||
run.add(step);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,23 @@
|
||||
package com.dfsek.terra.procgen.voxel;
|
||||
package com.dfsek.terra.api.math.voxel;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
import org.polydev.gaea.util.GlueList;
|
||||
import com.dfsek.terra.api.math.vector.Vector3;
|
||||
import com.dfsek.terra.api.util.GlueList;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class VoxelGeometry {
|
||||
private final List<Vector> geometry = new GlueList<>();
|
||||
private final List<Vector3> geometry = new GlueList<>();
|
||||
|
||||
public static VoxelGeometry getBlank() {
|
||||
return new VoxelGeometry() {
|
||||
};
|
||||
}
|
||||
|
||||
public List<Vector> getGeometry() {
|
||||
public List<Vector3> getGeometry() {
|
||||
return geometry;
|
||||
}
|
||||
|
||||
protected void addVector(Vector v) {
|
||||
protected void addVector(Vector3 v) {
|
||||
geometry.add(v);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.dfsek.terra.api.platform;
|
||||
|
||||
public interface CommandSender extends Handle {
|
||||
void sendMessage(String message);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.dfsek.terra.api.platform;
|
||||
|
||||
/**
|
||||
* An interface that contains a platform delegate.
|
||||
*/
|
||||
public interface Handle {
|
||||
Object getHandle();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.dfsek.terra.api.platform;
|
||||
|
||||
import com.dfsek.terra.TerraWorld;
|
||||
import com.dfsek.terra.api.LoaderRegistrar;
|
||||
import com.dfsek.terra.api.language.Language;
|
||||
import com.dfsek.terra.api.platform.handle.ItemHandle;
|
||||
import com.dfsek.terra.api.platform.handle.WorldHandle;
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
import com.dfsek.terra.config.base.PluginConfig;
|
||||
import com.dfsek.terra.registry.ConfigRegistry;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public interface TerraPlugin extends LoaderRegistrar {
|
||||
WorldHandle getWorldHandle();
|
||||
|
||||
boolean isEnabled();
|
||||
|
||||
TerraWorld getWorld(World world);
|
||||
|
||||
Logger getLogger();
|
||||
|
||||
PluginConfig getTerraConfig();
|
||||
|
||||
File getDataFolder();
|
||||
|
||||
boolean isDebug();
|
||||
|
||||
Language getLanguage();
|
||||
|
||||
ConfigRegistry getRegistry();
|
||||
|
||||
void reload();
|
||||
|
||||
ItemHandle getItemHandle();
|
||||
|
||||
void saveDefaultConfig();
|
||||
|
||||
String platformName();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.dfsek.terra.api.platform.block;
|
||||
|
||||
public enum Axis {
|
||||
X, Y, Z
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.dfsek.terra.api.platform.block;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.block.state.BlockState;
|
||||
|
||||
public interface Block extends Handle {
|
||||
void setBlockData(BlockData data, boolean physics);
|
||||
|
||||
BlockData getBlockData();
|
||||
|
||||
BlockState getState();
|
||||
|
||||
Block getRelative(BlockFace face);
|
||||
|
||||
Block getRelative(BlockFace face, int len);
|
||||
|
||||
boolean isEmpty();
|
||||
|
||||
Location getLocation();
|
||||
|
||||
MaterialData getType();
|
||||
|
||||
int getX();
|
||||
|
||||
int getZ();
|
||||
|
||||
int getY();
|
||||
|
||||
boolean isPassable();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.dfsek.terra.api.platform.block;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface BlockData extends Cloneable, Handle {
|
||||
MaterialData getMaterial();
|
||||
|
||||
boolean matches(MaterialData materialData);
|
||||
|
||||
BlockData clone();
|
||||
|
||||
String getAsString();
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.dfsek.terra.api.platform.block;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Vector3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public enum BlockFace {
|
||||
NORTH(0, 0, -1),
|
||||
EAST(1, 0, 0),
|
||||
SOUTH(0, 0, 1),
|
||||
WEST(-1, 0, 0),
|
||||
UP(0, 1, 0),
|
||||
DOWN(0, -1, 0),
|
||||
NORTH_EAST(NORTH, EAST),
|
||||
NORTH_WEST(NORTH, WEST),
|
||||
SOUTH_EAST(SOUTH, EAST),
|
||||
SOUTH_WEST(SOUTH, WEST),
|
||||
WEST_NORTH_WEST(WEST, NORTH_WEST),
|
||||
NORTH_NORTH_WEST(NORTH, NORTH_WEST),
|
||||
NORTH_NORTH_EAST(NORTH, NORTH_EAST),
|
||||
EAST_NORTH_EAST(EAST, NORTH_EAST),
|
||||
EAST_SOUTH_EAST(EAST, SOUTH_EAST),
|
||||
SOUTH_SOUTH_EAST(SOUTH, SOUTH_EAST),
|
||||
SOUTH_SOUTH_WEST(SOUTH, SOUTH_WEST),
|
||||
WEST_SOUTH_WEST(WEST, SOUTH_WEST),
|
||||
SELF(0, 0, 0);
|
||||
|
||||
private final int modX;
|
||||
private final int modY;
|
||||
private final int modZ;
|
||||
|
||||
BlockFace(final int modX, final int modY, final int modZ) {
|
||||
this.modX = modX;
|
||||
this.modY = modY;
|
||||
this.modZ = modZ;
|
||||
}
|
||||
|
||||
BlockFace(final BlockFace face1, final BlockFace face2) {
|
||||
this.modX = face1.getModX() + face2.getModX();
|
||||
this.modY = face1.getModY() + face2.getModY();
|
||||
this.modZ = face1.getModZ() + face2.getModZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of X-coordinates to modify to get the represented block
|
||||
*
|
||||
* @return Amount of X-coordinates to modify
|
||||
*/
|
||||
public int getModX() {
|
||||
return modX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of Y-coordinates to modify to get the represented block
|
||||
*
|
||||
* @return Amount of Y-coordinates to modify
|
||||
*/
|
||||
public int getModY() {
|
||||
return modY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of Z-coordinates to modify to get the represented block
|
||||
*
|
||||
* @return Amount of Z-coordinates to modify
|
||||
*/
|
||||
public int getModZ() {
|
||||
return modZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the normal vector corresponding to this block face.
|
||||
*
|
||||
* @return the normal vector
|
||||
*/
|
||||
@NotNull
|
||||
public Vector3 getDirection() {
|
||||
Vector3 direction = new Vector3(modX, modY, modZ);
|
||||
if(modX != 0 || modY != 0 || modZ != 0) {
|
||||
direction.normalize();
|
||||
}
|
||||
return direction;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public BlockFace getOppositeFace() {
|
||||
switch(this) {
|
||||
case NORTH:
|
||||
return BlockFace.SOUTH;
|
||||
|
||||
case SOUTH:
|
||||
return BlockFace.NORTH;
|
||||
|
||||
case EAST:
|
||||
return BlockFace.WEST;
|
||||
|
||||
case WEST:
|
||||
return BlockFace.EAST;
|
||||
|
||||
case UP:
|
||||
return BlockFace.DOWN;
|
||||
|
||||
case DOWN:
|
||||
return BlockFace.UP;
|
||||
|
||||
case NORTH_EAST:
|
||||
return BlockFace.SOUTH_WEST;
|
||||
|
||||
case NORTH_WEST:
|
||||
return BlockFace.SOUTH_EAST;
|
||||
|
||||
case SOUTH_EAST:
|
||||
return BlockFace.NORTH_WEST;
|
||||
|
||||
case SOUTH_WEST:
|
||||
return BlockFace.NORTH_EAST;
|
||||
|
||||
case WEST_NORTH_WEST:
|
||||
return BlockFace.EAST_SOUTH_EAST;
|
||||
|
||||
case NORTH_NORTH_WEST:
|
||||
return BlockFace.SOUTH_SOUTH_EAST;
|
||||
|
||||
case NORTH_NORTH_EAST:
|
||||
return BlockFace.SOUTH_SOUTH_WEST;
|
||||
|
||||
case EAST_NORTH_EAST:
|
||||
return BlockFace.WEST_SOUTH_WEST;
|
||||
|
||||
case EAST_SOUTH_EAST:
|
||||
return BlockFace.WEST_NORTH_WEST;
|
||||
|
||||
case SOUTH_SOUTH_EAST:
|
||||
return BlockFace.NORTH_NORTH_WEST;
|
||||
|
||||
case SOUTH_SOUTH_WEST:
|
||||
return BlockFace.NORTH_NORTH_EAST;
|
||||
|
||||
case WEST_SOUTH_WEST:
|
||||
return BlockFace.EAST_NORTH_EAST;
|
||||
|
||||
case SELF:
|
||||
return BlockFace.SELF;
|
||||
}
|
||||
|
||||
return BlockFace.SELF;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.dfsek.terra.api.platform.block;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface MaterialData extends Handle {
|
||||
boolean matches(MaterialData other);
|
||||
|
||||
boolean matches(BlockData other);
|
||||
|
||||
boolean isSolid();
|
||||
|
||||
boolean isAir();
|
||||
|
||||
double getMaxDurability();
|
||||
|
||||
BlockData createBlockData();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
|
||||
public interface AnaloguePowerable extends BlockData {
|
||||
int getMaximumPower();
|
||||
int getPower();
|
||||
void setPower(int power);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
|
||||
public interface Bisected extends BlockData {
|
||||
Half getHalf();
|
||||
|
||||
void setHalf(Half half);
|
||||
|
||||
enum Half {
|
||||
/**
|
||||
* The top half of the block, normally with the higher y coordinate.
|
||||
*/
|
||||
TOP,
|
||||
/**
|
||||
* The bottom half of the block, normally with the lower y coordinate.
|
||||
*/
|
||||
BOTTOM
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.block.BlockFace;
|
||||
|
||||
public interface Directional extends BlockData {
|
||||
BlockFace getFacing();
|
||||
|
||||
void setFacing(BlockFace facing);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.block.BlockFace;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface MultipleFacing extends BlockData {
|
||||
Set<BlockFace> getFaces();
|
||||
|
||||
void setFace(BlockFace face, boolean facing);
|
||||
|
||||
Set<BlockFace> getAllowedFaces();
|
||||
|
||||
boolean hasFace(BlockFace f);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.Axis;
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface Orientable extends BlockData {
|
||||
Set<Axis> getAxes();
|
||||
|
||||
Axis getAxis();
|
||||
|
||||
void setAxis(Axis axis);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
|
||||
public interface Rail extends BlockData {
|
||||
Shape getShape();
|
||||
|
||||
void setShape(Shape newShape);
|
||||
|
||||
enum Shape {
|
||||
ASCENDING_EAST,
|
||||
ASCENDING_NORTH,
|
||||
ASCENDING_SOUTH,
|
||||
ASCENDING_WEST,
|
||||
EAST_WEST,
|
||||
NORTH_EAST,
|
||||
NORTH_SOUTH,
|
||||
NORTH_WEST,
|
||||
SOUTH_EAST,
|
||||
SOUTH_WEST
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.block.BlockFace;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface RedstoneWire extends BlockData, AnaloguePowerable {
|
||||
Set<BlockFace> getAllowedFaces();
|
||||
Connection getFace(BlockFace face);
|
||||
void setFace(BlockFace face, Connection connection);
|
||||
enum Connection {
|
||||
NONE, SIDE, UP
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.block.BlockFace;
|
||||
|
||||
public interface Rotatable extends BlockData {
|
||||
BlockFace getRotation();
|
||||
|
||||
void setRotation(BlockFace face);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
public interface Slab extends Waterlogged {
|
||||
Type getType();
|
||||
|
||||
void setType(Type type);
|
||||
|
||||
enum Type {
|
||||
TOP, BOTTOM, DOUBLE
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
public interface Stairs extends Waterlogged, Directional, Bisected {
|
||||
Shape getShape();
|
||||
|
||||
void setShape(Shape shape);
|
||||
|
||||
enum Shape {
|
||||
/**
|
||||
* Regular stair block.
|
||||
*/
|
||||
STRAIGHT,
|
||||
/**
|
||||
* Inner corner stair block with higher left side.
|
||||
*/
|
||||
INNER_LEFT,
|
||||
/**
|
||||
* Inner corner stair block with higher right side.
|
||||
*/
|
||||
INNER_RIGHT,
|
||||
/**
|
||||
* Outer corner stair block with higher left side.
|
||||
*/
|
||||
OUTER_LEFT,
|
||||
/**
|
||||
* Outer corner stair block with higher right side.
|
||||
*/
|
||||
OUTER_RIGHT
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.block.BlockFace;
|
||||
|
||||
public interface Wall extends BlockData, Waterlogged {
|
||||
boolean isUp();
|
||||
void setHeight(BlockFace face, Height height);
|
||||
Height getHeight(BlockFace face);
|
||||
void setUp(boolean up);
|
||||
|
||||
enum Height {
|
||||
LOW, NONE, TALL
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
|
||||
public interface Waterlogged extends BlockData {
|
||||
boolean isWaterlogged();
|
||||
|
||||
void setWaterlogged(boolean waterlogged);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.dfsek.terra.api.platform.block.state;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.block.Block;
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
|
||||
public interface BlockState extends Handle {
|
||||
Block getBlock();
|
||||
|
||||
int getX();
|
||||
|
||||
int getY();
|
||||
|
||||
int getZ();
|
||||
|
||||
BlockData getBlockData();
|
||||
|
||||
boolean update(boolean applyPhysics);
|
||||
|
||||
default void applyState(String state) {
|
||||
// Do nothing by default.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.dfsek.terra.api.platform.block.state;
|
||||
|
||||
import com.dfsek.terra.api.platform.inventory.BlockInventoryHolder;
|
||||
|
||||
public interface Container extends BlockState, BlockInventoryHolder {
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.dfsek.terra.api.platform.block.state;
|
||||
|
||||
import com.dfsek.terra.api.platform.world.entity.EntityType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface MobSpawner extends BlockState {
|
||||
EntityType getSpawnedType();
|
||||
|
||||
void setSpawnedType(@NotNull EntityType creatureType);
|
||||
|
||||
int getDelay();
|
||||
|
||||
void setDelay(int delay);
|
||||
|
||||
int getMinSpawnDelay();
|
||||
|
||||
void setMinSpawnDelay(int delay);
|
||||
|
||||
int getMaxSpawnDelay();
|
||||
|
||||
void setMaxSpawnDelay(int delay);
|
||||
|
||||
int getSpawnCount();
|
||||
|
||||
void setSpawnCount(int spawnCount);
|
||||
|
||||
int getMaxNearbyEntities();
|
||||
|
||||
void setMaxNearbyEntities(int maxNearbyEntities);
|
||||
|
||||
int getRequiredPlayerRange();
|
||||
|
||||
void setRequiredPlayerRange(int requiredPlayerRange);
|
||||
|
||||
int getSpawnRange();
|
||||
|
||||
void setSpawnRange(int spawnRange);
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.dfsek.terra.api.platform.block.state;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SerialState {
|
||||
protected final Map<String, Property<?>> properties = new HashMap<>();
|
||||
|
||||
public SerialState() {
|
||||
}
|
||||
|
||||
public static Map<String, String> parse(String props) {
|
||||
String[] sep = props.split(",");
|
||||
Map<String, String> map = new HashMap<>();
|
||||
for(String item : sep) {
|
||||
map.put(item.substring(0, item.indexOf('=')), item.substring(item.indexOf('=') + 1));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private void checkExists(String prop) {
|
||||
if(!properties.containsKey(prop)) throw new IllegalArgumentException("No such property \"" + prop + "\"");
|
||||
}
|
||||
|
||||
private void checkType(Class<?> clazz, Object o, String id) {
|
||||
if(!clazz.isInstance(o))
|
||||
throw new IllegalArgumentException("Invalid data for property " + id + ": " + o);
|
||||
}
|
||||
|
||||
public void setProperty(String id, Object value) {
|
||||
checkExists(id);
|
||||
Property<?> prop = properties.get(id);
|
||||
checkType(prop.getValueClass(), value, id);
|
||||
prop.setValue(value);
|
||||
}
|
||||
|
||||
public int getInteger(String id) {
|
||||
checkExists(id);
|
||||
Property<?> prop = properties.get(id);
|
||||
checkType(Integer.class, prop.getValue(), id);
|
||||
return (Integer) prop.getValue();
|
||||
}
|
||||
|
||||
public String getString(String id) {
|
||||
checkExists(id);
|
||||
Property<?> prop = properties.get(id);
|
||||
checkType(String.class, prop.getValue(), id);
|
||||
return (String) prop.getValue();
|
||||
}
|
||||
|
||||
public long getLong(String id) {
|
||||
checkExists(id);
|
||||
Property<?> prop = properties.get(id);
|
||||
checkType(Long.class, prop.getValue(), id);
|
||||
return (Long) prop.getValue();
|
||||
}
|
||||
|
||||
public boolean getBoolean(String id) {
|
||||
checkExists(id);
|
||||
Property<?> prop = properties.get(id);
|
||||
checkType(Boolean.class, prop.getValue(), id);
|
||||
return (Boolean) prop.getValue();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(String id, Class<T> clazz) {
|
||||
checkExists(id);
|
||||
Property<?> prop = properties.get(id);
|
||||
checkType(clazz, prop.getValue(), id);
|
||||
return (T) prop.getValue();
|
||||
}
|
||||
|
||||
protected static class Property<T> {
|
||||
private final Class<T> clazz;
|
||||
private Object value;
|
||||
|
||||
public Property(Class<T> clazz) {
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
public Class<T> getValueClass() {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T getValue() {
|
||||
return (T) value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.dfsek.terra.api.platform.block.state;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface Sign extends BlockState {
|
||||
@NotNull String[] getLines();
|
||||
|
||||
@NotNull String getLine(int index) throws IndexOutOfBoundsException;
|
||||
|
||||
void setLine(int index, @NotNull String line) throws IndexOutOfBoundsException;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.dfsek.terra.api.platform.generator;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public interface BlockPopulator extends Handle {
|
||||
void populate(World world, Random random, Chunk chunk);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.dfsek.terra.api.platform.generator;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.world.BiomeGrid;
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public interface ChunkGenerator extends Handle {
|
||||
boolean isParallelCapable();
|
||||
|
||||
boolean shouldGenerateCaves();
|
||||
|
||||
boolean shouldGenerateDecorations();
|
||||
|
||||
boolean shouldGenerateMobs();
|
||||
|
||||
boolean shouldGenerateStructures();
|
||||
|
||||
ChunkData generateChunkData(@NotNull World world, @NotNull Random random, int x, int z, @NotNull BiomeGrid biome);
|
||||
|
||||
|
||||
List<BlockPopulator> getDefaultPopulators(World world);
|
||||
|
||||
@Nullable
|
||||
TerraChunkGenerator getTerraGenerator();
|
||||
|
||||
interface ChunkData extends Handle {
|
||||
/**
|
||||
* Get the maximum height for the chunk.
|
||||
* <p>
|
||||
* Setting blocks at or above this height will do nothing.
|
||||
*
|
||||
* @return the maximum height
|
||||
*/
|
||||
int getMaxHeight();
|
||||
|
||||
|
||||
/**
|
||||
* Set the block at x,y,z in the chunk data to material.
|
||||
* <p>
|
||||
* Setting blocks outside the chunk's bounds does nothing.
|
||||
*
|
||||
* @param x the x location in the chunk from 0-15 inclusive
|
||||
* @param y the y location in the chunk from 0 (inclusive) - maxHeight (exclusive)
|
||||
* @param z the z location in the chunk from 0-15 inclusive
|
||||
* @param blockData the type to set the block to
|
||||
*/
|
||||
void setBlock(int x, int y, int z, @NotNull BlockData blockData);
|
||||
|
||||
|
||||
/**
|
||||
* Get the type and data of the block at x, y, z.
|
||||
* <p>
|
||||
* Getting blocks outside the chunk's bounds returns air.
|
||||
*
|
||||
* @param x the x location in the chunk from 0-15 inclusive
|
||||
* @param y the y location in the chunk from 0 (inclusive) - maxHeight (exclusive)
|
||||
* @param z the z location in the chunk from 0-15 inclusive
|
||||
* @return the data of the block or the BlockData for air if x, y or z are outside the chunk's bounds
|
||||
*/
|
||||
@NotNull BlockData getBlockData(int x, int y, int z);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.dfsek.terra.api.platform.generator;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface GeneratorWrapper extends Handle {
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.dfsek.terra.api.platform.handle;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.MaterialData;
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
import com.dfsek.terra.api.platform.inventory.item.Enchantment;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface ItemHandle {
|
||||
ItemStack newItemStack(MaterialData material, int amount);
|
||||
|
||||
Enchantment getEnchantment(String id);
|
||||
|
||||
Set<Enchantment> getEnchantments();
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.dfsek.terra.api.platform.handle;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.Block;
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.block.MaterialData;
|
||||
import com.dfsek.terra.api.platform.world.Tree;
|
||||
import com.dfsek.terra.api.platform.world.entity.EntityType;
|
||||
|
||||
/**
|
||||
* Interface to be implemented for world manipulation.
|
||||
*/
|
||||
public interface WorldHandle {
|
||||
void setBlockData(Block block, BlockData data, boolean physics);
|
||||
|
||||
BlockData getBlockData(Block block);
|
||||
|
||||
MaterialData getType(Block block);
|
||||
|
||||
BlockData createBlockData(String data);
|
||||
|
||||
MaterialData createMaterialData(String data);
|
||||
|
||||
Tree getTree(String id);
|
||||
|
||||
EntityType getEntity(String id);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.dfsek.terra.api.platform.inventory;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.Block;
|
||||
|
||||
public interface BlockInventoryHolder extends InventoryHolder {
|
||||
Block getBlock();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.dfsek.terra.api.platform.inventory;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface Inventory extends Handle {
|
||||
int getSize();
|
||||
|
||||
ItemStack getItem(int slot);
|
||||
|
||||
void setItem(int slot, ItemStack newStack);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.dfsek.terra.api.platform.inventory;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface InventoryHolder extends Handle {
|
||||
Inventory getInventory();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.dfsek.terra.api.platform.inventory;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.block.MaterialData;
|
||||
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
|
||||
|
||||
public interface ItemStack extends Handle, Cloneable {
|
||||
int getAmount();
|
||||
|
||||
void setAmount(int i);
|
||||
|
||||
MaterialData getType();
|
||||
|
||||
ItemStack clone();
|
||||
|
||||
ItemMeta getItemMeta();
|
||||
|
||||
void setItemMeta(ItemMeta meta);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.dfsek.terra.api.platform.inventory.item;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface Damageable extends Handle {
|
||||
int getDamage();
|
||||
|
||||
void setDamage(int damage);
|
||||
|
||||
boolean hasDamage();
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.dfsek.terra.api.platform.inventory.item;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
|
||||
public interface Enchantment extends Handle {
|
||||
boolean canEnchantItem(ItemStack itemStack);
|
||||
|
||||
String getID();
|
||||
|
||||
boolean conflictsWith(Enchantment other);
|
||||
|
||||
int getMaxLevel();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.dfsek.terra.api.platform.inventory.item;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface ItemMeta extends Handle {
|
||||
Map<Enchantment, Integer> getEnchantments();
|
||||
|
||||
void addEnchantment(Enchantment enchantment, int level);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* API for platform implementations. Mostly interfaces to be implemented by platform delegates.
|
||||
*/
|
||||
package com.dfsek.terra.api.platform;
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.dfsek.terra.api.platform.world;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface Biome extends Handle {
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.dfsek.terra.api.platform.world;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface BiomeGrid extends Handle {
|
||||
/**
|
||||
* Get biome at x, z within chunk being generated
|
||||
*
|
||||
* @param x - 0-15
|
||||
* @param z - 0-15
|
||||
* @return Biome value
|
||||
*/
|
||||
@NotNull
|
||||
Biome getBiome(int x, int z);
|
||||
|
||||
/**
|
||||
* Get biome at x, z within chunk being generated
|
||||
*
|
||||
* @param x - 0-15
|
||||
* @param y - 0-255
|
||||
* @param z - 0-15
|
||||
* @return Biome value
|
||||
*/
|
||||
@NotNull
|
||||
Biome getBiome(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Set biome at x, z within chunk being generated
|
||||
*
|
||||
* @param x - 0-15
|
||||
* @param z - 0-15
|
||||
* @param bio - Biome value
|
||||
*/
|
||||
void setBiome(int x, int z, @NotNull Biome bio);
|
||||
|
||||
/**
|
||||
* Set biome at x, z within chunk being generated
|
||||
*
|
||||
* @param x - 0-15
|
||||
* @param y - 0-255
|
||||
* @param z - 0-15
|
||||
* @param bio - Biome value
|
||||
*/
|
||||
void setBiome(int x, int y, int z, @NotNull Biome bio);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.dfsek.terra.api.platform.world;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.block.Block;
|
||||
|
||||
public interface Chunk extends Handle {
|
||||
int getX();
|
||||
|
||||
int getZ();
|
||||
|
||||
World getWorld();
|
||||
|
||||
Block getBlock(int x, int y, int z);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.dfsek.terra.api.platform.world;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface Tree extends Handle, com.dfsek.terra.api.world.tree.Tree {
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.dfsek.terra.api.platform.world;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.block.Block;
|
||||
import com.dfsek.terra.api.platform.generator.ChunkGenerator;
|
||||
import com.dfsek.terra.api.platform.world.entity.Entity;
|
||||
import com.dfsek.terra.api.platform.world.entity.EntityType;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface World extends Handle {
|
||||
long getSeed();
|
||||
|
||||
int getMaxHeight();
|
||||
|
||||
ChunkGenerator getGenerator();
|
||||
|
||||
String getName();
|
||||
|
||||
UUID getUID();
|
||||
|
||||
boolean isChunkGenerated(int x, int z);
|
||||
|
||||
Chunk getChunkAt(int x, int z);
|
||||
|
||||
File getWorldFolder();
|
||||
|
||||
Block getBlockAt(int x, int y, int z);
|
||||
|
||||
Block getBlockAt(Location l);
|
||||
|
||||
boolean generateTree(Location l, Tree vanillaTreeType);
|
||||
|
||||
Entity spawnEntity(Location location, EntityType entityType);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.dfsek.terra.api.platform.world.entity;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface Entity extends Handle {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.dfsek.terra.api.platform.world.entity;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface EntityType extends Handle {
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.dfsek.terra.api.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.api.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.api.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
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.dfsek.terra.api.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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.dfsek.terra.api.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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.dfsek.terra.api.profiler;
|
||||
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
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(w.getGenerator().getTerraGenerator() == null)
|
||||
throw new IllegalArgumentException("Attempted to instantiate profiler on non-Gaea managed world!");
|
||||
this.addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "TotalChunkGenTime");
|
||||
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.api.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.dfsek.terra.api.structures.loot;
|
||||
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.api.platform.block.MaterialData;
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
import com.dfsek.terra.api.structures.loot.functions.AmountFunction;
|
||||
import com.dfsek.terra.api.structures.loot.functions.DamageFunction;
|
||||
import com.dfsek.terra.api.structures.loot.functions.EnchantFunction;
|
||||
import com.dfsek.terra.api.structures.loot.functions.LootFunction;
|
||||
import com.dfsek.terra.api.util.GlueList;
|
||||
import net.jafama.FastMath;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Representation of a single item entry within a Loot Table pool.
|
||||
*/
|
||||
public class Entry {
|
||||
private final MaterialData item;
|
||||
private final long weight;
|
||||
private final List<LootFunction> functions = new GlueList<>();
|
||||
private final TerraPlugin main;
|
||||
|
||||
/**
|
||||
* Instantiates an Entry from a JSON representation.
|
||||
*
|
||||
* @param entry The JSON Object to instantiate from.
|
||||
*/
|
||||
public Entry(JSONObject entry, TerraPlugin main) {
|
||||
this.main = main;
|
||||
String id = entry.get("name").toString();
|
||||
this.item = main.getWorldHandle().createMaterialData(id);
|
||||
|
||||
long weight1;
|
||||
try {
|
||||
weight1 = (long) entry.get("weight");
|
||||
} catch(NullPointerException e) {
|
||||
weight1 = 1;
|
||||
}
|
||||
|
||||
this.weight = weight1;
|
||||
if(entry.containsKey("functions")) {
|
||||
for(Object function : (JSONArray) entry.get("functions")) {
|
||||
switch(((String) ((JSONObject) function).get("function"))) {
|
||||
case "minecraft:set_count":
|
||||
case "set_count":
|
||||
Object loot = ((JSONObject) function).get("count");
|
||||
long max, min;
|
||||
if(loot instanceof Long) {
|
||||
max = (Long) loot;
|
||||
min = (Long) loot;
|
||||
} else {
|
||||
max = (long) ((JSONObject) loot).get("max");
|
||||
min = (long) ((JSONObject) loot).get("min");
|
||||
}
|
||||
functions.add(new AmountFunction(FastMath.toIntExact(min), FastMath.toIntExact(max)));
|
||||
break;
|
||||
case "minecraft:set_damage":
|
||||
case "set_damage":
|
||||
long maxDamage = (long) ((JSONObject) ((JSONObject) function).get("damage")).get("max");
|
||||
long minDamage = (long) ((JSONObject) ((JSONObject) function).get("damage")).get("min");
|
||||
functions.add(new DamageFunction(FastMath.toIntExact(minDamage), FastMath.toIntExact(maxDamage)));
|
||||
break;
|
||||
case "minecraft:enchant_with_levels":
|
||||
case "enchant_with_levels":
|
||||
long maxEnchant = (long) ((JSONObject) ((JSONObject) function).get("levels")).get("max");
|
||||
long minEnchant = (long) ((JSONObject) ((JSONObject) function).get("levels")).get("min");
|
||||
JSONArray disabled = null;
|
||||
if(((JSONObject) function).containsKey("disabled_enchants"))
|
||||
disabled = (JSONArray) ((JSONObject) function).get("disabled_enchants");
|
||||
functions.add(new EnchantFunction(FastMath.toIntExact(minEnchant), FastMath.toIntExact(maxEnchant), disabled, main));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a single ItemStack from the Entry, applying all functions to it.
|
||||
*
|
||||
* @param r The Random instance to apply functions with
|
||||
* @return ItemStack - The ItemStack with all functions applied.
|
||||
*/
|
||||
public ItemStack getItem(Random r) {
|
||||
ItemStack item = main.getItemHandle().newItemStack(this.item, 1);
|
||||
for(LootFunction f : functions) {
|
||||
item = f.apply(item, r);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the weight attribute of the Entry.
|
||||
*
|
||||
* @return long - The weight of the Entry.
|
||||
*/
|
||||
public long getWeight() {
|
||||
return this.weight;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.dfsek.terra.api.structures.loot;
|
||||
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.api.platform.inventory.Inventory;
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
import com.dfsek.terra.api.util.GlueList;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Class representation of a Loot Table to populate chest loot.
|
||||
*/
|
||||
public class LootTable {
|
||||
private final List<Pool> pools = new GlueList<>();
|
||||
|
||||
/**
|
||||
* Instantiates a LootTable from a JSON String.
|
||||
*
|
||||
* @param json The JSON String representing the loot table.
|
||||
* @throws ParseException if malformed JSON is passed.
|
||||
*/
|
||||
public LootTable(String json, TerraPlugin main) throws ParseException {
|
||||
JSONParser jsonParser = new JSONParser();
|
||||
Object tableJSON = jsonParser.parse(json);
|
||||
JSONArray poolArray = (JSONArray) ((JSONObject) tableJSON).get("pools");
|
||||
for(Object pool : poolArray) {
|
||||
pools.add(new Pool((JSONObject) pool, main));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of ItemStacks from the loot table using the given Random instance.
|
||||
*
|
||||
* @param r The Random instance to use.
|
||||
* @return List<ItemStack> - The list of loot fetched.
|
||||
*/
|
||||
public List<ItemStack> getLoot(Random r) {
|
||||
List<ItemStack> itemList = new GlueList<>();
|
||||
for(Pool pool : pools) {
|
||||
itemList.addAll(pool.getItems(r));
|
||||
}
|
||||
return itemList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills an Inventory with loot.
|
||||
*
|
||||
* @param i The Inventory to fill.
|
||||
* @param r The The Random instance to use.
|
||||
*/
|
||||
public void fillInventory(Inventory i, Random r) {
|
||||
List<ItemStack> loot = getLoot(r);
|
||||
for(ItemStack stack : loot) {
|
||||
int attempts = 0;
|
||||
while(stack.getAmount() != 0 && attempts < 10) {
|
||||
ItemStack newStack = stack.clone();
|
||||
newStack.setAmount(1);
|
||||
int slot = r.nextInt(i.getSize());
|
||||
ItemStack slotItem = i.getItem(slot);
|
||||
if(slotItem == null) {
|
||||
i.setItem(slot, newStack);
|
||||
stack.setAmount(stack.getAmount() - 1);
|
||||
} else if(slotItem.getType().equals(newStack.getType())) {
|
||||
ItemStack dep = newStack.clone();
|
||||
dep.setAmount(newStack.getAmount() + slotItem.getAmount());
|
||||
i.setItem(slot, dep);
|
||||
stack.setAmount(stack.getAmount() - 1);
|
||||
}
|
||||
attempts++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.dfsek.terra.api.structures.loot;
|
||||
|
||||
import com.dfsek.terra.api.math.ProbabilityCollection;
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
import com.dfsek.terra.api.util.GlueList;
|
||||
import net.jafama.FastMath;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Representation of a Loot Table pool, or a set of items to be fetched independently.
|
||||
*/
|
||||
public class Pool {
|
||||
private final int max;
|
||||
private final int min;
|
||||
private final ProbabilityCollection<Entry> entries;
|
||||
|
||||
/**
|
||||
* Instantiates a Pool from a JSON representation.
|
||||
*
|
||||
* @param pool The JSON Object to instantiate from.
|
||||
*/
|
||||
public Pool(JSONObject pool, TerraPlugin main) {
|
||||
entries = new ProbabilityCollection<>();
|
||||
Object amount = pool.get("rolls");
|
||||
if(amount instanceof Long) {
|
||||
max = FastMath.toIntExact((Long) amount);
|
||||
min = FastMath.toIntExact((Long) amount);
|
||||
} else {
|
||||
max = FastMath.toIntExact((Long) ((JSONObject) amount).get("max"));
|
||||
min = FastMath.toIntExact((Long) ((JSONObject) amount).get("min"));
|
||||
}
|
||||
|
||||
for(Object entryJSON : (JSONArray) pool.get("entries")) {
|
||||
Entry entry = new Entry((JSONObject) entryJSON, main);
|
||||
entries.add(entry, FastMath.toIntExact(entry.getWeight()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of items from the pool using the provided Random instance.
|
||||
*
|
||||
* @param r The Random instance to use.
|
||||
* @return List<ItemStack> - The list of items fetched.
|
||||
*/
|
||||
public List<ItemStack> getItems(Random r) {
|
||||
|
||||
int rolls = r.nextInt(max - min + 1) + min;
|
||||
List<ItemStack> items = new GlueList<>();
|
||||
for(int i = 0; i < rolls; i++) {
|
||||
items.add(entries.get(r).getItem(r));
|
||||
}
|
||||
return items;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.dfsek.terra.api.structures.loot.functions;
|
||||
|
||||
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Loot LootFunction fot setting the amount of an item.
|
||||
*/
|
||||
public class AmountFunction implements LootFunction {
|
||||
private final int max;
|
||||
private final int min;
|
||||
|
||||
/**
|
||||
* Instantiates an AmountFunction.
|
||||
*
|
||||
* @param min Minimum amount.
|
||||
* @param max Maximum amount.
|
||||
*/
|
||||
public AmountFunction(int min, int max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the function to an ItemStack.
|
||||
*
|
||||
* @param original The ItemStack on which to apply the function.
|
||||
* @param r The Random instance to use.
|
||||
* @return - ItemStack - The mutated ItemStack.
|
||||
*/
|
||||
@Override
|
||||
public ItemStack apply(ItemStack original, Random r) {
|
||||
original.setAmount(r.nextInt(max - min + 1) + min);
|
||||
return original;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.dfsek.terra.api.structures.loot.functions;
|
||||
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
import com.dfsek.terra.api.platform.inventory.item.Damageable;
|
||||
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Loot LootFunction for setting the damage on items in Loot Tables
|
||||
*/
|
||||
public class DamageFunction implements LootFunction {
|
||||
private final int max;
|
||||
private final int min;
|
||||
|
||||
/**
|
||||
* Instantiates a DamageFunction.
|
||||
*
|
||||
* @param min Minimum amount of damage (percentage, out of 100)
|
||||
* @param max Maximum amount of damage (percentage, out of 100)
|
||||
*/
|
||||
public DamageFunction(int min, int max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the function to an ItemStack.
|
||||
*
|
||||
* @param original The ItemStack on which to apply the function.
|
||||
* @param r The Random instance to use.
|
||||
* @return - ItemStack - The mutated ItemStack.
|
||||
*/
|
||||
@Override
|
||||
public ItemStack apply(ItemStack original, Random r) {
|
||||
double itemDurability = (r.nextDouble() * (max - min)) + min;
|
||||
Damageable damage = (Damageable) original.getItemMeta();
|
||||
damage.setDamage((int) (original.getType().getMaxDurability() - (itemDurability / 100) * original.getType().getMaxDurability()));
|
||||
original.setItemMeta((ItemMeta) damage);
|
||||
return original;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.dfsek.terra.api.structures.loot.functions;
|
||||
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
import com.dfsek.terra.api.platform.inventory.item.Enchantment;
|
||||
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
|
||||
import com.dfsek.terra.api.util.GlueList;
|
||||
import net.jafama.FastMath;
|
||||
import org.json.simple.JSONArray;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class EnchantFunction implements LootFunction {
|
||||
private final int min;
|
||||
private final int max;
|
||||
private final JSONArray disabled;
|
||||
private final TerraPlugin main;
|
||||
|
||||
|
||||
public EnchantFunction(int min, int max, JSONArray disabled, TerraPlugin main) {
|
||||
this.max = max;
|
||||
this.min = min;
|
||||
this.disabled = disabled;
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the function to an ItemStack.
|
||||
*
|
||||
* @param original The ItemStack on which to apply the function.
|
||||
* @param r The Random instance to use.
|
||||
* @return - ItemStack - The mutated ItemStack.
|
||||
*/
|
||||
@Override
|
||||
public ItemStack apply(ItemStack original, Random r) {
|
||||
double enchant = (r.nextDouble() * (max - min)) + min;
|
||||
List<Enchantment> possible = new GlueList<>();
|
||||
for(Enchantment ench : main.getItemHandle().getEnchantments()) {
|
||||
if(ench.canEnchantItem(original) && (disabled == null || !this.disabled.contains(ench.getID()))) {
|
||||
possible.add(ench);
|
||||
}
|
||||
}
|
||||
int numEnchant = (r.nextInt((int) FastMath.abs(enchant)) / 10 + 1);
|
||||
Collections.shuffle(possible);
|
||||
ItemMeta meta = original.getItemMeta();
|
||||
iter:
|
||||
for(int i = 0; i < numEnchant && i < possible.size(); i++) {
|
||||
Enchantment chosen = possible.get(i);
|
||||
for(Enchantment ench : meta.getEnchantments().keySet()) {
|
||||
if(chosen.conflictsWith(ench)) continue iter;
|
||||
}
|
||||
int lvl = r.nextInt(1 + (int) (((enchant / 40 > 1) ? 1 : enchant / 40) * (chosen.getMaxLevel())));
|
||||
try {
|
||||
meta.addEnchantment(chosen, FastMath.max(lvl, 1));
|
||||
} catch(IllegalArgumentException e) {
|
||||
main.getLogger().warning("Attempted to enchant " + original.getType() + " with " + chosen + " at level " + FastMath.max(lvl, 1) + ", but an unexpected exception occurred! Usually this is caused by a misbehaving enchantment plugin.");
|
||||
}
|
||||
}
|
||||
original.setItemMeta(meta);
|
||||
return original;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.dfsek.terra.api.structures.loot.functions;
|
||||
|
||||
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Interface for mutating items in Loot Tables.
|
||||
*/
|
||||
public interface LootFunction {
|
||||
/**
|
||||
* Applies the function to an ItemStack.
|
||||
*
|
||||
* @param original The ItemStack on which to apply the function.
|
||||
* @param r The Random instance to use.
|
||||
* @return - ItemStack - The mutated ItemStack.
|
||||
*/
|
||||
ItemStack apply(ItemStack original, Random r);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user