9
0
mirror of https://github.com/VolmitSoftware/Iris.git synced 2025-12-30 20:39:21 +00:00

Compare commits

...

78 Commits

Author SHA1 Message Date
Brian Neumann-Fopiano
93db7ee0ee coco's other pr 2023-06-11 14:09:15 -04:00
Brian Fopiano
9ba4dd4099 Merge pull request #995 from CocoTheOwner/printWrongSpawner
Better print information about wrong spawner on marker
2023-06-11 14:00:09 -04:00
Brian Neumann-Fopiano
36efacf43c inc dim 2023-06-11 13:36:35 -04:00
Brian Neumann-Fopiano
d9bf91afa5 1.20 2023-06-11 13:05:23 -04:00
Brian Neumann-Fopiano
b0c96be841 1.20 Baseline 2023-06-07 16:50:44 -04:00
Sjoerd van de Goor
673b08f174 Merge branch 'master' into printWrongSpawner 2023-06-06 19:19:47 +02:00
Sjoerd van de Goor
989778af26 print in case a wrong spawner is specified 2023-06-06 19:18:47 +02:00
Brian Neumann-Fopiano
f5a3a7eb1a wm 2023-06-01 14:11:41 -04:00
Brian Neumann-Fopiano
7a97928c21 added a configurable 2023-05-31 12:19:32 -04:00
Brian Neumann-Fopiano
12a6d022cf other updates! 2023-05-16 23:38:37 -04:00
Brian Neumann-Fopiano
e3d2dfa99e Merge remote-tracking branch 'origin/master' 2023-05-16 23:32:12 -04:00
Brian Neumann-Fopiano
35cc39e9e2 cleanup plugin 2023-05-16 23:32:01 -04:00
Brian Fopiano
006b0b4a03 Update README.md 2023-04-29 18:52:20 -04:00
Brian Neumann-Fopiano
ec939b9f78 updated dependencies 2023-04-25 12:21:11 -04:00
Brian Neumann-Fopiano
7a94f53735 V+ 2023-04-20 00:12:20 -04:00
Brian Neumann-Fopiano
a9efe146ba Probably fixed * 2023-04-13 21:28:46 -04:00
Vatuu
956e2f6b06 Fixed Oraxen integration. 2023-04-13 23:24:12 +02:00
Brian Neumann-Fopiano
72623e0acf V+ 2023-04-12 18:05:47 -04:00
Brian Neumann-Fopiano
e0f673bc3c Overworld Tag update to 3001 2023-04-12 18:05:08 -04:00
Brian Neumann-Fopiano
fe40f12d2e Merge remote-tracking branch 'origin/master' 2023-04-12 18:02:18 -04:00
Brian Fopiano
0fda7a8506 Merge pull request #990 from CrazyDev05/oraxen_implementation_fix 2023-04-11 00:06:06 -04:00
Brian Neumann-Fopiano
22887da769 Added IPECTER's nms line
should fix compiling
2023-04-10 18:14:57 -04:00
Vatuu
a1e0a8ffc1 Fixed ItemsAdder integration. 2023-04-10 19:26:29 +02:00
CrazyDev22
62010116d7 change split limit from '1' to '2' 2023-04-10 13:05:09 +02:00
Brian Neumann-Fopiano
6ebcd02ae6 Fixed the pregen error! 2023-04-08 00:26:05 -04:00
Brian Fopiano
051015656a Merge pull request #986 from CocoTheOwner/re-slope-condition
Patches an issue with slope conditions when placing with commands
2023-04-04 14:00:19 -04:00
Sjoerd van de Goor
ee082762c6 Update object placer to ignore some stuff when using commands 2023-04-03 21:22:08 +02:00
Brian Fopiano
e967b5e052 Merge pull request #982 from CocoTheOwner/re-slope-condition
Reimplement slope condition
2023-04-02 15:39:42 -04:00
Brian Neumann-Fopiano
36505e2fa1 forgot v+ 2023-04-02 15:19:58 -04:00
Vatuu
502aa054f6 🧌 Fixed Color and Seed Issue. 2023-04-02 21:10:44 +02:00
Sjoerd van de Goor
cc5a880fd7 reimplement slope condition 2023-03-29 21:36:18 +02:00
Vatuu
6f9ad8b0eb Update to 1.19.4 2023-03-27 23:24:58 +02:00
Vatuu
ac6ab74d48 🧌 CustomItems support is pretty scuffed. Make it a gradle dependency already. 2023-03-27 23:22:15 +02:00
Brian Neumann-Fopiano
807ed2b247 gradelized patch
I'm not including this until it can be gradle-ized for sake of public compilation
2023-03-16 14:10:32 -04:00
Brian Neumann-Fopiano
367de5a8fd v+ 2023-03-16 14:03:54 -04:00
Vatuu
5bf2da714a Whoops. 2023-03-13 19:28:02 +01:00
Vatuu
cc90f42deb Implement CustomItems support. 2023-03-13 13:19:37 +01:00
Vatuu
20ceaead09 Fixed Oraxen and IA Integration. 2023-03-10 19:08:46 +01:00
Brian Fopiano
3ec2f8fb7b Merge pull request #962 from CocoTheOwner/render-continent-v2
Replace continent renderer with biomeStream
2023-03-05 19:18:54 -05:00
Brian Fopiano
6c5fac154e Merge pull request #975 from CocoTheOwner/mm-fix
Fixed mythicmobs and implements it properly.
2023-03-05 19:18:10 -05:00
Sjoerd van de Goor
540ab8f0d2 If special then unknown default should still be skipped 2023-03-03 23:57:37 +01:00
Brian Fopiano
17d2ac8d70 Merge pull request #973 from CocoTheOwner/spawn-entity
Entity spawn command for testing
2023-03-03 14:38:23 -08:00
Brian Fopiano
a6ebdead19 Merge pull request #966 from CocoTheOwner/update-world-nice
nicer command :)
2023-03-03 14:37:31 -08:00
Brian Fopiano
aa7631ecd0 Merge pull request #974 from CocoTheOwner/copypastafix
Fix copy paste of string gone wrong
2023-03-03 14:37:04 -08:00
Sjoerd van de Goor
4e138cad9f Why 2023-03-03 23:23:19 +01:00
Sjoerd van de Goor
7e55b5fcee Import MM 2023-03-03 23:23:15 +01:00
Sjoerd van de Goor
e19e5278b4 shouldve seen that, oops. 2023-03-03 23:01:09 +01:00
Sjoerd van de Goor
dfcd2dc83e lol 2023-03-03 21:59:42 +01:00
Sjoerd van de Goor
8775f842e6 Spawn command 2023-03-03 21:57:13 +01:00
Sjoerd van de Goor
7b07a4ba6c Location context needed to spawn entities 2023-03-03 21:56:33 +01:00
Sjoerd van de Goor
d78e5973e9 nicer command :) 2023-02-23 19:13:14 +01:00
CocoTheOwner
110d296184 Replace bridge with stream used in /ir what biome 2023-02-17 11:51:27 +01:00
CocoTheOwner
23cd5c117b Replace continent renderer with bridgeStream 2023-02-17 11:25:26 +01:00
CocoTheOwner
131c4692bc Remove DEFER from InferredType
Unused
2023-02-17 11:25:10 +01:00
Brian Neumann-Fopiano
f6571367db v+ oops 2023-02-15 18:41:17 -05:00
Brian Fopiano
f5c64c7480 Merge pull request #960 from CocoTheOwner/render-continent
Continent (i.e. heightmap + ocean/land division) render
2023-02-15 14:47:14 -08:00
Brian Fopiano
085f63a915 Merge pull request #961 from CocoTheOwner/slopes-rotation
Implements slope rotation
2023-02-15 14:46:48 -08:00
Brian Fopiano
3e022e1931 Merge pull request #954 from CocoTheOwner/slopes
Slope condition
2023-02-15 14:46:28 -08:00
Brian Fopiano
0dba3725ae Merge pull request #953 from CocoTheOwner/mm-set-stuff
MM should set its own stuff
2023-02-15 14:44:42 -08:00
Brian Fopiano
8bb409df4e Merge pull request #952 from CocoTheOwner/fix-image-math
Fix image mapping math
2023-02-15 14:44:09 -08:00
Brian Fopiano
603168a147 Merge pull request #951 from CocoTheOwner/fix-decree-conv
Actually check for origin on command invoke
2023-02-15 14:42:57 -08:00
Sjoerd van de Goor
2a95edd860 further documentation and cleaner code 2023-02-15 14:14:26 +01:00
Sjoerd van de Goor
e94406fb45 Implement rotation, remove precise rotation. 2023-02-15 14:05:34 +01:00
Sjoerd van de Goor
e5a7b5d0c6 Reformulate todo 2023-02-15 13:12:34 +01:00
Sjoerd van de Goor
d6f816fe2f Flipped water / land 2023-02-15 13:00:13 +01:00
Sjoerd van de Goor
c15d4a349f map to 255 range 2023-02-15 12:55:43 +01:00
Sjoerd van de Goor
3ce832583c Continent (i.e. heightmap + ocean/land division) render 2023-02-15 12:49:20 +01:00
Sjoerd van de Goor
5514fd2645 Proper ordering 2023-02-08 01:51:39 +01:00
Sjoerd van de Goor
66d07dcaca Revert "Slope condition"
This reverts commit d4c0e07b1d.
2023-02-08 01:35:18 +01:00
Sjoerd van de Goor
c1cf8e88ee That is pretty necessary 2023-02-08 01:33:31 +01:00
Sjoerd van de Goor
684bd739b9 Slope rotation (unfinished) 2023-02-08 01:30:12 +01:00
Sjoerd van de Goor
d4c0e07b1d Slope condition 2023-02-08 01:29:30 +01:00
Sjoerd van de Goor
a6ea6fcfb2 better 2023-02-07 17:39:44 +01:00
Sjoerd van de Goor
c366ec0c40 MM should set its own stuff 2023-02-07 17:26:06 +01:00
CocoTheOwner
8d715e2e4e x != z 2023-02-06 15:43:27 +01:00
CocoTheOwner
dea3ec80ac Fix image mapping math
Fixes snippet code, prevents an NPE, fixes centered for coordinateScale scaled image noises, fixes tiling on negative numbers (-1 % 2 = -1, a free fuck you from java)
2023-02-06 15:39:28 +01:00
CocoTheOwner
4053f05ba9 Actually check for origin on command invoke 2023-02-06 14:58:17 +01:00
Brian Neumann-Fopiano
ef07ec2c62 Datapack Shenanigans 2023-02-04 14:38:30 -05:00
54 changed files with 6729 additions and 6237 deletions

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
build/
libs/
.gradle/

View File

@@ -11,6 +11,8 @@ development.
Consider supporting our development by buying Iris on spigot! We work hard to make Iris the best it can be for everyone.
## Preface: if you need help compiling and you are a developer / intend to help out in the community or with development we would love to help you regardless in the discord! however do not come to the discord asking for free copies, or a tutorial on how to compile.
### Command Line Builds
1. Install [Java JDK 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)

View File

