Compare commits

...

147 Commits

Author SHA1 Message Date
dfsek 1df09f44ea add BiomeCreationEvent 2021-05-11 15:34:02 -07:00
dfsek fa8a6f38cc addon Platform annotation 2021-05-11 10:04:27 -07:00
dfsek f83dcd802c Merge remote-tracking branch 'origin/master' 2021-05-11 09:03:14 -07:00
dfsek 808aa50f5f update config.yml 2021-05-11 09:02:59 -07:00
dfsek e00271e493 Merge pull request #162 from PolyhedralDev/dev/fabric-late-init
initialize later
2021-05-10 23:14:57 -07:00
dfsek 76bf245e16 type check ChunkGenerator in PopulatorFeature 2021-05-10 22:52:34 -07:00
dfsek 37e441206a fix getHandle overwrite conflicts and annotate getHandle methods as @Intrinsic. 2021-05-10 01:11:22 -07:00
dfsek 5376f7e22e fix server init 2021-05-10 01:03:13 -07:00
dfsek 1186fc6624 bump version 2021-05-05 15:24:55 -07:00
dfsek a1b3680643 initialize later 2021-05-05 15:22:02 -07:00
dfsek fd48f5f110 Merge pull request #158 from PolyhedralDev/dev/fabric-locate
Override structure location on Fabric
2021-05-04 16:45:25 -07:00
dfsek 77a4c95c4a override structure location on Fabric 2021-05-04 16:44:43 -07:00
dfsek dbc60b1d82 Merge pull request #153 from PolyhedralDev/dev/fabric-mixins
Implement Terra interfaces directly in Minecraft classes using Mixin.
2021-05-04 16:16:31 -07:00
dfsek ed942bb997 update README.md 2021-05-04 16:13:05 -07:00
dfsek 6866084872 SignBlockEntityMixin cleanup 2021-05-04 16:10:37 -07:00
dfsek 4c77419dcd fix sign getText on server 2021-05-04 15:04:53 -07:00
dfsek ecba6e0843 Merge remote-tracking branch 'origin/dev/fabric-mixins' into dev/fabric-mixins 2021-05-04 09:21:21 -07:00
dfsek 86dcb476f1 update README with modern build instructions and Forge download links 2021-05-04 09:21:12 -07:00
dfsek 13e0857882 merge FabricEnumAdapter into FabricAdapter 2021-05-03 22:49:21 -07:00
dfsek bf93a9239c bump version 2021-05-03 22:28:01 -07:00
dfsek 2d18aab709 fix funky yaml formatting 2021-05-03 22:13:42 -07:00
dfsek a1359da374 terrascript trig functions 2021-05-03 22:13:32 -07:00
dfsek f7bda835f9 fix itemmeta application 2021-05-03 20:52:03 -07:00
dfsek 7595896831 fix refmap issues 2021-05-03 20:40:56 -07:00
dfsek 6614d19845 suppress warnings 2021-05-03 20:14:06 -07:00
dfsek 6209b86560 mixin maintenance 2021-05-03 20:12:48 -07:00
dfsek a30859a3d4 dont try to remap Terra interfaces 2021-05-03 20:08:13 -07:00
dfsek ddbb46289b add package-info.java to implementation mixin package. 2021-05-03 20:03:25 -07:00
dfsek 64c35a9609 refactor Fabric project 2021-05-03 20:02:08 -07:00
dfsek f21069ab2e fix cache misses 2021-05-03 19:43:52 -07:00
dfsek 457729b832 replace most access wideners with mixins 2021-05-03 19:33:57 -07:00
dfsek 756f04a0b3 implement LockableContainerBlockEntityMixin 2021-05-03 18:38:40 -07:00
dfsek 5ee32cc3ba add ConfiguredFeatureMixin 2021-05-03 17:35:43 -07:00
dfsek 955558bc21 implement BlockMixin 2021-05-03 11:37:54 -07:00
dfsek c43a872c23 finish blockstate mixins 2021-05-03 11:27:36 -07:00
dfsek de41b92d5d add SignBlockEntityMixin 2021-05-03 10:27:40 -07:00
dfsek 03091230ed refactor mixins 2021-05-03 10:09:21 -07:00
dfsek a8c88915ea override chunkregion hashcode 2021-05-02 23:39:40 -07:00
dfsek 4cd4720101 fix loot NPE 2021-05-02 23:08:54 -07:00
dfsek 3b9280b19c start work on state mixins 2021-05-02 23:00:21 -07:00
dfsek 2d27e07441 implement BiomeMixin 2021-05-02 22:49:57 -07:00
dfsek 20a5762d2e refactor mixins 2021-05-02 22:48:21 -07:00
dfsek 146f71f704 finish World mixins 2021-05-02 22:45:34 -07:00
dfsek 1d4b0bc100 cleanup 2021-05-02 22:26:23 -07:00
dfsek 138ee0a448 refactor fabric handles 2021-05-02 22:22:32 -07:00
dfsek 2c8cae9d45 create ChunkGeneratorMixin 2021-05-02 22:21:50 -07:00
dfsek 061d2b6493 implement EntityTypeMixin 2021-05-02 21:48:06 -07:00
dfsek e71df936ab EnchantmentMixin 2021-05-02 21:35:39 -07:00
dfsek f4253acb78 item mixins 2021-05-02 21:27:25 -07:00
dfsek c12518fa49 delete FabricItem.java 2021-05-02 21:11:09 -07:00
dfsek 4704b2ebf7 implement ItemMixin 2021-05-02 21:10:48 -07:00
dfsek 89fdfdfb34 suppress warnings 2021-05-02 20:42:54 -07:00
dfsek 35d85f2aa3 PlayerEntityMixin and EntityMixin 2021-05-02 20:38:25 -07:00
dfsek c0368f1c6d implement ServerCommandSourceMixin 2021-05-02 20:17:59 -07:00
dfsek abc069046c add ProtoChunkMixin and WorldChunkMixin 2021-05-02 20:13:24 -07:00
dfsek 46d0b08068 implement ChunkRegionMixin 2021-05-02 19:49:59 -07:00
dfsek a7e3a0286e add -forge and -fabric to Modrinth version numbers. 2021-05-02 17:46:55 -07:00
dfsek 6da8924868 Merge pull request #145 from PolyhedralDev/dev/forge
Forge implementation
2021-05-02 17:38:56 -07:00
dfsek d9dd6afe4b Merge pull request #143 from solonovamax/improvement/better-gradle-performance
Improve gradle performance significantly
2021-05-02 17:37:36 -07:00
dfsek dfec26f789 fix forge modrinth task 2021-05-02 17:21:05 -07:00
dfsek d13be5e159 add Forge modrinth publish task 2021-05-02 17:16:03 -07:00
dfsek 51c5f70d64 forge jarfile nightmare "solution" 2021-05-02 17:08:59 -07:00
dfsek 05b1902c06 Merge pull request #151 from DJtheRedstoner/patch-mixin-ap
Fix mixin annotation processor issues
2021-05-02 15:47:32 -07:00
dfsek f4ae2cac68 add MixinGeneratorOptions 2021-05-02 15:46:03 -07:00
dfsek ea3995afce fix refmap name 2021-05-02 15:44:30 -07:00
dfsek c41d60c38f remove manual refmap 2021-05-02 15:43:12 -07:00
DJtheRedstoner 19edcbddd5 Fix mixin annotation processor issues
These issues were caused by CompilationConfig.configureCompilation()
overwriting JavaCompile's options.compilerArgs list which removed any
previously added arguments, including those added by fabric-loom and
mixingradle.
2021-05-02 18:17:18 -04:00
dfsek 4f65555e82 remove mixins until annotation processor gets fixed. 2021-05-02 14:37:34 -07:00
dfsek 9956cab507 dont use vanilla registries 2021-05-01 22:21:27 -07:00
dfsek fddf0c51b7 cleanup PopulationManager 2021-05-01 20:27:59 -07:00
dfsek e2a52afb67 remove methods only used for cursed Bukkit stuff from common World interface. 2021-05-01 19:07:19 -07:00
dfsek c8c3a33912 fix loot table issue 2021-05-01 18:40:31 -07:00
dfsek b178f69e47 Merge remote-tracking branch 'origin/dev/forge' into dev/forge 2021-05-01 18:20:23 -07:00
dfsek 049a56fcb0 Mixin on Forge 2021-05-01 18:20:11 -07:00
solonovamax 2d41dd8f08 Don't use all cores processors for tests
Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>
2021-05-01 16:53:45 -04:00
solonovamax aa9e33af1d Remove old and deprecated compile configuration + some minor refactoring
Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>
2021-05-01 16:53:45 -04:00
dfsek 02870805c7 hoist calculations in chunk generator 2021-04-30 09:35:15 -07:00
dfsek e493825ab7 bump version 2021-04-30 09:25:56 -07:00
dfsek 762b248641 update to latest Tectonic 2021-04-29 23:42:56 -07:00
dfsek f81ccee020 cleanup 2021-04-29 23:31:03 -07:00
dfsek 3561e5f30f commands on Forge 2021-04-29 23:19:49 -07:00
dfsek c67817b9d2 fix structure issues 2021-04-29 22:00:40 -07:00
dfsek 756619edb6 Forge actually loads to worlds now 2021-04-29 21:48:32 -07:00
dfsek ee1c889d54 world screen type 2021-04-29 21:11:26 -07:00
dfsek 9f3dcf07b6 Pack loading on Forge 2021-04-29 20:30:48 -07:00
dfsek 93a2f103f7 add pack.mcmeta 2021-04-29 16:41:14 -07:00
dfsek 3ea12ceeab start implementing terraplugin 2021-04-29 12:30:17 -07:00
dfsek ce8ec51ae4 forge actually loads now 2021-04-29 12:24:29 -07:00
dfsek 54bb4ef109 sort of working Forge project 2021-04-29 01:55:24 -07:00
dfsek 59b655ce5d working forge buildscript 2021-04-29 01:27:28 -07:00
solonovamax 4c1e1bb7d5 Improve gradle performance significantly
Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>
2021-04-28 20:43:53 -04:00
dfsek eee54f507e Merge pull request #138 from PolyhedralDev/dev/profilerimpl
Fancy stack-based profiler
2021-04-26 21:32:42 -07:00
dfsek 6f1b1611ab fix dumb gradle issue 2021-04-26 21:26:44 -07:00
dfsek 205499220d profile more things 2021-04-26 20:59:21 -07:00
dfsek a0c5631eba bump version 2021-04-26 20:46:36 -07:00
dfsek 9323abc788 document Profiler 2021-04-26 19:04:20 -07:00
dfsek 632f898dc8 implement Profiler#reset 2021-04-26 19:01:53 -07:00
dfsek 8737b0d984 resolve merge conflict 2021-04-25 17:12:42 -07:00
dfsek bcb68853d5 @SuppressWarnings go brrr 2021-04-25 17:11:50 -07:00
dfsek 8823d6d65e fix stack size assumption at profiler start 2021-04-25 17:11:50 -07:00
dfsek 5d3a2b6e84 profile more things 2021-04-25 17:11:50 -07:00
dfsek 23fb7753ab fancy unicode symbols B) 2021-04-25 17:11:50 -07:00
dfsek f8e7e343cb fix % parent issue 2021-04-25 17:11:50 -07:00
dfsek e5f4c5dc8d implement terrascript profiling 2021-04-25 17:11:49 -07:00
dfsek 8a10867e5f implement new profiler 2021-04-25 17:11:04 -07:00
dfsek da366a75e8 add autocloseable option 2021-04-25 17:09:08 -07:00
dfsek eb4bf74cc6 implement TerraPlugin#getProfier 2021-04-25 17:09:08 -07:00
dfsek 168c0ced13 improve performance in deep operations 2021-04-25 17:09:07 -07:00
dfsek 5d4bdb431b improve data output 2021-04-25 17:09:07 -07:00
dfsek 40188c671f basic profiler implementation 2021-04-25 17:09:07 -07:00
dfsek f396e0e5eb Merge pull request #133 from PolyhedralDev/ver/5.1.4
Fix minor Fabric issues
2021-04-16 09:01:29 -07:00
dfsek 942a8c9c8b Merge pull request #131 from xieve/fix-disable-config
Fixed populator disable config (#130)
2021-04-15 10:29:20 -07:00
dfsek 414dcdae3e use vanilla delegate spawn rules 2021-04-15 10:20:14 -07:00
dfsek 1195a6676f implement getHeight on Fabric 2021-04-15 10:00:22 -07:00
dfsek 5501f53056 implement TerraFabricPlugin#getWorld(long) 2021-04-15 09:59:13 -07:00
xieve 41d6e1c648 Fixed populator disable config (#130) 2021-04-15 18:18:27 +02:00
dfsek 5ac7257517 Merge pull request #119 from PolyhedralDev/ver/5.1.3
Fix Fabric Physics, add "dead" entry checking to registries.
2021-04-11 18:56:25 -07:00
dfsek 9f4f9702a6 bump version 2021-04-11 17:54:07 -07:00
dfsek 01d169256e properly relocate dependencies 2021-04-11 17:49:39 -07:00
dfsek 7a703ad091 add publication config to Fabric 2021-04-11 14:15:13 -07:00
dfsek ce9273c7e8 proper fluid updating on Fabric 2021-04-11 00:45:53 -07:00
dfsek 653a414ac1 should(tm) fix fabric physics 2021-04-10 23:49:02 -07:00
dfsek 2080db21ca warn about dead registry entries when debug mode is enabled 2021-04-10 19:22:41 -07:00
dfsek 8a933609ee Merge pull request #107 from PolyhedralDev/ver/5.1.2
5.1.2 LootPopulateEvent patch
2021-04-01 15:14:14 -07:00
dfsek ba4a50e234 add getStructureScript method to LootPopulateEvent 2021-04-01 15:03:48 -07:00
dfsek f8e8ce8bc2 Bump version 2021-03-31 20:50:17 -07:00
dfsek 0013d4e682 Merge pull request #106 from PolyhedralDev/ver/5.1.2
Add LootPopulateEvent and EntitySpawnEvent
2021-03-31 20:49:44 -07:00
dfsek 9a97f1178d release modrinth to beta channel 2021-03-31 08:34:17 -07:00
dfsek e6a551d84d add getter/setter for loot table in LootPopulateEvent 2021-03-30 09:23:21 -07:00
dfsek 92921430d8 add EntitySpawnEvent 2021-03-30 00:27:16 -07:00
dfsek 20c905aae4 add LootPopulateEvent 2021-03-30 00:19:32 -07:00
dfsek ec0730ef73 test commit so version is different B) 2021-03-29 21:14:34 -07:00
dfsek e4576b3405 Add modrinth publish task 2021-03-29 21:09:36 -07:00
dfsek c5800970a8 i totally didnt forget to bump version 2021-03-29 16:39:10 -07:00
dfsek 8f88b1c156 Merge pull request #101 from PolyhedralDev/ver/5.1.1
API to add populators, Buildscript improvements
2021-03-29 16:26:59 -07:00
dfsek 1360994a67 Add options to disable default populators 2021-03-29 11:56:16 -07:00
dfsek e00b28d27e remove sysout 2021-03-29 10:07:25 -07:00
dfsek c5ff5c101d custom biome color configuration 2021-03-29 09:52:54 -07:00
dfsek b1a1001c49 clean up buildscripts 2021-03-26 08:50:58 -07:00
dfsek 77d5162e73 add API for addons to register populators 2021-03-23 11:40:22 -07:00
dfsek 2e8cd54ac2 Merge pull request #96 from PolyhedralDev/ver/5.1.0
Address several issues
2021-03-17 10:53:32 -07:00
dfsek 28222c074e bump version 2021-03-16 22:29:13 -07:00
dfsek 1b70766a17 remove legacy fractal trees (will be available in an addon) 2021-03-16 21:49:08 -07:00
dfsek cda2d4688c implement DynamicBlockFunction 2021-03-16 21:20:02 -07:00
dfsek 5028582198 add smart waterlog 2021-03-16 21:04:56 -07:00
dfsek 5458564cfa fix CommandTest issues 2021-03-16 11:06:58 -07:00
dfsek 7f11373f75 Merge pull request #80 from PolyhedralDev/ver/5.0.0
Addon loader, fleshed out addon API, and Fabric finalization
2021-03-16 10:45:42 -07:00
250 changed files with 5676 additions and 2626 deletions
+1 -1
View File
@@ -342,6 +342,6 @@ ij_json_wrap_long_lines = false
indent_size = 2
ij_yaml_keep_indents_on_empty_lines = true
ij_yaml_keep_line_breaks = true
ij_yaml_space_before_colon = true
ij_yaml_space_before_colon = false
ij_yaml_spaces_within_braces = true
ij_yaml_spaces_within_brackets = true
+25 -9
View File
@@ -7,20 +7,36 @@ to your specifications, with no knowledge of Java required.
* Paper+ servers (Paper, Tuinity, Purpur, etc): [SpigotMC](https://www.spigotmc.org/resources/85151/)
* Fabric: [Modrinth](https://modrinth.com/mod/terra) / [CurseForge](https://www.curseforge.com/minecraft/mc-mods/terra-world-generator)
* Forge: [Modrinth](https://modrinth.com/mod/terra) / [CurseForge](https://www.curseforge.com/minecraft/mc-mods/terra-world-generator)
## Building and running Terra
## Building and Running Terra
To build, simply run `./gradlew build` (`gradlew.bat build` on Windows). This will produce a jar in `build/libs`
called `Terra-[CURRENT VERSION].jar`. You can put this right into your plugins dir, along with the correct Gaea version.
To build, simply run `./gradlew build` (`gradlew.bat build` on Windows). This will build all platforms, and
produce JARs in `platforms/<platform>/build/libs`
If you would like to test it with a default server config, just run `./gradlew setupServer` or
`./gradlew.bat setupServer` to set up the server, then `./gradlew testWithPaper` or `gradlew.bat testWithPaper` to run the server. If you
want a clean installation of the server, re-run the `setupServer` task. This will download a default server config
from [here](https://github.com/PolyhedralDev/WorldGenTestServer)
and install the server in the `target/server` directory, along with all the needed plugins.
### Production JARs:
* Bukkit: `Terra-<version>-shaded.jar`
* Fabric: `Terra-<version>-shaded-mapped.jar`
* Forge: `Terra-<version>-shaded.jar`
**Note: You will need to adjust the `NAME` variable `bukkit.yml` of the test server if you are not using the default Terra config.**
### Building a Specific Platform
To build a specific platform, run `gradlew :platforms:<platform>:build`.
JARs are produced in `platforms/<platform>/build/libs`.
### Running Minecraft in the IDE
To run Minecraft with Terra in the IDE (for testing) use the following tasks:
* Bukkit
* `installPaper` - Install a [Paper](https://github.com/PaperMC/Paper) test server. (Only needs to be run once).
* `installPurpur` - Install a [Purpur](https://github.com/pl3xgaming/Purpur) test server. (Only needs to be run once).
* `runPaper` - Run the Paper test server with Terra (`installPaper` must have been run previously).
* `runPurpur` - Run the Purpur test server with Terra (`installPurpur` must have been run previously).
* Fabric
* `runClient` - Run a Minecraft client with Terra installed.
* `runServer` - Run a Minecraft server with Terra installed.
* Forge
* `runClient` - Run a Minecraft client with Terra installed.
* `runServer` - Run a Minecraft server with Terra installed.
## Contributing
Contributions are welcome! If you want to see a feature in Terra, please, open an issue, or implement it yourself and
submit a PR!
+19 -2
View File
@@ -1,10 +1,27 @@
import com.dfsek.terra.getGitHash
val versionObj = Version("5", "0", "0", true)
val versionObj = Version("5", "3", "1", true)
allprojects {
version = versionObj
group = "com.dfsek.terra"
tasks.withType<JavaCompile>().configureEach {
options.isFork = true
options.isIncremental = true
}
tasks.withType<Test>().configureEach {
useJUnitPlatform()
maxHeapSize = "2G"
ignoreFailures = false
failFast = true
maxParallelForks = (Runtime.getRuntime().availableProcessors() - 1).takeIf { it > 0 } ?: 1
reports.html.isEnabled = false
reports.junitXml.isEnabled = false
}
}
/**
* Version class that does version stuff.
@@ -18,4 +35,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()}"
}
}
}
@@ -7,30 +7,15 @@ 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()
val stdout = ByteArrayOutputStream()
exec {
commandLine = mutableListOf("git", "rev-parse", "--short", "HEAD")
standardOutput = stdout
@@ -3,14 +3,16 @@ package com.dfsek.terra
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.filter
import org.gradle.kotlin.dsl.withType
import org.gradle.kotlin.dsl.*
import org.gradle.language.jvm.tasks.ProcessResources
fun Project.configureCompilation() {
apply(plugin = "maven-publish")
apply(plugin = "idea")
configure<JavaPluginConvention> {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
@@ -19,7 +21,7 @@ fun Project.configureCompilation() {
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
doFirst {
options.compilerArgs = mutableListOf("-Xlint:all")
options.compilerArgs.add("-Xlint:all")
}
}
@@ -35,4 +37,19 @@ fun Project.configureCompilation() {
tasks.withType<Javadoc> {
options.encoding = "UTF-8"
}
tasks.withType<Jar> {
archiveBaseName.set("Terra-${archiveBaseName.get()}")
from("../LICENSE", "../../LICENSE")
}
tasks.register<Jar>("sourcesJar") {
archiveClassifier.set("sources")
}
tasks.register<Jar>("javadocJar") {
dependsOn("javadoc")
archiveClassifier.set("javadoc")
from(tasks.getByName<Javadoc>("javadoc").destinationDir)
}
}
@@ -1,13 +1,27 @@
package com.dfsek.terra
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.invoke
import org.gradle.kotlin.dsl.repositories
fun Project.configureDependencies() {
apply(plugin = "java")
apply(plugin = "java-library")
configurations {
val shaded = create("shaded")
val shadedApi = create("shadedApi")
shaded.extendsFrom(shadedApi)
getByName("api").extendsFrom(shadedApi)
val shadedImplementation = create("shadedImplementation")
shaded.extendsFrom(shadedImplementation)
getByName("implementation").extendsFrom(shadedImplementation)
}
repositories {
maven { url = uri("http://maven.enginehub.org/repo/") }
maven { url = uri("https://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/") }
@@ -18,9 +32,7 @@ fun Project.configureDependencies() {
dependencies {
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.7.0")
"testImplementation"("org.yaml:snakeyaml:1.27")
"testImplementation"("com.googlecode.json-simple:json-simple:1.1.1")
"testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.7.0")
"compileOnly"("org.jetbrains:annotations:20.1.0")
"testImplementation"("org.junit.jupiter:junit-jupiter-engine:5.7.0")
"api"("org.jetbrains:annotations:20.1.0")
}
}
@@ -14,26 +14,8 @@ 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") {
group = "terra"
doFirst {
file("${buildDir}/resources/main/packs/").deleteRecursively()
@@ -45,21 +27,6 @@ fun Project.configureDistribution() {
}
tasks["processResources"].dependsOn(downloadDefaultPacks)
tasks.withType<Jar> {
archiveBaseName.set("Terra-${archiveBaseName.get()}")
from("../LICENSE", "../../LICENSE")
}
tasks.register<Jar>("sourcesJar") {
archiveClassifier.set("sources")
}
tasks.register<Jar>("javadocJar") {
dependsOn("javadoc")
archiveClassifier.set("javadoc")
from(tasks.getByName<Javadoc>("javadoc").destinationDir)
}
tasks.named<ShadowJar>("shadowJar") {
// Tell shadow to download the packs
dependsOn(downloadDefaultPacks)
@@ -69,8 +36,14 @@ fun Project.configureDistribution() {
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")
relocate("org.objectweb.asm", "com.dfsek.terra.lib.asm")
relocate("com.google.errorprone", "com.dfsek.terra.lib.google.errorprone")
relocate("com.google.j2objc", "com.dfsek.terra.lib.google.j2objc")
relocate("org.checkerframework", "com.dfsek.terra.lib.checkerframework")
relocate("org.javax.annotation", "com.dfsek.terra.lib.javax.annotation")
relocate("org.json", "com.dfsek.terra.lib.json")
relocate("org.yaml", "com.dfsek.terra.lib.yaml")
minimize()
}
convention.getPlugin<BasePluginConvention>().archivesBaseName = project.name
+8 -4
View File
@@ -1,11 +1,14 @@
import com.dfsek.terra.configureCommon
import com.dfsek.terra.configureCompilation
import com.dfsek.terra.configureDependencies
plugins {
`java-library`
`maven-publish`
idea
}
configureCommon()
configureCompilation()
configureDependencies()
group = "com.dfsek.terra.common"
@@ -14,13 +17,14 @@ dependencies {
"shadedApi"("commons-io:commons-io:2.4")
"shadedApi"("com.dfsek:Paralithic:0.3.2")
"shadedApi"("com.dfsek:Tectonic:1.2.3")
"shadedApi"("com.dfsek:Tectonic:1.3.1")
"shadedApi"("net.jafama:jafama:2.3.2")
"shadedApi"("org.yaml:snakeyaml:1.27")
"shadedApi"("org.ow2.asm:asm:9.0")
"shadedApi"("commons-io:commons-io:2.6")
"compileOnly"("com.googlecode.json-simple:json-simple:1.1")
"shadedApi"("com.googlecode.json-simple:json-simple:1.1.1")
"shadedApi"("org.yaml:snakeyaml:1.27")
"compileOnly"("com.google.guava:guava:30.0-jre")
@@ -7,14 +7,19 @@ import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.LockedRegistry;
import com.dfsek.terra.api.util.JarUtil;
import com.dfsek.terra.api.util.logging.DebugLogger;
import com.dfsek.terra.api.util.logging.Logger;
import com.dfsek.terra.config.PluginConfig;
import com.dfsek.terra.config.lang.Language;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.profiler.Profiler;
import com.dfsek.terra.world.TerraWorld;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.jar.JarFile;
/**
* Represents a Terra mod/plugin instance.
@@ -64,4 +69,10 @@ public interface TerraPlugin extends LoaderRegistrar {
default void runPossiblyUnsafeTask(Runnable task) {
task.run();
}
Profiler getProfiler();
default JarFile getModJar() throws URISyntaxException, IOException {
return JarUtil.getJarFile();
}
}
@@ -0,0 +1,16 @@
package com.dfsek.terra.api.addons.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Optional annotation that specifies platforms
* addon is made for.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Platform {
String[] value();
}
@@ -65,7 +65,7 @@ public class TerraCommandManager implements CommandManager {
return;
}
if(commandClass.isAnnotationPresent(WorldCommand.class) && (!(sender instanceof Player) || !TerraWorld.isTerraWorld(((Player) sender).getWorld()))) {
if(commandClass.isAnnotationPresent(WorldCommand.class) && (!(sender instanceof Player) || !(((Player) sender).getWorld()).isTerraWorld())) {
sender.sendMessage("Command must be executed in a Terra world.");
return;
}
@@ -160,7 +160,6 @@ public class TerraCommandManager implements CommandManager {
if(field.isAnnotationPresent(SwitchTarget.class)) {
SwitchTarget switchTarget = field.getAnnotation(SwitchTarget.class);
if(!holder.switches.containsValue(switchTarget.value())) {
System.out.println(holder.switches);
throw new MalformedCommandException("Switch Target specifies nonexistent switch \"" + switchTarget.value() + "\"");
}
@@ -0,0 +1,20 @@
package com.dfsek.terra.api.event.events;
import com.dfsek.terra.api.util.mutable.MutableBoolean;
/**
* Abstract class containing basic {@link Cancellable} implementation.
*/
public abstract class AbstractCancellable implements Cancellable {
private final MutableBoolean cancelled = new MutableBoolean(false);
@Override
public boolean isCancelled() {
return cancelled.get();
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled.set(cancelled);
}
}
@@ -1,6 +1,5 @@
package com.dfsek.terra.api.event.events.world;
import com.dfsek.terra.api.event.events.Event;
import com.dfsek.terra.api.event.events.PackEvent;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
@@ -9,18 +8,24 @@ import com.dfsek.terra.world.TerraWorld;
/**
* Called upon initialization of a TerraWorld.
*/
public class TerraWorldLoadEvent implements Event {
public class TerraWorldLoadEvent implements PackEvent {
private final TerraWorld world;
private final ConfigPack pack;
public TerraWorldLoadEvent(TerraWorld world) {
public TerraWorldLoadEvent(TerraWorld world, ConfigPack pack) {
this.world = world;
this.pack = pack;
}
public TerraWorld getWorld() {
return world;
}
public WorldConfig getPack() {
public ConfigPack getPack() {
return pack;
}
public WorldConfig getWorldConfig() {
return world.getConfig();
}
}
@@ -0,0 +1,45 @@
package com.dfsek.terra.api.event.events.world.generation;
import com.dfsek.terra.api.event.events.PackEvent;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.structures.structure.buffer.items.BufferedEntity;
import com.dfsek.terra.config.pack.ConfigPack;
/**
* Called when an entity is spawned via {@link BufferedEntity}.
*/
public class EntitySpawnEvent implements PackEvent {
private final ConfigPack pack;
private final Entity entity;
private final Location location;
public EntitySpawnEvent(ConfigPack pack, Entity entity, Location location) {
this.pack = pack;
this.entity = entity;
this.location = location;
}
@Override
public ConfigPack getPack() {
return pack;
}
/**
* Get the entity that triggered the event.
*
* @return The entity.
*/
public Entity getEntity() {
return entity;
}
/**
* Get the location of the entity.
*
* @return Location of the entity.
*/
public Location getLocation() {
return location;
}
}
@@ -0,0 +1,80 @@
package com.dfsek.terra.api.event.events.world.generation;
import com.dfsek.terra.api.event.events.AbstractCancellable;
import com.dfsek.terra.api.event.events.Cancellable;
import com.dfsek.terra.api.event.events.PackEvent;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.block.state.Container;
import com.dfsek.terra.api.structures.loot.LootTable;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.structures.structure.buffer.items.BufferedLootApplication;
import com.dfsek.terra.config.pack.ConfigPack;
import org.jetbrains.annotations.NotNull;
/**
* Called when loot is populated via {@link BufferedLootApplication}.
*/
public class LootPopulateEvent extends AbstractCancellable implements PackEvent, Cancellable {
private final Block block;
private final Container container;
private LootTable table;
private final ConfigPack pack;
private final StructureScript script;
public LootPopulateEvent(Block block, Container container, LootTable table, ConfigPack pack, StructureScript script) {
this.block = block;
this.container = container;
this.table = table;
this.pack = pack;
this.script = script;
}
@Override
public ConfigPack getPack() {
return pack;
}
/**
* Get the block containing the tile entity loot is applied to.
*
* @return Block at which loot is applied.
*/
public Block getBlock() {
return block;
}
/**
* Get the {@link Container} representing the inventory.
*
* @return Inventory recieving loot.
*/
public Container getContainer() {
return container;
}
/**
* Get the loot table to be populated.
* @return Loot table.
*/
public LootTable getTable() {
return table;
}
/**
* Set the loot table to be populated.
*
* @param table New loot table.
*/
public void setTable(@NotNull LootTable table) {
this.table = table;
}
/**
* Get the script used to generate the structure.
*
* @return Structure script.
*/
public StructureScript getStructureScript() {
return script;
}
}
@@ -6,4 +6,6 @@ public interface BlockType extends Handle {
BlockData getDefaultData();
boolean isSolid();
boolean isWater();
}
@@ -1,6 +1,7 @@
package com.dfsek.terra.api.platform.inventory;
import com.dfsek.terra.api.platform.Handle;
import com.dfsek.terra.api.platform.inventory.item.Damageable;
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
public interface ItemStack extends Handle {
@@ -13,4 +14,8 @@ public interface ItemStack extends Handle {
ItemMeta getItemMeta();
void setItemMeta(ItemMeta meta);
default boolean isDamageable() {
return getItemMeta() instanceof Damageable;
}
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.api.world.tree;
package com.dfsek.terra.api.platform.world;
import com.dfsek.terra.api.math.vector.Location;
@@ -6,6 +6,8 @@ import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import java.io.File;
import java.util.UUID;
@@ -17,20 +19,12 @@ public interface World extends Handle {
ChunkGenerator getGenerator();
String getName();
UUID getUID();
boolean isChunkGenerated(int x, int z);
Chunk getChunkAt(int x, int z);
default Chunk getChunkAt(Location location) {
return getChunkAt(location.getBlockX() >> 4, location.getBlockZ() >> 4);
}
File getWorldFolder();
Block getBlockAt(int x, int y, int z);
default Block getBlockAt(Location l) {
@@ -40,4 +34,12 @@ public interface World extends Handle {
Entity spawnEntity(Location location, EntityType entityType);
int getMinHeight();
default boolean isTerraWorld() {
return getGenerator().getHandle() instanceof GeneratorWrapper;
}
default TerraChunkGenerator getTerraGenerator() {
return ((GeneratorWrapper) getGenerator().getHandle()).getHandle();
}
}
@@ -34,8 +34,8 @@ public class DamageFunction implements LootFunction {
@Override
public ItemStack apply(ItemStack original, Random r) {
if(original == null) return null;
if(!original.isDamageable()) return original;
ItemMeta meta = original.getItemMeta();
if(!(meta instanceof Damageable)) return original;
double itemDurability = (r.nextDouble() * (max - min)) + min;
Damageable damage = (Damageable) meta;
damage.setDamage((int) (original.getType().getMaxDurability() - (itemDurability / 100) * original.getType().getMaxDurability()));
@@ -21,6 +21,7 @@ import com.dfsek.terra.api.structures.script.builders.RecursionsFunctionBuilder;
import com.dfsek.terra.api.structures.script.builders.SetMarkFunctionBuilder;
import com.dfsek.terra.api.structures.script.builders.StateFunctionBuilder;
import com.dfsek.terra.api.structures.script.builders.StructureFunctionBuilder;
import com.dfsek.terra.api.structures.script.builders.UnaryBooleanFunctionBuilder;
import com.dfsek.terra.api.structures.script.builders.UnaryNumberFunctionBuilder;
import com.dfsek.terra.api.structures.script.builders.UnaryStringFunctionBuilder;
import com.dfsek.terra.api.structures.script.builders.ZeroArgFunctionBuilder;
@@ -28,6 +29,7 @@ import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.structure.buffer.Buffer;
import com.dfsek.terra.api.structures.structure.buffer.DirectBuffer;
import com.dfsek.terra.api.structures.structure.buffer.StructureBuffer;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.registry.config.FunctionRegistry;
import com.dfsek.terra.registry.config.LootRegistry;
import com.dfsek.terra.registry.config.ScriptRegistry;
@@ -38,6 +40,7 @@ import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Random;
import java.util.concurrent.ExecutionException;
@@ -51,14 +54,15 @@ public class StructureScript {
public StructureScript(InputStream inputStream, TerraPlugin main, ScriptRegistry registry, LootRegistry lootRegistry, FunctionRegistry functionRegistry) throws ParseException {
Parser parser;
try {
parser = new Parser(IOUtils.toString(inputStream));
parser = new Parser(IOUtils.toString(inputStream, Charset.defaultCharset()));
} catch(IOException e) {
throw new RuntimeException(e);
}
functionRegistry.forEach(parser::registerFunction); // Register registry functions.
parser.registerFunction("block", new BlockFunctionBuilder(main))
parser.registerFunction("block", new BlockFunctionBuilder(main, false))
.registerFunction("dynamicBlock", new BlockFunctionBuilder(main, true))
.registerFunction("check", new CheckFunctionBuilder(main))
.registerFunction("structure", new StructureFunctionBuilder(registry, main))
.registerFunction("randomInt", new RandomFunctionBuilder())
@@ -66,11 +70,12 @@ public class StructureScript {
.registerFunction("setMark", new SetMarkFunctionBuilder())
.registerFunction("getMark", new GetMarkFunctionBuilder())
.registerFunction("pull", new PullFunctionBuilder(main))
.registerFunction("loot", new LootFunctionBuilder(main, lootRegistry))
.registerFunction("loot", new LootFunctionBuilder(main, lootRegistry, this))
.registerFunction("entity", new EntityFunctionBuilder(main))
.registerFunction("getBiome", new BiomeFunctionBuilder(main))
.registerFunction("getBlock", new CheckBlockFunctionBuilder())
.registerFunction("state", new StateFunctionBuilder(main))
.registerFunction("setWaterlog", new UnaryBooleanFunctionBuilder((waterlog, args) -> args.setWaterlog(waterlog)))
.registerFunction("originX", new ZeroArgFunctionBuilder<Number>(arguments -> arguments.getBuffer().getOrigin().getX(), Returnable.ReturnType.NUMBER))
.registerFunction("originY", new ZeroArgFunctionBuilder<Number>(arguments -> arguments.getBuffer().getOrigin().getY(), Returnable.ReturnType.NUMBER))
.registerFunction("originZ", new ZeroArgFunctionBuilder<Number>(arguments -> arguments.getBuffer().getOrigin().getZ(), Returnable.ReturnType.NUMBER))
@@ -84,6 +89,12 @@ public class StructureScript {
.registerFunction("ceil", new UnaryNumberFunctionBuilder(number -> FastMath.ceil(number.doubleValue())))
.registerFunction("log", new UnaryNumberFunctionBuilder(number -> FastMath.log(number.doubleValue())))
.registerFunction("round", new UnaryNumberFunctionBuilder(number -> FastMath.round(number.doubleValue())))
.registerFunction("sin", new UnaryNumberFunctionBuilder(number -> FastMath.sin(number.doubleValue())))
.registerFunction("cos", new UnaryNumberFunctionBuilder(number -> FastMath.cos(number.doubleValue())))
.registerFunction("tan", new UnaryNumberFunctionBuilder(number -> FastMath.tan(number.doubleValue())))
.registerFunction("asin", new UnaryNumberFunctionBuilder(number -> FastMath.asin(number.doubleValue())))
.registerFunction("acos", new UnaryNumberFunctionBuilder(number -> FastMath.acos(number.doubleValue())))
.registerFunction("atan", new UnaryNumberFunctionBuilder(number -> FastMath.atan(number.doubleValue())))
.registerFunction("max", new BinaryNumberFunctionBuilder((number, number2) -> FastMath.max(number.doubleValue(), number2.doubleValue())))
.registerFunction("min", new BinaryNumberFunctionBuilder((number, number2) -> FastMath.min(number.doubleValue(), number2.doubleValue())));
@@ -101,22 +112,31 @@ public class StructureScript {
* @param rotation Rotation of structure
* @return Whether generation was successful
*/
@SuppressWarnings("try")
public boolean execute(Location location, Random random, Rotation rotation) {
StructureBuffer buffer = new StructureBuffer(location);
boolean level = applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
buffer.paste();
return level;
try(ProfileFrame ignore = main.getProfiler().profile("terrascript:" + id)) {
StructureBuffer buffer = new StructureBuffer(location);
boolean level = applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
buffer.paste();
return level;
}
}
@SuppressWarnings("try")
public boolean execute(Location location, Chunk chunk, Random random, Rotation rotation) {
StructureBuffer buffer = computeBuffer(location, random, rotation);
buffer.paste(chunk);
return buffer.succeeded();
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_chunk:" + id)) {
StructureBuffer buffer = computeBuffer(location, random, rotation);
buffer.paste(chunk);
return buffer.succeeded();
}
}
@SuppressWarnings("try")
public boolean test(Location location, Random random, Rotation rotation) {
StructureBuffer buffer = computeBuffer(location, random, rotation);
return buffer.succeeded();
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_test:" + id)) {
StructureBuffer buffer = computeBuffer(location, random, rotation);
return buffer.succeeded();
}
}
private StructureBuffer computeBuffer(Location location, Random random, Rotation rotation) {
@@ -131,13 +151,19 @@ public class StructureScript {
}
}
@SuppressWarnings("try")
public boolean executeInBuffer(Buffer buffer, Random random, Rotation rotation, int recursions) {
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, recursions));
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_recursive:" + id)) {
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, recursions));
}
}
@SuppressWarnings("try")
public boolean executeDirect(Location location, Random random, Rotation rotation) {
DirectBuffer buffer = new DirectBuffer(location);
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
try(ProfileFrame ignore = main.getProfiler().profile("terrascript_direct:" + id)) {
DirectBuffer buffer = new DirectBuffer(location);
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, 0));
}
}
public String getId() {
@@ -146,7 +172,7 @@ public class StructureScript {
private boolean applyBlock(TerraImplementationArguments arguments) {
try {
return !block.apply(arguments).getLevel().equals(Block.ReturnLevel.FAIL);
return block.apply(arguments).getLevel() != Block.ReturnLevel.FAIL;
} catch(RuntimeException e) {
main.logger().severe("Failed to generate structure at " + arguments.getBuffer().getOrigin() + ": " + e.getMessage());
main.getDebugLogger().stack(e);
@@ -11,6 +11,7 @@ public class TerraImplementationArguments implements ImplementationArguments {
private final Rotation rotation;
private final Random random;
private final int recursions;
private boolean waterlog = false;
public TerraImplementationArguments(Buffer buffer, Rotation rotation, Random random, int recursions) {
this.buffer = buffer;
@@ -34,4 +35,12 @@ public class TerraImplementationArguments implements ImplementationArguments {
public Rotation getRotation() {
return rotation;
}
public boolean isWaterlog() {
return waterlog;
}
public void setWaterlog(boolean waterlog) {
this.waterlog = waterlog;
}
}
@@ -5,24 +5,30 @@ import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.constants.BooleanConstant;
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.api.structures.script.functions.AbstractBlockFunction;
import com.dfsek.terra.api.structures.script.functions.BlockFunction;
import com.dfsek.terra.api.structures.script.functions.DynamicBlockFunction;
import com.dfsek.terra.api.structures.tokenizer.Position;
import java.util.List;
public class BlockFunctionBuilder implements FunctionBuilder<BlockFunction> {
public class BlockFunctionBuilder implements FunctionBuilder<AbstractBlockFunction> {
private final TerraPlugin main;
private final boolean dynamic;
public BlockFunctionBuilder(TerraPlugin main) {
public BlockFunctionBuilder(TerraPlugin main, boolean dynamic) {
this.main = main;
this.dynamic = dynamic;
}
@SuppressWarnings("unchecked")
@Override
public BlockFunction build(List<Returnable<?>> argumentList, Position position) throws ParseException {
public AbstractBlockFunction build(List<Returnable<?>> argumentList, Position position) throws ParseException {
if(argumentList.size() < 4) throw new ParseException("Expected data", position);
Returnable<Boolean> booleanReturnable = new BooleanConstant(true, position);
if(argumentList.size() == 5) booleanReturnable = (Returnable<Boolean>) argumentList.get(4);
if(dynamic)
return new DynamicBlockFunction((Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1), (Returnable<Number>) argumentList.get(2), (Returnable<String>) argumentList.get(3), booleanReturnable, main, position);
return new BlockFunction((Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1), (Returnable<Number>) argumentList.get(2), (Returnable<String>) argumentList.get(3), booleanReturnable, main, position);
}
@@ -3,6 +3,7 @@ package com.dfsek.terra.api.structures.script.builders;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.structures.script.functions.LootFunction;
import com.dfsek.terra.api.structures.tokenizer.Position;
import com.dfsek.terra.registry.config.LootRegistry;
@@ -12,16 +13,18 @@ import java.util.List;
public class LootFunctionBuilder implements FunctionBuilder<LootFunction> {
private final TerraPlugin main;
private final LootRegistry registry;
private final StructureScript script;
public LootFunctionBuilder(TerraPlugin main, LootRegistry registry) {
public LootFunctionBuilder(TerraPlugin main, LootRegistry registry, StructureScript script) {
this.main = main;
this.registry = registry;
this.script = script;
}
@SuppressWarnings("unchecked")
@Override
public LootFunction build(List<Returnable<?>> argumentList, Position position) {
return new LootFunction(registry, (Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1), (Returnable<Number>) argumentList.get(2), (Returnable<String>) argumentList.get(3), main, position);
return new LootFunction(registry, (Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1), (Returnable<Number>) argumentList.get(2), (Returnable<String>) argumentList.get(3), main, position, script);
}
@Override
@@ -0,0 +1,55 @@
package com.dfsek.terra.api.structures.script.builders;
import com.dfsek.terra.api.structures.parser.lang.ImplementationArguments;
import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.api.structures.parser.lang.variables.Variable;
import com.dfsek.terra.api.structures.script.TerraImplementationArguments;
import com.dfsek.terra.api.structures.tokenizer.Position;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
public class UnaryBooleanFunctionBuilder implements FunctionBuilder<Function<Void>> {
private final BiConsumer<Boolean, TerraImplementationArguments> function;
public UnaryBooleanFunctionBuilder(BiConsumer<Boolean, TerraImplementationArguments> function) {
this.function = function;
}
@Override
public Function<Void> build(List<Returnable<?>> argumentList, Position position) {
return new Function<Void>() {
@Override
public ReturnType returnType() {
return ReturnType.VOID;
}
@SuppressWarnings("unchecked")
@Override
public Void apply(ImplementationArguments implementationArguments, Map<String, Variable<?>> variableMap) {
function.accept(((Returnable<Boolean>) argumentList.get(0)).apply(implementationArguments, variableMap), (TerraImplementationArguments) implementationArguments);
return null;
}
@Override
public Position getPosition() {
return position;
}
};
}
@Override
public int argNumber() {
return 1;
}
@Override
public Returnable.ReturnType getArgument(int position) {
if(position == 0) return Returnable.ReturnType.BOOLEAN;
return null;
}
}
@@ -0,0 +1,54 @@
package com.dfsek.terra.api.structures.script.functions;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.structures.parser.lang.ImplementationArguments;
import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
import com.dfsek.terra.api.structures.parser.lang.variables.Variable;
import com.dfsek.terra.api.structures.script.TerraImplementationArguments;
import com.dfsek.terra.api.structures.structure.RotationUtil;
import com.dfsek.terra.api.structures.structure.buffer.items.BufferedBlock;
import com.dfsek.terra.api.structures.tokenizer.Position;
import net.jafama.FastMath;
import java.util.Map;
public abstract class AbstractBlockFunction implements Function<Void> {
protected final Returnable<Number> x, y, z;
protected final Returnable<String> blockData;
protected final TerraPlugin main;
private final Returnable<Boolean> overwrite;
private final Position position;
protected AbstractBlockFunction(Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Returnable<String> blockData, Returnable<Boolean> overwrite, TerraPlugin main, Position position) {
this.x = x;
this.y = y;
this.z = z;
this.blockData = blockData;
this.overwrite = overwrite;
this.main = main;
this.position = position;
}
void setBlock(ImplementationArguments implementationArguments, Map<String, Variable<?>> variableMap, TerraImplementationArguments arguments, BlockData rot) {
Vector2 xz = new Vector2(x.apply(implementationArguments, variableMap).doubleValue(), z.apply(implementationArguments, variableMap).doubleValue());
RotationUtil.rotateVector(xz, arguments.getRotation());
RotationUtil.rotateBlockData(rot, arguments.getRotation().inverse());
arguments.getBuffer().addItem(new BufferedBlock(rot, overwrite.apply(implementationArguments, variableMap), main, arguments.isWaterlog()), new Vector3(FastMath.roundToInt(xz.getX()), y.apply(implementationArguments, variableMap).doubleValue(), FastMath.roundToInt(xz.getZ())).toLocation(arguments.getBuffer().getOrigin().getWorld()));
}
@Override
public Position getPosition() {
return position;
}
@Override
public ReturnType returnType() {
return ReturnType.VOID;
}
}
@@ -1,67 +1,36 @@
package com.dfsek.terra.api.structures.script.functions;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
import com.dfsek.terra.api.structures.parser.lang.ImplementationArguments;
import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.constants.ConstantExpression;
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
import com.dfsek.terra.api.structures.parser.lang.variables.Variable;
import com.dfsek.terra.api.structures.script.TerraImplementationArguments;
import com.dfsek.terra.api.structures.structure.RotationUtil;
import com.dfsek.terra.api.structures.structure.buffer.items.BufferedBlock;
import com.dfsek.terra.api.structures.tokenizer.Position;
import net.jafama.FastMath;
import java.util.Map;
public class BlockFunction implements Function<Void> {
public class BlockFunction extends AbstractBlockFunction {
private final BlockData data;
private final Returnable<Number> x, y, z;
private final Position position;
private final Returnable<Boolean> overwrite;
private final TerraPlugin main;
public BlockFunction(Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Returnable<String> data, Returnable<Boolean> overwrite, TerraPlugin main, Position position) throws ParseException {
this.position = position;
this.main = main;
if(!(data instanceof ConstantExpression)) throw new ParseException("Block data must be constant", data.getPosition());
super(x, y, z, data, overwrite, main, position);
if(!(data instanceof ConstantExpression)) throw new ParseException("Block data must be constant", data.getPosition());
try {
this.data = main.getWorldHandle().createBlockData(((ConstantExpression<String>) data).getConstant());
} catch(IllegalArgumentException e) {
throw new ParseException("Could not parse block data", data.getPosition(), e);
}
this.x = x;
this.y = y;
this.z = z;
this.overwrite = overwrite;
}
@Override
public Void apply(ImplementationArguments implementationArguments, Map<String, Variable<?>> variableMap) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
BlockData rot = data.clone();
Vector2 xz = new Vector2(x.apply(implementationArguments, variableMap).doubleValue(), z.apply(implementationArguments, variableMap).doubleValue());
RotationUtil.rotateVector(xz, arguments.getRotation());
RotationUtil.rotateBlockData(rot, arguments.getRotation().inverse());
arguments.getBuffer().addItem(new BufferedBlock(rot, overwrite.apply(implementationArguments, variableMap), main), new Vector3(FastMath.roundToInt(xz.getX()), y.apply(implementationArguments, variableMap).doubleValue(), FastMath.roundToInt(xz.getZ())).toLocation(arguments.getBuffer().getOrigin().getWorld()));
setBlock(implementationArguments, variableMap, arguments, rot);
return null;
}
@Override
public Position getPosition() {
return position;
}
@Override
public ReturnType returnType() {
return ReturnType.VOID;
}
}
@@ -0,0 +1,31 @@
package com.dfsek.terra.api.structures.script.functions;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.structures.parser.lang.ImplementationArguments;
import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.variables.Variable;
import com.dfsek.terra.api.structures.script.TerraImplementationArguments;
import com.dfsek.terra.api.structures.tokenizer.Position;
import java.util.HashMap;
import java.util.Map;
public class DynamicBlockFunction extends AbstractBlockFunction {
private final Map<String, BlockData> data = new HashMap<>();
private final Position position;
public DynamicBlockFunction(Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Returnable<String> data, Returnable<Boolean> overwrite, TerraPlugin main, Position position) {
super(x, y, z, data, overwrite, main, position);
this.position = position;
}
@Override
public Void apply(ImplementationArguments implementationArguments, Map<String, Variable<?>> variableMap) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
BlockData rot = data.computeIfAbsent(blockData.apply(implementationArguments, variableMap), main.getWorldHandle()::createBlockData).clone();
setBlock(implementationArguments, variableMap, arguments, rot);
return null;
}
}
@@ -21,9 +21,11 @@ public class EntityFunction implements Function<Void> {
private final EntityType data;
private final Returnable<Number> x, y, z;
private final Position position;
private final TerraPlugin main;
public EntityFunction(Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Returnable<String> data, TerraPlugin main, Position position) throws ParseException {
this.position = position;
this.main = main;
if(!(data instanceof ConstantExpression)) throw new ParseException("Entity data must be constant", data.getPosition());
this.data = main.getWorldHandle().getEntity(((ConstantExpression<String>) data).getConstant());
@@ -39,7 +41,7 @@ public class EntityFunction implements Function<Void> {
RotationUtil.rotateVector(xz, arguments.getRotation());
arguments.getBuffer().addItem(new BufferedEntity(data), new Vector3(xz.getX(), y.apply(implementationArguments, variableMap).doubleValue(), xz.getZ()).toLocation(arguments.getBuffer().getOrigin().getWorld()));
arguments.getBuffer().addItem(new BufferedEntity(data, main), new Vector3(xz.getX(), y.apply(implementationArguments, variableMap).doubleValue(), xz.getZ()).toLocation(arguments.getBuffer().getOrigin().getWorld()));
return null;
}
@@ -8,6 +8,7 @@ import com.dfsek.terra.api.structures.parser.lang.ImplementationArguments;
import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
import com.dfsek.terra.api.structures.parser.lang.variables.Variable;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.structures.script.TerraImplementationArguments;
import com.dfsek.terra.api.structures.structure.RotationUtil;
import com.dfsek.terra.api.structures.structure.buffer.items.BufferedLootApplication;
@@ -23,8 +24,9 @@ public class LootFunction implements Function<Void> {
private final Returnable<Number> x, y, z;
private final Position position;
private final TerraPlugin main;
private final StructureScript script;
public LootFunction(LootRegistry registry, Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Returnable<String> data, TerraPlugin main, Position position) {
public LootFunction(LootRegistry registry, Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Returnable<String> data, TerraPlugin main, Position position, StructureScript script) {
this.registry = registry;
this.position = position;
this.data = data;
@@ -32,6 +34,7 @@ public class LootFunction implements Function<Void> {
this.y = y;
this.z = z;
this.main = main;
this.script = script;
}
@Override
@@ -49,7 +52,7 @@ public class LootFunction implements Function<Void> {
return null;
}
arguments.getBuffer().addItem(new BufferedLootApplication(table, main), new Vector3(FastMath.roundToInt(xz.getX()), y.apply(implementationArguments, variableMap).intValue(), FastMath.roundToInt(xz.getZ())).toLocation(arguments.getBuffer().getOrigin().getWorld()));
arguments.getBuffer().addItem(new BufferedLootApplication(table, main, script), new Vector3(FastMath.roundToInt(xz.getX()), y.apply(implementationArguments, variableMap).intValue(), FastMath.roundToInt(xz.getZ())).toLocation(arguments.getBuffer().getOrigin().getWorld()));
return null;
}
@@ -4,23 +4,30 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.data.Waterlogged;
public class BufferedBlock implements BufferedItem {
private final BlockData data;
private final boolean overwrite;
private final TerraPlugin main;
private final boolean waterlog;
public BufferedBlock(BlockData data, boolean overwrite, TerraPlugin main) {
public BufferedBlock(BlockData data, boolean overwrite, TerraPlugin main, boolean waterlog) {
this.data = data;
this.overwrite = overwrite;
this.main = main;
this.waterlog = waterlog;
}
@Override
public void paste(Location origin) {
Block block = origin.getBlock();
try {
if(overwrite || block.isEmpty()) block.setBlockData(data, false);
if(overwrite || block.isEmpty()) {
if(waterlog && data instanceof Waterlogged && block.getBlockData().getBlockType().isWater())
((Waterlogged) data).setWaterlogged(true);
block.setBlockData(data, false);
}
} catch(RuntimeException e) {
main.logger().severe("Failed to place block at location " + origin + ": " + e.getMessage());
main.getDebugLogger().stack(e);
@@ -1,18 +1,24 @@
package com.dfsek.terra.api.structures.structure.buffer.items;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.event.events.world.generation.EntitySpawnEvent;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.entity.EntityType;
public class BufferedEntity implements BufferedItem {
private final EntityType type;
private final TerraPlugin main;
public BufferedEntity(EntityType type) {
public BufferedEntity(EntityType type, TerraPlugin main) {
this.type = type;
this.main = main;
}
@Override
public void paste(Location origin) {
origin.clone().add(0.5, 0, 0.5).getWorld().spawnEntity(origin, type);
Entity entity = origin.clone().add(0.5, 0, 0.5).getWorld().spawnEntity(origin, type);
main.getEventManager().callEvent(new EntitySpawnEvent(entity.getWorld().getTerraGenerator().getConfigPack(), entity, entity.getLocation()));
}
}
@@ -1,35 +1,46 @@
package com.dfsek.terra.api.structures.structure.buffer.items;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.event.events.world.generation.LootPopulateEvent;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.Block;
import com.dfsek.terra.api.platform.block.state.BlockState;
import com.dfsek.terra.api.platform.block.state.Container;
import com.dfsek.terra.api.structures.loot.LootTable;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.util.FastRandom;
public class BufferedLootApplication implements BufferedItem {
private final LootTable table;
private final TerraPlugin main;
private final StructureScript structure;
public BufferedLootApplication(LootTable table, TerraPlugin main) {
public BufferedLootApplication(LootTable table, TerraPlugin main, StructureScript structure) {
this.table = table;
this.main = main;
this.structure = structure;
}
@Override
public void paste(Location origin) {
try {
BlockState data = origin.getBlock().getState();
Block block = origin.getBlock();
BlockState data = block.getState();
if(!(data instanceof Container)) {
main.logger().severe("Failed to place loot at " + origin + "; block " + data + " is not container.");
return;
}
Container container = (Container) data;
table.fillInventory(container.getInventory(), new FastRandom(origin.hashCode()));
LootPopulateEvent event = new LootPopulateEvent(block, container, table, block.getLocation().getWorld().getTerraGenerator().getConfigPack(), structure);
main.getEventManager().callEvent(event);
if(event.isCancelled()) return;
event.getTable().fillInventory(container.getInventory(), new FastRandom(origin.hashCode()));
data.update(false);
} catch(Exception e) {
main.logger().warning("Could not apply loot at " + origin + ": " + e.getMessage());
main.getDebugLogger().stack(e);
e.printStackTrace();
}
}
}
@@ -21,7 +21,7 @@ public class BufferedStateManipulator implements BufferedItem {
state.update(false);
} catch(Exception e) {
main.logger().warning("Could not apply BlockState at " + origin + ": " + e.getMessage());
main.getDebugLogger().stack(e);
e.printStackTrace();
}
}
}
@@ -53,6 +53,7 @@ public class Transformer<F, T> {
private final LinkedHashMap<Transform<F, T>, List<Validator<T>>> transforms = new LinkedHashMap<>();
@SafeVarargs
@SuppressWarnings("varargs")
public final Builder<F, T> addTransform(Transform<F, T> transform, Validator<T>... validators) {
transforms.put(transform, Arrays.asList(validators));
return this;
@@ -1,9 +1,13 @@
package com.dfsek.terra.api.util;
import com.dfsek.terra.api.TerraPlugin;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -32,4 +36,12 @@ public class JarUtil {
}
}
}
public static JarFile getJarFile() throws URISyntaxException, IOException {
return new JarFile(new File(getJarURL().toURI()));
}
public static URL getJarURL() {
return TerraPlugin.class.getProtectionDomain().getCodeSource().getLocation();
}
}
@@ -5,6 +5,14 @@ import org.jetbrains.annotations.NotNull;
public class MutableBoolean implements MutablePrimitive<Boolean> {
private boolean value;
public MutableBoolean() {
this.value = false;
}
public MutableBoolean(boolean value) {
this.value = value;
}
@Override
public Boolean get() {
return value;
@@ -0,0 +1,7 @@
package com.dfsek.terra.api.world.generation;
/**
* Marker interface that marks a feature as "chunkified" (only modifying one chunk at a time)
*/
public interface Chunkified {
}
@@ -1,8 +0,0 @@
package com.dfsek.terra.api.world.generation;
/**
* The phase of terrain generation. Used for modifying values based on the phase of generation.
*/
public enum GenerationPhase {
BASE, POPULATE, GENERATION_POPULATE, PALETTE_APPLY, POST_GEN
}
@@ -6,10 +6,10 @@ import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkData;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.world.generation.math.SamplerCache;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Random;
public interface TerraChunkGenerator {
@@ -32,4 +32,6 @@ public interface TerraChunkGenerator {
TerraPlugin getMain();
Sampler createSampler(int chunkX, int chunkZ, BiomeProvider provider, World world, int elevationSmooth);
List<TerraBlockPopulator> getPopulators();
}
@@ -1,32 +0,0 @@
package com.dfsek.terra.api.world.tree.fractal;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.entity.Entity;
import java.util.function.Consumer;
public class EntitySpawnHolder {
private final Location l;
private final Class<? extends Entity> e;
private final Consumer<Entity> c;
public EntitySpawnHolder(Location l, Class<? extends Entity> e, Consumer<Entity> c) {
this.l = l;
this.e = e;
this.c = c;
}
@SuppressWarnings("rawtypes")
public Class getEntity() {
return e;
}
public Consumer<Entity> getConsumer() {
return c;
}
public Location getLocation() {
return l;
}
}
@@ -1,48 +0,0 @@
package com.dfsek.terra.api.world.tree.fractal;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.entity.Entity;
import com.dfsek.terra.api.platform.entity.EntityType;
import com.dfsek.terra.api.util.collections.MaterialSet;
import java.util.Random;
import java.util.function.Consumer;
public abstract class FractalTree {
protected final TerraPlugin main;
public abstract MaterialSet getSpawnable();
/**
* Instantiates a TreeGrower at an origin location.
*/
public FractalTree(TerraPlugin plugin) {
this.main = plugin;
}
/**
* Sets a block in the tree's storage map to a material.
*
* @param l - The location to set.
* @param m - The material to which it will be set.
*/
public void setBlock(Location l, BlockData m) {
l.getBlock().setBlockData(m, false);
}
public TerraPlugin getMain() {
return main;
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
public abstract void grow(Location origin, Random random);
public void spawnEntity(Location spawn, EntityType type, Consumer<Entity> consumer) {
consumer.accept(spawn.getWorld().spawnEntity(spawn, type));
}
}
@@ -1,68 +0,0 @@
package com.dfsek.terra.api.world.tree.fractal;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import java.util.Random;
public class TreeGeometry {
private final FractalTree tree;
public TreeGeometry(FractalTree tree) {
this.tree = tree;
}
public static Vector3 getPerpendicular(Vector3 v) {
return v.getZ() < v.getX() ? new Vector3(v.getY(), -v.getX(), 0) : new Vector3(0, -v.getZ(), v.getY());
}
public FractalTree getTree() {
return tree;
}
public void generateSphere(Location l, BlockData m, int radius, boolean overwrite, Random r) {
generateSphere(l, new ProbabilityCollection<BlockData>().add(m, 1), radius, overwrite, r);
}
public void generateCylinder(Location l, BlockData m, int radius, int height, boolean overwrite, Random r) {
generateCylinder(l, new ProbabilityCollection<BlockData>().add(m, 1), radius, height, overwrite, r);
}
public void generateSphere(Location l, ProbabilityCollection<BlockData> m, int radius, boolean overwrite, Random r) {
for(int x = -radius; x <= radius; x++) {
for(int y = -radius; y <= radius; y++) {
for(int z = -radius; z <= radius; z++) {
Vector3 position = l.toVector().clone().add(new Vector3(x, y, z));
if(l.toVector().distance(position) <= radius + 0.5 && (overwrite || position.toLocation(l.getWorld()).getBlock().isEmpty()))
tree.setBlock(position.toLocation(l.getWorld()), m.get(r));
}
}
}
}
public void generateSponge(Location l, ProbabilityCollection<BlockData> m, int radius, boolean overwrite, int sponginess, Random r) {
for(int x = -radius; x <= radius; x++) {
for(int y = -radius; y <= radius; y++) {
for(int z = -radius; z <= radius; z++) {
Vector3 position = l.toVector().clone().add(new Vector3(x, y, z));
if(r.nextInt(100) < sponginess && l.toVector().distance(position) <= radius + 0.5 && (overwrite || position.toLocation(l.getWorld()).getBlock().isEmpty()))
tree.setBlock(position.toLocation(l.getWorld()), m.get(r));
}
}
}
}
public void generateCylinder(Location l, ProbabilityCollection<BlockData> m, int radius, int height, boolean overwrite, Random r) {
for(int x = -radius; x <= radius; x++) {
for(int y = 0; y <= height; y++) {
for(int z = -radius; z <= radius; z++) {
Vector3 position = l.toVector().clone().add(new Vector3(x, 0, z));
if(l.toVector().distance(position) <= radius + 0.5 && (overwrite || position.toLocation(l.getWorld()).getBlock().isEmpty()))
tree.setBlock(position.toLocation(l.getWorld()), m.get(r));
}
}
}
}
}
@@ -1,35 +0,0 @@
package com.dfsek.terra.api.world.tree.fractal.trees;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.api.world.tree.fractal.FractalTree;
import java.util.Random;
public class Cactus extends FractalTree {
@Override
public MaterialSet getSpawnable() {
return MaterialSet.get(main.getWorldHandle().createBlockData("minecraft:sand"),
main.getWorldHandle().createBlockData("minecraft:red_sand"));
}
/**
* Instantiates a TreeGrower at an origin location.
*/
public Cactus(TerraPlugin main) {
super(main);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
@Override
public void grow(Location origin, Random random) {
BlockData cactus = getMain().getWorldHandle().createBlockData("minecraft:cactus");
int h = random.nextInt(4) + 1;
for(int i = 0; i < h; i++) setBlock(origin.clone().add(0, i, 0), cactus);
}
}
@@ -1,57 +0,0 @@
package com.dfsek.terra.api.world.tree.fractal.trees;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.api.world.tree.fractal.FractalTree;
import com.dfsek.terra.api.world.tree.fractal.TreeGeometry;
import java.util.Random;
public class IceSpike extends FractalTree {
private final TreeGeometry geo;
private final ProbabilityCollection<BlockData> ice;
@Override
public MaterialSet getSpawnable() {
return MaterialSet.get(main.getWorldHandle().createBlockData("minecraft:stone"),
main.getWorldHandle().createBlockData("minecraft:gravel"),
main.getWorldHandle().createBlockData("minecraft:snow_block"),
main.getWorldHandle().createBlockData("minecraft:grass_block"));
}
/**
* Instantiates a TreeGrower at an origin location.
*/
public IceSpike(TerraPlugin main) {
super(main);
geo = new TreeGeometry(this);
WorldHandle handle = main.getWorldHandle();
ice = new ProbabilityCollection<BlockData>().add(handle.createBlockData("minecraft:packed_ice"), 95).add(handle.createBlockData("minecraft:blue_ice"), 5);
}
private double getOffset(Random r) {
return (r.nextDouble() - 0.5D);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
@Override
public void grow(Location origin, Random random) {
Vector3 direction = new Vector3(getOffset(random), 0, getOffset(random));
Location l1 = origin.clone();
int h = random.nextInt(16) + 8;
for(int i = 0; i < h; i++) {
geo.generateSponge(l1.clone().add(0, i, 0).add(direction.clone().multiply(i)), ice, (int) ((1 - ((double) i / h)) * 2 + 1), true, 80, random);
}
for(int i = 0; i < h / 3; i++) {
setBlock(l1.clone().add(0, h + i, 0).add(direction.clone().multiply(h + i)), ice.get(random));
}
}
}
@@ -1,66 +0,0 @@
package com.dfsek.terra.api.world.tree.fractal.trees;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.api.world.tree.fractal.FractalTree;
import com.dfsek.terra.api.world.tree.fractal.TreeGeometry;
import net.jafama.FastMath;
import java.util.Random;
public class OakTree extends FractalTree {
private final TreeGeometry geo;
@Override
public MaterialSet getSpawnable() {
return MaterialSet.get(main.getWorldHandle().createBlockData("minecraft:podzol"),
main.getWorldHandle().createBlockData("minecraft:grass_block"));
}
/**
* Instantiates a TreeGrower at an origin location.
*/
public OakTree(TerraPlugin main) {
super(main);
geo = new TreeGeometry(this);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
@Override
public void grow(Location origin, Random random) {
growBranch(origin.clone(), new Vector3(random.nextInt(5) - 2, random.nextInt(4) + 6, random.nextInt(5) - 2), 2, 0, random);
}
private void growBranch(Location l1, Vector3 diff, double d1, int recursions, Random r) {
BlockData wood = getMain().getWorldHandle().createBlockData("minecraft:oak_wood");
BlockData leaves = getMain().getWorldHandle().createBlockData("minecraft:oak_leaves");
if(recursions > 1) {
geo.generateSphere(l1, leaves, 1 + r.nextInt(2) + (3 - recursions), false, r);
if(recursions > 2) return;
}
if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI);
int d = (int) diff.length();
for(int i = 0; i < d; i++) {
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), wood, FastMath.max((int) d1, 0), true, r);
}
double runningAngle = (double) 45 / (recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.75).rotateAroundX(FastMath.toRadians(runningAngle + getNoise(r))).rotateAroundZ(FastMath.toRadians(getNoise(r))),
d1 - 1, recursions + 1, r);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.75).rotateAroundX(FastMath.toRadians(-runningAngle + getNoise(r))).rotateAroundZ(FastMath.toRadians(getNoise(r))),
d1 - 1, recursions + 1, r);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.75).rotateAroundZ(FastMath.toRadians(runningAngle + getNoise(r))).rotateAroundX(FastMath.toRadians(getNoise(r))),
d1 - 1, recursions + 1, r);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.75).rotateAroundZ(FastMath.toRadians(-runningAngle + getNoise(r))).rotateAroundX(FastMath.toRadians(getNoise(r))),
d1 - 1, recursions + 1, r);
}
private int getNoise(Random r) {
return r.nextInt(60) - 30;
}
}
@@ -1,56 +0,0 @@
package com.dfsek.terra.api.world.tree.fractal.trees;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.api.world.tree.fractal.FractalTree;
import java.util.Random;
public class ShatteredPillar extends FractalTree {
@Override
public MaterialSet getSpawnable() {
return MaterialSet.get(main.getWorldHandle().createBlockData("minecraft:end_stone"));
}
/**
* Instantiates a TreeGrower at an origin location.
*/
public ShatteredPillar(TerraPlugin main) {
super(main);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
* @param origin
* @param random
*/
@Override
public void grow(Location origin, Random random) {
BlockData obsidian = getMain().getWorldHandle().createBlockData("minecraft:obsidian");
int h = random.nextInt(5) + 8;
int max = h;
for(int i = -h; i < h; i++) setBlock(origin.clone().add(0, i, 0), obsidian);
h = h + (random.nextBoolean() ? random.nextInt(3) + 1 : -(random.nextInt(3) + 1));
int[] crystalLoc = new int[] {0, 0};
if(h > max) {
max = h;
crystalLoc = new int[] {1, 0};
}
for(int i = -h; i < h; i++) setBlock(origin.clone().add(1, i, 0), obsidian);
h = h + (random.nextBoolean() ? random.nextInt(3) + 1 : -(random.nextInt(3) + 1));
if(h > max) {
max = h;
crystalLoc = new int[] {0, 1};
}
for(int i = -h; i < h; i++) setBlock(origin.clone().add(0, i, 1), obsidian);
h = h + (random.nextBoolean() ? random.nextInt(3) + 1 : -(random.nextInt(3) + 1));
if(h > max) {
max = h;
crystalLoc = new int[] {1, 1};
}
for(int i = -h; i < h; i++) setBlock(origin.clone().add(1, i, 1), obsidian);
}
}
@@ -1,75 +0,0 @@
package com.dfsek.terra.api.world.tree.fractal.trees;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.api.world.tree.fractal.FractalTree;
import com.dfsek.terra.api.world.tree.fractal.TreeGeometry;
import net.jafama.FastMath;
import java.util.Random;
public class ShatteredTree extends FractalTree {
private final TreeGeometry geo;
private final ProbabilityCollection<BlockData> bark;
private final ProbabilityCollection<BlockData> leaves;
@Override
public MaterialSet getSpawnable() {
return MaterialSet.get(main.getWorldHandle().createBlockData("minecraft:end_stone"));
}
/**
* Instantiates a TreeGrower at an origin location.
*/
public ShatteredTree(TerraPlugin main) {
super(main);
geo = new TreeGeometry(this);
WorldHandle handle = main.getWorldHandle();
bark = new ProbabilityCollection<BlockData>()
.add(handle.createBlockData("minecraft:obsidian"), 1)
.add(handle.createBlockData("minecraft:black_concrete"), 1);
leaves = new ProbabilityCollection<BlockData>()
.add(handle.createBlockData("minecraft:purple_stained_glass"), 1)
.add(handle.createBlockData("minecraft:magenta_stained_glass"), 1);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
@Override
public void grow(Location origin, Random random) {
growBranch(origin.clone(), new Vector3(random.nextInt(5) - 2, random.nextInt(4) + 6, random.nextInt(5) - 2), 1, 0, random);
}
private void growBranch(Location l1, Vector3 diff, double d1, int recursions, Random r) {
if(recursions > 2) {
geo.generateSphere(l1, leaves, 1 + r.nextInt(2), false, r);
return;
}
if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI);
int d = (int) diff.length();
for(int i = 0; i < d; i++) {
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), bark, FastMath.max((int) d1, 0), true, r);
}
double runningAngle = (double) 45 / (recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.9).rotateAroundX(FastMath.toRadians(runningAngle + getNoise(r))).rotateAroundZ(FastMath.toRadians(getNoise(r))),
d1 - 1, recursions + 1, r);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.9).rotateAroundX(FastMath.toRadians(-runningAngle + getNoise(r))).rotateAroundZ(FastMath.toRadians(getNoise(r))),
d1 - 1, recursions + 1, r);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.9).rotateAroundZ(FastMath.toRadians(runningAngle + getNoise(r))).rotateAroundX(FastMath.toRadians(getNoise(r))),
d1 - 1, recursions + 1, r);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.9).rotateAroundZ(FastMath.toRadians(-runningAngle + getNoise(r))).rotateAroundX(FastMath.toRadians(getNoise(r))),
d1 - 1, recursions + 1, r);
}
private int getNoise(Random r) {
return r.nextInt(90) - 45;
}
}
@@ -1,36 +0,0 @@
package com.dfsek.terra.api.world.tree.fractal.trees;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.api.world.tree.fractal.FractalTree;
import java.util.Random;
public class SmallShatteredPillar extends FractalTree {
@Override
public MaterialSet getSpawnable() {
return MaterialSet.get(main.getWorldHandle().createBlockData("minecraft:end_stone"));
}
/**
* Instantiates a TreeGrower at an origin location.
*/
public SmallShatteredPillar(TerraPlugin main) {
super(main);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
* @param origin
* @param random
*/
@Override
public void grow(Location origin, Random random) {
int h = random.nextInt(5) + 5;
BlockData obsidian = getMain().getWorldHandle().createBlockData("minecraft:obsidian");
for(int i = -h; i < h; i++) setBlock(origin.clone().add(0, i, 0), obsidian);
}
}
@@ -1,75 +0,0 @@
package com.dfsek.terra.api.world.tree.fractal.trees;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.api.world.tree.fractal.FractalTree;
import com.dfsek.terra.api.world.tree.fractal.TreeGeometry;
import net.jafama.FastMath;
import java.util.Random;
public class SmallShatteredTree extends FractalTree {
private final TreeGeometry geo;
private final ProbabilityCollection<BlockData> bark;
private final ProbabilityCollection<BlockData> leaves;
@Override
public MaterialSet getSpawnable() {
return MaterialSet.get(main.getWorldHandle().createBlockData("minecraft:end_stone"));
}
/**
* Instantiates a TreeGrower at an origin location.
*/
public SmallShatteredTree(TerraPlugin main) {
super(main);
geo = new TreeGeometry(this);
WorldHandle handle = main.getWorldHandle();
bark = new ProbabilityCollection<BlockData>()
.add(handle.createBlockData("minecraft:obsidian"), 1)
.add(handle.createBlockData("minecraft:black_concrete"), 1);
leaves = new ProbabilityCollection<BlockData>()
.add(handle.createBlockData("minecraft:purple_stained_glass"), 1)
.add(handle.createBlockData("minecraft:magenta_stained_glass"), 1);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
@Override
public void grow(Location origin, Random random) {
growBranch(origin.clone(), new Vector3(random.nextInt(5) - 2, random.nextInt(3) + 4, random.nextInt(5) - 2), 1.5, 0, random);
}
private void growBranch(Location l1, Vector3 diff, double d1, int recursions, Random r) {
if(recursions > 2) {
geo.generateSphere(l1, leaves, 1 + r.nextInt(2) + (3 - recursions), false, r);
return;
}
if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI);
int d = (int) diff.length();
for(int i = 0; i < d; i++) {
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), bark, FastMath.max((int) d1, 0), true, r);
}
double runningAngle = (double) 45 / (recursions + 1);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.7).rotateAroundX(FastMath.toRadians(runningAngle + getNoise(r))).rotateAroundZ(FastMath.toRadians(getNoise(r))),
d1 - 1, recursions + 1, r);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.7).rotateAroundX(FastMath.toRadians(-runningAngle + getNoise(r))).rotateAroundZ(FastMath.toRadians(getNoise(r))),
d1 - 1, recursions + 1, r);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.7).rotateAroundZ(FastMath.toRadians(runningAngle + getNoise(r))).rotateAroundX(FastMath.toRadians(getNoise(r))),
d1 - 1, recursions + 1, r);
growBranch(l1.clone().add(diff), diff.clone().multiply(0.7).rotateAroundZ(FastMath.toRadians(-runningAngle + getNoise(r))).rotateAroundX(FastMath.toRadians(getNoise(r))),
d1 - 1, recursions + 1, r);
}
private int getNoise(Random r) {
return r.nextInt(90) - 45;
}
}
@@ -1,53 +0,0 @@
package com.dfsek.terra.api.world.tree.fractal.trees;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.api.world.tree.fractal.FractalTree;
import com.dfsek.terra.api.world.tree.fractal.TreeGeometry;
import net.jafama.FastMath;
import java.util.Random;
public class SpruceTree extends FractalTree {
private final TreeGeometry geo;
@Override
public MaterialSet getSpawnable() {
return MaterialSet.get(main.getWorldHandle().createBlockData("minecraft:podzol"),
main.getWorldHandle().createBlockData("minecraft:grass_block"));
}
/**
* Instantiates a TreeGrower at an origin location.
*/
public SpruceTree(TerraPlugin main) {
super(main);
geo = new TreeGeometry(this);
}
/**
* Grows the tree in memory. Intended to be invoked from an async thread.
*/
@Override
public void grow(Location origin, Random random) {
growTrunk(origin.clone(), new Vector3(0, 16 + random.nextInt(5), 0), random);
}
private void growTrunk(Location l1, Vector3 diff, Random r) {
if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI);
int d = (int) diff.length();
int rad = 7;
BlockData wood = getMain().getWorldHandle().createBlockData("minecraft:spruce_wood");
BlockData leaves = getMain().getWorldHandle().createBlockData("minecraft:spruce_leave");
for(int i = 0; i < d; i++) {
geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), wood, (int) ((i > d * 0.65) ? 0.5 : 1.5), true, r);
if(i > 3)
geo.generateCylinder(l1.clone().add(diff.clone().multiply((double) i / d)), leaves, (int) (((6 - (i % 4))) * (1.25 - ((double) i / d))), 1, false, r);
}
setBlock(l1.clone().add(diff), leaves);
setBlock(l1.clone().add(diff).add(0, 1, 0), leaves);
}
}
@@ -4,16 +4,10 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileQueryCommand implements CommandTemplate {
@Inject
@@ -21,8 +15,9 @@ public class ProfileQueryCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
player.sendMessage(world.getProfiler().getResultsFormatted());
StringBuilder data = new StringBuilder("Terra Profiler data dump: \n");
main.getProfiler().getTimings().forEach((id, timings) -> data.append(id).append(": ").append(timings.toString()).append('\n'));
main.logger().info(data.toString());
sender.sendMessage("Profiler data dumped to console.");
}
}
@@ -4,16 +4,10 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileResetCommand implements CommandTemplate {
@Inject
@@ -21,9 +15,7 @@ public class ProfileResetCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
world.getProfiler().reset();
player.sendMessage("Profiler reset.");
main.getProfiler().reset();
sender.sendMessage("Profiler reset.");
}
}
@@ -4,16 +4,10 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileStartCommand implements CommandTemplate {
@Inject
@@ -21,9 +15,7 @@ public class ProfileStartCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
world.getProfiler().setProfiling(true);
player.sendMessage("Profiling enabled.");
main.getProfiler().start();
sender.sendMessage("Profiling enabled.");
}
}
@@ -4,16 +4,10 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.CommandTemplate;
import com.dfsek.terra.api.command.annotation.Command;
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.platform.CommandSender;
import com.dfsek.terra.api.platform.entity.Player;
import com.dfsek.terra.world.TerraWorld;
@Command
@WorldCommand
@PlayerCommand
@DebugCommand
public class ProfileStopCommand implements CommandTemplate {
@Inject
@@ -21,9 +15,7 @@ public class ProfileStopCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
Player player = (Player) sender;
TerraWorld world = main.getWorld(player.getWorld());
world.getProfiler().setProfiling(false);
player.sendMessage("Profiling disabled.");
main.getProfiler().stop();
sender.sendMessage("Profiling disabled.");
}
}
@@ -63,8 +63,6 @@ public class StructureLoadCommand implements CommandTemplate {
@Override
public void execute(CommandSender sender) {
System.out.println(rotation);
Player player = (Player) sender;
long t = System.nanoTime();
@@ -69,12 +69,12 @@ public class PluginConfig implements ConfigTemplate {
ConfigLoader loader = new ConfigLoader();
loader.load(this, file);
if(dumpDefaultConfig) { // Don't dump default config if already loaded.
try(JarFile jar = new JarFile(new File(TerraPlugin.class.getProtectionDomain().getCodeSource().getLocation().toURI()))) {
try(JarFile jar = main.getModJar()) {
JarUtil.copyResourcesToDirectory(jar, "packs", new File(main.getDataFolder(), "packs").toString());
} catch(IOException | URISyntaxException e) {
main.getDebugLogger().error("Failed to dump default config files!");
e.printStackTrace();
main.getDebugLogger().error("Report this to Terra!");
main.getDebugLogger().error("Either you're on Forge, or this is a bug. If it's the latter, report this to Terra!");
}
}
} catch(ConfigException | IOException e) {
@@ -4,7 +4,10 @@ import com.dfsek.terra.api.platform.world.Biome;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.SeededBuilder;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.config.templates.BiomeTemplate;
public interface BiomeBuilder extends SeededBuilder<TerraBiome> {
ProbabilityCollection<Biome> getVanillaBiomes();
BiomeTemplate getTemplate();
}
@@ -66,4 +66,9 @@ public class UserDefinedBiomeBuilder implements BiomeBuilder {
public ProbabilityCollection<Biome> getVanillaBiomes() {
return template.getVanilla();
}
@Override
public BiomeTemplate getTemplate() {
return template;
}
}
@@ -9,9 +9,6 @@ import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
import com.dfsek.terra.api.platform.world.generator.GeneratorWrapper;
import java.io.File;
import java.util.UUID;
public class DummyWorld implements World {
@Override
public Object getHandle() {
@@ -33,31 +30,11 @@ public class DummyWorld implements World {
return () -> (GeneratorWrapper) () -> null;
}
@Override
public String getName() {
return "DUMMY";
}
@Override
public UUID getUID() {
return UUID.randomUUID();
}
@Override
public boolean isChunkGenerated(int x, int z) {
return false;
}
@Override
public Chunk getChunkAt(int x, int z) {
throw new UnsupportedOperationException("Cannot get chunk in DummyWorld");
}
@Override
public File getWorldFolder() {
throw new UnsupportedOperationException("Cannot get folder of DummyWorld");
}
@Override
public Block getBlockAt(int x, int y, int z) {
throw new UnsupportedOperationException("Cannot get block in DummyWorld");
@@ -1,7 +1,7 @@
package com.dfsek.terra.config.factories;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.world.tree.Tree;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.config.templates.TreeTemplate;
import com.dfsek.terra.world.population.items.tree.TerraTree;
@@ -1,5 +1,6 @@
package com.dfsek.terra.config.fileloaders;
import com.dfsek.tectonic.config.Configuration;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.terra.api.util.GlueList;
@@ -18,8 +19,12 @@ public abstract class Loader {
*
* @param consumer Something to do with the streams.
*/
public Loader then(ExceptionalConsumer<List<InputStream>> consumer) throws ConfigException {
consumer.accept(new GlueList<>(streams.values()));
public Loader then(ExceptionalConsumer<List<Configuration>> consumer) throws ConfigException {
List<Configuration> list = new GlueList<>();
streams.forEach((id, stream) -> {
list.add(new Configuration(stream, id));
});
consumer.accept(list);
return this;
}
@@ -17,7 +17,7 @@ public final class LangUtil {
public static void load(String langID, TerraPlugin main) {
Logger logger = main.logger();
File file = new File(main.getDataFolder(), "lang");
try(JarFile jar = new JarFile(new File(TerraPlugin.class.getProtectionDomain().getCodeSource().getLocation().toURI()))) {
try(JarFile jar = main.getModJar()) {
copyResourcesToDirectory(jar, "lang", file.toString());
} catch(IOException | URISyntaxException e) {
main.getDebugLogger().error("Failed to dump language files!");
@@ -1,11 +1,11 @@
package com.dfsek.terra.config.loaders;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.flora.Flora;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.tree.Tree;
import java.lang.reflect.Type;
import java.util.Map;
@@ -18,7 +18,7 @@ public class OreHolderLoader implements TypeLoader<OreHolder> {
Map<String, Object> map = (Map<String, Object>) o;
for(Map.Entry<String, Object> entry : map.entrySet()) {
holder.add(configLoader.loadClass(Ore.class, entry.getKey()), (OreConfig) configLoader.loadType(OreConfig.class, entry.getValue()));
holder.add(configLoader.loadClass(Ore.class, entry.getKey()), configLoader.loadClass(OreConfig.class, entry.getValue()), entry.getKey());
}
return holder;
@@ -5,9 +5,9 @@ import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import com.dfsek.terra.api.math.Range;
import com.dfsek.terra.api.math.noise.samplers.noise.random.WhiteNoiseSampler;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.tree.Tree;
import com.dfsek.terra.config.loaders.Types;
import com.dfsek.terra.world.population.items.tree.TreeLayer;
@@ -65,7 +65,6 @@ public class ExpressionFunctionTemplate extends SamplerTemplate<ExpressionFuncti
Map<String, Function> noiseFunctionMap = new HashMap<>();
for(Map.Entry<String, FunctionTemplate> entry : expressions.entrySet()) {
System.out.println(entry);
noiseFunctionMap.put(entry.getKey(), UserDefinedFunction.newInstance(entry.getValue(), new Parser(), new Scope()));
}
@@ -12,6 +12,7 @@ import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.event.events.config.ConfigPackPostLoadEvent;
import com.dfsek.terra.api.event.events.config.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.structures.loot.LootTable;
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
@@ -20,7 +21,6 @@ import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.flora.Flora;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.tree.Tree;
import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.config.builder.BiomeBuilder;
import com.dfsek.terra.config.dummy.DummyWorld;
@@ -120,7 +120,7 @@ public class ConfigPack implements LoaderRegistrar {
long l = System.nanoTime();
floraRegistry = new FloraRegistry(main);
paletteRegistry = new PaletteRegistry(main);
treeRegistry = new TreeRegistry(main);
treeRegistry = new TreeRegistry();
register(abstractConfigLoader);
register(selfLoader);
@@ -139,6 +139,7 @@ public class ConfigPack implements LoaderRegistrar {
selfLoader.load(packPostTemplate, new FileInputStream(pack));
biomeProviderBuilder = packPostTemplate.getProviderBuilder();
biomeProviderBuilder.build(0); // Build dummy provider to catch errors at load time.
checkDeadEntries(main);
} catch(FileNotFoundException e) {
throw new LoadException("No pack.yml file found in " + folder.getAbsolutePath(), e);
}
@@ -156,7 +157,7 @@ public class ConfigPack implements LoaderRegistrar {
long l = System.nanoTime();
floraRegistry = new FloraRegistry(main);
paletteRegistry = new PaletteRegistry(main);
treeRegistry = new TreeRegistry(main);
treeRegistry = new TreeRegistry();
register(abstractConfigLoader);
register(selfLoader);
@@ -183,6 +184,7 @@ public class ConfigPack implements LoaderRegistrar {
selfLoader.load(packPostTemplate, file.getInputStream(pack));
biomeProviderBuilder = packPostTemplate.getProviderBuilder();
biomeProviderBuilder.build(0); // Build dummy provider to catch errors at load time.
checkDeadEntries(main);
} catch(IOException e) {
throw new LoadException("Unable to load pack.yml from ZIP file", e);
}
@@ -198,6 +200,16 @@ public class ConfigPack implements LoaderRegistrar {
for(C template : configTemplates) registry.add(template.getID(), factory.build(template, main));
}
private void checkDeadEntries(TerraPlugin main) {
biomeRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in biome registry: '" + id + "'"));
paletteRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in palette registry: '" + id + "'"));
floraRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in flora registry: '" + id + "'"));
carverRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in carver registry: '" + id + "'"));
treeRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in tree registry: '" + id + "'"));
oreRegistry.getDeadEntries().forEach((id, value) -> main.getDebugLogger().warn("Dead entry in ore registry: '" + id + "'"));
}
private void load(long start, TerraPlugin main) throws ConfigException {
main.getEventManager().callEvent(new ConfigPackPreLoadEvent(this));
@@ -225,13 +237,13 @@ public class ConfigPack implements LoaderRegistrar {
}).close();
loader
.open("carving", ".yml").then(streams -> buildAll(new CarverFactory(this), carverRegistry, abstractConfigLoader.load(streams, CarverTemplate::new), main)).close()
.open("palettes", ".yml").then(streams -> buildAll(new PaletteFactory(), paletteRegistry, abstractConfigLoader.load(streams, PaletteTemplate::new), main)).close()
.open("ores", ".yml").then(streams -> buildAll(new OreFactory(), oreRegistry, abstractConfigLoader.load(streams, OreTemplate::new), main)).close()
.open("structures/trees", ".yml").then(streams -> buildAll(new TreeFactory(), treeRegistry, abstractConfigLoader.load(streams, TreeTemplate::new), main)).close()
.open("structures/structures", ".yml").then(streams -> buildAll(new StructureFactory(), structureRegistry, abstractConfigLoader.load(streams, StructureTemplate::new), main)).close()
.open("flora", ".yml").then(streams -> buildAll(new FloraFactory(), floraRegistry, abstractConfigLoader.load(streams, FloraTemplate::new), main)).close()
.open("biomes", ".yml").then(streams -> buildAll(new BiomeFactory(this), biomeRegistry, abstractConfigLoader.load(streams, () -> new BiomeTemplate(this, main)), main)).close();
.open("carving", ".yml").then(configs -> buildAll(new CarverFactory(this), carverRegistry, abstractConfigLoader.loadConfigs(configs, CarverTemplate::new), main)).close()
.open("palettes", ".yml").then(configs -> buildAll(new PaletteFactory(), paletteRegistry, abstractConfigLoader.loadConfigs(configs, PaletteTemplate::new), main)).close()
.open("ores", ".yml").then(configs -> buildAll(new OreFactory(), oreRegistry, abstractConfigLoader.loadConfigs(configs, OreTemplate::new), main)).close()
.open("structures/trees", ".yml").then(configs -> buildAll(new TreeFactory(), treeRegistry, abstractConfigLoader.loadConfigs(configs, TreeTemplate::new), main)).close()
.open("structures/structures", ".yml").then(configs -> buildAll(new StructureFactory(), structureRegistry, abstractConfigLoader.loadConfigs(configs, StructureTemplate::new), main)).close()
.open("flora", ".yml").then(configs -> buildAll(new FloraFactory(), floraRegistry, abstractConfigLoader.loadConfigs(configs, FloraTemplate::new), main)).close()
.open("biomes", ".yml").then(configs -> buildAll(new BiomeFactory(this), biomeRegistry, abstractConfigLoader.loadConfigs(configs, () -> new BiomeTemplate(this, main)), main)).close();
main.getEventManager().callEvent(new ConfigPackPostLoadEvent(this));
main.logger().info("Loaded config pack \"" + template.getID() + "\" v" + template.getVersion() + " by " + template.getAuthor() + " in " + (System.nanoTime() - start) / 1000000D + "ms.");
@@ -73,6 +73,46 @@ public class ConfigPackTemplate implements ConfigTemplate {
@Default
private String version = "0.1.0";
@Value("disable.carvers")
@Default
private boolean disableCarvers = false;
@Value("disable.structures")
@Default
private boolean disableStructures = false;
@Value("disable.ores")
@Default
private boolean disableOres = false;
@Value("disable.trees")
@Default
private boolean disableTrees = false;
@Value("disable.flora")
@Default
private boolean disableFlora = false;
public boolean disableCarvers() {
return disableCarvers;
}
public boolean disableFlora() {
return disableFlora;
}
public boolean disableOres() {
return disableOres;
}
public boolean disableStructures() {
return disableStructures;
}
public boolean disableTrees() {
return disableTrees;
}
public LinkedHashMap<String, FunctionTemplate> getFunctions() {
return functions;
}
@@ -1,19 +1,15 @@
package com.dfsek.terra.config.pack;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.api.registry.LockedRegistry;
import com.dfsek.terra.api.structures.loot.LootTable;
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.flora.Flora;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.tree.Tree;
import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.registry.OpenRegistry;
import com.dfsek.terra.world.TerraWorld;
@@ -22,7 +18,6 @@ import com.dfsek.terra.world.population.items.TerraStructure;
import com.dfsek.terra.world.population.items.ores.Ore;
import java.util.Set;
import java.util.function.Supplier;
public class WorldConfig {
private final LockedRegistry<StructureScript> scriptRegistry;
@@ -190,10 +190,19 @@ public class BiomeTemplate extends AbstractableTemplate implements ValidatedConf
@Default
private Map<UserDefinedCarver, Integer> carvers = new HashMap<>();
@Value("colors")
@Abstractable
@Default
private Map<String, Integer> colors = new HashMap<>(); // Plain ol' map, so platforms can decide what to do with colors (if anything).
public Set<String> getTags() {
return tags;
}
public Map<String, Integer> getColors() {
return colors;
}
public Map<UserDefinedCarver, Integer> getCarvers() {
return carvers;
}
@@ -1,36 +0,0 @@
package com.dfsek.terra.profiler;
/**
* Class to hold a profiler data value. Contains formatting method to highlight value based on desired range.
*/
public class DataHolder {
private final long desired;
private final DataType type;
private final double desiredRangePercent;
/**
* Constructs a DataHolder with a DataType and a desired value, including a percentage around the desired value considered acceptable
*
* @param type The type of data held in this instance.
* @param desired The desired value. This should be the average value of whatever is being measured.
* @param desiredRangePercent The percentage around the desired value to be considered acceptable.
*/
public DataHolder(DataType type, long desired, double desiredRangePercent) {
this.desired = desired;
this.type = type;
this.desiredRangePercent = desiredRangePercent;
}
/**
* Returns a String, formatted with Bungee ChatColors.<br>
* GREEN if the value is better than desired and outside of acceptable range.<br>
* YELLOW if the value is better or worse than desired, and within acceptable range.<br>
* RED if the value is worse than desired and outside of acceptable range.<br>
*
* @param data The data to format.
* @return String - The formatted data.
*/
public String getFormattedData(long data) {
return type.getFormatted(data);
}
}
@@ -1,24 +0,0 @@
package com.dfsek.terra.profiler;
import net.jafama.FastMath;
public enum DataType {
PERIOD_MILLISECONDS(Desire.LOW, 1000000, "ms"), PERIOD_NANOSECONDS(Desire.LOW, 1, "ns");
private final Desire desire;
private final long divisor;
private final String unit;
DataType(Desire d, long divisor, String unit) {
this.desire = d;
this.divisor = divisor;
this.unit = unit;
}
public String getFormatted(long value) {
return (double) FastMath.round(((double) value / divisor) * 100D) / 100D + unit;
}
public Desire getDesire() {
return desire;
}
}
@@ -1,10 +0,0 @@
package com.dfsek.terra.profiler;
/**
* Enum to represent the "goal" of a value, whether it is desirable for the value to be high (e.g. Frequency), or low (e.g. Period)
*/
public enum Desire {
LOW, HIGH
}
@@ -0,0 +1,24 @@
package com.dfsek.terra.profiler;
public class Frame {
private final String id;
private final long start;
public Frame(String id) {
this.id = id;
this.start = System.nanoTime();
}
public String getId() {
return id;
}
public long getStart() {
return start;
}
@Override
public String toString() {
return id;
}
}
@@ -1,87 +0,0 @@
package com.dfsek.terra.profiler;
import com.dfsek.terra.api.math.MathUtil;
import com.dfsek.terra.api.util.GlueList;
import net.jafama.FastMath;
import java.math.BigInteger;
import java.util.LinkedList;
import java.util.List;
/**
* Class to record and hold all data for a single type of measurement performed by the profiler.
*/
public class Measurement {
private final List<Long> measurements = new LinkedList<>();
private final long desirable;
private final DataType type;
private long min = Long.MAX_VALUE;
private long max = Long.MIN_VALUE;
/**
* Constructs a new Measurement with a desired value and DataType.
*
* @param desirable The desired value of the measurement.
* @param type The type of data the measurement is holding.
*/
public Measurement(long desirable, DataType type) {
this.desirable = desirable;
this.type = type;
}
public void record(long value) {
max = FastMath.max(value, max);
min = FastMath.min(value, min);
measurements.add(value);
}
public int size() {
return measurements.size();
}
public ProfileFuture beginMeasurement() {
ProfileFuture future = new ProfileFuture();
long current = System.nanoTime();
future.thenRun(() -> record(System.nanoTime() - current));
return future;
}
public void reset() {
min = Long.MAX_VALUE;
max = Long.MIN_VALUE;
measurements.clear();
}
public DataHolder getDataHolder() {
return new DataHolder(type, desirable, 0.25);
}
public long getMin() {
if(min == Long.MAX_VALUE) return 0;
return min;
}
public long getMax() {
if(max == Long.MIN_VALUE) return 0;
return max;
}
public long average() {
BigInteger running = BigInteger.valueOf(0);
List<Long> mTemp = new GlueList<>(measurements);
for(Long l : mTemp) {
running = running.add(BigInteger.valueOf(l));
}
if(measurements.size() == 0) return 0;
return running.divide(BigInteger.valueOf(measurements.size())).longValue();
}
public double getStdDev() {
return MathUtil.standardDeviation(new GlueList<>(measurements));
}
public int entries() {
return measurements.size();
}
}
@@ -0,0 +1,14 @@
package com.dfsek.terra.profiler;
public class ProfileFrame implements AutoCloseable {
private final Runnable action;
public ProfileFrame(Runnable action) {
this.action = action;
}
@Override
public void close() {
action.run();
}
}
@@ -1,18 +0,0 @@
package com.dfsek.terra.profiler;
import java.util.concurrent.CompletableFuture;
public class ProfileFuture extends CompletableFuture<Boolean> implements AutoCloseable {
public ProfileFuture() {
super();
}
public boolean complete() {
return super.complete(true);
}
@Override
public void close() {
this.complete();
}
}
@@ -0,0 +1,56 @@
package com.dfsek.terra.profiler;
import java.util.Map;
public interface Profiler {
/**
* Push a frame to this profiler.
*
* @param frame ID of frame.
*/
void push(String frame);
/**
* Pop a frame from this profiler.
*
* @param frame ID of frame. Must match ID
* at the top of the profiler stack.
*/
void pop(String frame);
/**
* Start profiling.
*/
void start();
/**
* Stop profiling.
*/
void stop();
/**
* Get the profiler data.
*
* @return Profiler data.
*/
Map<String, Timings> getTimings();
/**
* Return a {@link AutoCloseable} implementation that
* may be used in a try-with-resources statement for
* more intuitive profiling, with auto-push/pop.
*
* @param frame ID of frame.
* @return {@link AutoCloseable} implementation for use
* in try-with-resources.
*/
default ProfileFrame profile(String frame) {
push(frame);
return new ProfileFrame(() -> pop(frame));
}
/**
* Clear the profiler data.
*/
void reset();
}
@@ -0,0 +1,91 @@
package com.dfsek.terra.profiler;
import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.profiler.exception.MalformedStackException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
public class ProfilerImpl implements Profiler {
private static final ThreadLocal<Stack<Frame>> THREAD_STACK = ThreadLocal.withInitial(Stack::new);
private static final ThreadLocal<Map<String, List<Long>>> TIMINGS = ThreadLocal.withInitial(HashMap::new);
private final List<Map<String, List<Long>>> accessibleThreadMaps = new ArrayList<>();
private volatile boolean running = false;
private static boolean instantiated = false;
private static final ThreadLocal<Boolean> SAFE = ThreadLocal.withInitial(() -> false);
private static final ThreadLocal<MutableInteger> STACK_SIZE = ThreadLocal.withInitial(() -> new MutableInteger(0));
public ProfilerImpl() {
if(instantiated) throw new IllegalStateException("Only one instance of Profiler may exist!");
instantiated = true;
}
@Override
public void push(String frame) {
STACK_SIZE.get().increment();
if(running && SAFE.get()) {
Stack<Frame> stack = THREAD_STACK.get();
stack.push(new Frame(stack.isEmpty() ? frame : stack.peek().getId() + "." + frame));
} else SAFE.set(false);
}
@Override
public void pop(String frame) {
MutableInteger size = STACK_SIZE.get();
size.decrement();
if(running && SAFE.get()) {
long time = System.nanoTime();
Stack<Frame> stack = THREAD_STACK.get();
Map<String, List<Long>> timingsMap = TIMINGS.get();
if(timingsMap.size() == 0) {
synchronized(accessibleThreadMaps) {
accessibleThreadMaps.add(timingsMap);
}
}
Frame top = stack.pop();
if((stack.size() != 0 && !top.getId().endsWith("." + frame)) || (stack.size() == 0 && !top.getId().equals(frame)))
throw new MalformedStackException("Expected " + frame + ", found " + top);
List<Long> timings = timingsMap.computeIfAbsent(top.getId(), id -> new ArrayList<>());
timings.add(time - top.getStart());
}
if(size.get() == 0) SAFE.set(true);
}
@Override
public void start() {
running = true;
}
@Override
public void stop() {
running = false;
}
@Override
public Map<String, Timings> getTimings() {
Map<String, Timings> map = new HashMap<>();
accessibleThreadMaps.forEach(smap -> smap.forEach((key, list) -> {
String[] keys = key.split("\\.");
Timings timings = map.computeIfAbsent(keys[0], id -> new Timings());
for(int i = 1; i < keys.length; i++) {
timings = timings.getSubItem(keys[i]);
}
list.forEach(timings::addTime);
}));
return map;
}
@Override
public void reset() {
accessibleThreadMaps.forEach(Map::clear);
}
}
@@ -0,0 +1,73 @@
package com.dfsek.terra.profiler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Timings {
private final Map<String, Timings> subItems = new HashMap<>();
private final List<Long> timings = new ArrayList<>();
public void addTime(long time) {
timings.add(time);
}
public List<Long> getTimings() {
return timings;
}
public double average() {
return (double) timings.stream().reduce(0L, Long::sum) / timings.size();
}
public long max() {
return timings.stream().mapToLong(Long::longValue).max().orElse(0L);
}
public long min() {
return timings.stream().mapToLong(Long::longValue).min().orElse(0L);
}
public double sum() {
return timings.stream().mapToDouble(Long::doubleValue).sum();
}
public Timings getSubItem(String id) {
return subItems.computeIfAbsent(id, s -> new Timings());
}
public String toString(int indent, Timings parent, Set<Integer> branches) {
StringBuilder builder = new StringBuilder();
builder.append((double) min() / 1000000).append("ms min / ").append(average() / 1000000).append("ms avg / ")
.append((double) max() / 1000000).append("ms max (").append(timings.size()).append(" samples, ")
.append((sum() / parent.sum()) * 100).append("% of parent)");
List<String> frames = new ArrayList<>();
Set<Integer> newBranches = new HashSet<>(branches);
newBranches.add(indent);
subItems.forEach((id, timings) -> frames.add(id + ": " + timings.toString(indent + 1, this, newBranches)));
for(int i = 0; i < frames.size(); i++) {
builder.append('\n');
for(int j = 0; j < indent; j++) {
if(branches.contains(j)) builder.append("");
else builder.append(" ");
}
if(i == frames.size() - 1 && !frames.get(i).contains("\n")) builder.append("└───");
else builder.append("├───");
builder.append(frames.get(i));
}
return builder.toString();
}
@Override
public String toString() {
return toString(1, this, Collections.emptySet());
}
}
@@ -1,85 +0,0 @@
package com.dfsek.terra.profiler;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.world.TerraWorld;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import net.jafama.FastMath;
import java.util.Map;
public class WorldProfiler {
private final BiMap<String, Measurement> measures = HashBiMap.create();
private final World world;
private boolean isProfiling;
public WorldProfiler(World w) {
if(!TerraWorld.isTerraWorld(w))
throw new IllegalArgumentException("Attempted to instantiate profiler on non-Terra managed world!");
this.addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "TotalChunkGenTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "FloraTime")
.addMeasurement(new Measurement(10000000, DataType.PERIOD_MILLISECONDS), "TreeTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "OreTime")
.addMeasurement(new Measurement(5000000, DataType.PERIOD_MILLISECONDS), "CaveTime")
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "StructureTime");
isProfiling = false;
this.world = w;
}
public String getResultsFormatted() {
if(! isProfiling) return "Profiler is not currently running.";
StringBuilder result = new StringBuilder("Gaea World Profiler Results (Min / Avg / Max / Std Dev): \n");
for(Map.Entry<String, Measurement> e : measures.entrySet()) {
result
.append(e.getKey())
.append(": ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().getMin()))
.append(" / ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().average()))
.append(" / ")
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().getMax()))
.append(" / ")
.append((double) FastMath.round((e.getValue().getStdDev() / 1000000) * 100D) / 100D)
.append("ms")
.append(" (x").append(e.getValue().size()).append(")\n");
}
return result.toString();
}
public void reset() {
for(Map.Entry<String, Measurement> e : measures.entrySet()) {
e.getValue().reset();
}
}
public com.dfsek.terra.profiler.WorldProfiler addMeasurement(Measurement m, String name) {
measures.put(name, m);
return this;
}
public void setMeasurement(String id, long value) {
if(isProfiling) measures.get(id).record(value);
}
public ProfileFuture measure(String id) {
if(isProfiling) return measures.get(id).beginMeasurement();
else return null;
}
public String getID(Measurement m) {
return measures.inverse().get(m);
}
public boolean isProfiling() {
return isProfiling;
}
public void setProfiling(boolean enabled) {
this.isProfiling = enabled;
}
public World getWorld() {
return world;
}
}
@@ -0,0 +1,17 @@
package com.dfsek.terra.profiler.exception;
public class MalformedStackException extends ProfilerException {
private static final long serialVersionUID = -3009539681021691054L;
public MalformedStackException(String message) {
super(message);
}
public MalformedStackException(String message, Throwable cause) {
super(message, cause);
}
public MalformedStackException(Throwable cause) {
super(cause);
}
}
@@ -0,0 +1,17 @@
package com.dfsek.terra.profiler.exception;
public class ProfilerException extends RuntimeException {
private static final long serialVersionUID = 8206737998791649002L;
public ProfilerException(String message) {
super(message);
}
public ProfilerException(String message, Throwable cause) {
super(message, cause);
}
public ProfilerException(Throwable cause) {
super(cause);
}
}
@@ -7,18 +7,19 @@ import com.dfsek.terra.registry.exception.DuplicateEntryException;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* Registry implementation with read/write access. For internal use only.
* @param <T>
*/
public class OpenRegistry<T> implements Registry<T> {
private final Map<String, T> objects = new HashMap<>();
private final Map<String, Entry<T>> objects = new HashMap<>();
@Override
public T load(Type type, Object o, ConfigLoader configLoader) throws LoadException {
@@ -35,6 +36,10 @@ public class OpenRegistry<T> implements Registry<T> {
* @param value Value to add.
*/
public boolean add(String identifier, T value) {
return add(identifier, new Entry<>(value));
}
protected boolean add(String identifier, Entry<T> value) {
boolean exists = objects.containsKey(identifier);
objects.put(identifier, value);
return exists;
@@ -60,22 +65,24 @@ public class OpenRegistry<T> implements Registry<T> {
@Override
public T get(String identifier) {
return objects.get(identifier);
Entry<T> entry = objects.get(identifier);
if(entry == null) return null;
return entry.getValue();
}
@Override
public void forEach(Consumer<T> consumer) {
objects.forEach((id, obj) -> consumer.accept(obj));
objects.forEach((id, obj) -> consumer.accept(obj.getRaw()));
}
@Override
public void forEach(BiConsumer<String, T> consumer) {
objects.forEach(consumer);
objects.forEach((id, entry) -> consumer.accept(id, entry.getRaw()));
}
@Override
public Set<T> entries() {
return new HashSet<>(objects.values());
return objects.values().stream().map(Entry::getRaw).collect(Collectors.toSet());
}
@Override
@@ -83,10 +90,41 @@ public class OpenRegistry<T> implements Registry<T> {
return objects.keySet();
}
public Map<String, T> getDeadEntries() {
Map<String, T> dead = new HashMap<>();
objects.forEach((id, entry) -> {
if(entry.dead()) dead.put(id, entry.value); // dont increment value here.
});
return dead;
}
/**
* Clears all entries from the registry.
*/
public void clear() {
objects.clear();
}
protected static final class Entry<T> {
private final T value;
private final AtomicInteger access = new AtomicInteger(0);
public Entry(T value) {
this.value = value;
}
public T getValue() {
access.incrementAndGet();
return value;
}
private T getRaw() {
return value;
}
public boolean dead() {
return access.get() == 0;
}
}
}
@@ -57,7 +57,9 @@ public class FloraRegistry extends OpenRegistry<Flora> {
private void addItem(String id, Callable<ConstantFlora> flora) {
try {
add(id, flora.call());
Entry<Flora> entry = new Entry<>(flora.call());
entry.getValue(); // Mark as not dead.
add(id, entry);
} catch(Exception e) {
main.logger().warning("Failed to load Flora item: " + id + ": " + e.getMessage());
}
@@ -66,10 +68,4 @@ public class FloraRegistry extends OpenRegistry<Flora> {
private BlockData data(String s) {
return main.getWorldHandle().createBlockData(s);
}
@Override
public Flora get(String identifier) {
return super.get(identifier);
}
}
@@ -1,77 +1,11 @@
package com.dfsek.terra.registry.config;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.block.BlockFace;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.api.world.tree.Tree;
import com.dfsek.terra.api.world.tree.fractal.FractalTree;
import com.dfsek.terra.api.world.tree.fractal.trees.Cactus;
import com.dfsek.terra.api.world.tree.fractal.trees.IceSpike;
import com.dfsek.terra.api.world.tree.fractal.trees.OakTree;
import com.dfsek.terra.api.world.tree.fractal.trees.ShatteredPillar;
import com.dfsek.terra.api.world.tree.fractal.trees.ShatteredTree;
import com.dfsek.terra.api.world.tree.fractal.trees.SmallShatteredPillar;
import com.dfsek.terra.api.world.tree.fractal.trees.SmallShatteredTree;
import com.dfsek.terra.api.world.tree.fractal.trees.SpruceTree;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.registry.OpenRegistry;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Random;
public class TreeRegistry extends OpenRegistry<Tree> {
private final TerraPlugin main;
public TreeRegistry(TerraPlugin main) {
this.main = main;
tryAdd("CACTUS", Cactus.class);
tryAdd("GIANT_OAK", OakTree.class);
tryAdd("GIANT_SPRUCE", SpruceTree.class);
tryAdd("LARGE_SHATTERED_PILLAR", ShatteredPillar.class);
tryAdd("SHATTERED_LARGE", ShatteredTree.class);
tryAdd("SHATTERED_SMALL", SmallShatteredTree.class);
tryAdd("SMALL_SHATTERED_PILLAR", SmallShatteredPillar.class);
tryAdd("ICE_SPIKE", IceSpike.class);
}
private void tryAdd(String id, Class<? extends FractalTree> value) {
try {
add(id, new FractalTreeHolder(value));
} catch(Exception e) {
main.logger().warning("Unable to load tree " + id + ": " + e.getMessage());
}
}
@Override
public boolean add(String identifier, Tree value) {
return super.add(identifier, value);
}
private final class FractalTreeHolder implements Tree {
private final FractalTree tree;
private FractalTreeHolder(Class<? extends FractalTree> clazz) throws NoSuchMethodException {
Constructor<? extends FractalTree> constructor = clazz.getConstructor(TerraPlugin.class);
try {
tree = constructor.newInstance(main);
} catch(InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
throw new IllegalArgumentException("Unable to load tree: " + clazz);
}
}
@Override
public boolean plant(Location l, Random r) {
if(!getSpawnable().contains(l.getBlock().getType())) return false;
if(!l.getBlock().getRelative(BlockFace.UP).isEmpty()) return false;
tree.grow(l.add(0, 1, 0), r);
return true;
}
@Override
public MaterialSet getSpawnable() {
return tree.getSpawnable();
}
}
}
@@ -6,6 +6,7 @@ import com.dfsek.terra.addon.PreLoadAddon;
import com.dfsek.terra.addon.exception.AddonLoadException;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.addons.TerraAddon;
import com.dfsek.terra.api.addons.annotations.Platform;
import com.dfsek.terra.api.injection.Injector;
import com.dfsek.terra.api.injection.exception.InjectionException;
import com.dfsek.terra.registry.OpenRegistry;
@@ -15,6 +16,8 @@ import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import java.util.logging.LogManager;
import java.util.logging.Logger;
@@ -66,6 +69,12 @@ public class AddonRegistry extends OpenRegistry<TerraAddon> {
for(PreLoadAddon addon : pool.getAddons()) {
Class<? extends TerraAddon> addonClass = addon.getAddonClass();
if(addonClass.isAnnotationPresent(Platform.class)) {
List<String> platforms = Arrays.asList(addonClass.getAnnotation(Platform.class).value());
if(!platforms.contains(main.platformName())) throw new AddonLoadException("Addon \"" + addon.getId() + "\" cannot run on platform " + main.platformName() + ". Allowed platforms: " + platforms);
}
Constructor<? extends TerraAddon> constructor;
String logPrefix = "Terra:" + addon.getId();
@@ -13,7 +13,6 @@ import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.profiler.WorldProfiler;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import net.jafama.FastMath;
@@ -21,33 +20,25 @@ public class TerraWorld {
private final BiomeProvider provider;
private final WorldConfig config;
private final boolean safe;
private final WorldProfiler profiler;
private final World world;
private final BlockData air;
public TerraWorld(World w, ConfigPack c, TerraPlugin main) {
if(!isTerraWorld(w)) throw new IllegalArgumentException("World " + w + " is not a Terra World!");
if(!w.isTerraWorld()) throw new IllegalArgumentException("World " + w + " is not a Terra World!");
this.world = w;
config = c.toWorldConfig(this);
this.provider = config.getProvider();
profiler = new WorldProfiler(w);
air = main.getWorldHandle().createBlockData("minecraft:air");
main.getEventManager().callEvent(new TerraWorldLoadEvent(this));
main.getEventManager().callEvent(new TerraWorldLoadEvent(this, c));
safe = true;
}
public static boolean isTerraWorld(World w) {
return w.getGenerator().getHandle() instanceof GeneratorWrapper;
}
public World getWorld() {
return world;
}
public TerraChunkGenerator getGenerator() {
return ((GeneratorWrapper) world.getGenerator().getHandle()).getHandle();
}
public BiomeProvider getBiomeProvider() {
return provider;
@@ -61,9 +52,6 @@ public class TerraWorld {
return safe;
}
public WorldProfiler getProfiler() {
return profiler;
}
/**
* Get a block at an ungenerated location
@@ -10,20 +10,27 @@ import com.dfsek.terra.api.util.world.PaletteUtil;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.Carver;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.carving.NoiseCarver;
import com.dfsek.terra.world.generation.math.SamplerCache;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import com.dfsek.terra.world.generation.math.samplers.Sampler2D;
import com.dfsek.terra.world.population.CavePopulator;
import com.dfsek.terra.world.population.OrePopulator;
import com.dfsek.terra.world.population.StructurePopulator;
import com.dfsek.terra.world.population.TreePopulator;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class DefaultChunkGenerator2D implements TerraChunkGenerator {
@@ -31,12 +38,18 @@ public class DefaultChunkGenerator2D implements TerraChunkGenerator {
private final TerraPlugin main;
private final Carver carver;
private final List<TerraBlockPopulator> blockPopulators = new ArrayList<>();
private final SamplerCache cache;
public DefaultChunkGenerator2D(ConfigPack c, TerraPlugin main, SamplerCache cache) {
this.configPack = c;
this.main = main;
blockPopulators.add(new CavePopulator(main));
blockPopulators.add(new StructurePopulator(main));
blockPopulators.add(new OrePopulator(main));
blockPopulators.add(new TreePopulator(main));
blockPopulators.add(new TreePopulator(main));
carver = new NoiseCarver(new Range(0, 255), main.getWorldHandle().createBlockData("minecraft:air"), main);
this.cache = cache;
}
@@ -81,7 +94,7 @@ public class DefaultChunkGenerator2D implements TerraChunkGenerator {
public ChunkData generateChunkData(@NotNull World world, Random random, int chunkX, int chunkZ, ChunkData chunk) {
TerraWorld tw = main.getWorld(world);
BiomeProvider grid = tw.getBiomeProvider();
try(ProfileFuture ignore = tw.getProfiler().measure("TotalChunkGenTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("chunk_base_2d")) {
if(!tw.isSafe()) return chunk;
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
@@ -125,4 +138,9 @@ public class DefaultChunkGenerator2D implements TerraChunkGenerator {
public Sampler createSampler(int chunkX, int chunkZ, BiomeProvider provider, World world, int elevationSmooth) {
return new Sampler2D(chunkX, chunkZ, provider, world, elevationSmooth);
}
@Override
public List<TerraBlockPopulator> getPopulators() {
return blockPopulators;
}
}
@@ -17,19 +17,27 @@ import com.dfsek.terra.api.util.world.PaletteUtil;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.palette.SinglePalette;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.Carver;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.carving.NoiseCarver;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import com.dfsek.terra.world.generation.math.samplers.Sampler3D;
import com.dfsek.terra.world.population.CavePopulator;
import com.dfsek.terra.world.population.FloraPopulator;
import com.dfsek.terra.world.population.OrePopulator;
import com.dfsek.terra.world.population.StructurePopulator;
import com.dfsek.terra.world.population.TreePopulator;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
@@ -38,14 +46,20 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
private final TerraPlugin main;
private final BlockType water;
private final SinglePalette<BlockData> blank;
private final List<TerraBlockPopulator> blockPopulators = new ArrayList<>();
private final Carver carver;
public DefaultChunkGenerator3D(ConfigPack c, TerraPlugin main) {
this.configPack = c;
this.main = main;
blockPopulators.add(new CavePopulator(main));
blockPopulators.add(new StructurePopulator(main));
blockPopulators.add(new OrePopulator(main));
blockPopulators.add(new TreePopulator(main));
blockPopulators.add(new FloraPopulator(main));
carver = new NoiseCarver(new Range(0, 255), main.getWorldHandle().createBlockData("minecraft:air"), main);
water = main.getWorldHandle().createBlockData("minecraft:water").getBlockType();
blank = new SinglePalette<>(main.getWorldHandle().createBlockData("minecraft:air"));
@@ -89,9 +103,10 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
@Override
@SuppressWarnings({"try"})
public ChunkData generateChunkData(@NotNull World world, Random random, int chunkX, int chunkZ, ChunkData chunk) {
TerraWorld tw = main.getWorld(world);
BiomeProvider grid = tw.getBiomeProvider();
try(ProfileFuture ignore = tw.getProfiler().measure("TotalChunkGenTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("chunk_base_3d")) {
TerraWorld tw = main.getWorld(world);
BiomeProvider grid = tw.getBiomeProvider();
if(!tw.isSafe()) return chunk;
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
@@ -105,7 +120,7 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
int cx = xOrig + x;
int cz = zOrig + z;
TerraBiome b = grid.getBiome(xOrig + x, zOrig + z);
TerraBiome b = grid.getBiome(cx, cz);
BiomeTemplate c = ((UserDefinedBiome) b).getConfig();
int sea = c.getSeaLevel();
@@ -212,17 +227,20 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
return false;
}
@SuppressWarnings({"try"})
static void biomes(@NotNull World world, int chunkX, int chunkZ, @NotNull BiomeGrid biome, TerraPlugin main) {
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
BiomeProvider grid = main.getWorld(world).getBiomeProvider();
for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) {
int cx = xOrig + (x << 2);
int cz = zOrig + (z << 2);
TerraBiome b = grid.getBiome(cx, cz);
try(ProfileFrame ignore = main.getProfiler().profile("biomes")) {
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
BiomeProvider grid = main.getWorld(world).getBiomeProvider();
for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) {
int cx = xOrig + (x << 2);
int cz = zOrig + (z << 2);
TerraBiome b = grid.getBiome(cx, cz);
biome.setBiome(cx, cz, b.getVanillaBiomes().get(b.getGenerator(world).getBiomeNoise(), cx, 0, cz));
biome.setBiome(cx, cz, b.getVanillaBiomes().get(b.getGenerator(world).getBiomeNoise(), cx, 0, cz));
}
}
}
}
@@ -236,4 +254,9 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
public Sampler createSampler(int chunkX, int chunkZ, BiomeProvider provider, World world, int elevationSmooth) {
return new Sampler3D(chunkX, chunkZ, provider, world, elevationSmooth);
}
@Override
public List<TerraBlockPopulator> getPopulators() {
return blockPopulators;
}
}
@@ -25,7 +25,7 @@ public class SamplerCache {
public Sampler load(@NotNull Long key) {
int cx = (int) (key >> 32);
int cz = (int) key.longValue();
return world.getGenerator().createSampler(cx, cz, world.getBiomeProvider(), world.getWorld(), world.getConfig().getTemplate().getElevationBlend());
return world.getWorld().getTerraGenerator().createSampler(cx, cz, world.getBiomeProvider(), world.getWorld(), world.getConfig().getTemplate().getElevationBlend());
}
});
}
@@ -9,11 +9,12 @@ import com.dfsek.terra.api.platform.handle.WorldHandle;
import com.dfsek.terra.api.platform.world.Chunk;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.util.world.PopulationUtil;
import com.dfsek.terra.api.world.generation.Chunkified;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.config.templates.CarverTemplate;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import org.jetbrains.annotations.NotNull;
@@ -23,7 +24,7 @@ import java.util.Map;
import java.util.Random;
import java.util.Set;
public class CavePopulator implements TerraBlockPopulator {
public class CavePopulator implements TerraBlockPopulator, Chunkified {
private static final Map<BlockType, BlockData> shiftStorage = new HashMap<>(); // Persist BlockData created for shifts, to avoid re-calculating each time.
private final TerraPlugin main;
@@ -37,48 +38,51 @@ public class CavePopulator implements TerraBlockPopulator {
TerraWorld tw = main.getWorld(world);
WorldHandle handle = main.getWorldHandle();
BlockData AIR = handle.createBlockData("minecraft:air");
try(ProfileFuture ignored = tw.getProfiler().measure("CaveTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("carving")) {
Random random = PopulationUtil.getRandom(chunk);
if(!tw.isSafe()) return;
WorldConfig config = tw.getConfig();
if(config.getTemplate().disableCarvers()) return;
for(UserDefinedCarver c : config.getCarvers()) {
CarverTemplate template = c.getConfig();
Map<Location, BlockData> shiftCandidate = new HashMap<>();
Set<Block> updateNeeded = new HashSet<>();
c.carve(chunk.getX(), chunk.getZ(), world, (v, type) -> {
Block b = chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ());
BlockData m = b.getBlockData();
BlockType re = m.getBlockType();
switch(type) {
case CENTER:
if(template.getInner().canReplace(re)) {
b.setBlockData(template.getInner().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case WALL:
if(template.getOuter().canReplace(re)) {
b.setBlockData(template.getOuter().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case TOP:
if(template.getTop().canReplace(re)) {
b.setBlockData(template.getTop().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case BOTTOM:
if(template.getBottom().canReplace(re)) {
b.setBlockData(template.getBottom().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
try(ProfileFrame ignored = main.getProfiler().profile("carving:" + c.getConfig().getID())) {
Block b = chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ());
BlockData m = b.getBlockData();
BlockType re = m.getBlockType();
switch(type) {
case CENTER:
if(template.getInner().canReplace(re)) {
b.setBlockData(template.getInner().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case WALL:
if(template.getOuter().canReplace(re)) {
b.setBlockData(template.getOuter().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case TOP:
if(template.getTop().canReplace(re)) {
b.setBlockData(template.getTop().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
case BOTTOM:
if(template.getBottom().canReplace(re)) {
b.setBlockData(template.getBottom().get(v.getBlockY()).get(random), false);
if(template.getUpdate().contains(re)) updateNeeded.add(b);
if(template.getShift().containsKey(re)) shiftCandidate.put(b.getLocation(), m);
}
break;
}
}
});
for(Map.Entry<Location, BlockData> entry : shiftCandidate.entrySet()) {
@@ -91,7 +95,7 @@ public class CavePopulator implements TerraBlockPopulator {
if(template.getShift().get(entry.getValue().getBlockType()).contains(mut.getBlock().getBlockData().getBlockType())) {
mut.getBlock().setBlockData(shiftStorage.computeIfAbsent(entry.getValue().getBlockType(), BlockType::getDefaultData), false);
}
} catch(NullPointerException ignore) {
} catch(NullPointerException ignored) {
}
}
for(Block b : updateNeeded) {
@@ -8,7 +8,7 @@ import com.dfsek.terra.api.util.world.PopulationUtil;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.population.items.flora.FloraLayer;
import org.jetbrains.annotations.NotNull;
@@ -32,7 +32,9 @@ public class FloraPopulator implements TerraBlockPopulator {
@Override
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("FloraTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("flora")) {
if(tw.getConfig().getTemplate().disableFlora()) return;
if(!tw.isSafe()) return;
BiomeProvider provider = tw.getBiomeProvider();
Map<Vector2, List<FloraLayer>> layers = new HashMap<>();
@@ -10,7 +10,7 @@ import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import org.jetbrains.annotations.NotNull;
@@ -27,7 +27,9 @@ public class OrePopulator implements TerraBlockPopulator {
@Override
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("OreTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("ore")) {
if(tw.getConfig().getTemplate().disableOres()) return;
if(!tw.isSafe()) return;
for(int cx = -1; cx <= 1; cx++) {
for(int cz = -1; cz <= 1; cz++) {
@@ -38,11 +40,13 @@ public class OrePopulator implements TerraBlockPopulator {
BiomeTemplate config = ((UserDefinedBiome) b).getConfig();
int finalCx = cx;
int finalCz = cz;
config.getOreHolder().forEach((ore, oreConfig) -> {
int amount = oreConfig.getAmount().get(random);
for(int i = 0; i < amount; i++) {
Vector3 location = new Vector3(random.nextInt(16) + 16 * finalCx, oreConfig.getHeight().get(random), random.nextInt(16) + 16 * finalCz);
ore.generate(location, chunk, random);
config.getOreHolder().forEach((id, orePair) -> {
try(ProfileFrame ignored = main.getProfiler().profile("ore:" + id)) {
int amount = orePair.getRight().getAmount().get(random);
for(int i = 0; i < amount; i++) {
Vector3 location = new Vector3(random.nextInt(16) + 16 * finalCx, orePair.getRight().getHeight().get(random), random.nextInt(16) + 16 * finalCz);
orePair.getLeft().generate(location, chunk, random);
}
}
});
}
@@ -9,10 +9,10 @@ import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.util.FastRandom;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.Chunkified;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.pack.WorldConfig;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.population.items.TerraStructure;
import net.jafama.FastMath;
@@ -20,7 +20,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.Random;
public class StructurePopulator implements TerraBlockPopulator {
public class StructurePopulator implements TerraBlockPopulator, Chunkified {
private final TerraPlugin main;
public StructurePopulator(TerraPlugin main) {
@@ -31,7 +31,9 @@ public class StructurePopulator implements TerraBlockPopulator {
@Override
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("StructureTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("structure")) {
if(tw.getConfig().getTemplate().disableStructures()) return;
int cx = (chunk.getX() << 4);
int cz = (chunk.getZ() << 4);
if(!tw.isSafe()) return;
@@ -8,7 +8,7 @@ import com.dfsek.terra.api.util.world.PopulationUtil;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.profiler.ProfileFrame;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.population.items.tree.TreeLayer;
import net.jafama.FastMath;
@@ -32,7 +32,9 @@ public class TreePopulator implements TerraBlockPopulator {
@SuppressWarnings("try")
public void populate(@NotNull World world, @NotNull Chunk chunk) {
TerraWorld tw = main.getWorld(world);
try(ProfileFuture ignored = tw.getProfiler().measure("TreeTime")) {
try(ProfileFrame ignore = main.getProfiler().profile("tree")) {
if(tw.getConfig().getTemplate().disableTrees()) return;
if(!tw.isSafe()) return;
BiomeProvider provider = tw.getBiomeProvider();
Random random = PopulationUtil.getRandom(chunk);
@@ -40,8 +42,9 @@ public class TreePopulator implements TerraBlockPopulator {
for(int z = 0; z < 16; z += 2) {
UserDefinedBiome biome = (UserDefinedBiome) provider.getBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z);
for(TreeLayer layer : biome.getConfig().getTrees()) {
if(layer.getDensity() >= random.nextDouble() * 100)
if(layer.getDensity() >= random.nextDouble() * 100) {
layer.place(chunk, new Vector2(offset(random, x), offset(random, z)));
}
}
}
}
@@ -16,7 +16,6 @@ public abstract class Ore {
protected TerraPlugin main;
public Ore(BlockData material, MaterialSet replaceable, boolean applyGravity, TerraPlugin main) {
this.material = material;
this.replaceable = replaceable;
this.applyGravity = applyGravity;
@@ -1,6 +1,7 @@
package com.dfsek.terra.world.population.items.ores;
import com.dfsek.terra.api.util.GlueList;
import com.dfsek.terra.api.util.generic.pair.ImmutablePair;
import java.util.List;
import java.util.function.BiConsumer;
@@ -11,22 +12,24 @@ import java.util.function.BiConsumer;
public class OreHolder {
private final List<Entry> entries = new GlueList<>();
public void forEach(BiConsumer<Ore, OreConfig> consumer) {
entries.forEach(entry -> consumer.accept(entry.getOre(), entry.getConfig()));
public void forEach(BiConsumer<String, ImmutablePair<Ore, OreConfig>> consumer) {
entries.forEach(entry -> consumer.accept(entry.getId(), ImmutablePair.of(entry.getOre(), entry.getConfig())));
}
public OreHolder add(Ore ore, OreConfig config) {
entries.add(new Entry(ore, config));
public OreHolder add(Ore ore, OreConfig config, String id) {
entries.add(new Entry(ore, config, id));
return this;
}
private static final class Entry {
private final Ore ore;
private final OreConfig config;
private final String id;
private Entry(Ore ore, OreConfig config) {
private Entry(Ore ore, OreConfig config, String id) {
this.ore = ore;
this.config = config;
this.id = id;
}
public OreConfig getConfig() {
@@ -36,5 +39,9 @@ public class OreHolder {
public Ore getOre() {
return ore;
}
public String getId() {
return id;
}
}
}
@@ -1,11 +1,11 @@
package com.dfsek.terra.world.population.items.tree;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.platform.world.Tree;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.util.collections.MaterialSet;
import com.dfsek.terra.api.util.collections.ProbabilityCollection;
import com.dfsek.terra.api.world.tree.Tree;
import java.util.Random;

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