@@ -1,321 +1,332 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2021 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
id 'java'
id 'java-library'
id "io.freefair.lombok" version "6.3.0"
id "com.github.johnrengelman.shadow" version "7.1.2"
id "de.undercouch.download" version "5.0.1"
}
version '2.3.13-1.19.3' // Needs to be version specific
def nmsVersion = "1.19.3" //[NMS]
def apiVersion = '1.19'
def specialSourceVersion = '1.11.0' //[NMS]
def spigotJarVersion = '1.19.3-R0.1-SNAPSHOT' //[NMS]
def name = getRootProject().getName() // Defined in settings.gradle
def main = 'com.volmit.iris.Iris'
// ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED
// ======================== WINDOWS =============================
registerCustomOutputTask('Cyberpwn', 'C://Users/cyberpwn/Documents/development/server/plugins')
registerCustomOutputTask('Psycho', 'C://Dan/MinecraftDevelopment/Server/plugins')
registerCustomOutputTask('ArcaneArts', 'C://Users/arcane/Documents/development/server/plugins')
registerCustomOutputTask('Coco', 'D://Documents/MC/plugins')
registerCustomOutputTask('Strange', 'D://Servers/1.17 Test Server/plugins')
registerCustomOutputTask('Vatuu', 'D://Minecraft/Servers/1.19.3/plugins')
// ========================== UNIX ==============================
registerCustomOutputTaskUnix('CyberpwnLT', '/Users/danielmills/development/server/plugins')
registerCustomOutputTaskUnix('PsychoLT', '/Users/brianfopiano/Desktop/REMOTES/RemoteMinecraft/plugins')
// ==============================================================
/**
* Gradle is weird sometimes, we need to delete the plugin yml from the build folder to actually filter properly.
*/
file(jar.archiveFile.get().getAsFile().getParentFile().getParentFile().getParentFile().getAbsolutePath() + '/build/resources/main/plugin.yml').delete()
/**
* Expand properties into plugin yml
*/
processResources {
filesMatching('**/plugin.yml') {
expand(
'name': name.toString(),
'version': version.toString(),
'main': main.toString(),
'apiversion': apiVersion.toString()
)
}
}
/**
* Unified repo
*/
repositories {
mavenLocal {
content {
includeGroup("org.bukkit")
includeGroup("org.spigotmc")
}
}
maven { url "https://arcanearts.jfrog.io/artifactory/archives" }
}
/**
* We need parameter meta for the decree command system
*/
compileJava {
options.compilerArgs << '-parameters'
}
/**
* Configure Iris for shading
*/
shadowJar {
//minimize()
append("plugin.yml")
relocate 'com.dfsek.paralithic', 'com.volmit.iris.util.paralithic'
relocate 'io.papermc.lib', 'com.volmit.iris.util.paper'
relocate 'net.kyori', 'com.volmit.iris.util.kyori'
dependencies {
include(dependency('io.papermc:paperlib'))
include(dependency('com.dfsek:Paralithic'))
include(dependency('net.kyori:'))
}
}
configurations.all {
resolutionStrategy.cacheChangingModulesFor 60, 'minutes'
resolutionStrategy.cacheDynamicVersionsFor 60, 'minutes'
}
/**
* Dependencies.
*
* Provided or classpath dependencies are not shaded and are available on the runtime classpath
*
* Shaded dependencies are not available at runtime, nor are they available on mvn central so they
* need to be shaded into the jar (increasing binary size)
*
* Dynamically loaded dependencies are defined in the plugin.yml (updating these must be updated in the
* plugin.yml also, otherwise they wont be available). These do not increase binary size). Only declare
* these dependencies if they are available on mvn central.
*/
dependencies {
// Provided or Classpath
compileOnly 'org.projectlombok:lombok:1.18.24'
annotationProcessor 'org.projectlombok:lombok:1.18.24'
implementation 'org.spigotmc:spigot-api:1.19.3-R0.1-SNAPSHOT'
implementation 'me.clip:placeholderapi:2.11.1'
implementation 'io.th0rgal:oraxen:1.94.0'
implementation 'org.bukkit:craftbukkit:1.19.3-R0.1-SNAPSHOT:remapped-mojang' //[NMS]
implementation 'com.github.LoneDev6:api-itemsadder:3.1.0b'
// Shaded
implementation 'com.dfsek:Paralithic:0.4.0'
implementation 'io.papermc:paperlib:1.0.5'
implementation "net.kyori:adventure-text-minimessage:4.11.0"
implementation 'net.kyori:adventure-platform-bukkit:4.1.0'
implementation 'net.kyori:adventure-api:4.11.0'
// Dynamically Loaded
implementation 'io.timeandspace:smoothie-map:2.0.2'
implementation 'it.unimi.dsi:fastutil:8.5.8'
implementation 'com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2'
implementation 'org.zeroturnaround:zt-zip:1.14'
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'org.ow2.asm:asm:9.2'
implementation 'com.google.guava:guava:31.1-jre'
implementation 'bsf:bsf:2.4.0'
implementation 'rhino:js:1.7R2'
implementation 'com.github.ben-manes.caffeine:caffeine:3.0.6'
implementation 'org.apache.commons:commons-lang3:3.12.0'
}
if (JavaVersion.current().toString() != "17") {
System.err.println()
System.err.println("=========================================================================================================")
System.err.println("You must run gradle on Java 17. You are using " + JavaVersion.current())
System.err.println()
System.err.println("=== For IDEs ===")
System.err.println("1. Configure the project for Java 17")
System.err.println("2. Configure the bundled gradle to use Java 17 in settings")
System.err.println()
System.err.println("=== For Command Line (gradlew) ===")
System.err.println("1. Install JDK 17 from https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html")
System.err.println("2. Set JAVA_HOME environment variable to the new jdk installation folder such as C:\\Program Files\\Java\\jdk-17.0.1")
System.err.println("3. Open a new command prompt window to get the new environment variables if need be.")
System.err.println("=========================================================================================================")
System.err.println()
System.exit(69);
}
def buildToolsJar = new File(buildDir, "buildtools/BuildTools.jar");
def specialSourceJar = new File(buildDir, "specialsource/SpecialSource.jar");
def buildToolsFolder = new File(buildDir, "buildtools");
def specialSourceFolder = new File(buildDir, "specialsource");
def buildToolsHint = new File(buildDir, "buildtools/craftbukkit-" + nmsVersion + ".jar");
def outputShadeJar = new File(buildDir, "libs/Iris-" + version + "-all.jar");
def ssiJar = new File(buildDir, "specialsource/Iris-" + version + "-all.jar");
def ssobfJar = new File(buildDir, "specialsource/Iris-" + version + "-rmo.jar");
def ssJar = new File(buildDir, "specialsource/Iris-" + version + "-rma.jar");
def homePath = System.properties['user.home']
def m2 = new File(homePath + "/.m2/repository")
def m2s = m2.getAbsolutePath();
// ======================== Building Mapped Jars =============================
task downloadBuildtools(type: Download) {
group "remapping"
src 'https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar'
dest buildToolsJar
onlyIf {
!buildToolsJar.exists()
}
}
task downloadSpecialSource(type: Download) {
group "remapping"
src 'https://repo.maven.apache.org/maven2/net/md-5/SpecialSource/' + specialSourceVersion + '/SpecialSource-'+specialSourceVersion+'-shaded.jar'
dest specialSourceJar
onlyIf {
!specialSourceJar.exists()
}
}
task executeBuildTools(dependsOn: downloadBuildtools, type: JavaExec)
{
group "remapping"
classpath = files(buildToolsJar)
workingDir = buildToolsFolder
args = [
"--rev",
nmsVersion,
"--compile",
"craftbukkit",
"--remap"
]
onlyIf {
!buildToolsHint.exists()
}
}
task copyBuildToSpecialSource(type: Copy)
{
group "remapping"
from outputShadeJar
into specialSourceFolder
dependsOn(downloadSpecialSource, shadowJar)
}
task specialSourceRemapObfuscate(type: JavaExec)
{
group "remapping"
dependsOn(copyBuildToSpecialSource, downloadSpecialSource, shadowJar)
workingDir = specialSourceFolder
classpath = files(specialSourceJar,
new File(m2s + "/org/spigotmc/spigot/" + spigotJarVersion + "/spigot-" + spigotJarVersion + "-remapped-mojang.jar"))
mainClass = "net.md_5.specialsource.SpecialSource"
args = [
"--live",
"-i",
ssiJar.getName(),
"-o",
ssobfJar.getName(),
"-m",
m2s + "/org/spigotmc/minecraft-server/" + spigotJarVersion + "/minecraft-server-" + spigotJarVersion + "-maps-mojang.txt",
"--reverse",
]
}
task specialSourceRemap(type: JavaExec)
{
group "remapping"
dependsOn(specialSourceRemapObfuscate)
workingDir = specialSourceFolder
classpath = files(specialSourceJar,
new File(m2s + "/org/spigotmc/spigot/" + spigotJarVersion + "/spigot-" + spigotJarVersion + "-remapped-obf.jar"))
mainClass = "net.md_5.specialsource.SpecialSource"
args = [
"--live",
"-i",
ssobfJar.getName(),
"-o",
ssJar.getName(),
"-m",
m2s + "/org/spigotmc/minecraft-server/" + spigotJarVersion + "/minecraft-server-" + spigotJarVersion + "-maps-spigot.csrg"
]
}
tasks.compileJava.dependsOn(executeBuildTools)
compileJava {
options.encoding = "UTF-8"
}
task setup()
{
group("iris")
dependsOn(clean, executeBuildTools)
}
task iris(type: Copy)
{
group "iris"
from ssJar
into buildDir
rename { String fileName ->
fileName.replace('Iris-' + version + '-rma.jar', "Iris-" + version + ".jar")
}
dependsOn(specialSourceRemap)
}
def registerCustomOutputTask(name, path) {
if (!System.properties['os.name'].toLowerCase().contains('windows')) {
return;
}
tasks.register('build' + name, Copy) {
group('development')
outputs.upToDateWhen { false }
dependsOn(iris)
from(new File(buildDir, "Iris-" + version + ".jar"))
into(file(path))
rename { String fileName ->
fileName.replace("Iris-" + version + ".jar", "Iris.jar")
}
}
}
def registerCustomOutputTaskUnix(name, path) {
if (System.properties['os.name'].toLowerCase().contains('windows')) {
return;
}
tasks.register('build' + name, Copy) {
group('development')
outputs.upToDateWhen { false }
dependsOn(iris)
from(new File(buildDir, "Iris-" + version + ".jar"))
into(file(path))
rename { String fileName ->
fileName.replace("Iris-" + version + ".jar", "Iris.jar")
}
}
}
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2021 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
id 'java'
id 'java-library'
id "io.freefair.lombok" version "6.3.0"
id "com.github.johnrengelman.shadow" version "7.1.2"
id "de.undercouch.download" version "5.0.1"
}
version '2.7.0-1.20.0'
def nmsVersion = '1.20' //[NMS]
def apiVersion = '1.20'
def specialSourceVersion = '1.11.0' //[NMS]
def spigotJarVersion = '1.20-R0.1-SNAPSHOT' //[NMS]
def name = getRootProject().getName() // Defined in settings.gradle
def main = 'com.volmit.iris.Iris'
// ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED
// ======================== WINDOWS =============================
registerCustomOutputTask('Cyberpwn', 'C://Users/cyberpwn/Documents/development/server/plugins')
registerCustomOutputTask('Psycho', 'C://Dan/MinecraftDevelopment/Server/plugins')
registerCustomOutputTask('ArcaneArts', 'C://Users/arcane/Documents/development/server/plugins')
registerCustomOutputTask('Coco', 'D://mcsm/plugins')
registerCustomOutputTask('Strange', 'D://Servers/1.17 Test Server/plugins')
registerCustomOutputTask('Vatuu', 'D://Minecraft/Servers/1.19.4/plugins')
// ========================== UNIX ==============================
registerCustomOutputTaskUnix('CyberpwnLT', '/Users/danielmills/development/server/plugins')
registerCustomOutputTaskUnix('PsychoLT', '/Users/brianfopiano/Desktop/REMOTES/RemoteMinecraft/plugins')
// ==============================================================
/**
* Gradle is weird sometimes, we need to delete the plugin yml from the build folder to actually filter properly.
*/
file(jar.archiveFile.get().getAsFile().getParentFile().getParentFile().getParentFile().getAbsolutePath() + '/build/resources/main/plugin.yml').delete()
/**
* Expand properties into plugin yml
*/
processResources {
filesMatching('**/plugin.yml') {
expand(
'name': name.toString(),
'version': version.toString(),
'main': main.toString(),
'apiversion': apiVersion.toString()
)
}
}
/**
* Unified repo
*/
repositories {
mavenLocal {
content {
includeGroup("org.bukkit")
includeGroup("org.spigotmc")
}
}
mavenCentral()
maven { url "https://arcanearts.jfrog.io/artifactory/archives" }
maven { url "https://mvn.lumine.io/repository/maven-public/" }
maven { url "https://jitpack.io"}
maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots" }
maven { url "https://mvn.lumine.io/repository/maven/" }
maven { url "https://repo.triumphteam.dev/snapshots" }
maven { url "https://repo.mineinabyss.com/releases" }
}
/**
* We need parameter meta for the decree command system
*/
compileJava {
options.compilerArgs << '-parameters'
}
/**
* Configure Iris for shading
*/
shadowJar {
//minimize()
append("plugin.yml")
relocate 'com.dfsek.paralithic', 'com.volmit.iris.util.paralithic'
relocate 'io.papermc.lib', 'com.volmit.iris.util.paper'
relocate 'net.kyori', 'com.volmit.iris.util.kyori'
dependencies {
include(dependency('io.papermc:paperlib'))
include(dependency('com.dfsek:Paralithic'))
include(dependency('net.kyori:'))
}
}
configurations.all {
resolutionStrategy.cacheChangingModulesFor 60, 'minutes'
resolutionStrategy.cacheDynamicVersionsFor 60, 'minutes'
}
/**
* Dependencies.
*
* Provided or classpath dependencies are not shaded and are available on the runtime classpath
*
* Shaded dependencies are not available at runtime, nor are they available on mvn central so they
* need to be shaded into the jar (increasing binary size)
*
* Dynamically loaded dependencies are defined in the plugin.yml (updating these must be updated in the
* plugin.yml also, otherwise they wont be available). These do not increase binary size). Only declare
* these dependencies if they are available on mvn central.
*/
dependencies {
// Provided or Classpath
compileOnly 'org.projectlombok:lombok:1.18.24'
annotationProcessor 'org.projectlombok:lombok:1.18.24'
implementation 'org.spigotmc:spigot-api:1.20-R0.1-SNAPSHOT'
implementation 'org.bukkit:craftbukkit:1.20-R0.1-SNAPSHOT:remapped-mojang' //[NMS]
// Third Party Integrations
implementation 'com.github.oraxen:oraxen:1.152.5'
implementation 'com.github.LoneDev6:api-itemsadder:3.4.1-r4'
implementation 'me.clip:placeholderapi:2.11.3'
//implementation files('libs/CustomItems.jar')
// Shaded
implementation 'com.dfsek:Paralithic:0.4.0'
implementation 'io.papermc:paperlib:1.0.5'
implementation "net.kyori:adventure-text-minimessage:4.13.1"
implementation 'net.kyori:adventure-platform-bukkit:4.3.0'
implementation 'net.kyori:adventure-api:4.13.1'
implementation 'io.lumine:Mythic-Dist:5.2.1'
// Dynamically Loaded
implementation 'io.timeandspace:smoothie-map:2.0.2'
implementation 'it.unimi.dsi:fastutil:8.5.8'
implementation 'com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2'
implementation 'org.zeroturnaround:zt-zip:1.14'
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'org.ow2.asm:asm:9.2'
implementation 'com.google.guava:guava:31.1-jre'
implementation 'bsf:bsf:2.4.0'
implementation 'rhino:js:1.7R2'
implementation 'com.github.ben-manes.caffeine:caffeine:3.0.6'
implementation 'org.apache.commons:commons-lang3:3.12.0'
}
if (JavaVersion.current().toString() != "17") {
System.err.println()
System.err.println("=========================================================================================================")
System.err.println("You must run gradle on Java 17. You are using " + JavaVersion.current())
System.err.println()
System.err.println("=== For IDEs ===")
System.err.println("1. Configure the project for Java 17")
System.err.println("2. Configure the bundled gradle to use Java 17 in settings")
System.err.println()
System.err.println("=== For Command Line (gradlew) ===")
System.err.println("1. Install JDK 17 from https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html")
System.err.println("2. Set JAVA_HOME environment variable to the new jdk installation folder such as C:\\Program Files\\Java\\jdk-17.0.1")
System.err.println("3. Open a new command prompt window to get the new environment variables if need be.")
System.err.println("=========================================================================================================")
System.err.println()
System.exit(69);
}
def buildToolsJar = new File(buildDir, "buildtools/BuildTools.jar");
def specialSourceJar = new File(buildDir, "specialsource/SpecialSource.jar");
def buildToolsFolder = new File(buildDir, "buildtools");
def specialSourceFolder = new File(buildDir, "specialsource");
def buildToolsHint = new File(buildDir, "buildtools/craftbukkit-" + nmsVersion + ".jar");
def outputShadeJar = new File(buildDir, "libs/Iris-" + version + "-all.jar");
def ssiJar = new File(buildDir, "specialsource/Iris-" + version + "-all.jar");
def ssobfJar = new File(buildDir, "specialsource/Iris-" + version + "-rmo.jar");
def ssJar = new File(buildDir, "specialsource/Iris-" + version + "-rma.jar");
def homePath = System.properties['user.home']
def m2 = new File(homePath + "/.m2/repository")
def m2s = m2.getAbsolutePath();
// ======================== Building Mapped Jars =============================
task downloadBuildtools(type: Download) {
group "remapping"
src 'https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar'
dest buildToolsJar
onlyIf {
!buildToolsJar.exists()
}
}
task downloadSpecialSource(type: Download) {
group "remapping"
src 'https://repo.maven.apache.org/maven2/net/md-5/SpecialSource/' + specialSourceVersion + '/SpecialSource-'+specialSourceVersion+'-shaded.jar'
dest specialSourceJar
onlyIf {
!specialSourceJar.exists()
}
}
task executeBuildTools(dependsOn: downloadBuildtools, type: JavaExec)
{
group "remapping"
classpath = files(buildToolsJar)
workingDir = buildToolsFolder
args = [
"--rev",
nmsVersion,
"--compile",
"craftbukkit",
"--remap"
]
onlyIf {
!buildToolsHint.exists()
}
}
task copyBuildToSpecialSource(type: Copy)
{
group "remapping"
from outputShadeJar
into specialSourceFolder
dependsOn(downloadSpecialSource, shadowJar)
}
task specialSourceRemapObfuscate(type: JavaExec)
{
group "remapping"
dependsOn(copyBuildToSpecialSource, downloadSpecialSource, shadowJar)
workingDir = specialSourceFolder
classpath = files(specialSourceJar,
new File(m2s + "/org/spigotmc/spigot/" + spigotJarVersion + "/spigot-" + spigotJarVersion + "-remapped-mojang.jar"))
mainClass = "net.md_5.specialsource.SpecialSource"
args = [
"--live",
"-i",
ssiJar.getName(),
"-o",
ssobfJar.getName(),
"-m",
m2s + "/org/spigotmc/minecraft-server/" + spigotJarVersion + "/minecraft-server-" + spigotJarVersion + "-maps-mojang.txt",
"--reverse",
]
}
task specialSourceRemap(type: JavaExec)
{
group "remapping"
dependsOn(specialSourceRemapObfuscate)
workingDir = specialSourceFolder
classpath = files(specialSourceJar,
new File(m2s + "/org/spigotmc/spigot/" + spigotJarVersion + "/spigot-" + spigotJarVersion + "-remapped-obf.jar"))
mainClass = "net.md_5.specialsource.SpecialSource"
args = [
"--live",
"-i",
ssobfJar.getName(),
"-o",
ssJar.getName(),
"-m",
m2s + "/org/spigotmc/minecraft-server/" + spigotJarVersion + "/minecraft-server-" + spigotJarVersion + "-maps-spigot.csrg"
]
}
tasks.compileJava.dependsOn(executeBuildTools)
compileJava {
options.encoding = "UTF-8"
}
task setup()
{
group("iris")
dependsOn(clean, executeBuildTools)
}
task iris(type: Copy)
{
group "iris"
from ssJar
into buildDir
rename { String fileName ->
fileName.replace('Iris-' + version + '-rma.jar', "Iris-" + version + ".jar")
}
dependsOn(specialSourceRemap)
}
def registerCustomOutputTask(name, path) {
if (!System.properties['os.name'].toLowerCase().contains('windows')) {
return;
}
tasks.register('build' + name, Copy) {
group('development')
outputs.upToDateWhen { false }
dependsOn(iris)
from(new File(buildDir, "Iris-" + version + ".jar"))
into(file(path))
rename { String fileName ->
fileName.replace("Iris-" + version + ".jar", "Iris.jar")
}
}
}
def registerCustomOutputTaskUnix(name, path) {
if (System.properties['os.name'].toLowerCase().contains('windows')) {
return;
}
tasks.register('build' + name, Copy) {
group('development')
outputs.upToDateWhen { false }
dependsOn(iris)
from(new File(buildDir, "Iris-" + version + ".jar"))
into(file(path))
rename { String fileName ->
fileName.replace("Iris-" + version + ".jar", "Iris.jar")
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -156,6 +156,8 @@ public class IrisSettings {
public int spinh = -20;
public int spins = 7;
public int spinb = 8;
public String cartographerMessage = "Iris does not allow cartographers in its world due to crashes.";
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public boolean canUseCustomColors(VolmitSender volmitSender) {

View File

@@ -1,342 +1,342 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.decree.DecreeContext;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.jobs.QueueJob;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command")
public class CommandIris implements DecreeExecutor {
private CommandStudio studio;
private CommandPregen pregen;
private CommandSettings settings;
private CommandObject object;
private CommandJigsaw jigsaw;
private CommandWhat what;
private CommandEdit edit;
private CommandFind find;
@Decree(description = "Create a new world", aliases = {"+", "c"})
public void create(
@Param(aliases = "world-name", description = "The name of the world to create")
String name,
@Param(aliases = "dimension", description = "The dimension type to create the world with", defaultValue = "default")
IrisDimension type,
@Param(description = "The seed to generate the world with", defaultValue = "1337")
long seed
) {
if (name.equals("iris")) {
sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds.");
sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?");
return;
}
if (new File(Bukkit.getWorldContainer(), name).exists()) {
sender().sendMessage(C.RED + "That folder already exists!");
return;
}
try {
IrisToolbelt.createWorld()
.dimension(type.getLoadKey())
.name(name)
.seed(seed)
.sender(sender())
.studio(false)
.create();
} catch (Throwable e) {
sender().sendMessage(C.RED + "Exception raised during creation. See the console for more details.");
Iris.error("Exception raised during world creation: " + e.getMessage());
Iris.reportError(e);
return;
}
sender().sendMessage(C.GREEN + "Successfully created your world!");
}
@Decree(description = "Remove an Iris world", aliases = {"del", "rm"}, sync = true)
public void remove(
@Param(description = "The world to remove")
World world,
@Param(description = "Whether to also remove the folder (if set to false, just does not load the world)", defaultValue = "true")
boolean delete
) {
if (!IrisToolbelt.isIrisWorld(world)) {
sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", Bukkit.getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList()));
return;
}
sender().sendMessage(C.GREEN + "Removing world: " + world.getName());
try {
if (IrisToolbelt.removeWorld(world)) {
sender().sendMessage(C.GREEN + "Successfully removed " + world.getName() + " from bukkit.yml");
} else {
sender().sendMessage(C.YELLOW + "Looks like the world was already removed from bukkit.yml");
}
} catch (IOException e) {
sender().sendMessage(C.RED + "Failed to save bukkit.yml because of " + e.getMessage());
e.printStackTrace();
}
IrisToolbelt.evacuate(world, "Deleting world");
Bukkit.unloadWorld(world, false);
if (delete && world.getWorldFolder().delete()) {
sender().sendMessage(C.GREEN + "Successfully removed world folder");
} else {
sender().sendMessage(C.RED + "Failed to remove world folder");
}
}
@Decree(description = "Print version information")
public void version() {
sender().sendMessage(C.GREEN + "Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software");
}
@Decree(description = "Print world height information", origin = DecreeOrigin.PLAYER)
public void height() {
sender().sendMessage(C.GREEN + "" + sender().player().getWorld().getMinHeight() + " to " + sender().player().getWorld().getMaxHeight());
sender().sendMessage(C.GREEN + "Total Height: " + (sender().player().getWorld().getMaxHeight() - sender().player().getWorld().getMinHeight()));
}
@Decree(description = "QOL command to open a overworld studio world.", sync = true)
public void so() {
sender().sendMessage(C.GREEN + "Opening studio for the \"Overworld\" pack (seed: 1337)");
Iris.service(StudioSVC.class).open(sender(), 1337, "overworld");
}
@Decree(description = "Set aura spins")
public void aura(
@Param(description = "The h color value", defaultValue = "-20")
int h,
@Param(description = "The s color value", defaultValue = "7")
int s,
@Param(description = "The b color value", defaultValue = "8")
int b
) {
IrisSettings.get().getGeneral().setSpinh(h);
IrisSettings.get().getGeneral().setSpins(s);
IrisSettings.get().getGeneral().setSpinb(b);
IrisSettings.get().forceSave();
sender().sendMessage("<rainbow>Aura Spins updated to " + h + " " + s + " " + b);
}
@Decree(description = "Bitwise calculations")
public void bitwise(
@Param(description = "The first value to run calculations on")
int value1,
@Param(description = "The operator: | & ^ ≺≺ ≻≻ ")
String operator,
@Param(description = "The second value to run calculations on")
int value2
) {
Integer v = null;
switch (operator) {
case "|" -> v = value1 | value2;
case "&" -> v = value1 & value2;
case "^" -> v = value1 ^ value2;
case "%" -> v = value1 % value2;
case ">>" -> v = value1 >> value2;
case "<<" -> v = value1 << value2;
}
if (v == null) {
sender().sendMessage(C.RED + "The operator you entered: (" + operator + ") is invalid!");
return;
}
sender().sendMessage(C.GREEN + "" + value1 + " " + C.GREEN + operator.replaceAll("<", "").replaceAll(">", "").replaceAll("%", "") + " " + C.GREEN + value2 + C.GREEN + " returns " + C.GREEN + v);
}
@Decree(description = "Toggle debug")
public void debug(
@Param(name = "on", description = "Whether or not debug should be on", defaultValue = "other")
Boolean on
) {
boolean to = on == null ? !IrisSettings.get().getGeneral().isDebug() : on;
IrisSettings.get().getGeneral().setDebug(to);
IrisSettings.get().forceSave();
sender().sendMessage(C.GREEN + "Set debug to: " + to);
}
@Decree(description = "Download a project.", aliases = "dl")
public void download(
@Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project")
String pack,
@Param(name = "branch", description = "The branch to download from", defaultValue = "main")
String branch,
@Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false")
boolean trim,
@Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false")
boolean overwrite
) {
sender().sendMessage(C.GREEN + "Downloading pack: " + pack + "/" + branch + (trim ? " trimmed" : "") + (overwrite ? " overwriting" : ""));
if (pack.equals("overworld")) {
String url = "https://github.com/IrisDimensions/overworld/releases/download/" + Iris.OVERWORLD_TAG + "/overworld.zip";
Iris.service(StudioSVC.class).downloadRelease(sender(), url, trim, overwrite);
} else {
Iris.service(StudioSVC.class).downloadSearch(sender(), "IrisDimensions/" + pack + "/" + branch, trim, overwrite);
}
}
@Decree(description = "Get metrics for your world", aliases = "measure", origin = DecreeOrigin.PLAYER)
public void metrics() {
if (!IrisToolbelt.isIrisWorld(world())) {
sender().sendMessage(C.RED + "You must be in an Iris world");
return;
}
sender().sendMessage(C.GREEN + "Sending metrics...");
engine().printMetrics(sender());
}
@Decree(description = "Reload configuration file (this is also done automatically)")
public void reload() {
IrisSettings.invalidate();
IrisSettings.get();
sender().sendMessage(C.GREEN + "Hotloaded settings");
}
@Decree(name = "regen", description = "Regenerate nearby chunks.", aliases = "rg", sync = true, origin = DecreeOrigin.PLAYER)
public void regen(
@Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5")
int radius
) {
if (IrisToolbelt.isIrisWorld(player().getWorld())) {
VolmitSender sender = sender();
J.a(() -> {
DecreeContext.touch(sender);
PlatformChunkGenerator plat = IrisToolbelt.access(player().getWorld());
Engine engine = plat.getEngine();
try {
Chunk cx = player().getLocation().getChunk();
KList<Runnable> js = new KList<>();
BurstExecutor b = MultiBurst.burst.burst();
b.setMulticore(false);
int rad = engine.getMantle().getRealRadius();
for (int i = -(radius + rad); i <= radius + rad; i++) {
for (int j = -(radius + rad); j <= radius + rad; j++) {
engine.getMantle().getMantle().deleteChunk(i + cx.getX(), j + cx.getZ());
}
}
for (int i = -radius; i <= radius; i++) {
for (int j = -radius; j <= radius; j++) {
int finalJ = j;
int finalI = i;
b.queue(() -> plat.injectChunkReplacement(player().getWorld(), finalI + cx.getX(), finalJ + cx.getZ(), (f) -> {
synchronized (js) {
js.add(f);
}
}));
}
}
b.complete();
sender().sendMessage(C.GREEN + "Regenerating " + Form.f(js.size()) + " Sections");
QueueJob<Runnable> r = new QueueJob<>() {
final KList<Future<?>> futures = new KList<>();
@Override
public void execute(Runnable runnable) {
futures.add(J.sfut(runnable));
if (futures.size() > 64) {
while (futures.isNotEmpty()) {
try {
futures.remove(0).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
@Override
public String getName() {
return "Regenerating";
}
};
r.queue(js);
r.execute(sender());
} catch (Throwable e) {
sender().sendMessage("Unable to parse view-distance");
}
});
} else {
sender().sendMessage(C.RED + "You must be in an Iris World to use regen!");
}
}
@Decree(description = "Update the pack of a world (UNSAFE!)", name = "^world", aliases = "update-world")
public void updateWorld(
@Param(description = "The world to update", contextual = true)
World world,
@Param(description = "The pack to install into the world", contextual = true, aliases = "dimension")
IrisDimension pack,
@Param(description = "Make sure to make a backup & read the warnings first!", defaultValue = "false", aliases = "c")
boolean confirm,
@Param(description = "Should Iris download the pack again for you", defaultValue = "false", name = "fresh-download", aliases = {"fresh", "new"})
boolean freshDownload
) {
if (!confirm) {
sender().sendMessage(new String[]{
C.RED + "You should always make a backup before using this",
C.YELLOW + "Issues caused by this can be, but are not limited to:",
C.YELLOW + " - Broken chunks (cut-offs) between old and new chunks (before & after the update)",
C.YELLOW + " - Regenerated chunks that do not fit in with the old chunks",
C.YELLOW + " - Structures not spawning again when regenerating",
C.YELLOW + " - Caves not lining up",
C.YELLOW + " - Terrain layers not lining up",
C.RED + "Now that you are aware of the risks, and have made a back-up:",
C.RED + "/iris ^world <world> <pack> confirm=true"
});
return;
}
File folder = world.getWorldFolder();
folder.mkdirs();
if (freshDownload) {
Iris.service(StudioSVC.class).downloadSearch(sender(), pack.getLoadKey(), false, true);
}
Iris.service(StudioSVC.class).installIntoWorld(sender(), pack.getLoadKey(), folder);
}
}
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.decree.DecreeContext;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.jobs.QueueJob;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command")
public class CommandIris implements DecreeExecutor {
private CommandStudio studio;
private CommandPregen pregen;
private CommandSettings settings;
private CommandObject object;
private CommandJigsaw jigsaw;
private CommandWhat what;
private CommandEdit edit;
private CommandFind find;
@Decree(description = "Create a new world", aliases = {"+", "c"})
public void create(
@Param(aliases = "world-name", description = "The name of the world to create")
String name,
@Param(aliases = "dimension", description = "The dimension type to create the world with", defaultValue = "default")
IrisDimension type,
@Param(description = "The seed to generate the world with", defaultValue = "1337")
long seed
) {
if (name.equals("iris")) {
sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds.");
sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?");
return;
}
if (new File(Bukkit.getWorldContainer(), name).exists()) {
sender().sendMessage(C.RED + "That folder already exists!");
return;
}
try {
IrisToolbelt.createWorld()
.dimension(type.getLoadKey())
.name(name)
.seed(seed)
.sender(sender())
.studio(false)
.create();
} catch (Throwable e) {
sender().sendMessage(C.RED + "Exception raised during creation. See the console for more details.");
Iris.error("Exception raised during world creation: " + e.getMessage());
Iris.reportError(e);
return;
}
sender().sendMessage(C.GREEN + "Successfully created your world!");
}
@Decree(description = "Remove an Iris world", aliases = {"del", "rm"}, sync = true)
public void remove(
@Param(description = "The world to remove")
World world,
@Param(description = "Whether to also remove the folder (if set to false, just does not load the world)", defaultValue = "true")
boolean delete
) {
if (!IrisToolbelt.isIrisWorld(world)) {
sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", Bukkit.getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList()));
return;
}
sender().sendMessage(C.GREEN + "Removing world: " + world.getName());
try {
if (IrisToolbelt.removeWorld(world)) {
sender().sendMessage(C.GREEN + "Successfully removed " + world.getName() + " from bukkit.yml");
} else {
sender().sendMessage(C.YELLOW + "Looks like the world was already removed from bukkit.yml");
}
} catch (IOException e) {
sender().sendMessage(C.RED + "Failed to save bukkit.yml because of " + e.getMessage());
e.printStackTrace();
}
IrisToolbelt.evacuate(world, "Deleting world");
Bukkit.unloadWorld(world, false);
if (delete && world.getWorldFolder().delete()) {
sender().sendMessage(C.GREEN + "Successfully removed world folder");
} else {
sender().sendMessage(C.RED + "Failed to remove world folder");
}
}
@Decree(description = "Print version information")
public void version() {
sender().sendMessage(C.GREEN + "Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software");
}
@Decree(description = "Print world height information", origin = DecreeOrigin.PLAYER)
public void height() {
sender().sendMessage(C.GREEN + "" + sender().player().getWorld().getMinHeight() + " to " + sender().player().getWorld().getMaxHeight());
sender().sendMessage(C.GREEN + "Total Height: " + (sender().player().getWorld().getMaxHeight() - sender().player().getWorld().getMinHeight()));
}
@Decree(description = "QOL command to open a overworld studio world.", sync = true)
public void so() {
sender().sendMessage(C.GREEN + "Opening studio for the \"Overworld\" pack (seed: 1337)");
Iris.service(StudioSVC.class).open(sender(), 1337, "overworld");
}
@Decree(description = "Set aura spins")
public void aura(
@Param(description = "The h color value", defaultValue = "-20")
int h,
@Param(description = "The s color value", defaultValue = "7")
int s,
@Param(description = "The b color value", defaultValue = "8")
int b
) {
IrisSettings.get().getGeneral().setSpinh(h);
IrisSettings.get().getGeneral().setSpins(s);
IrisSettings.get().getGeneral().setSpinb(b);
IrisSettings.get().forceSave();
sender().sendMessage("<rainbow>Aura Spins updated to " + h + " " + s + " " + b);
}
@Decree(description = "Bitwise calculations")
public void bitwise(
@Param(description = "The first value to run calculations on")
int value1,
@Param(description = "The operator: | & ^ ≺≺ ≻≻ ")
String operator,
@Param(description = "The second value to run calculations on")
int value2
) {
Integer v = null;
switch (operator) {
case "|" -> v = value1 | value2;
case "&" -> v = value1 & value2;
case "^" -> v = value1 ^ value2;
case "%" -> v = value1 % value2;
case ">>" -> v = value1 >> value2;
case "<<" -> v = value1 << value2;
}
if (v == null) {
sender().sendMessage(C.RED + "The operator you entered: (" + operator + ") is invalid!");
return;
}
sender().sendMessage(C.GREEN + "" + value1 + " " + C.GREEN + operator.replaceAll("<", "").replaceAll(">", "").replaceAll("%", "") + " " + C.GREEN + value2 + C.GREEN + " returns " + C.GREEN + v);
}
@Decree(description = "Toggle debug")
public void debug(
@Param(name = "on", description = "Whether or not debug should be on", defaultValue = "other")
Boolean on
) {
boolean to = on == null ? !IrisSettings.get().getGeneral().isDebug() : on;
IrisSettings.get().getGeneral().setDebug(to);
IrisSettings.get().forceSave();
sender().sendMessage(C.GREEN + "Set debug to: " + to);
}
@Decree(description = "Download a project.", aliases = "dl")
public void download(
@Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project")
String pack,
@Param(name = "branch", description = "The branch to download from", defaultValue = "main")
String branch,
@Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false")
boolean trim,
@Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false")
boolean overwrite
) {
sender().sendMessage(C.GREEN + "Downloading pack: " + pack + "/" + branch + (trim ? " trimmed" : "") + (overwrite ? " overwriting" : ""));
if (pack.equals("overworld")) {
String url = "https://github.com/IrisDimensions/overworld/releases/download/" + Iris.OVERWORLD_TAG + "/overworld.zip";
Iris.service(StudioSVC.class).downloadRelease(sender(), url, trim, overwrite);
} else {
Iris.service(StudioSVC.class).downloadSearch(sender(), "IrisDimensions/" + pack + "/" + branch, trim, overwrite);
}
}
@Decree(description = "Get metrics for your world", aliases = "measure", origin = DecreeOrigin.PLAYER)
public void metrics() {
if (!IrisToolbelt.isIrisWorld(world())) {
sender().sendMessage(C.RED + "You must be in an Iris world");
return;
}
sender().sendMessage(C.GREEN + "Sending metrics...");
engine().printMetrics(sender());
}
@Decree(description = "Reload configuration file (this is also done automatically)")
public void reload() {
IrisSettings.invalidate();
IrisSettings.get();
sender().sendMessage(C.GREEN + "Hotloaded settings");
}
@Decree(name = "regen", description = "Regenerate nearby chunks.", aliases = "rg", sync = true, origin = DecreeOrigin.PLAYER)
public void regen(
@Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5")
int radius
) {
if (IrisToolbelt.isIrisWorld(player().getWorld())) {
VolmitSender sender = sender();
J.a(() -> {
DecreeContext.touch(sender);
PlatformChunkGenerator plat = IrisToolbelt.access(player().getWorld());
Engine engine = plat.getEngine();
try {
Chunk cx = player().getLocation().getChunk();
KList<Runnable> js = new KList<>();
BurstExecutor b = MultiBurst.burst.burst();
b.setMulticore(false);
int rad = engine.getMantle().getRealRadius();
for (int i = -(radius + rad); i <= radius + rad; i++) {
for (int j = -(radius + rad); j <= radius + rad; j++) {
engine.getMantle().getMantle().deleteChunk(i + cx.getX(), j + cx.getZ());
}
}
for (int i = -radius; i <= radius; i++) {
for (int j = -radius; j <= radius; j++) {
int finalJ = j;
int finalI = i;
b.queue(() -> plat.injectChunkReplacement(player().getWorld(), finalI + cx.getX(), finalJ + cx.getZ(), (f) -> {
synchronized (js) {
js.add(f);
}
}));
}
}
b.complete();
sender().sendMessage(C.GREEN + "Regenerating " + Form.f(js.size()) + " Sections");
QueueJob<Runnable> r = new QueueJob<>() {
final KList<Future<?>> futures = new KList<>();
@Override
public void execute(Runnable runnable) {
futures.add(J.sfut(runnable));
if (futures.size() > 64) {
while (futures.isNotEmpty()) {
try {
futures.remove(0).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
@Override
public String getName() {
return "Regenerating";
}
};
r.queue(js);
r.execute(sender());
} catch (Throwable e) {
sender().sendMessage("Unable to parse view-distance");
}
});
} else {
sender().sendMessage(C.RED + "You must be in an Iris World to use regen!");
}
}
@Decree(description = "Update the pack of a world (UNSAFE!)", name = "^world", aliases = "update-world")
public void updateWorld(
@Param(description = "The world to update", contextual = true)
World world,
@Param(description = "The pack to install into the world", contextual = true, aliases = "dimension")
IrisDimension pack,
@Param(description = "Make sure to make a backup & read the warnings first!", defaultValue = "false", aliases = "c")
boolean confirm,
@Param(description = "Should Iris download the pack again for you", defaultValue = "false", name = "fresh-download", aliases = {"fresh", "new"})
boolean freshDownload
) {
if (!confirm) {
sender().sendMessage(new String[]{
C.RED + "You should always make a backup before using this",
C.YELLOW + "Issues caused by this can be, but are not limited to:",
C.YELLOW + " - Broken chunks (cut-offs) between old and new chunks (before & after the update)",
C.YELLOW + " - Regenerated chunks that do not fit in with the old chunks",
C.YELLOW + " - Structures not spawning again when regenerating",
C.YELLOW + " - Caves not lining up",
C.YELLOW + " - Terrain layers not lining up",
C.RED + "Now that you are aware of the risks, and have made a back-up:",
C.RED + "/iris ^world " + world.getName() + " " + pack.getLoadKey() + " confirm=true"
});
return;
}
File folder = world.getWorldFolder();
folder.mkdirs();
if (freshDownload) {
Iris.service(StudioSVC.class).downloadSearch(sender(), pack.getLoadKey(), false, true);
}
Iris.service(StudioSVC.class).installIntoWorld(sender(), pack.getLoadKey(), folder);
}
}

View File

@@ -464,19 +464,16 @@ public class CommandStudio implements DecreeExecutor {
sender().sendMessage(C.GREEN + "Done! " + report.getPath());
}
@Decree(description = "Summon an Iris Entity", origin = DecreeOrigin.PLAYER)
public void summon(
@Param(description = "The Iris Entity to spawn")
@Decree(description = "Spawn an Iris entity", aliases = "summon", origin = DecreeOrigin.PLAYER)
public void spawn(
@Param(description = "The entity to spawn")
IrisEntity entity,
@Param(description = "The location at which to spawn the entity", defaultValue = "self")
@Param(description = "The location to spawn the entity at", contextual = true)
Vector location
) {
if (!sender().isPlayer()) {
sender().sendMessage(C.RED + "Players only (this is a config error. Ask support to add DecreeOrigin.PLAYER to the command you tried to run)");
return;
if (!IrisToolbelt.isIrisWorld(player().getWorld())) {
sender().sendMessage(C.RED + "You have to be in an Iris world to spawn entities properly. Trying to spawn the best we can do.");
}
sender().sendMessage(C.GREEN + "Spawning entity");
entity.spawn(engine(), new Location(world(), location.getX(), location.getY(), location.getZ()));
}

View File

@@ -1,67 +1,85 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui.components;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.interpolation.IrisInterpolation;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.function.BiFunction;
public class IrisRenderer {
private final Engine renderer;
public IrisRenderer(Engine renderer) {
this.renderer = renderer;
}
public BufferedImage render(double sx, double sz, double size, int resolution, RenderType currentType) {
BufferedImage image = new BufferedImage(resolution, resolution, BufferedImage.TYPE_INT_RGB);
BiFunction<Double, Double, Integer> colorFunction = (d, dx) -> Color.black.getRGB();
switch (currentType) {
case BIOME, DECORATOR_LOAD, OBJECT_LOAD, LAYER_LOAD ->
colorFunction = (x, z) -> renderer.getComplex().getTrueBiomeStream().get(x, z).getColor(renderer, currentType).getRGB();
case BIOME_LAND ->
colorFunction = (x, z) -> renderer.getComplex().getLandBiomeStream().get(x, z).getColor(renderer, currentType).getRGB();
case BIOME_SEA ->
colorFunction = (x, z) -> renderer.getComplex().getSeaBiomeStream().get(x, z).getColor(renderer, currentType).getRGB();
case REGION ->
colorFunction = (x, z) -> renderer.getComplex().getRegionStream().get(x, z).getColor(renderer.getComplex(), currentType).getRGB();
case CAVE_LAND ->
colorFunction = (x, z) -> renderer.getComplex().getCaveBiomeStream().get(x, z).getColor(renderer, currentType).getRGB();
case HEIGHT ->
colorFunction = (x, z) -> Color.getHSBColor(renderer.getComplex().getHeightStream().get(x, z).floatValue(), 100, 100).getRGB();
}
double x, z;
int i, j;
for (i = 0; i < resolution; i++) {
x = IrisInterpolation.lerp(sx, sx + size, (double) i / (double) (resolution));
for (j = 0; j < resolution; j++) {
z = IrisInterpolation.lerp(sz, sz + size, (double) j / (double) (resolution));
image.setRGB(i, j, colorFunction.apply(x, z));
}
}
return image;
}
}
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui.components;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBiomeGeneratorLink;
import com.volmit.iris.util.interpolation.IrisInterpolation;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.function.BiFunction;
public class IrisRenderer {
private final Engine renderer;
public IrisRenderer(Engine renderer) {
this.renderer = renderer;
}
public BufferedImage render(double sx, double sz, double size, int resolution, RenderType currentType) {
BufferedImage image = new BufferedImage(resolution, resolution, BufferedImage.TYPE_INT_RGB);
BiFunction<Double, Double, Integer> colorFunction = (d, dx) -> Color.black.getRGB();
switch (currentType) {
case BIOME, DECORATOR_LOAD, OBJECT_LOAD, LAYER_LOAD ->
colorFunction = (x, z) -> renderer.getComplex().getTrueBiomeStream().get(x, z).getColor(renderer, currentType).getRGB();
case BIOME_LAND ->
colorFunction = (x, z) -> renderer.getComplex().getLandBiomeStream().get(x, z).getColor(renderer, currentType).getRGB();
case BIOME_SEA ->
colorFunction = (x, z) -> renderer.getComplex().getSeaBiomeStream().get(x, z).getColor(renderer, currentType).getRGB();
case REGION ->
colorFunction = (x, z) -> renderer.getComplex().getRegionStream().get(x, z).getColor(renderer.getComplex(), currentType).getRGB();
case CAVE_LAND ->
colorFunction = (x, z) -> renderer.getComplex().getCaveBiomeStream().get(x, z).getColor(renderer, currentType).getRGB();
case HEIGHT ->
colorFunction = (x, z) -> Color.getHSBColor(renderer.getComplex().getHeightStream().get(x, z).floatValue(), 100, 100).getRGB();
case CONTINENT -> colorFunction = (x, z) -> {
IrisBiome b = renderer.getBiome((int) Math.round(x), renderer.getMaxHeight() - 1, (int) Math.round(z));
IrisBiomeGeneratorLink g = b.getGenerators().get(0);
Color c;
if (g.getMax() <= 0) {
// Max is below water level, so it is most likely an ocean biome
c = Color.BLUE;
} else if (g.getMin() < 0) {
// Min is below water level, but max is not, so it is most likely a shore biome
c = Color.YELLOW;
} else {
// Both min and max are above water level, so it is most likely a land biome
c = Color.GREEN;
}
return c.getRGB();
};
}
double x, z;
int i, j;
for (i = 0; i < resolution; i++) {
x = IrisInterpolation.lerp(sx, sx + size, (double) i / (double) (resolution));
for (j = 0; j < resolution; j++) {
z = IrisInterpolation.lerp(sz, sz + size, (double) j / (double) (resolution));
image.setRGB(i, j, colorFunction.apply(x, z));
}
}
return image;
}
}

View File

@@ -19,5 +19,5 @@
package com.volmit.iris.core.gui.components;
public enum RenderType {
BIOME, BIOME_LAND, BIOME_SEA, REGION, CAVE_LAND, HEIGHT, OBJECT_LOAD, DECORATOR_LOAD, LAYER_LOAD
BIOME, BIOME_LAND, BIOME_SEA, REGION, CAVE_LAND, HEIGHT, OBJECT_LOAD, DECORATOR_LOAD, CONTINENT, LAYER_LOAD
}

View File

@@ -0,0 +1,102 @@
//package com.volmit.iris.core.link;
//
//import com.jojodmo.customitems.api.CustomItemsAPI;
//import com.jojodmo.customitems.item.custom.CustomItem;
//import com.jojodmo.customitems.item.custom.block.CustomMushroomBlock;
//import com.jojodmo.customitems.version.SafeMaterial;
//import com.volmit.iris.util.collection.KList;
//import com.volmit.iris.util.reflect.WrappedField;
//import com.volmit.iris.util.reflect.WrappedReturningMethod;
//import org.bukkit.block.BlockFace;
//import org.bukkit.block.data.BlockData;
//import org.bukkit.block.data.MultipleFacing;
//import org.bukkit.inventory.ItemStack;
//
//import java.util.Map;
//import java.util.MissingResourceException;
//
//public class CustomItemsDataProvider extends ExternalDataProvider {
//
// private static final String FIELD_FACES = "faces";
// private static final String METHOD_GET_MATERIAL = "getMaterial";
//
// private WrappedField<CustomMushroomBlock, Map<Integer, boolean[]>> mushroomFaces;
// private WrappedReturningMethod<CustomMushroomBlock, SafeMaterial> mushroomMaterial;
//
// public CustomItemsDataProvider() {
// super("CustomItems");
// }
//
// @Override
// public void init() {
// this.mushroomFaces = new WrappedField<>(CustomMushroomBlock.class, FIELD_FACES);
// this.mushroomMaterial = new WrappedReturningMethod<>(CustomMushroomBlock.class, METHOD_GET_MATERIAL);
// }
//
// @Override
// public BlockData getBlockData(Identifier blockId) throws MissingResourceException {
// CustomItem item = CustomItem.get(blockId.key());
// if(item == null) {
// throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
// } else if(item.getBlockTexture().isSpawner()) {
// throw new MissingResourceException("Iris does not yet support SpawnerBlocks from CustomItems.", blockId.namespace(), blockId.key());
// } else if(item.getBlockTexture() != null && item.getBlockTexture().isValid()) {
// throw new MissingResourceException("Tried to fetch BlockData for a CustomItem that is not placeable!", blockId.namespace(), blockId.key());
// }
// return getMushroomData(item);
// }
//
// @Override
// public ItemStack getItemStack(Identifier itemId) throws MissingResourceException {
// ItemStack stack = CustomItemsAPI.getCustomItem(itemId.key());
// if(stack == null) {
// throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
// }
// return stack;
// }
//
// @Override
// public Identifier[] getBlockTypes() {
// KList<Identifier> names = new KList<>();
// for (String name : CustomItemsAPI.listBlockCustomItemIDs()) {
// try {
// Identifier key = new Identifier("cui", name);
// if (getItemStack(key) != null)
// names.add(key);
// } catch (MissingResourceException ignored) { }
// }
//
// return names.toArray(new Identifier[0]);
// }
//
// @Override
// public Identifier[] getItemTypes() {
// KList<Identifier> names = new KList<>();
// for (String name : CustomItemsAPI.listCustomItemIDs()) {
// try {
// Identifier key = new Identifier("cui", name);
// if (getItemStack(key) != null)
// names.add(key);
// } catch (MissingResourceException ignored) { }
// }
//
// return names.toArray(new Identifier[0]);
// }
//
// @Override
// public boolean isValidProvider(Identifier key, boolean isItem) {
// return key.namespace().equalsIgnoreCase("cui");
// }
//
// private BlockData getMushroomData(CustomItem item) {
// MultipleFacing data = (MultipleFacing)mushroomMaterial.invoke(item.getBlockTexture().getMushroomId()).parseMaterial().createBlockData();
// boolean[] values = mushroomFaces.get().get(item.getBlockTexture().getMushroomId());
// data.setFace(BlockFace.DOWN, values[0]);
// data.setFace(BlockFace.EAST, values[1]);
// data.setFace(BlockFace.NORTH, values[2]);
// data.setFace(BlockFace.SOUTH, values[3]);
// data.setFace(BlockFace.UP, values[4]);
// data.setFace(BlockFace.WEST, values[5]);
// return data;
// }
//}

View File

@@ -3,7 +3,6 @@ package com.volmit.iris.core.link;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
@@ -20,17 +19,19 @@ public abstract class ExternalDataProvider {
return Bukkit.getPluginManager().getPlugin(pluginId);
}
public boolean isPresent() {
return getPlugin() != null;
public boolean isReady() {
return getPlugin() != null && getPlugin().isEnabled();
}
public abstract void init();
public abstract BlockData getBlockData(NamespacedKey blockId) throws MissingResourceException;
public abstract BlockData getBlockData(Identifier blockId) throws MissingResourceException;
public abstract ItemStack getItemStack(NamespacedKey itemId) throws MissingResourceException;
public abstract ItemStack getItemStack(Identifier itemId) throws MissingResourceException;
public abstract NamespacedKey[] getBlockTypes();
public abstract Identifier[] getBlockTypes();
public abstract boolean isValidProvider(NamespacedKey namespace);
public abstract Identifier[] getItemTypes();
public abstract boolean isValidProvider(Identifier id, boolean isItem);
}

View File

@@ -0,0 +1,33 @@
package com.volmit.iris.core.link;
import org.bukkit.NamespacedKey;
public record Identifier(String namespace, String key) {
private static final String DEFAULT_NAMESPACE = "minecraft";
public static Identifier fromString(String id) {
String[] strings = id.split(":", 2);
if (strings.length == 1) {
return new Identifier(DEFAULT_NAMESPACE, strings[0]);
} else {
return new Identifier(strings[0], strings[1]);
}
}
@Override
public String toString() {
return namespace + ":" + key;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Identifier i) {
return i.namespace().equals(this.namespace) && i.key().equals(this.key);
} else if (obj instanceof NamespacedKey i) {
return i.getNamespace().equals(this.namespace) && i.getKey().equals(this.key);
} else {
return false;
}
}
}

View File

@@ -1,52 +1,70 @@
package com.volmit.iris.core.link;
import com.volmit.iris.util.collection.KList;
import dev.lone.itemsadder.api.CustomBlock;
import dev.lone.itemsadder.api.CustomStack;
import dev.lone.itemsadder.api.ItemsAdder;
import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import java.util.MissingResourceException;
public class ItemAdderDataProvider extends ExternalDataProvider {
public ItemAdderDataProvider() {
super("ItemsAdder");
}
@Override
public void init() {
}
@Override
public BlockData getBlockData(NamespacedKey blockId) throws MissingResourceException {
return CustomBlock.getBaseBlockData(blockId.toString());
}
@Override
public ItemStack getItemStack(NamespacedKey itemId) throws MissingResourceException {
CustomStack stack = CustomStack.getInstance(itemId.toString());
if (stack == null)
throw new MissingResourceException("Failed to find ItemData!", itemId.getNamespace(), itemId.getKey());
return stack.getItemStack();
}
@Override
public NamespacedKey[] getBlockTypes() {
KList<NamespacedKey> keys = new KList<>();
for (String s : ItemsAdder.getNamespacedBlocksNamesInConfig())
keys.add(NamespacedKey.fromString(s));
return keys.toArray(new NamespacedKey[0]);
}
@Override
public boolean isValidProvider(NamespacedKey blockId) {
for (NamespacedKey k : getBlockTypes())
if (k.equals(blockId)) {
return true;
}
return false;
}
}
package com.volmit.iris.core.link;
import com.volmit.iris.Iris;
import com.volmit.iris.util.collection.KList;
import dev.lone.itemsadder.api.CustomBlock;
import dev.lone.itemsadder.api.CustomStack;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import java.util.MissingResourceException;
public class ItemAdderDataProvider extends ExternalDataProvider {
private KList<String> itemNamespaces, blockNamespaces;
public ItemAdderDataProvider() {
super("ItemsAdder");
}
@Override
public void init() {
this.itemNamespaces = new KList<>();
this.blockNamespaces = new KList<>();
for (Identifier i : getItemTypes()) {
itemNamespaces.addIfMissing(i.namespace());
}
for (Identifier i : getBlockTypes()) {
blockNamespaces.addIfMissing(i.namespace());
Iris.info("Found ItemAdder Block: " + i);
}
}
@Override
public BlockData getBlockData(Identifier blockId) throws MissingResourceException {
return CustomBlock.getBaseBlockData(blockId.toString());
}
@Override
public ItemStack getItemStack(Identifier itemId) throws MissingResourceException {
CustomStack stack = CustomStack.getInstance(itemId.toString());
if (stack == null) {
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
}
return stack.getItemStack();
}
@Override
public Identifier[] getBlockTypes() {
KList<Identifier> keys = new KList<>();
for (String s : CustomBlock.getNamespacedIdsInRegistry()) {
keys.add(Identifier.fromString(s));
}
return keys.toArray(new Identifier[0]);
}
@Override
public Identifier[] getItemTypes() {
KList<Identifier> keys = new KList<>();
for (String s : CustomStack.getNamespacedIdsInRegistry()) {
keys.add(Identifier.fromString(s));
}
return keys.toArray(new Identifier[0]);
}
@Override
public boolean isValidProvider(Identifier id, boolean isItem) {
return isItem ? this.itemNamespaces.contains(id.namespace()) : this.blockNamespaces.contains(id.namespace());
}
}

View File

@@ -18,23 +18,17 @@
package com.volmit.iris.core.link;
import io.lumine.mythic.bukkit.MythicBukkit;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.plugin.Plugin;
import javax.annotation.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.BiFunction;
public class MythicMobsLink {
private Collection<String> mobs;
private BiFunction<String, Location, Entity> spawnMobFunction;
public MythicMobsLink() {
}
@@ -56,59 +50,10 @@ public class MythicMobsLink {
*/
public @Nullable
Entity spawnMob(String mob, Location location) {
if (!isEnabled()) return null;
if (spawnMobFunction != null) {
return spawnMobFunction.apply(mob, location);
}
try {
Class<?> mythicMobClass = Class.forName("io.lumine.mythic.bukkit.MythicBukkit");
Method getInst = mythicMobClass.getDeclaredMethod("inst");
Object inst = getInst.invoke(null);
Method getAPIHelper = mythicMobClass.getDeclaredMethod("getAPIHelper");
Object apiHelper = getAPIHelper.invoke(inst);
Method spawnMobMethod = apiHelper.getClass().getDeclaredMethod("spawnMythicMob", String.class, Location.class);
spawnMobFunction = (str, loc) -> {
try {
return (Entity) spawnMobMethod.invoke(apiHelper, str, loc);
} catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
};
return spawnMobFunction.apply(mob, location);
} catch (Exception e) {
e.printStackTrace();
}
return null;
return isEnabled() ? MythicBukkit.inst().getMobManager().spawnMob(mob, location).getEntity().getBukkitEntity() : null;
}
public Collection<String> getMythicMobTypes() {
if (mobs != null) {
return mobs;
}
if (isEnabled()) {
try {
Class<?> mythicMobClass = Class.forName("io.lumine.xikage.mythicmobs.MythicMobs");
Method getInst = mythicMobClass.getDeclaredMethod("inst");
Object inst = getInst.invoke(null);
Method getMobManager = mythicMobClass.getDeclaredMethod("getMobManager");
Object mobManager = getMobManager.invoke(inst);
Method getMobNames = mobManager.getClass().getDeclaredMethod("getMobNames");
mobs = (Collection<String>) getMobNames.invoke(mobManager);
return mobs;
} catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException |
IllegalAccessException e) {
e.printStackTrace();
}
}
return new ArrayList<>();
return isEnabled() ? MythicBukkit.inst().getMobManager().getMobNames() : null;
}
}

View File

@@ -1,115 +1,134 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.link;
import com.volmit.iris.Iris;
import com.volmit.iris.util.collection.KList;
import io.th0rgal.oraxen.items.ItemBuilder;
import io.th0rgal.oraxen.items.OraxenItems;
import io.th0rgal.oraxen.mechanics.MechanicFactory;
import io.th0rgal.oraxen.mechanics.MechanicsManager;
import io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanic;
import io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanicFactory;
import io.th0rgal.oraxen.mechanics.provided.gameplay.noteblock.NoteBlockMechanicFactory;
import io.th0rgal.oraxen.utils.Utils;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Optional;
public class OraxenDataProvider extends ExternalDataProvider {
private static final String FIELD_FACTORIES_MAP = "FACTORIES_BY_MECHANIC_ID";
private Map<String, MechanicFactory> factories;
public OraxenDataProvider() {
super("Oraxen");
}
@Override
public void init() {
try {
Field f = MechanicsManager.class.getDeclaredField(FIELD_FACTORIES_MAP);
f.setAccessible(true);
factories = (Map<String, MechanicFactory>) f.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
Iris.error("Failed to set up Oraxen Link:");
Iris.error("\t" + e.getClass().getSimpleName());
}
}
@Override
public BlockData getBlockData(NamespacedKey blockId) throws MissingResourceException {
MechanicFactory f = getFactory(blockId);
if (f instanceof NoteBlockMechanicFactory)
return ((NoteBlockMechanicFactory) f).createNoteBlockData(blockId.getKey());
else if (f instanceof BlockMechanicFactory) {
MultipleFacing newBlockData = (MultipleFacing) Bukkit.createBlockData(Material.MUSHROOM_STEM);
Utils.setBlockFacing(newBlockData, ((BlockMechanic) f.getMechanic(blockId.getKey())).getCustomVariation());
return newBlockData;
} else
throw new MissingResourceException("Failed to find BlockData!", blockId.getNamespace(), blockId.getKey());
}
@Override
public ItemStack getItemStack(NamespacedKey itemId) throws MissingResourceException {
Optional<ItemBuilder> opt = OraxenItems.getOptionalItemById(itemId.getKey());
return opt.orElseThrow(() -> new MissingResourceException("Failed to find ItemData!", itemId.getNamespace(), itemId.getKey())).build();
}
@Override
public NamespacedKey[] getBlockTypes() {
KList<NamespacedKey> names = new KList<>();
for (String name : OraxenItems.getItemNames()) {
try {
NamespacedKey key = new NamespacedKey("oraxen", name);
if (getBlockData(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
return names.toArray(new NamespacedKey[0]);
}
@Override
public boolean isPresent() {
return super.isPresent() && factories != null;
}
@Override
public boolean isValidProvider(NamespacedKey key) {
return key.getNamespace().equalsIgnoreCase("oraxen");
}
private MechanicFactory getFactory(NamespacedKey key) throws MissingResourceException {
return factories.values().stream()
.filter(i -> i.getItems().contains(key.getKey()))
.findFirst()
.orElseThrow(() -> new MissingResourceException("Failed to find BlockData!", key.getNamespace(), key.getKey()));
}
}
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.link;
import com.volmit.iris.Iris;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.reflect.WrappedField;
import io.th0rgal.oraxen.api.OraxenItems;
import io.th0rgal.oraxen.items.ItemBuilder;
import io.th0rgal.oraxen.mechanics.MechanicFactory;
import io.th0rgal.oraxen.mechanics.MechanicsManager;
import io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanic;
import io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanicFactory;
import io.th0rgal.oraxen.mechanics.provided.gameplay.noteblock.NoteBlockMechanicFactory;
import io.th0rgal.oraxen.mechanics.provided.gameplay.stringblock.StringBlockMechanicFactory;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing;
import org.bukkit.inventory.ItemStack;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Optional;
public class OraxenDataProvider extends ExternalDataProvider {
private static final String FIELD_FACTORIES_MAP = "FACTORIES_BY_MECHANIC_ID";
private WrappedField<MechanicsManager, Map<String, MechanicFactory>> factories;
public OraxenDataProvider() {
super("Oraxen");
}
@Override
public void init() {
Iris.info("Setting up Oraxen Link...");
this.factories = new WrappedField<>(MechanicsManager.class, FIELD_FACTORIES_MAP);
if (this.factories.hasFailed()) {
Iris.error("Failed to set up Oraxen Link: Unable to fetch MechanicFactoriesMap!");
}
}
@Override
public BlockData getBlockData(Identifier blockId) throws MissingResourceException {
MechanicFactory factory = getFactory(blockId);
if (factory instanceof NoteBlockMechanicFactory f)
return f.createNoteBlockData(blockId.key());
else if (factory instanceof BlockMechanicFactory f) {
MultipleFacing newBlockData = (MultipleFacing) Bukkit.createBlockData(Material.MUSHROOM_STEM);
BlockMechanic.setBlockFacing(newBlockData, ((BlockMechanic) f.getMechanic(blockId.key())).getCustomVariation());
return newBlockData;
} else if (factory instanceof StringBlockMechanicFactory f) {
return f.createTripwireData(blockId.key());
} else
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@Override
public ItemStack getItemStack(Identifier itemId) throws MissingResourceException {
Optional<ItemBuilder> opt = OraxenItems.getOptionalItemById(itemId.key());
return opt.orElseThrow(() -> new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key())).build();
}
@Override
public Identifier[] getBlockTypes() {
KList<Identifier> names = new KList<>();
for (String name : OraxenItems.getItemNames()) {
try {
Identifier key = new Identifier("oraxen", name);
if (getBlockData(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
return names.toArray(new Identifier[0]);
}
@Override
public Identifier[] getItemTypes() {
KList<Identifier> names = new KList<>();
for (String name : OraxenItems.getItemNames()) {
try {
Identifier key = new Identifier("oraxen", name);
if (getItemStack(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
return names.toArray(new Identifier[0]);
}
@Override
public boolean isReady() {
if (super.isReady()) {
if (factories == null) {
this.factories = new WrappedField<>(MechanicsManager.class, FIELD_FACTORIES_MAP);
}
return super.isReady() && !factories.hasFailed();
}
return false;
}
@Override
public boolean isValidProvider(Identifier key, boolean isItem) {
return key.namespace().equalsIgnoreCase("oraxen");
}
private MechanicFactory getFactory(Identifier key) throws MissingResourceException {
return factories.get().values().stream()
.filter(i -> i.getItems().contains(key.key()))
.findFirst()
.orElseThrow(() -> new MissingResourceException("Failed to find BlockData!", key.namespace(), key.key()));
}
}

View File

@@ -1,77 +1,77 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.nms;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.nms.v19_3.NMSBinding19_3;
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import com.volmit.iris.util.collection.KMap;
import org.bukkit.Bukkit;
public class INMS {
//@builder
private static final KMap<String, Class<? extends INMSBinding>> bindings = new KMap<String, Class<? extends INMSBinding>>()
.qput("v1_19_R2", NMSBinding19_3.class);
//@done
private static final INMSBinding binding = bind();
public static INMSBinding get() {
return binding;
}
public static String getNMSTag() {
if (IrisSettings.get().getGeneral().isDisableNMS()) {
return "BUKKIT";
}
try {
return Bukkit.getServer().getClass().getCanonicalName().split("\\Q.\\E")[3];
} catch (Throwable e) {
Iris.reportError(e);
Iris.error("Failed to determine server nms version!");
e.printStackTrace();
}
return "BUKKIT";
}
private static INMSBinding bind() {
String code = getNMSTag();
Iris.info("Locating NMS Binding for " + code);
if (bindings.containsKey(code)) {
try {
INMSBinding b = bindings.get(code).getConstructor().newInstance();
Iris.info("Craftbukkit " + code + " <-> " + b.getClass().getSimpleName() + " Successfully Bound");
return b;
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
}
Iris.info("Craftbukkit " + code + " <-> " + NMSBinding1X.class.getSimpleName() + " Successfully Bound");
Iris.warn("Note: Some features of Iris may not work the same since you are on an unsupported version of Minecraft.");
Iris.warn("Note: If this is a new version, expect an update soon.");
return new NMSBinding1X();
}
}
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.nms;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.nms.v20.NMSBinding1_20;
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import com.volmit.iris.util.collection.KMap;
import org.bukkit.Bukkit;
public class INMS {
//@builder
private static final KMap<String, Class<? extends INMSBinding>> bindings = new KMap<String, Class<? extends INMSBinding>>()
.qput("v1_20_R1", NMSBinding1_20.class);
//@done
private static final INMSBinding binding = bind();
public static INMSBinding get() {
return binding;
}
public static String getNMSTag() {
if (IrisSettings.get().getGeneral().isDisableNMS()) {
return "BUKKIT";
}
try {
return Bukkit.getServer().getClass().getCanonicalName().split("\\Q.\\E")[3];
} catch (Throwable e) {
Iris.reportError(e);
Iris.error("Failed to determine server nms version!");
e.printStackTrace();
}
return "BUKKIT";
}
private static INMSBinding bind() {
String code = getNMSTag();
Iris.info("Locating NMS Binding for " + code);
if (bindings.containsKey(code)) {
try {
INMSBinding b = bindings.get(code).getConstructor().newInstance();
Iris.info("Craftbukkit " + code + " <-> " + b.getClass().getSimpleName() + " Successfully Bound");
return b;
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
}
Iris.info("Craftbukkit " + code + " <-> " + NMSBinding1X.class.getSimpleName() + " Successfully Bound");
Iris.warn("Note: Some features of Iris may not work the same since you are on an unsupported version of Minecraft.");
Iris.warn("Note: If this is a new version, expect an update soon.");
return new NMSBinding1X();
}
}

View File

@@ -1,151 +1,169 @@
package com.volmit.iris.core.nms.v19_3;
import com.mojang.serialization.Codec;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.math.RNG;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Climate;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_19_R2.CraftServer;
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R2.block.CraftBlock;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class CustomBiomeSource extends BiomeSource {
private final long seed;
private final Engine engine;
private final Registry<Biome> biomeCustomRegistry;
private final Registry<Biome> biomeRegistry;
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
private final RNG rng;
private final KMap<String, Holder<Biome>> customBiomes;
public CustomBiomeSource(long seed, Engine engine, World world) {
super(getAllBiomes(
((RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer()))
.registry(Registries.BIOME).orElse(null),
((CraftWorld) world).getHandle().registryAccess().registry(Registries.BIOME).orElse(null),
engine));
this.engine = engine;
this.seed = seed;
this.biomeCustomRegistry = registry().registry(Registries.BIOME).orElse(null);
this.biomeRegistry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.BIOME).orElse(null);
this.rng = new RNG(engine.getSeedManager().getBiome());
this.customBiomes = fillCustomBiomes(biomeCustomRegistry, engine);
}
private static List<Holder<Biome>> getAllBiomes(Registry<Biome> customRegistry, Registry<Biome> registry, Engine engine) {
List<Holder<Biome>> b = new ArrayList<>();
for (IrisBiome i : engine.getAllBiomes()) {
if (i.isCustom()) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) {
b.add(customRegistry.getHolder(customRegistry.getResourceKey(customRegistry
.get(new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()))).get()).get());
}
} else {
b.add(CraftBlock.biomeToBiomeBase(registry, i.getVanillaDerivative()));
}
}
return b;
}
private static Object getFor(Class<?> type, Object source) {
Object o = fieldFor(type, source);
if (o != null) {
return o;
}
return invokeFor(type, source);
}
private static Object fieldFor(Class<?> returns, Object in) {
return fieldForClass(returns, in.getClass(), in);
}
private static Object invokeFor(Class<?> returns, Object in) {
for (Method i : in.getClass().getMethods()) {
if (i.getReturnType().equals(returns)) {
i.setAccessible(true);
try {
Iris.debug("[NMS] Found " + returns.getSimpleName() + " in " + in.getClass().getSimpleName() + "." + i.getName() + "()");
return i.invoke(in);
} catch (Throwable e) {
e.printStackTrace();
}
}
}
return null;
}
@SuppressWarnings("unchecked")
private static <T> T fieldForClass(Class<T> returnType, Class<?> sourceType, Object in) {
for (Field i : sourceType.getDeclaredFields()) {
if (i.getType().equals(returnType)) {
i.setAccessible(true);
try {
Iris.debug("[NMS] Found " + returnType.getSimpleName() + " in " + sourceType.getSimpleName() + "." + i.getName());
return (T) i.get(in);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return null;
}
private KMap<String, Holder<Biome>> fillCustomBiomes(Registry<Biome> customRegistry, Engine engine) {
KMap<String, Holder<Biome>> m = new KMap<>();
for (IrisBiome i : engine.getAllBiomes()) {
if (i.isCustom()) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) {
m.put(j.getId(), customRegistry.getHolder(customRegistry.getResourceKey(customRegistry
.get(new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()))).get()).get());
}
}
}
return m;
}
private RegistryAccess registry() {
return registryAccess.aquire(() -> (RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer()));
}
@Override
protected Codec<? extends BiomeSource> codec() {
throw new UnsupportedOperationException("Not supported");
}
@Override
public Holder<Biome> getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) {
int m = (y - engine.getMinHeight()) << 2;
IrisBiome ib = engine.getComplex().getTrueBiomeStream().get(x << 2, z << 2);
if (ib.isCustom()) {
return customBiomes.get(ib.getCustomBiome(rng, x << 2, m, z << 2).getId());
} else {
org.bukkit.block.Biome v = ib.getSkyBiome(rng, x << 2, m, z << 2);
return CraftBlock.biomeToBiomeBase(biomeRegistry, v);
}
}
package com.volmit.iris.core.nms.v20;
import com.mojang.serialization.Codec;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.math.RNG;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Climate;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlock;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class CustomBiomeSource extends BiomeSource {
private final long seed;
private final Engine engine;
private final Registry<Biome> biomeCustomRegistry;
private final Registry<Biome> biomeRegistry;
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
private final RNG rng;
private final KMap<String, Holder<Biome>> customBiomes;
public CustomBiomeSource(long seed, Engine engine, World world) {
this.engine = engine;
this.seed = seed;
this.biomeCustomRegistry = registry().registry(Registries.BIOME).orElse(null);
this.biomeRegistry = ((RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer())).registry(Registries.BIOME).orElse(null);
this.rng = new RNG(engine.getSeedManager().getBiome());
this.customBiomes = fillCustomBiomes(biomeCustomRegistry, engine);
}
private static List<Holder<Biome>> getAllBiomes(Registry<Biome> customRegistry, Registry<Biome> registry, Engine engine) {
List<Holder<Biome>> b = new ArrayList<>();
for (IrisBiome i : engine.getAllBiomes()) {
if (i.isCustom()) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) {
b.add(customRegistry.getHolder(customRegistry.getResourceKey(customRegistry
.get(new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()))).get()).get());
}
} else {
b.add(CraftBlock.biomeToBiomeBase(registry, i.getVanillaDerivative()));
}
}
return b;
}
private static Object getFor(Class<?> type, Object source) {
Object o = fieldFor(type, source);
if (o != null) {
return o;
}
return invokeFor(type, source);
}
private static Object fieldFor(Class<?> returns, Object in) {
return fieldForClass(returns, in.getClass(), in);
}
private static Object invokeFor(Class<?> returns, Object in) {
for (Method i : in.getClass().getMethods()) {
if (i.getReturnType().equals(returns)) {
i.setAccessible(true);
try {
Iris.debug("[NMS] Found " + returns.getSimpleName() + " in " + in.getClass().getSimpleName() + "." + i.getName() + "()");
return i.invoke(in);
} catch (Throwable e) {
e.printStackTrace();
}
}
}
return null;
}
@SuppressWarnings("unchecked")
private static <T> T fieldForClass(Class<T> returnType, Class<?> sourceType, Object in) {
for (Field i : sourceType.getDeclaredFields()) {
if (i.getType().equals(returnType)) {
i.setAccessible(true);
try {
Iris.debug("[NMS] Found " + returnType.getSimpleName() + " in " + sourceType.getSimpleName() + "." + i.getName());
return (T) i.get(in);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return null;
}
@Override
protected Stream<Holder<Biome>> collectPossibleBiomes() {
return getAllBiomes(
((RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer()))
.registry(Registries.BIOME).orElse(null),
((CraftWorld) engine.getWorld().realWorld()).getHandle().registryAccess().registry(Registries.BIOME).orElse(null),
engine).stream();
}
private KMap<String, Holder<Biome>> fillCustomBiomes(Registry<Biome> customRegistry, Engine engine) {
KMap<String, Holder<Biome>> m = new KMap<>();
for (IrisBiome i : engine.getAllBiomes()) {
if (i.isCustom()) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) {
ResourceLocation resourceLocation = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId());
Biome biome = customRegistry.get(resourceLocation);
Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome);
if (optionalBiomeKey.isEmpty()) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());
continue;
}
ResourceKey<Biome> biomeKey = optionalBiomeKey.get();
Optional<Holder.Reference<Biome>> optionalReferenceHolder = customRegistry.getHolder(biomeKey);
if (optionalReferenceHolder.isEmpty()) {
Iris.error("Cannot find reference to biome " + biomeKey + " for engine " + engine.getName());
continue;
}
m.put(j.getId(), optionalReferenceHolder.get());
}
}
}
return m;
}
private RegistryAccess registry() {
return registryAccess.aquire(() -> (RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer()));
}
@Override
protected Codec<? extends BiomeSource> codec() {
throw new UnsupportedOperationException("Not supported");
}
@Override
public Holder<Biome> getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) {
int m = (y - engine.getMinHeight()) << 2;
IrisBiome ib = engine.getComplex().getTrueBiomeStream().get(x << 2, z << 2);
if (ib.isCustom()) {
return customBiomes.get(ib.getCustomBiome(rng, x << 2, m, z << 2).getId());
} else {
org.bukkit.block.Biome v = ib.getSkyBiome(rng, x << 2, m, z << 2);
return CraftBlock.biomeToBiomeBase(biomeRegistry, v);
}
}
}

View File

@@ -1,453 +1,454 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.nms.v19_3;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMSBinding;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.matter.MatterBiomeInject;
import com.volmit.iris.util.nbt.io.NBTUtil;
import com.volmit.iris.util.nbt.mca.NBTWorld;
import com.volmit.iris.util.nbt.mca.palette.*;
import com.volmit.iris.util.nbt.tag.CompoundTag;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.NbtIo;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.*;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_19_R2.CraftChunk;
import org.bukkit.craftbukkit.v1_19_R2.CraftServer;
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData;
import org.bukkit.entity.Entity;
import org.bukkit.generator.ChunkGenerator;
import org.jetbrains.annotations.NotNull;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class NMSBinding19_3 implements INMSBinding {
public static final String NMS_VERSION = "1.19.3";
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
private final BlockData AIR = Material.AIR.createBlockData();
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
private Field biomeStorageCache = null;
private static Object getFor(Class<?> type, Object source) {
Object o = fieldFor(type, source);
if (o != null) {
return o;
}
return invokeFor(type, source);
}
private static Object invokeFor(Class<?> returns, Object in) {
for (Method i : in.getClass().getMethods()) {
if (i.getReturnType().equals(returns)) {
i.setAccessible(true);
try {
Iris.debug("[NMS] Found " + returns.getSimpleName() + " in " + in.getClass().getSimpleName() + "." + i.getName() + "()");
return i.invoke(in);
} catch (Throwable e) {
e.printStackTrace();
}
}
}
return null;
}
private static Object fieldFor(Class<?> returns, Object in) {
return fieldForClass(returns, in.getClass(), in);
}
@SuppressWarnings("unchecked")
private static <T> T fieldForClass(Class<T> returnType, Class<?> sourceType, Object in) {
for (Field i : sourceType.getDeclaredFields()) {
if (i.getType().equals(returnType)) {
i.setAccessible(true);
try {
Iris.debug("[NMS] Found " + returnType.getSimpleName() + " in " + sourceType.getSimpleName() + "." + i.getName());
return (T) i.get(in);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return null;
}
private static Class<?> getClassType(Class<?> type, int ordinal) {
return type.getDeclaredClasses()[ordinal];
}
@Override
public boolean hasTile(Location l) {
return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null;
}
@Override
public CompoundTag serializeTile(Location location) {
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true);
if (e == null) {
return null;
}
net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata();
return convert(tag);
}
private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) {
try {
ByteArrayOutputStream boas = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(boas);
tag.write(dos);
dos.close();
return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag();
} catch (Throwable ex) {
ex.printStackTrace();
}
return null;
}
private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) {
try {
ByteArrayOutputStream boas = new ByteArrayOutputStream();
NBTUtil.write(tag, boas, false);
DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray()));
net.minecraft.nbt.CompoundTag c = NbtIo.read(din);
din.close();
return c;
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
@Override
public void deserializeTile(CompoundTag c, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c));
}
@Override
public CompoundTag serializeEntity(Entity location) {
return null;// TODO:
}
@Override
public Entity deserializeEntity(CompoundTag s, Location newPosition) {
return null;// TODO:
}
@Override
public boolean supportsCustomHeight() {
return true;
}
private RegistryAccess registry() {
return registryAccess.aquire(() -> (RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer()));
}
private Registry<net.minecraft.world.level.biome.Biome> getCustomBiomeRegistry() {
return registry().registry(Registries.BIOME).orElse(null);
}
private Registry<Block> getBlockRegistry() {
return registry().registry(Registries.BLOCK).orElse(null);
}
@Override
public Object getBiomeBaseFromId(int id) {
return getCustomBiomeRegistry().getHolder(id);
}
@Override
public int getMinHeight(World world) {
return world.getMinHeight();
}
@Override
public boolean supportsCustomBiomes() {
return true;
}
@Override
public int getTrueBiomeBaseId(Object biomeBase) {
return getCustomBiomeRegistry().getId(((Holder<net.minecraft.world.level.biome.Biome>) biomeBase).value());
}
@Override
public Object getTrueBiomeBase(Location location) {
return ((CraftWorld) location.getWorld()).getHandle().getBiome(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()));
}
@Override
public String getTrueBiomeBaseKey(Location location) {
return getKeyForBiomeBase(getTrueBiomeBase(location));
}
@Override
public Object getCustomBiomeBaseFor(String mckey) {
return getCustomBiomeRegistry().get(new ResourceLocation(mckey));
}
@Override
public Object getCustomBiomeBaseHolderFor(String mckey) {
return getCustomBiomeRegistry().getHolder(getTrueBiomeBaseId(getCustomBiomeRegistry().get(new ResourceLocation(mckey)))).get();
}
public int getBiomeBaseIdForKey(String key) {
return getCustomBiomeRegistry().getId(getCustomBiomeRegistry().get(new ResourceLocation(key)));
}
@Override
public String getKeyForBiomeBase(Object biomeBase) {
return getCustomBiomeRegistry().getKey((net.minecraft.world.level.biome.Biome) biomeBase).getPath(); // something, not something:something
}
@Override
public Object getBiomeBase(World world, Biome biome) {
return org.bukkit.craftbukkit.v1_19_R2.block.CraftBlock.biomeToBiomeBase(((CraftWorld) world).getHandle()
.registryAccess().registry(Registries.BIOME).orElse(null), biome);
}
@Override
public Object getBiomeBase(Object registry, Biome biome) {
Object v = baseBiomeCache.get(biome);
if (v != null) {
return v;
}
//noinspection unchecked
v = org.bukkit.craftbukkit.v1_19_R2.block.CraftBlock.biomeToBiomeBase((Registry<net.minecraft.world.level.biome.Biome>) registry, biome);
if (v == null) {
// Ok so there is this new biome name called "CUSTOM" in Paper's new releases.
// But, this does NOT exist within CraftBukkit which makes it return an error.
// So, we will just return the ID that the plains biome returns instead.
//noinspection unchecked
return org.bukkit.craftbukkit.v1_19_R2.block.CraftBlock.biomeToBiomeBase((Registry<net.minecraft.world.level.biome.Biome>) registry, Biome.PLAINS);
}
baseBiomeCache.put(biome, v);
return v;
}
@Override
public boolean isBukkit() {
return true;
}
@Override
public int getBiomeId(Biome biome) {
for (World i : Bukkit.getWorlds()) {
if (i.getEnvironment().equals(World.Environment.NORMAL)) {
Registry<net.minecraft.world.level.biome.Biome> registry = ((CraftWorld) i).getHandle().registryAccess().registry(Registries.BIOME).orElse(null);
return registry.getId((net.minecraft.world.level.biome.Biome) getBiomeBase(registry, biome));
}
}
return biome.ordinal();
}
private MCAIdMap<net.minecraft.world.level.biome.Biome> getBiomeMapping() {
return biomeMapCache.aquire(() -> new MCAIdMap<>() {
@NotNull
@Override
public Iterator<net.minecraft.world.level.biome.Biome> iterator() {
return getCustomBiomeRegistry().iterator();
}
@Override
public int getId(net.minecraft.world.level.biome.Biome paramT) {
return getCustomBiomeRegistry().getId(paramT);
}
@Override
public net.minecraft.world.level.biome.Biome byId(int paramInt) {
return (net.minecraft.world.level.biome.Biome) getBiomeBaseFromId(paramInt);
}
});
}
@NotNull
private MCABiomeContainer getBiomeContainerInterface(MCAIdMap<net.minecraft.world.level.biome.Biome> biomeMapping, MCAChunkBiomeContainer<net.minecraft.world.level.biome.Biome> base) {
return new MCABiomeContainer() {
@Override
public int[] getData() {
return base.writeBiomes();
}
@Override
public void setBiome(int x, int y, int z, int id) {
base.setBiome(x, y, z, biomeMapping.byId(id));
}
@Override
public int getBiome(int x, int y, int z) {
return biomeMapping.getId(base.getBiome(x, y, z));
}
};
}
@Override
public MCABiomeContainer newBiomeContainer(int min, int max) {
MCAChunkBiomeContainer<net.minecraft.world.level.biome.Biome> base = new MCAChunkBiomeContainer<>(getBiomeMapping(), min, max);
return getBiomeContainerInterface(getBiomeMapping(), base);
}
@Override
public MCABiomeContainer newBiomeContainer(int min, int max, int[] data) {
MCAChunkBiomeContainer<net.minecraft.world.level.biome.Biome> base = new MCAChunkBiomeContainer<>(getBiomeMapping(), min, max, data);
return getBiomeContainerInterface(getBiomeMapping(), base);
}
@Override
public int countCustomBiomes() {
AtomicInteger a = new AtomicInteger(0);
getCustomBiomeRegistry().keySet().forEach((i) -> {
if (i.getNamespace().equals("minecraft")) {
return;
}
a.incrementAndGet();
Iris.debug("Custom Biome: " + i);
});
return a.get();
}
public boolean supportsDataPacks() {
return true;
}
public void setBiomes(int cx, int cz, World world, Hunk<Object> biomes) {
LevelChunk c = ((CraftWorld) world).getHandle().getChunk(cx, cz);
biomes.iterateSync((x, y, z, b) -> c.setBiome(x, y, z, (Holder<net.minecraft.world.level.biome.Biome>) b));
c.setUnsaved(true);
}
@Override
public void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk) {
try {
ChunkAccess s = (ChunkAccess) getFieldForBiomeStorage(chunk).get(chunk);
Holder<net.minecraft.world.level.biome.Biome> biome = (Holder<net.minecraft.world.level.biome.Biome>) somethingVeryDirty;
s.setBiome(x, y, z, biome);
} catch (IllegalAccessException e) {
Iris.reportError(e);
e.printStackTrace();
}
}
private Field getFieldForBiomeStorage(Object storage) {
Field f = biomeStorageCache;
if (f != null) {
return f;
}
try {
f = storage.getClass().getDeclaredField("biome");
f.setAccessible(true);
return f;
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
Iris.error(storage.getClass().getCanonicalName());
}
biomeStorageCache = f;
return null;
}
@Override
public MCAPaletteAccess createPalette() {
MCAIdMapper<BlockState> registry = registryCache.aquireNasty(() -> {
Field cf = net.minecraft.core.IdMapper.class.getDeclaredField("tToId");
Field df = net.minecraft.core.IdMapper.class.getDeclaredField("idToT");
Field bf = net.minecraft.core.IdMapper.class.getDeclaredField("nextId");
cf.setAccessible(true);
df.setAccessible(true);
bf.setAccessible(true);
net.minecraft.core.IdMapper<BlockState> blockData = Block.BLOCK_STATE_REGISTRY;
int b = bf.getInt(blockData);
Object2IntMap<BlockState> c = (Object2IntMap<BlockState>) cf.get(blockData);
List<BlockState> d = (List<BlockState>) df.get(blockData);
return new MCAIdMapper<BlockState>(c, d, b);
});
MCAPalette<BlockState> global = globalCache.aquireNasty(() -> new MCAGlobalPalette<>(registry, ((CraftBlockData) AIR).getState()));
MCAPalettedContainer<BlockState> container = new MCAPalettedContainer<>(global, registry,
i -> ((CraftBlockData) NBTWorld.getBlockData(i)).getState(),
i -> NBTWorld.getCompound(CraftBlockData.fromData(i)),
((CraftBlockData) AIR).getState());
return new MCAWrappedPalettedContainer<>(container,
i -> NBTWorld.getCompound(CraftBlockData.fromData(i)),
i -> ((CraftBlockData) NBTWorld.getBlockData(i)).getState());
}
@Override
public void injectBiomesFromMantle(Chunk e, Mantle mantle) {
LevelChunk chunk = ((CraftChunk) e).getHandle();
AtomicInteger c = new AtomicInteger();
AtomicInteger r = new AtomicInteger();
mantle.iterateChunk(e.getX(), e.getZ(), MatterBiomeInject.class, (x, y, z, b) -> {
if (b != null) {
if (b.isCustom()) {
chunk.setBiome(x, y, z, getCustomBiomeRegistry().getHolder(b.getBiomeId()).get());
c.getAndIncrement();
} else {
chunk.setBiome(x, y, z, (Holder<net.minecraft.world.level.biome.Biome>) getBiomeBase(e.getWorld(), b.getBiome()));
r.getAndIncrement();
}
}
});
}
}
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.nms.v20;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMSBinding;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.matter.MatterBiomeInject;
import com.volmit.iris.util.nbt.io.NBTUtil;
import com.volmit.iris.util.nbt.mca.NBTWorld;
import com.volmit.iris.util.nbt.mca.palette.*;
import com.volmit.iris.util.nbt.tag.CompoundTag;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.NbtIo;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.*;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_20_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlock;
import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData;
import org.bukkit.entity.Entity;
import org.bukkit.generator.ChunkGenerator;
import org.jetbrains.annotations.NotNull;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class NMSBinding1_20 implements INMSBinding {
public static final String NMS_VERSION = "1.20";
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
private final BlockData AIR = Material.AIR.createBlockData();
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
private Field biomeStorageCache = null;
private static Object getFor(Class<?> type, Object source) {
Object o = fieldFor(type, source);
if (o != null) {
return o;
}
return invokeFor(type, source);
}
private static Object invokeFor(Class<?> returns, Object in) {
for (Method i : in.getClass().getMethods()) {
if (i.getReturnType().equals(returns)) {
i.setAccessible(true);
try {
Iris.debug("[NMS] Found " + returns.getSimpleName() + " in " + in.getClass().getSimpleName() + "." + i.getName() + "()");
return i.invoke(in);
} catch (Throwable e) {
e.printStackTrace();
}
}
}
return null;
}
private static Object fieldFor(Class<?> returns, Object in) {
return fieldForClass(returns, in.getClass(), in);
}
@SuppressWarnings("unchecked")
private static <T> T fieldForClass(Class<T> returnType, Class<?> sourceType, Object in) {
for (Field i : sourceType.getDeclaredFields()) {
if (i.getType().equals(returnType)) {
i.setAccessible(true);
try {
Iris.debug("[NMS] Found " + returnType.getSimpleName() + " in " + sourceType.getSimpleName() + "." + i.getName());
return (T) i.get(in);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return null;
}
private static Class<?> getClassType(Class<?> type, int ordinal) {
return type.getDeclaredClasses()[ordinal];
}
@Override
public boolean hasTile(Location l) {
return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null;
}
@Override
public CompoundTag serializeTile(Location location) {
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true);
if (e == null) {
return null;
}
net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata();
return convert(tag);
}
private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) {
try {
ByteArrayOutputStream boas = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(boas);
tag.write(dos);
dos.close();
return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag();
} catch (Throwable ex) {
ex.printStackTrace();
}
return null;
}
private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) {
try {
ByteArrayOutputStream boas = new ByteArrayOutputStream();
NBTUtil.write(tag, boas, false);
DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray()));
net.minecraft.nbt.CompoundTag c = NbtIo.read(din);
din.close();
return c;
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
@Override
public void deserializeTile(CompoundTag c, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c));
}
@Override
public CompoundTag serializeEntity(Entity location) {
return null;// TODO:
}
@Override
public Entity deserializeEntity(CompoundTag s, Location newPosition) {
return null;// TODO:
}
@Override
public boolean supportsCustomHeight() {
return true;
}
private RegistryAccess registry() {
return registryAccess.aquire(() -> (RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer()));
}
private Registry<net.minecraft.world.level.biome.Biome> getCustomBiomeRegistry() {
return registry().registry(Registries.BIOME).orElse(null);
}
private Registry<Block> getBlockRegistry() {
return registry().registry(Registries.BLOCK).orElse(null);
}
@Override
public Object getBiomeBaseFromId(int id) {
return getCustomBiomeRegistry().getHolder(id);
}
@Override
public int getMinHeight(World world) {
return world.getMinHeight();
}
@Override
public boolean supportsCustomBiomes() {
return true;
}
@Override
public int getTrueBiomeBaseId(Object biomeBase) {
return getCustomBiomeRegistry().getId(((Holder<net.minecraft.world.level.biome.Biome>) biomeBase).value());
}
@Override
public Object getTrueBiomeBase(Location location) {
return ((CraftWorld) location.getWorld()).getHandle().getBiome(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()));
}
@Override
public String getTrueBiomeBaseKey(Location location) {
return getKeyForBiomeBase(getTrueBiomeBase(location));
}
@Override
public Object getCustomBiomeBaseFor(String mckey) {
return getCustomBiomeRegistry().get(new ResourceLocation(mckey));
}
@Override
public Object getCustomBiomeBaseHolderFor(String mckey) {
return getCustomBiomeRegistry().getHolder(getTrueBiomeBaseId(getCustomBiomeRegistry().get(new ResourceLocation(mckey)))).get();
}
public int getBiomeBaseIdForKey(String key) {
return getCustomBiomeRegistry().getId(getCustomBiomeRegistry().get(new ResourceLocation(key)));
}
@Override
public String getKeyForBiomeBase(Object biomeBase) {
return getCustomBiomeRegistry().getKey((net.minecraft.world.level.biome.Biome) biomeBase).getPath(); // something, not something:something
}
@Override
public Object getBiomeBase(World world, Biome biome) {
return CraftBlock.biomeToBiomeBase(((CraftWorld) world).getHandle()
.registryAccess().registry(Registries.BIOME).orElse(null), biome);
}
@Override
public Object getBiomeBase(Object registry, Biome biome) {
Object v = baseBiomeCache.get(biome);
if (v != null) {
return v;
}
//noinspection unchecked
v = CraftBlock.biomeToBiomeBase((Registry<net.minecraft.world.level.biome.Biome>) registry, biome);
if (v == null) {
// Ok so there is this new biome name called "CUSTOM" in Paper's new releases.
// But, this does NOT exist within CraftBukkit which makes it return an error.
// So, we will just return the ID that the plains biome returns instead.
//noinspection unchecked
return CraftBlock.biomeToBiomeBase((Registry<net.minecraft.world.level.biome.Biome>) registry, Biome.PLAINS);
}
baseBiomeCache.put(biome, v);
return v;
}
@Override
public boolean isBukkit() {
return true;
}
@Override
public int getBiomeId(Biome biome) {
for (World i : Bukkit.getWorlds()) {
if (i.getEnvironment().equals(World.Environment.NORMAL)) {
Registry<net.minecraft.world.level.biome.Biome> registry = ((CraftWorld) i).getHandle().registryAccess().registry(Registries.BIOME).orElse(null);
return registry.getId((net.minecraft.world.level.biome.Biome) getBiomeBase(registry, biome));
}
}
return biome.ordinal();
}
private MCAIdMap<net.minecraft.world.level.biome.Biome> getBiomeMapping() {
return biomeMapCache.aquire(() -> new MCAIdMap<>() {
@NotNull
@Override
public Iterator<net.minecraft.world.level.biome.Biome> iterator() {
return getCustomBiomeRegistry().iterator();
}
@Override
public int getId(net.minecraft.world.level.biome.Biome paramT) {
return getCustomBiomeRegistry().getId(paramT);
}
@Override
public net.minecraft.world.level.biome.Biome byId(int paramInt) {
return (net.minecraft.world.level.biome.Biome) getBiomeBaseFromId(paramInt);
}
});
}
@NotNull
private MCABiomeContainer getBiomeContainerInterface(MCAIdMap<net.minecraft.world.level.biome.Biome> biomeMapping, MCAChunkBiomeContainer<net.minecraft.world.level.biome.Biome> base) {
return new MCABiomeContainer() {
@Override
public int[] getData() {
return base.writeBiomes();
}
@Override
public void setBiome(int x, int y, int z, int id) {
base.setBiome(x, y, z, biomeMapping.byId(id));
}
@Override
public int getBiome(int x, int y, int z) {
return biomeMapping.getId(base.getBiome(x, y, z));
}
};
}
@Override
public MCABiomeContainer newBiomeContainer(int min, int max) {
MCAChunkBiomeContainer<net.minecraft.world.level.biome.Biome> base = new MCAChunkBiomeContainer<>(getBiomeMapping(), min, max);
return getBiomeContainerInterface(getBiomeMapping(), base);
}
@Override
public MCABiomeContainer newBiomeContainer(int min, int max, int[] data) {
MCAChunkBiomeContainer<net.minecraft.world.level.biome.Biome> base = new MCAChunkBiomeContainer<>(getBiomeMapping(), min, max, data);
return getBiomeContainerInterface(getBiomeMapping(), base);
}
@Override
public int countCustomBiomes() {
AtomicInteger a = new AtomicInteger(0);
getCustomBiomeRegistry().keySet().forEach((i) -> {
if (i.getNamespace().equals("minecraft")) {
return;
}
a.incrementAndGet();
Iris.debug("Custom Biome: " + i);
});
return a.get();
}
public boolean supportsDataPacks() {
return true;
}
public void setBiomes(int cx, int cz, World world, Hunk<Object> biomes) {
LevelChunk c = ((CraftWorld) world).getHandle().getChunk(cx, cz);
biomes.iterateSync((x, y, z, b) -> c.setBiome(x, y, z, (Holder<net.minecraft.world.level.biome.Biome>) b));
c.setUnsaved(true);
}
@Override
public void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk) {
try {
ChunkAccess s = (ChunkAccess) getFieldForBiomeStorage(chunk).get(chunk);
Holder<net.minecraft.world.level.biome.Biome> biome = (Holder<net.minecraft.world.level.biome.Biome>) somethingVeryDirty;
s.setBiome(x, y, z, biome);
} catch (IllegalAccessException e) {
Iris.reportError(e);
e.printStackTrace();
}
}
private Field getFieldForBiomeStorage(Object storage) {
Field f = biomeStorageCache;
if (f != null) {
return f;
}
try {
f = storage.getClass().getDeclaredField("biome");
f.setAccessible(true);
return f;
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
Iris.error(storage.getClass().getCanonicalName());
}
biomeStorageCache = f;
return null;
}
@Override
public MCAPaletteAccess createPalette() {
MCAIdMapper<BlockState> registry = registryCache.aquireNasty(() -> {
Field cf = net.minecraft.core.IdMapper.class.getDeclaredField("tToId");
Field df = net.minecraft.core.IdMapper.class.getDeclaredField("idToT");
Field bf = net.minecraft.core.IdMapper.class.getDeclaredField("nextId");
cf.setAccessible(true);
df.setAccessible(true);
bf.setAccessible(true);
net.minecraft.core.IdMapper<BlockState> blockData = Block.BLOCK_STATE_REGISTRY;
int b = bf.getInt(blockData);
Object2IntMap<BlockState> c = (Object2IntMap<BlockState>) cf.get(blockData);
List<BlockState> d = (List<BlockState>) df.get(blockData);
return new MCAIdMapper<BlockState>(c, d, b);
});
MCAPalette<BlockState> global = globalCache.aquireNasty(() -> new MCAGlobalPalette<>(registry, ((CraftBlockData) AIR).getState()));
MCAPalettedContainer<BlockState> container = new MCAPalettedContainer<>(global, registry,
i -> ((CraftBlockData) NBTWorld.getBlockData(i)).getState(),
i -> NBTWorld.getCompound(CraftBlockData.fromData(i)),
((CraftBlockData) AIR).getState());
return new MCAWrappedPalettedContainer<>(container,
i -> NBTWorld.getCompound(CraftBlockData.fromData(i)),
i -> ((CraftBlockData) NBTWorld.getBlockData(i)).getState());
}
@Override
public void injectBiomesFromMantle(Chunk e, Mantle mantle) {
ChunkAccess chunk = ((CraftChunk) e).getHandle(ChunkStatus.FULL);
AtomicInteger c = new AtomicInteger();
AtomicInteger r = new AtomicInteger();
mantle.iterateChunk(e.getX(), e.getZ(), MatterBiomeInject.class, (x, y, z, b) -> {
if (b != null) {
if (b.isCustom()) {
chunk.setBiome(x, y, z, getCustomBiomeRegistry().getHolder(b.getBiomeId()).get());
c.getAndIncrement();
} else {
chunk.setBiome(x, y, z, (Holder<net.minecraft.world.level.biome.Biome>) getBiomeBase(e.getWorld(), b.getBiome()));
r.getAndIncrement();
}
}
});
}
}

View File

@@ -101,7 +101,8 @@ public class IrisPregenerator {
eta, M.ms() - startTime.get(), currentGeneratorMethod.get());
if (cl.flip()) {
Iris.info("Pregen: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (" + Form.pc((double) generated.get() / (double) totalChunks.get(), 0) + ") " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration((double) eta, 2));
double percentage = ((double) generated.get() / (double) totalChunks.get()) * 100;
Iris.info("Pregen: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (%.0f%%) " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration((double) eta, 2), percentage);
}
return 1000;

View File

@@ -1,95 +1,95 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.function.Consumer4;
import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.matter.MatterStructurePOI;
import com.volmit.iris.util.plugin.IrisService;
import net.minecraft.core.BlockPos;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftDolphin;
import org.bukkit.entity.Dolphin;
import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.generator.structure.StructureType;
import java.util.concurrent.atomic.AtomicReference;
public class DolphinSVC implements IrisService {
@Override
public void onEnable() {
}
@Override
public void onDisable() {
}
@EventHandler
public void on(PlayerInteractEntityEvent event) {
if (!IrisToolbelt.isIrisWorld(event.getPlayer().getWorld())) {
return;
}
Material hand = event.getPlayer().getInventory().getItem(event.getHand()).getType();
if (event.getRightClicked().getType().equals(EntityType.DOLPHIN) && (hand.equals(Material.TROPICAL_FISH) || hand.equals(Material.PUFFERFISH) || hand.equals(Material.COD) || hand.equals(Material.SALMON))) {
Engine e = IrisToolbelt.access(event.getPlayer().getWorld()).getEngine();
searchNearestTreasure(e, event.getPlayer().getLocation().getBlockX() >> 4, event.getPlayer().getLocation().getBlockZ() >> 4, e.getMantle().getRadius() - 1, StructureType.BURIED_TREASURE, (x, y, z, p) -> {
event.setCancelled(true);
Dolphin d = (Dolphin) event.getRightClicked();
CraftDolphin cd = (CraftDolphin) d;
d.getWorld().playSound(d, Sound.ENTITY_DOLPHIN_EAT, SoundCategory.NEUTRAL, 1, 1);
cd.getHandle().setTreasurePos(new BlockPos(x, y, z));
cd.getHandle().setGotFish(true);
});
}
}
@ChunkCoordinates
public void findTreasure(Engine engine, int chunkX, int chunkY, StructureType type, Consumer4<Integer, Integer, Integer, MatterStructurePOI> consumer) {
AtomicReference<MatterStructurePOI> ref = new AtomicReference<>();
engine.getMantle().getMantle().iterateChunk(chunkX, chunkY, MatterStructurePOI.class, ref.get() == null ? (x, y, z, d) -> {
if (d.getType().equals(type.getKey().getKey())) {
ref.set(d);
consumer.accept(x, y, z, d);
}
} : (x, y, z, d) -> {
});
}
@ChunkCoordinates
public void searchNearestTreasure(Engine engine, int chunkX, int chunkY, int radius, StructureType type, Consumer4<Integer, Integer, Integer, MatterStructurePOI> consumer) {
AtomicReference<MatterStructurePOI> ref = new AtomicReference<>();
new Spiraler(radius * 2, radius * 2, (x, z) -> findTreasure(engine, x, z, type, ref.get() == null ? (i, d, g, a) -> {
ref.set(a);
consumer.accept(i, d, g, a);
} : (i, d, g, a) -> {
})).setOffset(chunkX, chunkY).drain();
}
}
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.function.Consumer4;
import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.matter.MatterStructurePOI;
import com.volmit.iris.util.plugin.IrisService;
import net.minecraft.core.BlockPos;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftDolphin;
import org.bukkit.entity.Dolphin;
import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.generator.structure.StructureType;
import java.util.concurrent.atomic.AtomicReference;
public class DolphinSVC implements IrisService {
@Override
public void onEnable() {
}
@Override
public void onDisable() {
}
@EventHandler
public void on(PlayerInteractEntityEvent event) {
if (!IrisToolbelt.isIrisWorld(event.getPlayer().getWorld())) {
return;
}
Material hand = event.getPlayer().getInventory().getItem(event.getHand()).getType();
if (event.getRightClicked().getType().equals(EntityType.DOLPHIN) && (hand.equals(Material.TROPICAL_FISH) || hand.equals(Material.PUFFERFISH) || hand.equals(Material.COD) || hand.equals(Material.SALMON))) {
Engine e = IrisToolbelt.access(event.getPlayer().getWorld()).getEngine();
searchNearestTreasure(e, event.getPlayer().getLocation().getBlockX() >> 4, event.getPlayer().getLocation().getBlockZ() >> 4, e.getMantle().getRadius() - 1, StructureType.BURIED_TREASURE, (x, y, z, p) -> {
event.setCancelled(true);
Dolphin d = (Dolphin) event.getRightClicked();
CraftDolphin cd = (CraftDolphin) d;
d.getWorld().playSound(d, Sound.ENTITY_DOLPHIN_EAT, SoundCategory.NEUTRAL, 1, 1);
cd.getHandle().setTreasurePos(new BlockPos(x, y, z));
cd.getHandle().setGotFish(true);
});
}
}
@ChunkCoordinates
public void findTreasure(Engine engine, int chunkX, int chunkY, StructureType type, Consumer4<Integer, Integer, Integer, MatterStructurePOI> consumer) {
AtomicReference<MatterStructurePOI> ref = new AtomicReference<>();
engine.getMantle().getMantle().iterateChunk(chunkX, chunkY, MatterStructurePOI.class, ref.get() == null ? (x, y, z, d) -> {
if (d.getType().equals(type.getKey().getKey())) {
ref.set(d);
consumer.accept(x, y, z, d);
}
} : (x, y, z, d) -> {
});
}
@ChunkCoordinates
public void searchNearestTreasure(Engine engine, int chunkX, int chunkY, int radius, StructureType type, Consumer4<Integer, Integer, Integer, MatterStructurePOI> consumer) {
AtomicReference<MatterStructurePOI> ref = new AtomicReference<>();
new Spiraler(radius * 2, radius * 2, (x, z) -> findTreasure(engine, x, z, type, ref.get() == null ? (i, d, g, a) -> {
ref.set(a);
consumer.accept(i, d, g, a);
} : (i, d, g, a) -> {
})).setOffset(chunkX, chunkY).drain();
}
}

View File

@@ -1,87 +1,118 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.ItemAdderDataProvider;
import com.volmit.iris.core.link.OraxenDataProvider;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.plugin.IrisService;
import lombok.Data;
import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import java.util.MissingResourceException;
import java.util.Optional;
@Data
public class ExternalDataSVC implements IrisService {
private KList<ExternalDataProvider> providers = new KList<>();
@Override
public void onEnable() {
addProvider(new OraxenDataProvider(), new ItemAdderDataProvider());
}
@Override
public void onDisable() {
}
public void addProvider(ExternalDataProvider... provider) {
for (ExternalDataProvider p : provider) {
if (p.getPlugin() != null) {
providers.add(p);
p.init();
}
}
}
public Optional<BlockData> getBlockData(NamespacedKey key) {
Optional<ExternalDataProvider> provider = providers.stream().filter(p -> p.isPresent() && p.isValidProvider(key)).findFirst();
if (provider.isEmpty())
return Optional.empty();
try {
return Optional.of(provider.get().getBlockData(key));
} catch (MissingResourceException e) {
Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]");
return Optional.empty();
}
}
public Optional<ItemStack> getItemStack(NamespacedKey key) {
Optional<ExternalDataProvider> provider = providers.stream().filter(p -> p.isPresent() && p.isValidProvider(key)).findFirst();
if (provider.isEmpty())
return Optional.empty();
try {
return Optional.of(provider.get().getItemStack(key));
} catch (MissingResourceException e) {
Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]");
return Optional.empty();
}
}
public NamespacedKey[] getAllIdentifiers() {
KList<NamespacedKey> names = new KList<>();
providers.stream().filter(ExternalDataProvider::isPresent).forEach(p -> names.add(p.getBlockTypes()));
return names.toArray(new NamespacedKey[0]);
}
}
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.link.ItemAdderDataProvider;
import com.volmit.iris.core.link.OraxenDataProvider;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.plugin.IrisService;
import lombok.Data;
import org.bukkit.Bukkit;
import org.bukkit.block.data.BlockData;
import org.bukkit.event.EventHandler;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.inventory.ItemStack;
import java.util.MissingResourceException;
import java.util.Optional;
@Data
public class ExternalDataSVC implements IrisService {
private KList<ExternalDataProvider> providers = new KList<>(), activeProviders = new KList<>();
@Override
public void onEnable() {
Iris.info("Loading ExternalDataProvider...");
Bukkit.getPluginManager().registerEvents(this, Iris.instance);
providers.add(new OraxenDataProvider());
if (Bukkit.getPluginManager().getPlugin("Oraxen") != null) {
Iris.info("Oraxen found, loading OraxenDataProvider...");
}
providers.add(new ItemAdderDataProvider());
if (Bukkit.getPluginManager().getPlugin("ItemAdder") != null) {
Iris.info("ItemAdder found, loading ItemAdderDataProvider...");
}
for (ExternalDataProvider p : providers) {
if (p.isReady()) {
activeProviders.add(p);
p.init();
Iris.info("Enabled ExternalDataProvider for %s.", p.getPluginId());
}
}
}
@Override
public void onDisable() {
}
@EventHandler
public void onPluginEnable(PluginEnableEvent e) {
if (activeProviders.stream().noneMatch(p -> p.getPlugin().equals(e.getPlugin()))) {
providers.stream().filter(p -> p.isReady() && p.getPlugin().equals(e.getPlugin())).findFirst().ifPresent(edp -> {
activeProviders.add(edp);
edp.init();
Iris.info("Enabled ExternalDataProvider for %s.", edp.getPluginId());
});
}
}
public Optional<BlockData> getBlockData(Identifier key) {
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(key, false)).findFirst();
if (provider.isEmpty())
return Optional.empty();
try {
return Optional.of(provider.get().getBlockData(key));
} catch (MissingResourceException e) {
Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]");
return Optional.empty();
}
}
public Optional<ItemStack> getItemStack(Identifier key) {
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(key, true)).findFirst();
if (provider.isEmpty()) {
Iris.warn("No matching Provider found for modded material \"%s\"!", key);
return Optional.empty();
}
try {
return Optional.of(provider.get().getItemStack(key));
} catch (MissingResourceException e) {
Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]");
return Optional.empty();
}
}
public Identifier[] getAllBlockIdentifiers() {
KList<Identifier> names = new KList<>();
activeProviders.forEach(p -> names.add(p.getBlockTypes()));
return names.toArray(new Identifier[0]);
}
public Identifier[] getAllItemIdentifiers() {
KList<Identifier> names = new KList<>();
activeProviders.forEach(p -> names.add(p.getItemTypes()));
return names.toArray(new Identifier[0]);
}
}

View File

@@ -19,6 +19,7 @@
package com.volmit.iris.core.service;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.format.C;
@@ -70,7 +71,7 @@ public class VillageSVC implements IrisService {
List<Player> playersInWorld = event.getEntity().getWorld().getPlayers();
String message = C.GOLD + "Iris does not allow cartographers in its world due to crashes.";
String message = C.GOLD + IrisSettings.get().getGeneral().cartographerMessage;
Iris.info("Cancelled Cartographer Villager to prevent server crash at " + eventLocation + "!");

View File

@@ -220,7 +220,6 @@ public class IrisComplex implements DataProvider {
return seaBiomeStream;
case SHORE:
return shoreBiomeStream;
case DEFER:
default:
break;
}

File diff suppressed because it is too large Load Diff

View File

@@ -552,7 +552,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
public void execute(Future<Chunk> chunkFuture) {
try {
chunkFuture.get();
} catch (InterruptedException | ExecutionException e) {
} catch (InterruptedException | ExecutionException ignored) {
}
}
@@ -597,6 +597,10 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
for (String i : mark.getSpawners()) {
IrisSpawner m = getData().getSpawnerLoader().load(i);
if (m == null) {
Iris.error("Cannot load spawner: " + i + " for marker on " + getName());
continue;
}
m.setReferenceMarker(mark);
// This is so fucking incorrect its a joke

View File

@@ -1,179 +1,179 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine.framework;
import com.volmit.iris.Iris;
import com.volmit.iris.core.events.IrisEngineHotloadEvent;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.plugin.VolmitSender;
import org.bukkit.*;
import org.bukkit.entity.EnderSignal;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.WorldSaveEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.inventory.EquipmentSlot;
import java.util.concurrent.atomic.AtomicBoolean;
public abstract class EngineAssignedWorldManager extends EngineAssignedComponent implements EngineWorldManager, Listener {
private final int taskId;
protected AtomicBoolean ignoreTP = new AtomicBoolean(false);
public EngineAssignedWorldManager() {
super(null, null);
taskId = -1;
}
public EngineAssignedWorldManager(Engine engine) {
super(engine, "World");
Iris.instance.registerListener(this);
taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::onTick, 0, 0);
}
@EventHandler
public void on(IrisEngineHotloadEvent e) {
for (Player i : e.getEngine().getWorld().getPlayers()) {
i.playSound(i.getLocation(), Sound.BLOCK_AMETHYST_BLOCK_BREAK, 1f, 1.8f);
VolmitSender s = new VolmitSender(i);
s.sendTitle(C.IRIS + "Engine " + C.AQUA + "<font:minecraft:uniform>Hotloaded", 70, 60, 410);
}
}
// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
// public void on(PlayerTeleportEvent e) {
// if(ignoreTP.get()) {
// System.out.println("IgTP1");
// return;
// }
//
// if(!PaperLib.isPaper() || e.getTo() == null) {
// System.out.println("IgTP2");
//
//// return;
// }
//
//// try {
//// System.out.println("IgTP3");
////
//// if(e.getTo().getWorld().equals(getTarget().getWorld().realWorld())) {
//// System.out.println("IgTP4");
////
//// getEngine().getWorldManager().teleportAsync(e);
//// }
//// } catch(Throwable ex) {
////
//// }
// }
@EventHandler
public void on(WorldSaveEvent e) {
if (e.getWorld().equals(getTarget().getWorld().realWorld())) {
getEngine().save();
}
}
@EventHandler
public void onItemUse(PlayerInteractEvent e) {
if (e.getItem() == null || e.getHand() != EquipmentSlot.HAND) {
return;
}
if (e.getAction() == Action.LEFT_CLICK_BLOCK || e.getAction() == Action.LEFT_CLICK_AIR) {
return;
}
if (e.getPlayer().getWorld().equals(getTarget().getWorld().realWorld()) && e.getItem().getType() == Material.ENDER_EYE) {
if (e.getClickedBlock() != null && e.getClickedBlock().getType() == Material.END_PORTAL_FRAME) {
return;
}
KList<Position2> positions = getEngine().getDimension().getStrongholds(getEngine().getSeedManager().getSpawn());
if (positions.isEmpty()) {
return;
}
Position2 playerPos = new Position2(e.getPlayer().getLocation().getBlockX(), e.getPlayer().getLocation().getBlockZ());
Position2 pr = positions.get(0);
double d = pr.distance(playerPos);
for (Position2 pos : positions) {
double distance = pos.distance(playerPos);
if (distance < d) {
d = distance;
pr = pos;
}
}
if (e.getPlayer().getGameMode() != GameMode.CREATIVE) {
if (e.getItem().getAmount() > 1) {
e.getPlayer().getInventory().getItemInMainHand().setAmount(e.getItem().getAmount() - 1);
} else {
e.getPlayer().getInventory().setItemInMainHand(null);
}
}
EnderSignal eye = e.getPlayer().getWorld().spawn(e.getPlayer().getLocation().clone().add(0, 0.5F, 0), EnderSignal.class);
eye.setTargetLocation(new Location(e.getPlayer().getWorld(), pr.getX(), 40, pr.getZ()));
eye.getWorld().playSound(eye, Sound.ENTITY_ENDER_EYE_LAUNCH, 1, 1);
Iris.debug("ESignal: " + eye.getTargetLocation().getBlockX() + " " + eye.getTargetLocation().getBlockX());
}
}
@EventHandler
public void on(WorldUnloadEvent e) {
if (e.getWorld().equals(getTarget().getWorld().realWorld())) {
getEngine().close();
}
}
@EventHandler
public void on(BlockBreakEvent e) {
if (e.getPlayer().getWorld().equals(getTarget().getWorld().realWorld())) {
onBlockBreak(e);
}
}
@EventHandler
public void on(BlockPlaceEvent e) {
if (e.getPlayer().getWorld().equals(getTarget().getWorld().realWorld())) {
onBlockPlace(e);
}
}
@EventHandler
public void on(ChunkLoadEvent e) {
if (e.getChunk().getWorld().equals(getTarget().getWorld().realWorld())) {
onChunkLoad(e.getChunk(), e.isNewChunk());
}
}
@Override
public void close() {
super.close();
Iris.instance.unregisterListener(this);
Bukkit.getScheduler().cancelTask(taskId);
}
}
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine.framework;
import com.volmit.iris.Iris;
import com.volmit.iris.core.events.IrisEngineHotloadEvent;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.plugin.VolmitSender;
import org.bukkit.*;
import org.bukkit.entity.EnderSignal;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.WorldSaveEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.inventory.EquipmentSlot;
import java.util.concurrent.atomic.AtomicBoolean;
public abstract class EngineAssignedWorldManager extends EngineAssignedComponent implements EngineWorldManager, Listener {
private final int taskId;
protected AtomicBoolean ignoreTP = new AtomicBoolean(false);
public EngineAssignedWorldManager() {
super(null, null);
taskId = -1;
}
public EngineAssignedWorldManager(Engine engine) {
super(engine, "World");
Iris.instance.registerListener(this);
taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::onTick, 0, 0);
}
@EventHandler
public void on(IrisEngineHotloadEvent e) {
for (Player i : e.getEngine().getWorld().getPlayers()) {
i.playSound(i.getLocation(), Sound.BLOCK_AMETHYST_BLOCK_BREAK, 1f, 1.8f);
VolmitSender s = new VolmitSender(i);
s.sendTitle(C.IRIS + "Engine " + C.AQUA + "<font:minecraft:uniform>Hotloaded", 70, 60, 410);
}
}
// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
// public void on(PlayerTeleportEvent e) {
// if(ignoreTP.get()) {
// System.out.println("IgTP1");
// return;
// }
//
// if(!PaperLib.isPaper() || e.getTo() == null) {
// System.out.println("IgTP2");
//
//// return;
// }
//
//// try {
//// System.out.println("IgTP3");
////
//// if(e.getTo().getWorld().equals(getTarget().getWorld().realWorld())) {
//// System.out.println("IgTP4");
////
//// getEngine().getWorldManager().teleportAsync(e);
//// }
//// } catch(Throwable ex) {
////
//// }
// }
@EventHandler
public void on(WorldSaveEvent e) {
if (e.getWorld().equals(getTarget().getWorld().realWorld())) {
getEngine().save();
}
}
@EventHandler
public void onItemUse(PlayerInteractEvent e) {
if (e.getItem() == null || e.getHand() != EquipmentSlot.HAND) {
return;
}
if (e.getAction() == Action.LEFT_CLICK_BLOCK || e.getAction() == Action.LEFT_CLICK_AIR) {
return;
}
if (e.getPlayer().getWorld().equals(getTarget().getWorld().realWorld()) && e.getItem().getType() == Material.ENDER_EYE) {
if (e.getClickedBlock() != null && e.getClickedBlock().getType() == Material.END_PORTAL_FRAME) {
return;
}
KList<Position2> positions = getEngine().getDimension().getStrongholds(getEngine().getSeedManager().getSpawn());
if (positions.isEmpty()) {
return;
}
Position2 playerPos = new Position2(e.getPlayer().getLocation().getBlockX(), e.getPlayer().getLocation().getBlockZ());
Position2 pr = positions.get(0);
double d = pr.distance(playerPos);
for (Position2 pos : positions) {
double distance = pos.distance(playerPos);
if (distance < d) {
d = distance;
pr = pos;
}
}
if (e.getPlayer().getGameMode() != GameMode.CREATIVE) {
if (e.getItem().getAmount() > 1) {
e.getPlayer().getInventory().getItemInMainHand().setAmount(e.getItem().getAmount() - 1);
} else {
e.getPlayer().getInventory().setItemInMainHand(null);
}
}
EnderSignal eye = e.getPlayer().getWorld().spawn(e.getPlayer().getLocation().clone().add(0, 0.5F, 0), EnderSignal.class);
eye.setTargetLocation(new Location(e.getPlayer().getWorld(), pr.getX(), 40, pr.getZ()));
eye.getWorld().playSound(eye, Sound.ENTITY_ENDER_EYE_LAUNCH, 1, 1);
Iris.debug("ESignal: " + eye.getTargetLocation().getBlockX() + " " + eye.getTargetLocation().getBlockX());
}
}
@EventHandler
public void on(WorldUnloadEvent e) {
if (e.getWorld().equals(getTarget().getWorld().realWorld())) {
getEngine().close();
}
}
@EventHandler
public void on(BlockBreakEvent e) {
if (e.getPlayer().getWorld().equals(getTarget().getWorld().realWorld())) {
onBlockBreak(e);
}
}
@EventHandler
public void on(BlockPlaceEvent e) {
if (e.getPlayer().getWorld().equals(getTarget().getWorld().realWorld())) {
onBlockPlace(e);
}
}
@EventHandler
public void on(ChunkLoadEvent e) {
if (e.getChunk().getWorld().equals(getTarget().getWorld().realWorld())) {
onChunkLoad(e.getChunk(), e.isNewChunk());
}
}
@Override
public void close() {
super.close();
Iris.instance.unregisterListener(this);
Bukkit.getScheduler().cancelTask(taskId);
}
}

View File

@@ -1,245 +1,245 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine.jigsaw;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.math.AxisAlignedBB;
import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.RNG;
import lombok.Data;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.util.BlockVector;
@SuppressWarnings("ALL")
@Data
public class PlannedPiece {
private IrisPosition position;
private IrisObject object;
private IrisObject ogObject;
private IrisJigsawPiece piece;
private IrisObjectRotation rotation;
private IrisData data;
private KList<IrisJigsawPieceConnector> connected;
private boolean dead = false;
private AxisAlignedBB box;
private PlannedStructure structure;
public PlannedPiece(PlannedStructure structure, IrisPosition position, IrisJigsawPiece piece) {
this(structure, position, piece, 0, 0, 0);
}
public PlannedPiece(PlannedStructure structure, IrisPosition position, IrisJigsawPiece piece, int rx, int ry, int rz) {
this(structure, position, piece, IrisObjectRotation.of(rx * 90D, ry * 90D, rz * 90D));
}
public PlannedPiece(PlannedStructure structure, IrisPosition position, IrisJigsawPiece piece, IrisObjectRotation rot) {
this.structure = structure;
this.position = position;
this.data = piece.getLoader();
this.setRotation(rot);
this.ogObject = data.getObjectLoader().load(piece.getObject());
this.object = structure.rotated(piece, rotation);
this.piece = rotation.rotateCopy(piece);
this.piece.setLoadKey(piece.getLoadKey());
this.object.setLoadKey(piece.getObject());
this.ogObject.setLoadKey(piece.getObject());
this.connected = new KList<>();
}
public void setPosition(IrisPosition p) {
this.position = p;
box = null;
}
public String toString() {
return piece.getLoadKey() + "@(" + position.getX() + "," + position.getY() + "," + position.getZ() + ")[rot:" + rotation.toString() + "]";
}
public AxisAlignedBB getBox() {
if (box != null) {
return box;
}
BlockVector v = getObject().getCenter();
box = object.getAABB().shifted(position.add(new IrisPosition(object.getCenter())));
return box;
}
public boolean contains(IrisPosition p) {
return getBox().contains(p);
}
public boolean collidesWith(PlannedPiece p) {
return getBox().intersects(p.getBox());
}
public KList<IrisJigsawPieceConnector> getAvailableConnectors() {
if (connected.isEmpty()) {
return piece.getConnectors().copy();
}
if (connected.size() == piece.getConnectors().size()) {
return new KList<>();
}
KList<IrisJigsawPieceConnector> c = new KList<>();
for (IrisJigsawPieceConnector i : piece.getConnectors()) {
if (!connected.contains(i)) {
c.add(i);
}
}
return c;
}
public boolean connect(IrisJigsawPieceConnector c) {
if (piece.getConnectors().contains(c)) {
return connected.addIfMissing(c);
}
return false;
}
public IrisPosition getWorldPosition(IrisJigsawPieceConnector c) {
return getWorldPosition(c.getPosition());
}
public IrisPosition getWorldPosition(IrisPosition position) {
return this.position.add(position).add(new IrisPosition(object.getCenter()));
}
public boolean isFull() {
return connected.size() >= piece.getConnectors().size() || isDead();
}
public void place(World world) {
PlatformChunkGenerator a = IrisToolbelt.access(world);
int minY = 0;
if (a != null) {
minY = a.getEngine().getMinHeight();
if (!a.getEngine().getDimension().isBedrock())
minY--; //If the dimension has no bedrock, allow it to go a block lower
}
getPiece().getPlacementOptions().setTranslate(new IrisObjectTranslate());
getPiece().getPlacementOptions().setRotation(rotation);
int finalMinY = minY;
RNG rng = getStructure().getRng().nextParallelRNG(37555);
// TODO: REAL CLASSES!!!!!!!
getOgObject().place(position.getX() + getObject().getCenter().getBlockX(), position.getY() + getObject().getCenter().getBlockY(), position.getZ() + getObject().getCenter().getBlockZ(), new IObjectPlacer() {
@Override
public int getHighest(int x, int z, IrisData data) {
return position.getY();
}
@Override
public int getHighest(int x, int z, IrisData data, boolean ignoreFluid) {
return position.getY();
}
@Override
public void set(int x, int y, int z, BlockData d) {
Block block = world.getBlockAt(x, y, z);
//Prevent blocks being set in or bellow bedrock
if (y <= finalMinY || block.getType() == Material.BEDROCK) return;
block.setBlockData(d);
if (a != null && getPiece().getPlacementOptions().getLoot().isNotEmpty() &&
block.getState() instanceof InventoryHolder) {
IrisLootTable table = getPiece().getPlacementOptions().getTable(block.getBlockData(), getData());
if (table == null) return;
Engine engine = a.getEngine();
engine.addItems(false, ((InventoryHolder) block.getState()).getInventory(),
rng.nextParallelRNG(BlockPosition.toLong(x, y, z)),
new KList<>(table), InventorySlotType.STORAGE, x, y, z, 15);
}
}
@Override
public BlockData get(int x, int y, int z) {
return world.getBlockAt(x, y, z).getBlockData();
}
@Override
public boolean isPreventingDecay() {
return false;
}
@Override
public boolean isCarved(int x, int y, int z) {
return false;
}
@Override
public boolean isSolid(int x, int y, int z) {
return world.getBlockAt(x, y, z).getType().isSolid();
}
@Override
public boolean isUnderwater(int x, int z) {
return false;
}
@Override
public int getFluidHeight() {
return 0;
}
@Override
public boolean isDebugSmartBore() {
return false;
}
@Override
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) {
BlockState state = world.getBlockAt(xx, yy, zz).getState();
tile.toBukkitTry(state);
state.update();
}
@Override
public Engine getEngine() {
if (IrisToolbelt.isIrisWorld(world)) {
return IrisToolbelt.access(world).getEngine();
}
return IrisContext.get().getEngine();
}
}, piece.getPlacementOptions(), rng, getData());
}
}
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine.jigsaw;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.math.AxisAlignedBB;
import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.RNG;
import lombok.Data;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.util.BlockVector;
@SuppressWarnings("ALL")
@Data
public class PlannedPiece {
private IrisPosition position;
private IrisObject object;
private IrisObject ogObject;
private IrisJigsawPiece piece;
private IrisObjectRotation rotation;
private IrisData data;
private KList<IrisJigsawPieceConnector> connected;
private boolean dead = false;
private AxisAlignedBB box;
private PlannedStructure structure;
public PlannedPiece(PlannedStructure structure, IrisPosition position, IrisJigsawPiece piece) {
this(structure, position, piece, 0, 0, 0);
}
public PlannedPiece(PlannedStructure structure, IrisPosition position, IrisJigsawPiece piece, int rx, int ry, int rz) {
this(structure, position, piece, IrisObjectRotation.of(rx * 90D, ry * 90D, rz * 90D));
}
public PlannedPiece(PlannedStructure structure, IrisPosition position, IrisJigsawPiece piece, IrisObjectRotation rot) {
this.structure = structure;
this.position = position;
this.data = piece.getLoader();
this.setRotation(rot);
this.ogObject = data.getObjectLoader().load(piece.getObject());
this.object = structure.rotated(piece, rotation);
this.piece = rotation.rotateCopy(piece);
this.piece.setLoadKey(piece.getLoadKey());
this.object.setLoadKey(piece.getObject());
this.ogObject.setLoadKey(piece.getObject());
this.connected = new KList<>();
}
public void setPosition(IrisPosition p) {
this.position = p;
box = null;
}
public String toString() {
return piece.getLoadKey() + "@(" + position.getX() + "," + position.getY() + "," + position.getZ() + ")[rot:" + rotation.toString() + "]";
}
public AxisAlignedBB getBox() {
if (box != null) {
return box;
}
BlockVector v = getObject().getCenter();
box = object.getAABB().shifted(position.add(new IrisPosition(object.getCenter())));
return box;
}
public boolean contains(IrisPosition p) {
return getBox().contains(p);
}
public boolean collidesWith(PlannedPiece p) {
return getBox().intersects(p.getBox());
}
public KList<IrisJigsawPieceConnector> getAvailableConnectors() {
if (connected.isEmpty()) {
return piece.getConnectors().copy();
}
if (connected.size() == piece.getConnectors().size()) {
return new KList<>();
}
KList<IrisJigsawPieceConnector> c = new KList<>();
for (IrisJigsawPieceConnector i : piece.getConnectors()) {
if (!connected.contains(i)) {
c.add(i);
}
}
return c;
}
public boolean connect(IrisJigsawPieceConnector c) {
if (piece.getConnectors().contains(c)) {
return connected.addIfMissing(c);
}
return false;
}
public IrisPosition getWorldPosition(IrisJigsawPieceConnector c) {
return getWorldPosition(c.getPosition());
}
public IrisPosition getWorldPosition(IrisPosition position) {
return this.position.add(position).add(new IrisPosition(object.getCenter()));
}
public boolean isFull() {
return connected.size() >= piece.getConnectors().size() || isDead();
}
public void place(World world) {
PlatformChunkGenerator a = IrisToolbelt.access(world);
int minY = 0;
if (a != null) {
minY = a.getEngine().getMinHeight();
if (!a.getEngine().getDimension().isBedrock())
minY--; //If the dimension has no bedrock, allow it to go a block lower
}
getPiece().getPlacementOptions().setTranslate(new IrisObjectTranslate());
getPiece().getPlacementOptions().setRotation(rotation);
int finalMinY = minY;
RNG rng = getStructure().getRng().nextParallelRNG(37555);
// TODO: REAL CLASSES!!!!!!!
getOgObject().place(position.getX() + getObject().getCenter().getBlockX(), position.getY() + getObject().getCenter().getBlockY(), position.getZ() + getObject().getCenter().getBlockZ(), new IObjectPlacer() {
@Override
public int getHighest(int x, int z, IrisData data) {
return position.getY();
}
@Override
public int getHighest(int x, int z, IrisData data, boolean ignoreFluid) {
return position.getY();
}
@Override
public void set(int x, int y, int z, BlockData d) {
Block block = world.getBlockAt(x, y, z);
//Prevent blocks being set in or bellow bedrock
if (y <= finalMinY || block.getType() == Material.BEDROCK) return;
block.setBlockData(d);
if (a != null && getPiece().getPlacementOptions().getLoot().isNotEmpty() &&
block.getState() instanceof InventoryHolder) {
IrisLootTable table = getPiece().getPlacementOptions().getTable(block.getBlockData(), getData());
if (table == null) return;
Engine engine = a.getEngine();
engine.addItems(false, ((InventoryHolder) block.getState()).getInventory(),
rng.nextParallelRNG(BlockPosition.toLong(x, y, z)),
new KList<>(table), InventorySlotType.STORAGE, x, y, z, 15);
}
}
@Override
public BlockData get(int x, int y, int z) {
return world.getBlockAt(x, y, z).getBlockData();
}
@Override
public boolean isPreventingDecay() {
return false;
}
@Override
public boolean isCarved(int x, int y, int z) {
return false;
}
@Override
public boolean isSolid(int x, int y, int z) {
return world.getBlockAt(x, y, z).getType().isSolid();
}
@Override
public boolean isUnderwater(int x, int z) {
return false;
}
@Override
public int getFluidHeight() {
return 0;
}
@Override
public boolean isDebugSmartBore() {
return false;
}
@Override
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) {
BlockState state = world.getBlockAt(xx, yy, zz).getState();
tile.toBukkitTry(state);
state.update();
}
@Override
public Engine getEngine() {
if (IrisToolbelt.isIrisWorld(world)) {
return IrisToolbelt.access(world).getEngine();
}
return IrisContext.get().getEngine();
}
}, piece.getPlacementOptions(), rng, getData());
}
}

View File

@@ -32,8 +32,5 @@ public enum InferredType {
SEA,
@Desc("Represents any cave biome type")
CAVE,
@Desc("Defers the type to whatever another biome type that already exists is.")
DEFER
CAVE
}

View File

@@ -484,11 +484,6 @@ public class IrisBiome extends IrisRegistrant implements IRare {
});
}
public IrisBiome infer(InferredType t, InferredType type) {
setInferredType(t.equals(InferredType.DEFER) ? type : t);
return this;
}
public KList<BlockData> generateSeaLayers(double wx, double wz, RNG random, int maxDepth, IrisData rdata) {
KList<BlockData> data = new KList<>();

View File

@@ -120,6 +120,7 @@ public class IrisBiomeCustom {
j.put("temperature", getTemperature());
j.put("downfall", getHumidity());
j.put("creature_spawn_probability", getSpawnRarity());
j.put("has_precipitation", getDownfallType() != IrisBiomeCustomPrecipType.none);
j.put("precipitation", getDownfallType().toString().toLowerCase());
j.put("category", getCategory().toString().toLowerCase());
j.put("effects", effects);

File diff suppressed because it is too large Load Diff

View File

@@ -154,6 +154,9 @@ public class IrisEntity extends IrisRegistrant {
@Desc("Create a mob from another plugin, such as Mythic Mobs. Should be in the format of a namespace of PluginName:MobName")
private String specialType = "";
@Desc("Set to true if you want to apply all of the settings here to the mob, even though an external plugin has already done so. Scripts are always applied.")
private boolean applySettingsToCustomMobAnyways = false;
@Desc("Set the entity type to UNKNOWN, then define a script here which ends with the entity variable (the result). You can use Iris.getLocation() to find the target location. You can spawn any entity this way.")
@RegistryListResource(IrisScript.class)
private String spawnerScript = "";
@@ -211,6 +214,10 @@ public class IrisEntity extends IrisRegistrant {
}
}
if (isSpecialType() && !applySettingsToCustomMobAnyways) {
return ee;
}
if (ee == null) {
return null;
}
@@ -413,7 +420,7 @@ public class IrisEntity extends IrisRegistrant {
return null;
}
if (type.equals(EntityType.UNKNOWN)) {
if (type.equals(EntityType.UNKNOWN) && !isSpecialType()) {
return null;
}

View File

@@ -32,7 +32,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Snippet("carving")
@Snippet("image-map")
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@@ -68,6 +68,7 @@ public class IrisImageMap {
IrisImage i = imageCache.aquire(() -> data.getImageLoader().load(image));
if (i == null) {
Iris.error("NULL IMAGE FOR " + image);
return 0;
}
return IrisInterpolation.getNoise(interpolationMethod, x, z, coordinateScale, (xx, zz) -> rawNoise(i, xx, zz));
@@ -76,11 +77,27 @@ public class IrisImageMap {
private double rawNoise(IrisImage i, double x, double z) {
x /= coordinateScale;
z /= coordinateScale;
x = isCentered() ? x + ((i.getWidth() / 2D) * coordinateScale) : x;
z = isCentered() ? z + ((i.getHeight() / 2D) * coordinateScale) : z;
x = isTiled() ? x % i.getWidth() : x;
z = isTiled() ? z % i.getHeight() : z;
// X and Z are now scaled to the image
// Add half the image width & height if centered
if (isCentered()) {
x += i.getWidth() / 2D;
z += i.getHeight() / 2D;
}
// If tiled modulo over width and height
if (isTiled()) {
x = x % i.getWidth();
x = x < 0 ? x + i.getWidth() : x; // Fix java's negative modulo shit
z = z % i.getHeight();
z = z < 0 ? z + i.getHeight() : z; // Fix java's negative modulo shit
}
// Retrieve value from image
double v = i.getValue(getChannel(), (int) x, (int) z);
// Return value, or 1 - value if inverted (value is in double set [0, 1] so this will return [0, 1])
return isInverted() ? 1D - v : v;
}
}

View File

@@ -1,250 +1,252 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine.object;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.volmit.iris.Iris;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.TagParser;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.bukkit.material.Colorable;
import java.awt.*;
import java.util.Optional;
@Snippet("loot")
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Desc("Represents a loot entry")
@Data
public class IrisLoot {
private final transient AtomicCache<CNG> chance = new AtomicCache<>();
@Desc("The target inventory slot types to fill this loot with")
private InventorySlotType slotTypes = InventorySlotType.STORAGE;
@MinNumber(1)
@Desc("The sub rarity of this loot. Calculated after this loot table has been picked.")
private int rarity = 1;
@MinNumber(1)
@Desc("Minimum amount of this loot")
private int minAmount = 1;
@MinNumber(1)
@Desc("Maximum amount of this loot")
private int maxAmount = 1;
@MinNumber(1)
@Desc("The display name of this item")
private String displayName = null;
@MinNumber(0)
@MaxNumber(1)
@Desc("Minimum durability percent")
private double minDurability = 0;
@MinNumber(0)
@MaxNumber(1)
@Desc("Maximum durability percent")
private double maxDurability = 1;
@Desc("Define a custom model identifier 1.14+ only")
private Integer customModel = null;
@Desc("Set this to true to prevent it from being broken")
private boolean unbreakable = false;
@ArrayType(min = 1, type = ItemFlag.class)
@Desc("The item flags to add")
private KList<ItemFlag> itemFlags = new KList<>();
@Desc("Apply enchantments to this item")
@ArrayType(min = 1, type = IrisEnchantment.class)
private KList<IrisEnchantment> enchantments = new KList<>();
@Desc("Apply attribute modifiers to this item")
@ArrayType(min = 1, type = IrisAttributeModifier.class)
private KList<IrisAttributeModifier> attributes = new KList<>();
@ArrayType(min = 1, type = String.class)
@Desc("Add lore to this item")
private KList<String> lore = new KList<>();
@RegistryListItemType
@Required
@Desc("This is the item or block type. Does not accept minecraft:*, only materials such as DIAMOND_SWORD or DIRT. The exception are modded materials, as they require a namespace.")
private String type = "";
@Desc("The dye color")
private DyeColor dyeColor = null;
@Desc("The leather armor color")
private String leatherColor = null;
@Desc("Defines a custom NBT Tag for the item.")
private KMap<String, Object> customNbt;
public Material getType() {
return B.getMaterial(type);
}
public ItemStack get(boolean debug, RNG rng) {
try {
ItemStack is = getItemStack(rng);
if (is == null)
return new ItemStack(Material.AIR);
is.setItemMeta(applyProperties(is, rng, debug, null));
return applyCustomNbt(is);
} catch (Throwable e) {
Iris.reportError(e);
return new ItemStack(Material.AIR);
}
}
public ItemStack get(boolean debug, boolean giveSomething, IrisLootTable table, RNG rng, int x, int y, int z) {
if (debug) {
chance.reset();
}
if (giveSomething || chance.aquire(() -> NoiseStyle.STATIC.create(rng)).fit(1, rarity * table.getRarity(), x, y, z) == 1) {
try {
ItemStack is = getItemStack(rng);
if (is == null)
return null;
is.setItemMeta(applyProperties(is, rng, debug, table));
return applyCustomNbt(is);
} catch (Throwable e) {
//Iris.reportError(e);
e.printStackTrace();
}
}
return null;
}
// TODO Better Third Party Item Acquisition
private ItemStack getItemStack(RNG rng) {
if (!type.startsWith("minecraft:") && type.contains(":")) {
Optional<ItemStack> opt = Iris.service(ExternalDataSVC.class).getItemStack(NamespacedKey.fromString(type));
if (opt.isEmpty()) {
Iris.warn("Unknown Material: " + type);
return null;
}
ItemStack is = opt.get();
is.setAmount(Math.max(1, rng.i(getMinAmount(), getMaxAmount())));
return is;
}
return new ItemStack(getType(), Math.max(1, rng.i(getMinAmount(), getMaxAmount())));
}
private ItemMeta applyProperties(ItemStack is, RNG rng, boolean debug, IrisLootTable table) {
ItemMeta m = is.getItemMeta();
if (m == null) {
return null;
}
for (IrisEnchantment i : getEnchantments()) {
i.apply(rng, m);
}
for (IrisAttributeModifier i : getAttributes()) {
i.apply(rng, m);
}
m.setUnbreakable(isUnbreakable());
for (ItemFlag i : getItemFlags()) {
m.addItemFlags(i);
}
if (getCustomModel() != null) {
m.setCustomModelData(getCustomModel());
}
if (is.getType().getMaxDurability() > 0 && m instanceof Damageable d) {
int max = is.getType().getMaxDurability();
d.setDamage((int) Math.round(Math.max(0, Math.min(max, (1D - rng.d(getMinDurability(), getMaxDurability())) * max))));
}
if (getLeatherColor() != null && m instanceof LeatherArmorMeta leather) {
Color c = Color.decode(getLeatherColor());
leather.setColor(org.bukkit.Color.fromRGB(c.getRed(), c.getGreen(), c.getBlue()));
}
if (getDyeColor() != null && m instanceof Colorable colorable) {
colorable.setColor(getDyeColor());
}
m.setLocalizedName(C.translateAlternateColorCodes('&', displayName));
m.setDisplayName(C.translateAlternateColorCodes('&', displayName));
KList<String> lore = new KList<>();
getLore().forEach((i) ->
{
String mf = C.translateAlternateColorCodes('&', i);
if (mf.length() > 24) {
for (String g : Form.wrapWords(mf, 24).split("\\Q\n\\E")) {
lore.add(g.trim());
}
} else {
lore.add(mf);
}
});
if (debug) {
if (table == null) {
if (lore.isNotEmpty()) {
lore.add(C.GRAY + "--------------------");
}
lore.add(C.GRAY + "1 in " + (getRarity()) + " Chance (" + Form.pc(1D / (getRarity()), 5) + ")");
} else {
if (lore.isNotEmpty()) {
lore.add(C.GRAY + "--------------------");
}
lore.add(C.GRAY + "From: " + table.getName() + " (" + Form.pc(1D / table.getRarity(), 5) + ")");
lore.add(C.GRAY + "1 in " + (table.getRarity() * getRarity()) + " Chance (" + Form.pc(1D / (table.getRarity() * getRarity()), 5) + ")");
}
}
m.setLore(lore);
return m;
}
private ItemStack applyCustomNbt(ItemStack stack) throws CommandSyntaxException {
if (customNbt == null || customNbt.isEmpty())
return stack;
net.minecraft.world.item.ItemStack s = CraftItemStack.asNMSCopy(stack);
CompoundTag tag = TagParser.parseTag(new JSONObject(customNbt).toString());
tag.merge(s.getOrCreateTag());
s.setTag(tag);
return CraftItemStack.asBukkitCopy(s);
}
}
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine.object;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.TagParser;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.bukkit.material.Colorable;
import java.awt.*;
import java.util.Optional;
@Snippet("loot")
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Desc("Represents a loot entry")
@Data
public class IrisLoot {
private final transient AtomicCache<CNG> chance = new AtomicCache<>();
@Desc("The target inventory slot types to fill this loot with")
private InventorySlotType slotTypes = InventorySlotType.STORAGE;
@MinNumber(1)
@Desc("The sub rarity of this loot. Calculated after this loot table has been picked.")
private int rarity = 1;
@MinNumber(1)
@Desc("Minimum amount of this loot")
private int minAmount = 1;
@MinNumber(1)
@Desc("Maximum amount of this loot")
private int maxAmount = 1;
@MinNumber(1)
@Desc("The display name of this item")
private String displayName = null;
@MinNumber(0)
@MaxNumber(1)
@Desc("Minimum durability percent")
private double minDurability = 0;
@MinNumber(0)
@MaxNumber(1)
@Desc("Maximum durability percent")
private double maxDurability = 1;
@Desc("Define a custom model identifier 1.14+ only")
private Integer customModel = null;
@Desc("Set this to true to prevent it from being broken")
private boolean unbreakable = false;
@ArrayType(min = 1, type = ItemFlag.class)
@Desc("The item flags to add")
private KList<ItemFlag> itemFlags = new KList<>();
@Desc("Apply enchantments to this item")
@ArrayType(min = 1, type = IrisEnchantment.class)
private KList<IrisEnchantment> enchantments = new KList<>();
@Desc("Apply attribute modifiers to this item")
@ArrayType(min = 1, type = IrisAttributeModifier.class)
private KList<IrisAttributeModifier> attributes = new KList<>();
@ArrayType(min = 1, type = String.class)
@Desc("Add lore to this item")
private KList<String> lore = new KList<>();
@RegistryListItemType
@Required
@Desc("This is the item or block type. Does not accept minecraft:*, only materials such as DIAMOND_SWORD or DIRT. The exception are modded materials, as they require a namespace.")
private String type = "";
@Desc("The dye color")
private DyeColor dyeColor = null;
@Desc("The leather armor color")
private String leatherColor = null;
@Desc("Defines a custom NBT Tag for the item.")
private KMap<String, Object> customNbt;
public Material getType() {
return B.getMaterial(type);
}
public ItemStack get(boolean debug, RNG rng) {
try {
ItemStack is = getItemStack(rng);
if (is == null)
return new ItemStack(Material.AIR);
is.setItemMeta(applyProperties(is, rng, debug, null));
return applyCustomNbt(is);
} catch (Throwable e) {
Iris.reportError(e);
return new ItemStack(Material.AIR);
}
}
public ItemStack get(boolean debug, boolean giveSomething, IrisLootTable table, RNG rng, int x, int y, int z) {
if (debug) {
chance.reset();
}
if (giveSomething || chance.aquire(() -> NoiseStyle.STATIC.create(rng)).fit(1, rarity * table.getRarity(), x, y, z) == 1) {
try {
ItemStack is = getItemStack(rng);
if (is == null)
return null;
is.setItemMeta(applyProperties(is, rng, debug, table));
return applyCustomNbt(is);
} catch (Throwable e) {
//Iris.reportError(e);
e.printStackTrace();
}
}
return null;
}
// TODO Better Third Party Item Acquisition
private ItemStack getItemStack(RNG rng) {
if (!type.startsWith("minecraft:") && type.contains(":")) {
Optional<ItemStack> opt = Iris.service(ExternalDataSVC.class).getItemStack(Identifier.fromString(type));
if (opt.isEmpty()) {
Iris.warn("Unknown Material: " + type);
return new ItemStack(Material.AIR);
}
ItemStack is = opt.get();
is.setAmount(Math.max(1, rng.i(getMinAmount(), getMaxAmount())));
return is;
}
return new ItemStack(getType(), Math.max(1, rng.i(getMinAmount(), getMaxAmount())));
}
private ItemMeta applyProperties(ItemStack is, RNG rng, boolean debug, IrisLootTable table) {
ItemMeta m = is.getItemMeta();
if (m == null) {
return null;
}
for (IrisEnchantment i : getEnchantments()) {
i.apply(rng, m);
}
for (IrisAttributeModifier i : getAttributes()) {
i.apply(rng, m);
}
m.setUnbreakable(isUnbreakable());
for (ItemFlag i : getItemFlags()) {
m.addItemFlags(i);
}
if (getCustomModel() != null) {
m.setCustomModelData(getCustomModel());
}
if (is.getType().getMaxDurability() > 0 && m instanceof Damageable d) {
int max = is.getType().getMaxDurability();
d.setDamage((int) Math.round(Math.max(0, Math.min(max, (1D - rng.d(getMinDurability(), getMaxDurability())) * max))));
}
if (getLeatherColor() != null && m instanceof LeatherArmorMeta leather) {
Color c = Color.decode(getLeatherColor());
leather.setColor(org.bukkit.Color.fromRGB(c.getRed(), c.getGreen(), c.getBlue()));
}
if (getDyeColor() != null && m instanceof Colorable colorable) {
colorable.setColor(getDyeColor());
}
if (displayName != null) {
m.setLocalizedName(C.translateAlternateColorCodes('&', displayName));
m.setDisplayName(C.translateAlternateColorCodes('&', displayName));
}
KList<String> lore = new KList<>();
getLore().forEach((i) ->
{
String mf = C.translateAlternateColorCodes('&', i);
if (mf.length() > 24) {
for (String g : Form.wrapWords(mf, 24).split("\\Q\n\\E")) {
lore.add(g.trim());
}
} else {
lore.add(mf);
}
});
if (debug) {
if (table == null) {
if (lore.isNotEmpty()) {
lore.add(C.GRAY + "--------------------");
}
lore.add(C.GRAY + "1 in " + (getRarity()) + " Chance (" + Form.pc(1D / (getRarity()), 5) + ")");
} else {
if (lore.isNotEmpty()) {
lore.add(C.GRAY + "--------------------");
}
lore.add(C.GRAY + "From: " + table.getName() + " (" + Form.pc(1D / table.getRarity(), 5) + ")");
lore.add(C.GRAY + "1 in " + (table.getRarity() * getRarity()) + " Chance (" + Form.pc(1D / (table.getRarity() * getRarity()), 5) + ")");
}
}
m.setLore(lore);
return m;
}
private ItemStack applyCustomNbt(ItemStack stack) throws CommandSyntaxException {
if (customNbt == null || customNbt.isEmpty())
return stack;
net.minecraft.world.item.ItemStack s = CraftItemStack.asNMSCopy(stack);
CompoundTag tag = TagParser.parseTag(new JSONObject(customNbt).toString());
tag.merge(s.getOrCreateTag());
s.setTag(tag);
return CraftItemStack.asBukkitCopy(s);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -62,6 +62,11 @@ public class IrisObjectPlacement {
private double snow = 0;
@Desc("Whether or not this object can be targeted by a dolphin.")
private boolean isDolphinTarget = false;
@Desc("The slope at which this object can be placed. Range from 0 to 10 by default. Calculated from a 3-block radius from the center of the object placement.")
private IrisSlopeClip slopeCondition = new IrisSlopeClip();
@Desc("Set to true to add the rotation of the direction of the slope of the terrain (wherever the slope is going down) to the y-axis rotation of the object." +
"Rounded to 90 degrees. Adds the *min* rotation of the y axis as well (to still allow you to rotate objects nicely). Discards *max* and *interval* on *yaxis*")
private boolean rotateTowardsSlope = false;
@MinNumber(0)
@MaxNumber(1)
@Desc("The chance for this to place in a chunk. If you need multiple per chunk, set this to 1 and use density.")

View File

@@ -76,17 +76,17 @@ public class IrisSpawner extends IrisRegistrant {
public boolean isValid(IrisBiome biome) {
return switch (group) {
case NORMAL -> switch (biome.getInferredType()) {
case SHORE, SEA, CAVE, DEFER -> false;
case SHORE, SEA, CAVE -> false;
case LAND -> true;
};
case CAVE -> true;
case UNDERWATER -> switch (biome.getInferredType()) {
case SHORE, LAND, CAVE, DEFER -> false;
case SHORE, LAND, CAVE -> false;
case SEA -> true;
};
case BEACH -> switch (biome.getInferredType()) {
case SHORE -> true;
case LAND, CAVE, SEA, DEFER -> false;
case LAND, CAVE, SEA -> false;
};
};
}

View File

@@ -1,422 +1,426 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine.platform;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.v19_3.CustomBiomeSource;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.IrisEngine;
import com.volmit.iris.engine.data.chunk.TerrainChunk;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineTarget;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisWorld;
import com.volmit.iris.engine.object.StudioMode;
import com.volmit.iris.engine.platform.studio.StudioGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.data.IrisBiomeStorage;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder;
import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder;
import com.volmit.iris.util.io.ReactiveFolder;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.Looper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Setter;
import net.minecraft.server.level.ServerLevel;
import org.bukkit.*;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.WorldInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import sun.misc.Unsafe;
import java.io.File;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
@EqualsAndHashCode(callSuper = true)
@Data
public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChunkGenerator, Listener {
private static final int LOAD_LOCKS = Runtime.getRuntime().availableProcessors() * 4;
private final Semaphore loadLock;
private final IrisWorld world;
private final File dataLocation;
private final String dimensionKey;
private final ReactiveFolder folder;
private final ReentrantLock lock = new ReentrantLock();
private final KList<BlockPopulator> populators;
private final ChronoLatch hotloadChecker;
private final AtomicBoolean setup;
private final boolean studio;
private final AtomicInteger a = new AtomicInteger(0);
private Engine engine;
private Looper hotloader;
private StudioMode lastMode;
private DummyBiomeProvider dummyBiomeProvider;
@Setter
private StudioGenerator studioGenerator;
public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) {
setup = new AtomicBoolean(false);
studioGenerator = null;
dummyBiomeProvider = new DummyBiomeProvider();
populators = new KList<>();
loadLock = new Semaphore(LOAD_LOCKS);
this.world = world;
this.hotloadChecker = new ChronoLatch(1000, false);
this.studio = studio;
this.dataLocation = dataLocation;
this.dimensionKey = dimensionKey;
this.folder = new ReactiveFolder(dataLocation, (_a, _b, _c) -> hotload());
Bukkit.getServer().getPluginManager().registerEvents(this, Iris.instance);
}
private static Field getField(Class clazz, String fieldName)
throws NoSuchFieldException {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
Class superClass = clazz.getSuperclass();
if (superClass == null) {
throw e;
} else {
return getField(superClass, fieldName);
}
}
}
@EventHandler
public void onWorldInit(WorldInitEvent event) {
try {
if (world.name().equals(event.getWorld().getName()) && world.getRawWorldSeed() == event.getWorld().getSeed()) {
ServerLevel serverLevel = ((CraftWorld) event.getWorld()).getHandle();
Engine engine = getEngine(event.getWorld());
Class<?> clazz = serverLevel.getChunkSource().chunkMap.generator.getClass();
Field biomeSource = getField(clazz, "b");
biomeSource.setAccessible(true);
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
CustomBiomeSource customBiomeSource = new CustomBiomeSource(event.getWorld().getSeed(), engine, event.getWorld());
unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource);
biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource);
Iris.info("Injected Iris Biome Source into " + event.getWorld().getName());
} else {
Iris.info("World " + event.getWorld().getName() + " is not an Iris world in this context");
}
} catch (Throwable e) {
e.printStackTrace();
}
}
private void setupEngine() {
IrisData data = IrisData.get(dataLocation);
IrisDimension dimension = data.getDimensionLoader().load(dimensionKey);
if (dimension == null) {
Iris.error("Oh No! There's no pack in " + data.getDataFolder().getPath() + " or... there's no dimension for the key " + dimensionKey);
IrisDimension test = IrisData.loadAnyDimension(dimensionKey);
if (test != null) {
Iris.warn("Looks like " + dimensionKey + " exists in " + test.getLoadFile().getPath() + " ");
Iris.service(StudioSVC.class).installIntoWorld(Iris.getSender(), dimensionKey, dataLocation.getParentFile().getParentFile());
Iris.warn("Attempted to install into " + data.getDataFolder().getPath());
data.dump();
data.clearLists();
test = data.getDimensionLoader().load(dimensionKey);
if (test != null) {
Iris.success("Woo! Patched the Engine!");
dimension = test;
} else {
Iris.error("Failed to patch dimension!");
throw new RuntimeException("Missing Dimension: " + dimensionKey);
}
} else {
Iris.error("Nope, you don't have an installation containing " + dimensionKey + " try downloading it?");
throw new RuntimeException("Missing Dimension: " + dimensionKey);
}
}
lastMode = StudioMode.NORMAL;
engine = new IrisEngine(new EngineTarget(world, dimension, data), studio);
populators.clear();
}
@Override
public void injectChunkReplacement(World world, int x, int z, Consumer<Runnable> jobs) {
try {
loadLock.acquire();
IrisBiomeStorage st = new IrisBiomeStorage();
TerrainChunk tc = TerrainChunk.createUnsafe(world, st);
Hunk<BlockData> blocks = Hunk.view(tc);
Hunk<Biome> biomes = Hunk.view(tc, tc.getMinHeight(), tc.getMaxHeight());
this.world.bind(world);
getEngine().generate(x << 4, z << 4, blocks, biomes, true);
Iris.debug("Regenerated " + x + " " + z);
int t = 0;
for (int i = getEngine().getHeight() >> 4; i >= 0; i--) {
if (!world.isChunkLoaded(x, z)) {
continue;
}
Chunk c = world.getChunkAt(x, z);
for (Entity ee : c.getEntities()) {
if (ee instanceof Player) {
continue;
}
J.s(ee::remove);
}
J.s(() -> engine.getWorldManager().onChunkLoad(c, false));
int finalI = i;
jobs.accept(() -> {
for (int xx = 0; xx < 16; xx++) {
for (int yy = 0; yy < 16; yy++) {
for (int zz = 0; zz < 16; zz++) {
if (yy + (finalI << 4) >= engine.getHeight() || yy + (finalI << 4) < 0) {
continue;
}
c.getBlock(xx, yy + (finalI << 4) + world.getMinHeight(), zz)
.setBlockData(tc.getBlockData(xx, yy + (finalI << 4) + world.getMinHeight(), zz), false);
}
}
}
});
}
loadLock.release();
} catch (Throwable e) {
loadLock.release();
Iris.error("======================================");
e.printStackTrace();
Iris.reportErrorChunk(x, z, e, "CHUNK");
Iris.error("======================================");
ChunkData d = Bukkit.createChunkData(world);
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData());
}
}
}
}
private Engine getEngine(WorldInfo world) {
if (setup.get()) {
return getEngine();
}
lock.lock();
if (setup.get()) {
return getEngine();
}
setup.set(true);
getWorld().setRawWorldSeed(world.getSeed());
setupEngine();
this.hotloader = studio ? new Looper() {
@Override
protected long loop() {
if (hotloadChecker.flip()) {
folder.check();
}
return 250;
}
} : null;
if (studio) {
hotloader.setPriority(Thread.MIN_PRIORITY);
hotloader.start();
hotloader.setName(getTarget().getWorld().name() + " Hotloader");
}
lock.unlock();
return engine;
}
@Override
public void close() {
withExclusiveControl(() -> {
if (isStudio()) {
hotloader.interrupt();
}
getEngine().close();
folder.clear();
populators.clear();
});
}
@Override
public boolean isStudio() {
return studio;
}
@Override
public void hotload() {
if (!isStudio()) {
return;
}
withExclusiveControl(() -> getEngine().hotload());
}
public void withExclusiveControl(Runnable r) {
J.a(() -> {
try {
loadLock.acquire(LOAD_LOCKS);
r.run();
loadLock.release(LOAD_LOCKS);
} catch (Throwable e) {
Iris.reportError(e);
}
});
}
@Override
public void touch(World world) {
getEngine(world);
}
@Override
public void generateNoise(@NotNull WorldInfo world, @NotNull Random random, int x, int z, @NotNull ChunkGenerator.ChunkData d) {
try {
getEngine(world);
computeStudioGenerator();
TerrainChunk tc = TerrainChunk.create(d, new IrisBiomeStorage());
this.world.bind(world);
if (studioGenerator != null) {
studioGenerator.generateChunk(getEngine(), tc, x, z);
} else {
ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc);
BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight());
getEngine().generate(x << 4, z << 4, blocks, biomes, false);
blocks.apply();
biomes.apply();
}
Iris.debug("Generated " + x + " " + z);
} catch (Throwable e) {
Iris.error("======================================");
e.printStackTrace();
Iris.reportErrorChunk(x, z, e, "CHUNK");
Iris.error("======================================");
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData());
}
}
}
}
@Override
public int getBaseHeight(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull HeightMap heightMap) {
return 4;
}
private void computeStudioGenerator() {
if (!getEngine().getDimension().getStudioMode().equals(lastMode)) {
lastMode = getEngine().getDimension().getStudioMode();
getEngine().getDimension().getStudioMode().inject(this);
}
}
@NotNull
@Override
public List<BlockPopulator> getDefaultPopulators(@NotNull World world) {
return populators;
}
@Override
public boolean isParallelCapable() {
return true;
}
@Override
public boolean shouldGenerateCaves() {
return false;
}
@Override
public boolean shouldGenerateDecorations() {
return false;
}
@Override
public boolean shouldGenerateMobs() {
return false;
}
@Override
public boolean shouldGenerateStructures() {
return false;
}
@Override
public boolean shouldGenerateNoise() {
return false;
}
@Override
public boolean shouldGenerateSurface() {
return false;
}
@Override
public boolean shouldGenerateBedrock() {
return false;
}
@Nullable
@Override
public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) {
return dummyBiomeProvider;
}
}
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine.platform;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.v20.CustomBiomeSource;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.IrisEngine;
import com.volmit.iris.engine.data.chunk.TerrainChunk;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineTarget;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisWorld;
import com.volmit.iris.engine.object.StudioMode;
import com.volmit.iris.engine.platform.studio.StudioGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.data.IrisBiomeStorage;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder;
import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder;
import com.volmit.iris.util.io.ReactiveFolder;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.Looper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Setter;
import net.minecraft.server.level.ServerLevel;
import org.bukkit.*;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.WorldInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import sun.misc.Unsafe;
import java.io.File;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
@EqualsAndHashCode(callSuper = true)
@Data
public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChunkGenerator, Listener {
private static final int LOAD_LOCKS = Runtime.getRuntime().availableProcessors() * 4;
private final Semaphore loadLock;
private final IrisWorld world;
private final File dataLocation;
private final String dimensionKey;
private final ReactiveFolder folder;
private final ReentrantLock lock = new ReentrantLock();
private final KList<BlockPopulator> populators;
private final ChronoLatch hotloadChecker;
private final AtomicBoolean setup;
private final boolean studio;
private final AtomicInteger a = new AtomicInteger(0);
private Engine engine;
private Looper hotloader;
private StudioMode lastMode;
private DummyBiomeProvider dummyBiomeProvider;
@Setter
private StudioGenerator studioGenerator;
private boolean initialized = false;
public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) {
setup = new AtomicBoolean(false);
studioGenerator = null;
dummyBiomeProvider = new DummyBiomeProvider();
populators = new KList<>();
loadLock = new Semaphore(LOAD_LOCKS);
this.world = world;
this.hotloadChecker = new ChronoLatch(1000, false);
this.studio = studio;
this.dataLocation = dataLocation;
this.dimensionKey = dimensionKey;
this.folder = new ReactiveFolder(dataLocation, (_a, _b, _c) -> hotload());
Bukkit.getServer().getPluginManager().registerEvents(this, Iris.instance);
}
private static Field getField(Class clazz, String fieldName)
throws NoSuchFieldException {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
Class superClass = clazz.getSuperclass();
if (superClass == null) {
throw e;
} else {
return getField(superClass, fieldName);
}
}
}
@EventHandler
public void onWorldInit(WorldInitEvent event) {
try {
if (!initialized) {
world.setRawWorldSeed(event.getWorld().getSeed());
if (world.name().equals(event.getWorld().getName())) {
ServerLevel serverLevel = ((CraftWorld) event.getWorld()).getHandle();
Engine engine = getEngine(event.getWorld());
Class<?> clazz = serverLevel.getChunkSource().chunkMap.generator.getClass();
Field biomeSource = getField(clazz, "b");
biomeSource.setAccessible(true);
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
CustomBiomeSource customBiomeSource = new CustomBiomeSource(event.getWorld().getSeed(), engine, event.getWorld());
unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource);
biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource);
Iris.info("Injected Iris Biome Source into " + event.getWorld().getName());
initialized = true;
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
private void setupEngine() {
IrisData data = IrisData.get(dataLocation);
IrisDimension dimension = data.getDimensionLoader().load(dimensionKey);
if (dimension == null) {
Iris.error("Oh No! There's no pack in " + data.getDataFolder().getPath() + " or... there's no dimension for the key " + dimensionKey);
IrisDimension test = IrisData.loadAnyDimension(dimensionKey);
if (test != null) {
Iris.warn("Looks like " + dimensionKey + " exists in " + test.getLoadFile().getPath() + " ");
Iris.service(StudioSVC.class).installIntoWorld(Iris.getSender(), dimensionKey, dataLocation.getParentFile().getParentFile());
Iris.warn("Attempted to install into " + data.getDataFolder().getPath());
data.dump();
data.clearLists();
test = data.getDimensionLoader().load(dimensionKey);
if (test != null) {
Iris.success("Woo! Patched the Engine!");
dimension = test;
} else {
Iris.error("Failed to patch dimension!");
throw new RuntimeException("Missing Dimension: " + dimensionKey);
}
} else {
Iris.error("Nope, you don't have an installation containing " + dimensionKey + " try downloading it?");
throw new RuntimeException("Missing Dimension: " + dimensionKey);
}
}
lastMode = StudioMode.NORMAL;
engine = new IrisEngine(new EngineTarget(world, dimension, data), studio);
populators.clear();
}
@Override
public void injectChunkReplacement(World world, int x, int z, Consumer<Runnable> jobs) {
try {
loadLock.acquire();
IrisBiomeStorage st = new IrisBiomeStorage();
TerrainChunk tc = TerrainChunk.createUnsafe(world, st);
Hunk<BlockData> blocks = Hunk.view(tc);
Hunk<Biome> biomes = Hunk.view(tc, tc.getMinHeight(), tc.getMaxHeight());
this.world.bind(world);
getEngine().generate(x << 4, z << 4, blocks, biomes, true);
Iris.debug("Regenerated " + x + " " + z);
int t = 0;
for (int i = getEngine().getHeight() >> 4; i >= 0; i--) {
if (!world.isChunkLoaded(x, z)) {
continue;
}
Chunk c = world.getChunkAt(x, z);
for (Entity ee : c.getEntities()) {
if (ee instanceof Player) {
continue;
}
J.s(ee::remove);
}
J.s(() -> engine.getWorldManager().onChunkLoad(c, false));
int finalI = i;
jobs.accept(() -> {
for (int xx = 0; xx < 16; xx++) {
for (int yy = 0; yy < 16; yy++) {
for (int zz = 0; zz < 16; zz++) {
if (yy + (finalI << 4) >= engine.getHeight() || yy + (finalI << 4) < 0) {
continue;
}
c.getBlock(xx, yy + (finalI << 4) + world.getMinHeight(), zz)
.setBlockData(tc.getBlockData(xx, yy + (finalI << 4) + world.getMinHeight(), zz), false);
}
}
}
});
}
loadLock.release();
} catch (Throwable e) {
loadLock.release();
Iris.error("======================================");
e.printStackTrace();
Iris.reportErrorChunk(x, z, e, "CHUNK");
Iris.error("======================================");
ChunkData d = Bukkit.createChunkData(world);
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData());
}
}
}
}
private Engine getEngine(WorldInfo world) {
if (setup.get()) {
return getEngine();
}
lock.lock();
if (setup.get()) {
return getEngine();
}
setup.set(true);
getWorld().setRawWorldSeed(world.getSeed());
setupEngine();
this.hotloader = studio ? new Looper() {
@Override
protected long loop() {
if (hotloadChecker.flip()) {
folder.check();
}
return 250;
}
} : null;
if (studio) {
hotloader.setPriority(Thread.MIN_PRIORITY);
hotloader.start();
hotloader.setName(getTarget().getWorld().name() + " Hotloader");
}
lock.unlock();
return engine;
}
@Override
public void close() {
withExclusiveControl(() -> {
if (isStudio()) {
hotloader.interrupt();
}
getEngine().close();
folder.clear();
populators.clear();
});
}
@Override
public boolean isStudio() {
return studio;
}
@Override
public void hotload() {
if (!isStudio()) {
return;
}
withExclusiveControl(() -> getEngine().hotload());
}
public void withExclusiveControl(Runnable r) {
J.a(() -> {
try {
loadLock.acquire(LOAD_LOCKS);
r.run();
loadLock.release(LOAD_LOCKS);
} catch (Throwable e) {
Iris.reportError(e);
}
});
}
@Override
public void touch(World world) {
getEngine(world);
}
@Override
public void generateNoise(@NotNull WorldInfo world, @NotNull Random random, int x, int z, @NotNull ChunkGenerator.ChunkData d) {
try {
getEngine(world);
computeStudioGenerator();
TerrainChunk tc = TerrainChunk.create(d, new IrisBiomeStorage());
this.world.bind(world);
if (studioGenerator != null) {
studioGenerator.generateChunk(getEngine(), tc, x, z);
} else {
ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc);
BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight());
getEngine().generate(x << 4, z << 4, blocks, biomes, false);
blocks.apply();
biomes.apply();
}
Iris.debug("Generated " + x + " " + z);
} catch (Throwable e) {
Iris.error("======================================");
e.printStackTrace();
Iris.reportErrorChunk(x, z, e, "CHUNK");
Iris.error("======================================");
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData());
}
}
}
}
@Override
public int getBaseHeight(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull HeightMap heightMap) {
return 4;
}
private void computeStudioGenerator() {
if (!getEngine().getDimension().getStudioMode().equals(lastMode)) {
lastMode = getEngine().getDimension().getStudioMode();
getEngine().getDimension().getStudioMode().inject(this);
}
}
@NotNull
@Override
public List<BlockPopulator> getDefaultPopulators(@NotNull World world) {
return populators;
}
@Override
public boolean isParallelCapable() {
return true;
}
@Override
public boolean shouldGenerateCaves() {
return false;
}
@Override
public boolean shouldGenerateDecorations() {
return false;
}
@Override
public boolean shouldGenerateMobs() {
return false;
}
@Override
public boolean shouldGenerateStructures() {
return false;
}
@Override
public boolean shouldGenerateNoise() {
return false;
}
@Override
public boolean shouldGenerateSurface() {
return false;
}
@Override
public boolean shouldGenerateBedrock() {
return false;
}
@Nullable
@Override
public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) {
return dummyBiomeProvider;
}
}

View File

@@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
public class DummyBiomeProvider extends BiomeProvider {
private final List<Biome> ALL = new KList<>(Biome.values()).qdel(Biome.CUSTOM);
private final List<Biome> ALL = new KList<>(Biome.values()).qdel(Biome.CHERRY_GROVE).qdel(Biome.CUSTOM);
@NotNull
@Override

View File

@@ -20,6 +20,7 @@ package com.volmit.iris.util.data;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
@@ -27,7 +28,6 @@ import com.volmit.iris.util.scheduling.ChronoLatch;
import it.unimi.dsi.fastutil.ints.*;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.block.data.type.Leaves;
@@ -471,8 +471,9 @@ public class B {
BlockData bx = null;
if (!ix.startsWith("minecraft:") && ix.contains(":")) {
NamespacedKey key = NamespacedKey.fromString(ix);
Identifier key = Identifier.fromString(ix);
Optional<BlockData> bd = Iris.service(ExternalDataSVC.class).getBlockData(key);
Iris.info("Loading block data " + key);
if (bd.isPresent())
bx = bd.get();
}
@@ -647,7 +648,7 @@ public class B {
}
}
for (NamespacedKey id : Iris.service(ExternalDataSVC.class).getAllIdentifiers())
for (Identifier id : Iris.service(ExternalDataSVC.class).getAllBlockIdentifiers())
bt.add(id.toString());
bt.addAll(custom.k());
@@ -662,6 +663,9 @@ public class B {
bt.add(v);
}
for (Identifier id : Iris.service(ExternalDataSVC.class).getAllItemIdentifiers())
bt.add(id.toString());
return bt.toArray(new String[0]);
}

View File

@@ -0,0 +1,37 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.util.decree.context;
import com.volmit.iris.util.decree.DecreeContextHandler;
import com.volmit.iris.util.plugin.VolmitSender;
import org.bukkit.util.Vector;
public class VectorContextHandler implements DecreeContextHandler<Vector> {
public Class<Vector> getType() {
return Vector.class;
}
public Vector handle(VolmitSender sender) {
if (sender.isPlayer()) {
return sender.player().getLocation().toVector();
}
return null;
}
}

View File

@@ -70,7 +70,7 @@ public class DimensionHandler implements DecreeParameterHandler<IrisDimension> {
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).toList().get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Biome \"" + in + "\"");
throw new DecreeParsingException("Unable to filter which Dimension \"" + in + "\"");
}
}

View File

@@ -83,7 +83,7 @@ public class EntityHandler implements DecreeParameterHandler<IrisEntity> {
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Biome \"" + in + "\"");
throw new DecreeParsingException("Unable to filter which Entity \"" + in + "\"");
}
}

View File

@@ -64,7 +64,7 @@ public class GeneratorHandler implements DecreeParameterHandler<IrisGenerator> {
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Biome \"" + in + "\"");
throw new DecreeParsingException("Unable to filter which Generator \"" + in + "\"");
}
}

View File

@@ -48,7 +48,7 @@ public class PlayerHandler implements DecreeParameterHandler<Player> {
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Biome \"" + in + "\"");
throw new DecreeParsingException("Unable to filter which Player \"" + in + "\"");
}
}

View File

@@ -67,7 +67,7 @@ public class RegionHandler implements DecreeParameterHandler<IrisRegion> {
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Biome \"" + in + "\"");
throw new DecreeParsingException("Unable to filter which Region \"" + in + "\"");
}
}

View File

@@ -64,7 +64,7 @@ public class ScriptHandler implements DecreeParameterHandler<IrisScript> {
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Biome \"" + in + "\"");
throw new DecreeParsingException("Unable to filter which Script \"" + in + "\"");
}
}

View File

@@ -53,7 +53,7 @@ public class WorldHandler implements DecreeParameterHandler<World> {
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Biome \"" + in + "\"");
throw new DecreeParsingException("Unable to filter which World \"" + in + "\"");
}
}

View File

@@ -58,7 +58,7 @@ public class ObjectHandler implements DecreeParameterHandler<String> {
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Biome \"" + in + "\"");
throw new DecreeParsingException("Unable to filter which Object \"" + in + "\"");
}
}

View File

@@ -23,10 +23,7 @@ import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.decree.DecreeContext;
import com.volmit.iris.util.decree.DecreeContextHandler;
import com.volmit.iris.util.decree.DecreeNode;
import com.volmit.iris.util.decree.DecreeParameter;
import com.volmit.iris.util.decree.*;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import com.volmit.iris.util.format.C;
@@ -381,6 +378,12 @@ public class VirtualDecreeCommand {
return false;
}
DecreeOrigin origin = type.getDeclaredAnnotation(Decree.class).origin();
if (!origin.validFor(sender)) {
sender.sendMessage(C.RED + "This command has to be sent from another origin: " + C.GOLD + origin);
return false;
}
Iris.debug("@ " + getPath() + " with " + args.toString(", "));
if (isNode()) {
Iris.debug("Invoke " + getPath() + "(" + args.toString(",") + ") at ");

View File

@@ -0,0 +1,42 @@
package com.volmit.iris.util.reflect;
import com.volmit.iris.Iris;
import java.lang.reflect.Field;
public class WrappedField<C, T> {
private final Field field;
public WrappedField(Class<C> origin, String methodName) {
Field f = null;
try {
f = origin.getDeclaredField(methodName);
f.setAccessible(true);
} catch (NoSuchFieldException e) {
Iris.error("Failed to created WrappedField %s#%s: %s%s", origin.getSimpleName(), methodName, e.getClass().getSimpleName(), e.getMessage().equals("") ? "" : " | " + e.getMessage());
}
this.field = f;
}
public T get() {
return get(null);
}
public T get(C instance) {
if (field == null) {
return null;
}
try {
return (T) field.get(instance);
} catch (IllegalAccessException e) {
Iris.error("Failed to get WrappedField %s#%s: %s%s", field.getDeclaringClass().getSimpleName(), field.getName(), e.getClass().getSimpleName(), e.getMessage().equals("") ? "" : " | " + e.getMessage());
return null;
}
}
public boolean hasFailed() {
return field == null;
}
}

View File

@@ -0,0 +1,39 @@
package com.volmit.iris.util.reflect;
import com.volmit.iris.Iris;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public final class WrappedReturningMethod<C, R> {
private final Method method;
public WrappedReturningMethod(Class<C> origin, String methodName, Class<?>... paramTypes) {
Method m = null;
try {
m = origin.getDeclaredMethod(methodName, paramTypes);
m.setAccessible(true);
} catch (NoSuchMethodException e) {
Iris.error("Failed to created WrappedMethod %s#%s: %s%s", origin.getSimpleName(), methodName, e.getClass().getSimpleName(), e.getMessage().equals("") ? "" : " | " + e.getMessage());
}
this.method = m;
}
public R invoke(Object... args) {
return invoke(null, args);
}
public R invoke(C instance, Object... args) {
if (method == null) {
return null;
}
try {
return (R) method.invoke(instance, args);
} catch (InvocationTargetException | IllegalAccessException e) {
Iris.error("Failed to invoke WrappedMethod %s#%s: %s%s", method.getDeclaringClass().getSimpleName(), method.getName(), e.getClass().getSimpleName(), e.getMessage().equals("") ? "" : " | " + e.getMessage());
return null;
}
}
}

View File

@@ -1,289 +1,289 @@
package com.volmit.iris.util.uniques;
import com.volmit.iris.engine.object.NoiseStyle;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.function.NoiseProvider;
import com.volmit.iris.util.interpolation.InterpolationMethod;
import com.volmit.iris.util.interpolation.IrisInterpolation;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.stream.ProceduralStream;
import com.volmit.iris.util.uniques.features.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
public class UniqueRenderer {
static final List<UFeature> backgrounds = List.of(new UFWarpedBackground());
static final List<UFeature> interpolators = List.of(new UFInterpolator(), new UFNOOP());
static final List<UFeature> features = List.of(new UFWarpedLines(), new UFWarpedDisc(), new UFWarpedDots(), new UFWarpedCircle());
static UniqueRenderer renderer;
private final String seed;
private final ProceduralStream<RNG> spatialSeed;
private final int width;
private final int height;
private final KMap<String, String> writing = new KMap<>();
private final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
int cores = Runtime.getRuntime().availableProcessors();
private final KList<NoiseStyle> sortedStyles = new KList<NoiseStyle>();
private final KList<InterpolationMethod> sortedInterpolators = new KList<InterpolationMethod>();
public UniqueRenderer(String seed, int width, int height) {
renderer = this;
computeNoiseStyles(3000, 2);
computeInterpolationMethods(3000, 2);
this.seed = seed;
this.width = width;
this.height = height;
spatialSeed = NoiseStyle.FRACTAL_WATER.stream(new RNG(seed)).convert((d) -> new RNG(Math.round(seed.hashCode() + (d * 934321234D))));
new Thread(() -> {
while (true) {
J.sleep(5000);
if (!writing.isEmpty()) {
System.out.println(Form.repeat("\n", 60));
System.out.println(Form.memSize(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(), 2) + " of " + Form.memSize(Runtime.getRuntime().totalMemory(), 2));
KMap<String, String> c = writing.copy();
for (String i : writing.k().sort()) {
String prog = "";
String f = writing.get(i);
if (f.contains("%")) {
String v = f.split("\\Q%\\E")[0];
try {
prog = drawProgress(Double.valueOf(Integer.parseInt(v.substring(v.length() - 2))) / 100D, 30);
} catch (Throwable e) {
try {
prog = drawProgress(Double.valueOf(Integer.parseInt(v.substring(v.length() - 1))) / 100D, 30);
} catch (Throwable ee) {
try {
prog = drawProgress(Double.valueOf(Integer.parseInt(v.substring(v.length() - 3))) / 100D, 30);
} catch (Throwable eee) {
}
}
}
}
System.out.println(prog + " " + i + " => " + f);
}
}
}
}).start();
}
public UMeta renderFrameBuffer(long id, double t) {
UMeta meta = new UMeta();
meta.setId(id);
meta.setTime(t);
RNG rng = spatialSeed.get(id, id + ((id * id) % (id / 3D)));
RNG rngbg = spatialSeed.get(id, -id + ((id * id) % (id / 4D)));
BufferedImage buf = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
BufferedImage bufFG = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
UImage image = new UBufferedImage(buf);
UImage imageFG = new UBufferedImage(bufFG);
ChronoLatch cl = new ChronoLatch(250);
UFeature background = rng.pick(backgrounds);
UFeature interpolator = rng.pick(interpolators);
UFeature foreground = rng.pick(features);
UFeature foregroundInterpolator = rng.pick(interpolators);
UFeatureMeta backgroundMeta = new UFeatureMeta();
UFeatureMeta foregroundMeta = new UFeatureMeta();
UFeatureMeta backgroundInterpolatorMeta = new UFeatureMeta();
UFeatureMeta foregroundInterpolatorMeta = new UFeatureMeta();
background.render(image, rngbg, t, (p) -> {
if (cl.flip()) {
writing.put("#" + id + ":" + t, Form.pc(p / 4D) + " [" + background.getClass().getSimpleName() + " " + Form.pc(p) + "]");
}
}, backgroundMeta);
backgroundMeta.setFeature(background.getClass().getSimpleName());
meta.registerFeature("background", backgroundMeta);
interpolator.render(image, rng, t, (p) -> {
if (cl.flip()) {
writing.put("#" + id + ":" + t, Form.pc(0.25 + (p / 4d)) + " [" + interpolator.getClass().getSimpleName() + " " + Form.pc(p) + "]");
}
}, backgroundInterpolatorMeta);
backgroundInterpolatorMeta.setFeature(interpolator.getClass().getSimpleName());
meta.registerFeature("backgroundInterpolator", backgroundInterpolatorMeta);
foreground.render(imageFG, rng, t, (p) -> {
if (cl.flip()) {
writing.put("#" + id + ":" + t, Form.pc(0.5 + (p / 4d)) + " [" + foreground.getClass().getSimpleName() + " " + Form.pc(p) + "]");
}
}, foregroundMeta);
foregroundMeta.setFeature(foreground.getClass().getSimpleName());
meta.registerFeature("foreground", foregroundMeta);
overlay(imageFG, bufFG, image);
foregroundInterpolator.render(image, rng, t, (p) -> {
if (cl.flip()) {
writing.put("#" + id + ":" + t, Form.pc(0.75 + (p / 4d)) + " [" + interpolator.getClass().getSimpleName() + " " + Form.pc(p) + "]");
}
}, foregroundInterpolatorMeta);
foregroundInterpolatorMeta.setFeature(foregroundInterpolator.getClass().getSimpleName());
meta.registerFeature("foregroundInterpolator", foregroundInterpolatorMeta);
overlay(imageFG, bufFG, image);
meta.setImage(buf);
writing.remove("#" + id + ":" + t);
return meta;
}
private void overlay(UImage layer, BufferedImage layerBuf, UImage onto) {
for (int i = 0; i < onto.getWidth(); i++) {
for (int j = 0; j < onto.getHeight(); j++) {
if (layerBuf.getRGB(i, j) != 0) {
onto.set(i, j, layer.get(i, j));
}
}
}
}
private String drawProgress(double progress, int len) {
int max = len;
int in = (int) Math.round(progress * max);
max -= in;
return "[" + Form.repeat("=", in) + Form.repeat(" ", max) + "]";
}
private void computeNoiseStyles(double time, double scope) {
List<NoiseStyle> allowedStyles = new KList<>(NoiseStyle.values());
allowedStyles.remove(NoiseStyle.FLAT);
KMap<NoiseStyle, Integer> speeds = new KMap<>();
double allocateMS = time;
double maxTestDuration = allocateMS / allowedStyles.size();
System.out.println("Running Noise Style Benchmark for " + Form.duration(allocateMS, 0) + ".");
System.out.println("Benchmarking " + allowedStyles.size() + " + Noise Styles for " + Form.duration(maxTestDuration, 1) + " each.");
System.out.println();
for (NoiseStyle i : allowedStyles) {
int score = 0;
CNG cng = i.create(new RNG("renderspeedtest"));
PrecisionStopwatch p = PrecisionStopwatch.start();
double g = 0;
while (p.getMilliseconds() < maxTestDuration) {
cng.noise(g, -g * 2);
g += 0.1;
g *= 1.25;
score++;
}
speeds.put(i, score);
}
for (NoiseStyle i : speeds.sortKNumber()) {
System.out.println(Form.capitalizeWords(i.name().toLowerCase(Locale.ROOT).replaceAll("\\Q_\\E", " ")) + " => " + Form.f(speeds.get(i)));
}
System.out.println();
int takeUpTo = (int) Math.max(1, scope * speeds.size());
System.out.println("Choosing the fastest " + Form.pc(scope) + " styles (" + takeUpTo + ")");
for (NoiseStyle i : speeds.sortKNumber().reverse()) {
if (takeUpTo-- <= 0) {
break;
}
sortedStyles.add(i);
System.out.println("- " + Form.capitalizeWords(i.name().toLowerCase(Locale.ROOT).replaceAll("\\Q_\\E", " ")));
}
}
private void computeInterpolationMethods(double time, double scope) {
List<InterpolationMethod> allowedStyles = new KList<>(InterpolationMethod.values());
allowedStyles.remove(InterpolationMethod.NONE);
KMap<InterpolationMethod, Integer> speeds = new KMap<>();
double allocateMS = time;
double maxTestDuration = allocateMS / allowedStyles.size();
System.out.println("Running Interpolation Method Benchmark for " + Form.duration(allocateMS, 0) + ".");
System.out.println("Benchmarking " + allowedStyles.size() + " + Interpolation Methods for " + Form.duration(maxTestDuration, 1) + " each.");
System.out.println();
RNG r = new RNG("renderspeedtestinterpolation");
CNG cng = NoiseStyle.SIMPLEX.create(r);
NoiseProvider np = (x, z) -> cng.noise(x, z);
for (InterpolationMethod i : allowedStyles) {
int score = 0;
PrecisionStopwatch p = PrecisionStopwatch.start();
double g = 0;
while (p.getMilliseconds() < maxTestDuration) {
IrisInterpolation.getNoise(i, (int) g, (int) (-g * 2.225), r.d(4, 64), np);
cng.noise(g, -g * 2);
g += 1.1;
g *= 1.25;
score++;
}
speeds.put(i, score);
}
for (InterpolationMethod i : speeds.sortKNumber()) {
System.out.println(Form.capitalizeWords(i.name().toLowerCase(Locale.ROOT).replaceAll("\\Q_\\E", " ")) + " => " + Form.f(speeds.get(i)));
}
System.out.println();
int takeUpTo = (int) Math.max(1, scope * speeds.size());
System.out.println("Choosing the fastest " + Form.pc(scope) + " interpolators (" + takeUpTo + ")");
for (InterpolationMethod i : speeds.sortKNumber().reverse()) {
if (takeUpTo-- <= 0) {
break;
}
sortedInterpolators.add(i);
System.out.println("- " + Form.capitalizeWords(i.name().toLowerCase(Locale.ROOT).replaceAll("\\Q_\\E", " ")));
}
}
public void writeCollectionFrames(File folder, int fromId, int toId) {
folder.mkdirs();
BurstExecutor burst = new BurstExecutor(executor, Math.min(toId - fromId, 1000));
burst.setMulticore(true);
AtomicInteger ai = new AtomicInteger(0);
int max = toId - fromId;
for (int i = fromId; i <= toId; i++) {
int ii = i;
burst.queue(() -> {
writing.put("!#[" + fromId + "-" + toId + "] Collection", ai.get() + " of " + max + " (" + Form.pc(ai.get() / (double) max, 0) + ")");
writeFrame(new File(folder, ii + ".png"), ii, 0);
ai.incrementAndGet();
writing.put("!#[" + fromId + "-" + toId + "] Collection", ai.get() + " of " + max + " (" + Form.pc(ai.get() / (double) max, 0) + ")");
});
}
burst.complete();
writing.remove("!#[" + fromId + "-" + toId + "] Collection");
}
public void writeFrame(File destination, long id, double t) {
try {
renderFrameBuffer(id, t).export(destination);
} catch (Throwable e) {
e.printStackTrace();
}
}
public void report(String s) {
System.out.println(s);
}
public KList<NoiseStyle> getStyles() {
return sortedStyles;
}
public List<InterpolationMethod> getInterpolators() {
return sortedInterpolators;
}
}
package com.volmit.iris.util.uniques;
import com.volmit.iris.engine.object.NoiseStyle;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.function.NoiseProvider;
import com.volmit.iris.util.interpolation.InterpolationMethod;
import com.volmit.iris.util.interpolation.IrisInterpolation;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.stream.ProceduralStream;
import com.volmit.iris.util.uniques.features.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
public class UniqueRenderer {
static final List<UFeature> backgrounds = List.of(new UFWarpedBackground());
static final List<UFeature> interpolators = List.of(new UFInterpolator(), new UFNOOP());
static final List<UFeature> features = List.of(new UFWarpedLines(), new UFWarpedDisc(), new UFWarpedDots(), new UFWarpedCircle());
static UniqueRenderer renderer;
private final String seed;
private final ProceduralStream<RNG> spatialSeed;
private final int width;
private final int height;
private final KMap<String, String> writing = new KMap<>();
private final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
private final KList<NoiseStyle> sortedStyles = new KList<NoiseStyle>();
private final KList<InterpolationMethod> sortedInterpolators = new KList<InterpolationMethod>();
int cores = Runtime.getRuntime().availableProcessors();
public UniqueRenderer(String seed, int width, int height) {
renderer = this;
computeNoiseStyles(3000, 2);
computeInterpolationMethods(3000, 2);
this.seed = seed;
this.width = width;
this.height = height;
spatialSeed = NoiseStyle.FRACTAL_WATER.stream(new RNG(seed)).convert((d) -> new RNG(Math.round(seed.hashCode() + (d * 934321234D))));
new Thread(() -> {
while (true) {
J.sleep(5000);
if (!writing.isEmpty()) {
System.out.println(Form.repeat("\n", 60));
System.out.println(Form.memSize(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(), 2) + " of " + Form.memSize(Runtime.getRuntime().totalMemory(), 2));
KMap<String, String> c = writing.copy();
for (String i : writing.k().sort()) {
String prog = "";
String f = writing.get(i);
if (f.contains("%")) {
String v = f.split("\\Q%\\E")[0];
try {
prog = drawProgress(Double.valueOf(Integer.parseInt(v.substring(v.length() - 2))) / 100D, 30);
} catch (Throwable e) {
try {
prog = drawProgress(Double.valueOf(Integer.parseInt(v.substring(v.length() - 1))) / 100D, 30);
} catch (Throwable ee) {
try {
prog = drawProgress(Double.valueOf(Integer.parseInt(v.substring(v.length() - 3))) / 100D, 30);
} catch (Throwable eee) {
}
}
}
}
System.out.println(prog + " " + i + " => " + f);
}
}
}
}).start();
}
public UMeta renderFrameBuffer(long id, double t) {
UMeta meta = new UMeta();
meta.setId(id);
meta.setTime(t);
RNG rng = spatialSeed.get(id, id + ((id * id) % (id / 3D)));
RNG rngbg = spatialSeed.get(id, -id + ((id * id) % (id / 4D)));
BufferedImage buf = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
BufferedImage bufFG = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
UImage image = new UBufferedImage(buf);
UImage imageFG = new UBufferedImage(bufFG);
ChronoLatch cl = new ChronoLatch(250);
UFeature background = rng.pick(backgrounds);
UFeature interpolator = rng.pick(interpolators);
UFeature foreground = rng.pick(features);
UFeature foregroundInterpolator = rng.pick(interpolators);
UFeatureMeta backgroundMeta = new UFeatureMeta();
UFeatureMeta foregroundMeta = new UFeatureMeta();
UFeatureMeta backgroundInterpolatorMeta = new UFeatureMeta();
UFeatureMeta foregroundInterpolatorMeta = new UFeatureMeta();
background.render(image, rngbg, t, (p) -> {
if (cl.flip()) {
writing.put("#" + id + ":" + t, Form.pc(p / 4D) + " [" + background.getClass().getSimpleName() + " " + Form.pc(p) + "]");
}
}, backgroundMeta);
backgroundMeta.setFeature(background.getClass().getSimpleName());
meta.registerFeature("background", backgroundMeta);
interpolator.render(image, rng, t, (p) -> {
if (cl.flip()) {
writing.put("#" + id + ":" + t, Form.pc(0.25 + (p / 4d)) + " [" + interpolator.getClass().getSimpleName() + " " + Form.pc(p) + "]");
}
}, backgroundInterpolatorMeta);
backgroundInterpolatorMeta.setFeature(interpolator.getClass().getSimpleName());
meta.registerFeature("backgroundInterpolator", backgroundInterpolatorMeta);
foreground.render(imageFG, rng, t, (p) -> {
if (cl.flip()) {
writing.put("#" + id + ":" + t, Form.pc(0.5 + (p / 4d)) + " [" + foreground.getClass().getSimpleName() + " " + Form.pc(p) + "]");
}
}, foregroundMeta);
foregroundMeta.setFeature(foreground.getClass().getSimpleName());
meta.registerFeature("foreground", foregroundMeta);
overlay(imageFG, bufFG, image);
foregroundInterpolator.render(image, rng, t, (p) -> {
if (cl.flip()) {
writing.put("#" + id + ":" + t, Form.pc(0.75 + (p / 4d)) + " [" + interpolator.getClass().getSimpleName() + " " + Form.pc(p) + "]");
}
}, foregroundInterpolatorMeta);
foregroundInterpolatorMeta.setFeature(foregroundInterpolator.getClass().getSimpleName());
meta.registerFeature("foregroundInterpolator", foregroundInterpolatorMeta);
overlay(imageFG, bufFG, image);
meta.setImage(buf);
writing.remove("#" + id + ":" + t);
return meta;
}
private void overlay(UImage layer, BufferedImage layerBuf, UImage onto) {
for (int i = 0; i < onto.getWidth(); i++) {
for (int j = 0; j < onto.getHeight(); j++) {
if (layerBuf.getRGB(i, j) != 0) {
onto.set(i, j, layer.get(i, j));
}
}
}
}
private String drawProgress(double progress, int len) {
int max = len;
int in = (int) Math.round(progress * max);
max -= in;
return "[" + Form.repeat("=", in) + Form.repeat(" ", max) + "]";
}
private void computeNoiseStyles(double time, double scope) {
List<NoiseStyle> allowedStyles = new KList<>(NoiseStyle.values());
allowedStyles.remove(NoiseStyle.FLAT);
KMap<NoiseStyle, Integer> speeds = new KMap<>();
double allocateMS = time;
double maxTestDuration = allocateMS / allowedStyles.size();
System.out.println("Running Noise Style Benchmark for " + Form.duration(allocateMS, 0) + ".");
System.out.println("Benchmarking " + allowedStyles.size() + " + Noise Styles for " + Form.duration(maxTestDuration, 1) + " each.");
System.out.println();
for (NoiseStyle i : allowedStyles) {
int score = 0;
CNG cng = i.create(new RNG("renderspeedtest"));
PrecisionStopwatch p = PrecisionStopwatch.start();
double g = 0;
while (p.getMilliseconds() < maxTestDuration) {
cng.noise(g, -g * 2);
g += 0.1;
g *= 1.25;
score++;
}
speeds.put(i, score);
}
for (NoiseStyle i : speeds.sortKNumber()) {
System.out.println(Form.capitalizeWords(i.name().toLowerCase(Locale.ROOT).replaceAll("\\Q_\\E", " ")) + " => " + Form.f(speeds.get(i)));
}
System.out.println();
int takeUpTo = (int) Math.max(1, scope * speeds.size());
System.out.println("Choosing the fastest " + Form.pc(scope) + " styles (" + takeUpTo + ")");
for (NoiseStyle i : speeds.sortKNumber().reverse()) {
if (takeUpTo-- <= 0) {
break;
}
sortedStyles.add(i);
System.out.println("- " + Form.capitalizeWords(i.name().toLowerCase(Locale.ROOT).replaceAll("\\Q_\\E", " ")));
}
}
private void computeInterpolationMethods(double time, double scope) {
List<InterpolationMethod> allowedStyles = new KList<>(InterpolationMethod.values());
allowedStyles.remove(InterpolationMethod.NONE);
KMap<InterpolationMethod, Integer> speeds = new KMap<>();
double allocateMS = time;
double maxTestDuration = allocateMS / allowedStyles.size();
System.out.println("Running Interpolation Method Benchmark for " + Form.duration(allocateMS, 0) + ".");
System.out.println("Benchmarking " + allowedStyles.size() + " + Interpolation Methods for " + Form.duration(maxTestDuration, 1) + " each.");
System.out.println();
RNG r = new RNG("renderspeedtestinterpolation");
CNG cng = NoiseStyle.SIMPLEX.create(r);
NoiseProvider np = (x, z) -> cng.noise(x, z);
for (InterpolationMethod i : allowedStyles) {
int score = 0;
PrecisionStopwatch p = PrecisionStopwatch.start();
double g = 0;
while (p.getMilliseconds() < maxTestDuration) {
IrisInterpolation.getNoise(i, (int) g, (int) (-g * 2.225), r.d(4, 64), np);
cng.noise(g, -g * 2);
g += 1.1;
g *= 1.25;
score++;
}
speeds.put(i, score);
}
for (InterpolationMethod i : speeds.sortKNumber()) {
System.out.println(Form.capitalizeWords(i.name().toLowerCase(Locale.ROOT).replaceAll("\\Q_\\E", " ")) + " => " + Form.f(speeds.get(i)));
}
System.out.println();
int takeUpTo = (int) Math.max(1, scope * speeds.size());
System.out.println("Choosing the fastest " + Form.pc(scope) + " interpolators (" + takeUpTo + ")");
for (InterpolationMethod i : speeds.sortKNumber().reverse()) {
if (takeUpTo-- <= 0) {
break;
}
sortedInterpolators.add(i);
System.out.println("- " + Form.capitalizeWords(i.name().toLowerCase(Locale.ROOT).replaceAll("\\Q_\\E", " ")));
}
}
public void writeCollectionFrames(File folder, int fromId, int toId) {
folder.mkdirs();
BurstExecutor burst = new BurstExecutor(executor, Math.min(toId - fromId, 1000));
burst.setMulticore(true);
AtomicInteger ai = new AtomicInteger(0);
int max = toId - fromId;
for (int i = fromId; i <= toId; i++) {
int ii = i;
burst.queue(() -> {
writing.put("!#[" + fromId + "-" + toId + "] Collection", ai.get() + " of " + max + " (" + Form.pc(ai.get() / (double) max, 0) + ")");
writeFrame(new File(folder, ii + ".png"), ii, 0);
ai.incrementAndGet();
writing.put("!#[" + fromId + "-" + toId + "] Collection", ai.get() + " of " + max + " (" + Form.pc(ai.get() / (double) max, 0) + ")");
});
}
burst.complete();
writing.remove("!#[" + fromId + "-" + toId + "] Collection");
}
public void writeFrame(File destination, long id, double t) {
try {
renderFrameBuffer(id, t).export(destination);
} catch (Throwable e) {
e.printStackTrace();
}
}
public void report(String s) {
System.out.println(s);
}
public KList<NoiseStyle> getStyles() {
return sortedStyles;
}
public List<InterpolationMethod> getInterpolators() {
return sortedInterpolators;
}
}

View File

@@ -1,24 +1,24 @@
name: ${name}
version: ${version}
main: ${main}
load: STARTUP
authors: [ cyberpwn, NextdoorPsycho, Vatuu ]
website: volmit.com
description: More than a Dimension!
libraries:
- com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2
- com.github.ben-manes.caffeine:caffeine:3.0.5
- org.apache.commons:commons-lang3:3.12.0
- io.timeandspace:smoothie-map:2.0.2
- com.google.guava:guava:31.0.1-jre
- com.google.code.gson:gson:2.8.9
- org.zeroturnaround:zt-zip:1.14
- it.unimi.dsi:fastutil:8.5.6
- org.ow2.asm:asm:9.2
- rhino:js:1.7R2
- bsf:bsf:2.4.0
commands:
iris:
aliases: [ ir, irs ]
api-version: ${apiversion}
name: ${name}
version: ${version}
main: ${main}
load: STARTUP
authors: [ cyberpwn, NextdoorPsycho, Vatuu ]
website: volmit.com
description: More than a Dimension!
libraries:
- com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2
- com.github.ben-manes.caffeine:caffeine:3.0.5
- org.apache.commons:commons-lang3:3.12.0
- io.timeandspace:smoothie-map:2.0.2
- com.google.guava:guava:31.0.1-jre
- com.google.code.gson:gson:2.8.9
- org.zeroturnaround:zt-zip:1.14
- it.unimi.dsi:fastutil:8.5.6
- org.ow2.asm:asm:9.2
- rhino:js:1.7R2
- bsf:bsf:2.4.0
commands:
iris:
aliases: [ ir, irs ]
api-version: '${apiversion}'
hotload-dependencies: false