Compare commits

...

91 Commits

Author SHA1 Message Date
Julian Krings eff598d005 update headless dev command 2025-04-02 16:42:39 +02:00
Julian Krings d86ec7b1cd Merge remote-tracking branch 'origin/dev' into feat/headless
# Conflicts:
#	core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java
#	core/src/main/java/com/volmit/iris/core/commands/CommandIris.java
#	core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java
#	core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java
#	nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java
#	nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java
#	nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java
#	nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java
#	nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java
#	nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java
#	nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java
2025-04-02 16:33:51 +02:00
Julian Krings 407e51378c fix applying x offset to z coords in Spiraler 2025-03-27 15:02:47 +01:00
Julian Krings c468eb1ab1 make pregen use block radius as input 2025-03-27 15:02:47 +01:00
Aidan Aeternum bdb7cc61e5 v+ 2025-03-26 15:41:35 -04:00
Aidan Aeternum e8f9e841c4 Merge pull request #1181 from VolmitSoftware/dev
3.6.5
2025-03-26 15:41:06 -04:00
Julian Krings 1b1b9d97b7 update overworld pack to 31020 2025-03-25 19:15:47 +01:00
Julian Krings 24355064ff add safeguard for missing dimension types to prevent world corruption 2025-03-25 19:14:20 +01:00
Julian Krings 06a45056d9 use flat level source instead of trying to get the levelstems 2025-03-22 12:38:25 +01:00
Aidan Aeternum dfe4894be7 v+ 2025-03-18 16:40:33 -04:00
Aidan Aeternum 8eb2287ec0 Merge pull request #1178 from VolmitSoftware/dev
3.6.4
2025-03-18 16:34:22 -04:00
Julian Krings c4f0722614 improve datapack setup speed 2025-03-18 16:18:37 +01:00
Julian Krings 7fa1484b21 fix levelstem injection not working for main worlds 2025-03-18 16:18:37 +01:00
Julian Krings 1c5eb8b910 automatically update vanilla dimension type if present in Iris datapack 2025-03-18 16:18:37 +01:00
Julian Krings 94bf530d93 add setting to enable changing to the vanilla dimension height values 2025-03-18 16:18:37 +01:00
Julian Krings 686ae57b5b switch from world preset to direct level stems 2025-03-18 16:18:37 +01:00
Julian Krings a911685aaf Fix world gen datapack incompatibilities 2025-03-18 16:18:37 +01:00
Julian Krings 0d9a45dfd9 disable headless pregen on world creation for benchmark worlds 2025-03-18 16:12:09 +01:00
Julian Krings 8a55bbfd20 Merge branch 'dev' into feat/headless
# Conflicts:
#	core/src/main/java/com/volmit/iris/core/commands/CommandIris.java
2025-03-07 16:17:23 +01:00
Aidan Aeternum 6899761ca9 v+ 2025-03-06 17:06:34 -05:00
Aidan Aeternum a58958fd62 Merge pull request #1176 from VolmitSoftware/dev
3.6.3
2025-03-06 17:04:57 -05:00
Julian Krings 307f3c9158 implement version specific overworld tag (#1175) 2025-03-06 15:57:30 +01:00
Julian Krings 4f275c2e06 Merge pull request #1174 from tavaresjoshua8/master
Fix: Nexo 1.0
2025-03-06 15:55:54 +01:00
tavaresjoshua8 7e4e3f3cd8 Fix: Nexo 1.0 Release 2025-03-05 13:43:26 -07:00
Aidan Aeternum 84e5add564 v+ 2025-02-23 14:39:52 -05:00
Aidan Aeternum 4d4adbb76f Merge pull request #1172 from VolmitSoftware/dev
3.6.2
2025-02-23 14:39:29 -05:00
Julian Krings ff2f285784 isolate iris world height into it's own dimension types (#1171) 2025-02-20 23:41:19 +01:00
Julian Krings 5934c43b70 Merge branch 'dev' into feat/headless 2025-02-18 17:10:23 +01:00
Julian Krings 11567b13d3 potentially fix chunk position bug 2025-02-18 17:08:08 +01:00
Aidan Aeternum 8b1636e78a v+ 2025-02-14 16:46:51 -05:00
Aidan Aeternum 3bdad10562 Merge pull request #1170 from VolmitSoftware/dev
3.6.1
2025-02-14 16:46:22 -05:00
Julian Krings ac03a977aa Mob spawning fixes (#1169)
* fix cooldown being 0 in most cases

* fix max entity count for spawners
2025-02-11 23:06:47 +01:00
Julian Krings 2087ba88b1 fix adding chunks to region while being saved 2025-02-09 12:33:20 +01:00
Julian Krings e9d1b9f18e prevent Biome.CUSTOM from being resolved on <1.21.3 2025-02-08 21:45:51 +01:00
Julian Krings 6e84d38680 set chunk status to full AFTER generation 2025-02-08 20:59:20 +01:00
Julian Krings 22622f6e8a set chunk status to full on creation 2025-02-08 20:22:18 +01:00
Julian Krings 735203aa95 exclude asm from shadowJar 2025-02-08 12:20:27 +01:00
Julian Krings 013bc365a9 implement headless on all supported versions 2025-02-08 12:07:13 +01:00
Julian Krings c2dfbac641 refactor headless to decrease duplicate code in nms bindings 2025-02-07 21:51:23 +01:00
Julian Krings 7d472c0b13 Merge branch 'dev' into feat/headless
# Conflicts:
#	core/src/main/java/com/volmit/iris/core/commands/CommandIris.java
2025-02-06 23:29:22 +01:00
Aidan Aeternum d7270f66e1 v+ 2025-02-06 16:16:11 -05:00
Aidan Aeternum b220b1bffa Merge pull request #1168 from VolmitSoftware/dev
3.6.0
2025-02-06 16:15:05 -05:00
Julian Krings 4796fe98cb fix modern tile states not applying properly 2025-02-05 15:20:34 +01:00
Julian Krings ece905ec6e fix registry lookup failing on some server versions 2025-02-04 21:11:08 +01:00
Julian Krings 53c9e7c04c drop 1.19.x support (#1167) 2025-02-04 13:04:48 +01:00
Julian Krings 29f6f52443 add noise based spread type (#1164) 2025-02-04 13:04:28 +01:00
Julian Krings a778cc51a6 Expression functions (#1165) 2025-02-04 13:03:49 +01:00
Julian Krings c6963d0cd3 fix world delete command crashing servers (#1166) 2025-02-04 13:03:33 +01:00
Julian Krings 5b4ab0a3c1 add headless pregen dev command 2025-02-04 10:55:39 +01:00
pixel 489844f61b Updated README.md to JDK21 2025-02-03 22:19:38 +01:00
Aidan Aeternum 4d1b0246ca v+ 2025-02-01 10:55:58 -05:00
Aidan Aeternum 13f3511fa8 Merge pull request #1159 from VolmitSoftware/dev
3.5.9
2025-02-01 10:54:00 -05:00
Julian Krings f6f2766315 fix ignoring some custom blocks (#1158) 2025-01-30 13:12:15 +01:00
Aidan Aeternum 56530a1245 v+ 2025-01-29 17:51:36 -05:00
Aidan Aeternum 210a1f29a7 Merge pull request #1156 from VolmitSoftware/dev
3.5.8
2025-01-29 15:51:16 -07:00
Julian Krings e8dd81b014 add headless to world creation 2025-01-29 16:36:04 +01:00
Julian Krings d32cc281e3 fix compile after merge 2025-01-29 14:32:04 +01:00
Julian Krings 2ff6b59271 Merge branch 'dev' into feat/headless 2025-01-29 14:30:17 +01:00
Julian Krings 847bf972ae improve performance related to custom blocks (#1155) 2025-01-27 15:22:10 +01:00
Julian Krings 3ff87566f5 implement headless for 1.21.4 2025-01-26 14:28:59 +01:00
Aidan Aeternum e5d21fdf7e v+ 2025-01-25 09:48:00 -07:00
Aidan Aeternum 0b2fd3b358 v+ 2025-01-25 09:47:17 -07:00
Aidan Aeternum 10484d1226 Merge pull request #1153 from VolmitSoftware/dev
3.5.7
2025-01-25 09:46:58 -07:00
Julian Krings ce0092c52a Fix creation deadlock (#1154) 2025-01-25 14:54:21 +01:00
Julian Krings 474e033c2b Feat/1.21.4 (#1152) 2025-01-24 18:03:12 +01:00
Aidan Aeternum 62aad1f497 v+ 2025-01-23 14:46:15 -07:00
Aidan Aeternum 32b5157682 Update build.gradle 2025-01-23 14:44:53 -07:00
Aidan Aeternum 70717ea282 Merge pull request #1151 from VolmitSoftware/dev
3.5.6
2025-01-23 14:44:24 -07:00
Julian Krings 15975f108c Fix compile 2025-01-22 22:52:21 +01:00
Julian Krings 66c66e82c1 remove "smart" vanilla height (#1150) 2025-01-22 22:47:39 +01:00
Julian Krings 4f6da95d8e fix radius calculation skipping pieces (#1149) 2025-01-22 22:47:28 +01:00
Aidan Aeternum b37ccbdf01 v+ 2025-01-17 08:27:58 -05:00
Aidan Aeternum 30dbe0881a Merge pull request #1145 from VolmitSoftware/dev
3.5.5
2025-01-17 05:26:26 -08:00
Julian Krings 20ad4657a9 fix null pointer preventing the entity schema from generating (#1142) 2025-01-15 11:30:55 +01:00
Julian Krings d4986f42a6 Fix decorator determinism (#1144) 2025-01-15 11:30:34 +01:00
Aidan Aeternum 8df15c0c2d v+ 2025-01-12 14:12:43 -08:00
Aidan Aeternum 24e1c578c8 Merge pull request #1139 from VolmitSoftware/dev
3.5.4
2025-01-12 14:10:50 -08:00
Julian Krings 1c3bff7559 fix sculk veins not properly placing with decorators (#1137) 2025-01-12 15:37:10 +01:00
Julian Krings a09657b4d0 precalculate pack hash on engine setup (#1138) 2025-01-12 15:36:54 +01:00
Aidan Aeternum 910220d3ca v+ 2025-01-08 18:22:26 -08:00
Aidan Aeternum fc05c24e3a Merge pull request #1135 from VolmitSoftware/dev
3.5.3
2025-01-08 18:20:43 -08:00
Julian Krings e1a7e772cf fix floating objects (#1134) 2025-01-07 22:03:53 +01:00
Aidan Aeternum 3c6411c322 v+ 2025-01-07 11:22:52 -08:00
Aidan Aeternum 628761affa Merge pull request #1130 from VolmitSoftware/dev
3.5.2
2025-01-07 11:21:06 -08:00
Julian Krings fa7b0f68ff Merge pull request #1129 from VolmitSoftware/feat/deposits
Feat/deposits
2025-01-05 16:25:03 +01:00
Aidan Aeternum 487d0ac237 Merge pull request #1128 from VolmitSoftware/dev
3.5.1
2025-01-04 09:57:30 -08:00
Julian Krings e79e3fbe45 implement <1 deposit spawn chance 2025-01-04 03:46:08 +01:00
Julian Krings 23a0ab23aa fixes to deposit clump generation and placement 2025-01-04 03:41:55 +01:00
Julian Krings c78ffab948 fix deposit clump calculation 2025-01-03 00:33:49 +01:00
Julian Krings d58f497b71 v+ 2025-01-02 23:21:32 +01:00
Julian Krings 3284ab84c5 fix biome&region deposits being placed ^2 2025-01-02 23:15:27 +01:00
152 changed files with 8725 additions and 4290 deletions
+4 -4
View File
@@ -15,17 +15,17 @@ Consider supporting our development by buying Iris on spigot! We work hard to ma
### Command Line Builds ### Command Line Builds
1. Install [Java JDK 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) 1. Install [Java JDK 21](https://www.oracle.com/java/technologies/javase/jdk21-archive-downloads.html)
2. Set the JDK installation path to `JAVA_HOME` as an environment variable. 2. Set the JDK installation path to `JAVA_HOME` as an environment variable.
* Windows * Windows
1. Start > Type `env` and press Enter 1. Start > Type `env` and press Enter
2. Advanced > Environment Variables 2. Advanced > Environment Variables
3. Under System Variables, click `New...` 3. Under System Variables, click `New...`
4. Variable Name: `JAVA_HOME` 4. Variable Name: `JAVA_HOME`
5. Variable Value: `C:\Program Files\Java\jdk-17.0.1` (verify this exists after installing java don't just copy 5. Variable Value: `C:\Program Files\Java\jdk-21.0.1` (verify this exists after installing java don't just copy
the example text) the example text)
* MacOS * MacOS
1. Run `/usr/libexec/java_home -V` and look for Java 17 1. Run `/usr/libexec/java_home -V` and look for Java 21
2. Run `sudo nano ~/.zshenv` 2. Run `sudo nano ~/.zshenv`
3. Add `export JAVA_HOME=$(/usr/libexec/java_home)` as a new line 3. Add `export JAVA_HOME=$(/usr/libexec/java_home)` as a new line
4. Use `CTRL + X`, then Press `Y`, Then `ENTER` 4. Use `CTRL + X`, then Press `Y`, Then `ENTER`
@@ -35,7 +35,7 @@ Consider supporting our development by buying Iris on spigot! We work hard to ma
### IDE Builds (for development) ### IDE Builds (for development)
* Configure ITJ Gradle to use JDK 17 (in settings, search for gradle) * Configure ITJ Gradle to use JDK 21 (in settings, search for gradle)
* Add a build line in the build.gradle for your own build task to directly compile Iris into your plugins folder if you * Add a build line in the build.gradle for your own build task to directly compile Iris into your plugins folder if you
prefer. prefer.
* Resync the project & run your newly created task (under the development folder in gradle tasks!) * Resync the project & run your newly created task (under the development folder in gradle tasks!)
+9 -5
View File
@@ -32,7 +32,8 @@ plugins {
id "de.undercouch.download" version "5.0.1" id "de.undercouch.download" version "5.0.1"
} }
version '3.5.0-1.19.2-1.21.3'
version '3.6.5-1.20.1-1.21.4'
// ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED // ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED
// ======================== WINDOWS ============================= // ======================== WINDOWS =============================
@@ -53,15 +54,13 @@ registerCustomOutputTaskUnix('CrazyDev22LT', '/home/julian/Desktop/server/plugin
// ============================================================== // ==============================================================
def NMS_BINDINGS = Map.of( def NMS_BINDINGS = Map.of(
"v1_21_R3", "1.21.4-R0.1-SNAPSHOT",
"v1_21_R2", "1.21.3-R0.1-SNAPSHOT", "v1_21_R2", "1.21.3-R0.1-SNAPSHOT",
"v1_21_R1", "1.21.1-R0.1-SNAPSHOT", "v1_21_R1", "1.21.1-R0.1-SNAPSHOT",
"v1_20_R4", "1.20.6-R0.1-SNAPSHOT", "v1_20_R4", "1.20.6-R0.1-SNAPSHOT",
"v1_20_R3", "1.20.4-R0.1-SNAPSHOT", "v1_20_R3", "1.20.4-R0.1-SNAPSHOT",
"v1_20_R2", "1.20.2-R0.1-SNAPSHOT", "v1_20_R2", "1.20.2-R0.1-SNAPSHOT",
"v1_20_R1", "1.20.1-R0.1-SNAPSHOT", "v1_20_R1", "1.20.1-R0.1-SNAPSHOT",
"v1_19_R3", "1.19.4-R0.1-SNAPSHOT",
"v1_19_R2", "1.19.3-R0.1-SNAPSHOT",
"v1_19_R1", "1.19.2-R0.1-SNAPSHOT"
) )
def JVM_VERSION = Map.of() def JVM_VERSION = Map.of()
NMS_BINDINGS.each { nms -> NMS_BINDINGS.each { nms ->
@@ -93,6 +92,11 @@ shadowJar {
relocate 'net.kyori', 'com.volmit.iris.util.kyori' relocate 'net.kyori', 'com.volmit.iris.util.kyori'
relocate 'org.bstats', 'com.volmit.util.metrics' relocate 'org.bstats', 'com.volmit.util.metrics'
archiveFileName.set("Iris-${project.version}.jar") archiveFileName.set("Iris-${project.version}.jar")
dependencies {
exclude(dependency("org.ow2.asm:asm:"))
exclude(dependency("org.jetbrains:"))
}
} }
dependencies { dependencies {
@@ -129,7 +133,7 @@ allprojects {
annotationProcessor 'org.projectlombok:lombok:1.18.36' annotationProcessor 'org.projectlombok:lombok:1.18.36'
// Shaded // Shaded
implementation 'com.dfsek:Paralithic:0.4.0' implementation 'com.dfsek:paralithic:0.8.1'
implementation 'io.papermc:paperlib:1.0.5' implementation 'io.papermc:paperlib:1.0.5'
implementation "net.kyori:adventure-text-minimessage:4.17.0" implementation "net.kyori:adventure-text-minimessage:4.17.0"
implementation 'net.kyori:adventure-platform-bukkit:4.3.4' implementation 'net.kyori:adventure-platform-bukkit:4.3.4'
+1 -1
View File
@@ -62,7 +62,7 @@ dependencies {
// Third Party Integrations // Third Party Integrations
compileOnly 'com.ticxo.playeranimator:PlayerAnimator:R1.2.7' compileOnly 'com.ticxo.playeranimator:PlayerAnimator:R1.2.7'
compileOnly 'com.nexomc:nexo:0.6.0-dev.0' compileOnly 'com.nexomc:nexo:1.0.0-dev.38'
compileOnly 'com.github.LoneDev6:api-itemsadder:3.4.1-r4' compileOnly 'com.github.LoneDev6:api-itemsadder:3.4.1-r4'
compileOnly 'com.github.PlaceholderAPI:placeholderapi:2.11.3' compileOnly 'com.github.PlaceholderAPI:placeholderapi:2.11.3'
compileOnly 'com.github.Ssomar-Developement:SCore:4.23.10.8' compileOnly 'com.github.Ssomar-Developement:SCore:4.23.10.8'
+16 -11
View File
@@ -32,8 +32,10 @@ import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import com.volmit.iris.core.pregenerator.LazyPregenerator; import com.volmit.iris.core.pregenerator.LazyPregenerator;
import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.core.tools.IrisWorldCreator;
import com.volmit.iris.engine.EnginePanic; import com.volmit.iris.engine.EnginePanic;
import com.volmit.iris.engine.object.IrisCompat; import com.volmit.iris.engine.object.IrisCompat;
import com.volmit.iris.engine.object.IrisContextInjector;
import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisWorld; import com.volmit.iris.engine.object.IrisWorld;
import com.volmit.iris.engine.platform.BukkitChunkGenerator; import com.volmit.iris.engine.platform.BukkitChunkGenerator;
@@ -101,8 +103,6 @@ import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware;
@SuppressWarnings("CanBeFinal") @SuppressWarnings("CanBeFinal")
public class Iris extends VolmitPlugin implements Listener { public class Iris extends VolmitPlugin implements Listener {
public static final String OVERWORLD_TAG = "31000";
private static final Queue<Runnable> syncJobs = new ShurikenQueue<>(); private static final Queue<Runnable> syncJobs = new ShurikenQueue<>();
public static Iris instance; public static Iris instance;
@@ -459,9 +459,12 @@ public class Iris extends VolmitPlugin implements Listener {
initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class<? extends IrisService>) i.getClass(), (IrisService) i)); initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class<? extends IrisService>) i.getClass(), (IrisService) i));
INMS.get(); INMS.get();
IO.delete(new File("iris")); IO.delete(new File("iris"));
compat = IrisCompat.configured(getDataFile("compat.json"));
ServerConfigurator.configure();
new IrisContextInjector();
IrisSafeguard.IrisSafeguardSystem(); IrisSafeguard.IrisSafeguardSystem();
getSender().setTag(getTag()); getSender().setTag(getTag());
compat = IrisCompat.configured(getDataFile("compat.json")); IrisSafeguard.earlySplash();
linkMultiverseCore = new MultiverseCoreLink(); linkMultiverseCore = new MultiverseCoreLink();
linkMythicMobs = new MythicMobsLink(); linkMythicMobs = new MythicMobsLink();
configWatcher = new FileWatcher(getDataFile("settings.json")); configWatcher = new FileWatcher(getDataFile("settings.json"));
@@ -516,10 +519,10 @@ public class Iris extends VolmitPlugin implements Listener {
Iris.info("Loading World: %s | Generator: %s", s, generator); Iris.info("Loading World: %s | Generator: %s", s, generator);
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "..."); Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "...");
new WorldCreator(s) WorldCreator c = new WorldCreator(s)
.generator(getDefaultWorldGenerator(s, generator)) .generator(getDefaultWorldGenerator(s, generator))
.environment(IrisData.loadAnyDimension(generator).getEnvironment()) .environment(IrisData.loadAnyDimension(generator).getEnvironment());
.createWorld(); INMS.get().createWorld(c);
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"); Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
} }
} catch (Throwable e) { } catch (Throwable e) {
@@ -672,10 +675,12 @@ public class Iris extends VolmitPlugin implements Listener {
metrics.addCustomChart(new DrilldownPie("used_packs", () -> Bukkit.getWorlds().stream() metrics.addCustomChart(new DrilldownPie("used_packs", () -> Bukkit.getWorlds().stream()
.map(IrisToolbelt::access) .map(IrisToolbelt::access)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.map(PlatformChunkGenerator::getTarget) .map(PlatformChunkGenerator::getEngine)
.collect(Collectors.toMap(target -> target.getDimension().getLoadKey(), target -> { .collect(Collectors.toMap(engine -> engine.getDimension().getLoadKey(), engine -> {
int version = target.getDimension().getVersion(); var hash32 = engine.getHash32().getNow(null);
String checksum = IO.hashRecursive(target.getData().getDataFolder()); if (hash32 == null) return Map.of();
int version = engine.getDimension().getVersion();
String checksum = Long.toHexString(hash32);
return Map.of("v" + version + " (" + checksum + ")", 1); return Map.of("v" + version + " (" + checksum + ")", 1);
}, (a, b) -> { }, (a, b) -> {
@@ -777,7 +782,7 @@ public class Iris extends VolmitPlugin implements Listener {
service(StudioSVC.class).installIntoWorld(getSender(), dim.getLoadKey(), w.worldFolder()); service(StudioSVC.class).installIntoWorld(getSender(), dim.getLoadKey(), w.worldFolder());
} }
return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey(), false); return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey());
} }
public void splash() { public void splash() {
@@ -181,6 +181,7 @@ public class IrisSettings {
public boolean splashLogoStartup = true; public boolean splashLogoStartup = true;
public boolean useConsoleCustomColors = true; public boolean useConsoleCustomColors = true;
public boolean useCustomColorsIngame = true; public boolean useCustomColorsIngame = true;
public boolean adjustVanillaHeight = false;
public String forceMainWorld = ""; public String forceMainWorld = "";
public int spinh = -20; public int spinh = -20;
public int spins = 7; public int spins = 7;
@@ -28,20 +28,28 @@ import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisRange; import com.volmit.iris.engine.object.IrisRange;
import com.volmit.iris.util.collection.KList; 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.collection.KSet;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
import com.volmit.iris.util.misc.ServerProperties;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
import lombok.Data;
import lombok.NonNull;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.Arrays;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import static com.volmit.iris.core.nms.datapack.IDataFixer.Dimension.*;
public class ServerConfigurator { public class ServerConfigurator {
public static void configure() { public static void configure() {
@@ -84,12 +92,13 @@ public class ServerConfigurator {
} }
} }
private static List<File> getDatapacksFolder() { private static KList<File> getDatapacksFolder() {
if (!IrisSettings.get().getGeneral().forceMainWorld.isEmpty()) { if (!IrisSettings.get().getGeneral().forceMainWorld.isEmpty()) {
return new KList<File>().qadd(new File(Bukkit.getWorldContainer(), IrisSettings.get().getGeneral().forceMainWorld + "/datapacks")); return new KList<File>().qadd(new File(Bukkit.getWorldContainer(), IrisSettings.get().getGeneral().forceMainWorld + "/datapacks"));
} }
KList<File> worlds = new KList<>(); KList<File> worlds = new KList<>();
Bukkit.getServer().getWorlds().forEach(w -> worlds.add(new File(w.getWorldFolder(), "datapacks"))); Bukkit.getServer().getWorlds().forEach(w -> worlds.add(new File(w.getWorldFolder(), "datapacks")));
if (worlds.isEmpty()) worlds.add(new File(Bukkit.getWorldContainer(), ServerProperties.LEVEL_NAME + "/datapacks"));
return worlds; return worlds;
} }
@@ -99,57 +108,17 @@ public class ServerConfigurator {
public static void installDataPacks(IDataFixer fixer, boolean fullInstall) { public static void installDataPacks(IDataFixer fixer, boolean fullInstall) {
Iris.info("Checking Data Packs..."); Iris.info("Checking Data Packs...");
File packs = new File("plugins/Iris/packs"); DimensionHeight height = new DimensionHeight(fixer);
double ultimateMaxHeight = 0; KList<File> folders = getDatapacksFolder();
double ultimateMinHeight = 0; KMap<String, KSet<String>> biomes = new KMap<>();
if (packs.exists() && packs.isDirectory()) {
for (File pack : packs.listFiles()) {
IrisData data = IrisData.get(pack);
if (pack.isDirectory()) {
File dimensionsFolder = new File(pack, "dimensions");
if (dimensionsFolder.exists() && dimensionsFolder.isDirectory()) {
for (File file : dimensionsFolder.listFiles()) {
if (file.isFile() && file.getName().endsWith(".json")) {
IrisDimension dim = data.getDimensionLoader().load(file.getName().split("\\Q.\\E")[0]);
if (ultimateMaxHeight < dim.getDimensionHeight().getMax()) {
ultimateMaxHeight = dim.getDimensionHeight().getMax();
}
if (ultimateMinHeight > dim.getDimensionHeight().getMin()) {
ultimateMinHeight = dim.getDimensionHeight().getMin();
}
}
}
}
}
}
}
if (packs.exists()) { allPacks().flatMap(height::merge)
for (File i : packs.listFiles()) { .parallel()
if (i.isDirectory()) { .forEach(dim -> {
Iris.verbose("Checking Pack: " + i.getPath()); Iris.verbose(" Checking Dimension " + dim.getLoadFile().getPath());
IrisData data = IrisData.get(i); dim.installBiomes(fixer, dim::getLoader, folders, biomes.computeIfAbsent(dim.getLoadKey(), k -> new KSet<>()));
File dims = new File(i, "dimensions"); });
IrisDimension.writeShared(folders, height);
if (dims.exists()) {
for (File j : dims.listFiles()) {
if (j.getName().endsWith(".json")) {
IrisDimension dim = data.getDimensionLoader().load(j.getName().split("\\Q.\\E")[0]);
if (dim == null) {
continue;
}
Iris.verbose(" Checking Dimension " + dim.getLoadFile().getPath());
for (File dpack : getDatapacksFolder()) {
dim.installDataPack(fixer, () -> data, dpack, ultimateMaxHeight, ultimateMinHeight);
}
}
}
}
}
}
}
Iris.info("Data Packs Setup!"); Iris.info("Data Packs Setup!");
@@ -158,57 +127,40 @@ public class ServerConfigurator {
} }
private static void verifyDataPacksPost(boolean allowRestarting) { private static void verifyDataPacksPost(boolean allowRestarting) {
File packs = new File("plugins/Iris/packs"); boolean bad = allPacks()
.map(data -> {
Iris.verbose("Checking Pack: " + data.getDataFolder().getPath());
var loader = data.getDimensionLoader();
return loader.loadAll(loader.getPossibleKeys())
.stream()
.map(ServerConfigurator::verifyDataPackInstalled)
.toList()
.contains(false);
})
.toList()
.contains(true);
if (!bad) return;
boolean bad = false;
if (packs.exists()) {
for (File i : packs.listFiles()) {
if (i.isDirectory()) {
Iris.verbose("Checking Pack: " + i.getPath());
IrisData data = IrisData.get(i);
File dims = new File(i, "dimensions");
if (dims.exists()) { if (allowRestarting) {
for (File j : dims.listFiles()) { restart();
if (j.getName().endsWith(".json")) { } else if (INMS.get().supportsDataPacks()) {
IrisDimension dim = data.getDimensionLoader().load(j.getName().split("\\Q.\\E")[0]); Iris.error("============================================================================");
Iris.error(C.ITALIC + "You need to restart your server to properly generate custom biomes.");
Iris.error(C.ITALIC + "By continuing, Iris will use backup biomes in place of the custom biomes.");
Iris.error("----------------------------------------------------------------------------");
Iris.error(C.UNDERLINE + "IT IS HIGHLY RECOMMENDED YOU RESTART THE SERVER BEFORE GENERATING!");
Iris.error("============================================================================");
if (dim == null) { for (Player i : Bukkit.getOnlinePlayers()) {
Iris.error("Failed to load " + j.getPath() + " "); if (i.isOp() || i.hasPermission("iris.all")) {
continue; VolmitSender sender = new VolmitSender(i, Iris.instance.getTag("WARNING"));
} sender.sendMessage("There are some Iris Packs that have custom biomes in them");
sender.sendMessage("You need to restart your server to use these packs.");
if (!verifyDataPackInstalled(dim)) {
bad = true;
}
}
}
}
} }
} }
}
if (bad) { J.sleep(3000);
if (allowRestarting) {
restart();
} else if (INMS.get().supportsDataPacks()) {
Iris.error("============================================================================");
Iris.error(C.ITALIC + "You need to restart your server to properly generate custom biomes.");
Iris.error(C.ITALIC + "By continuing, Iris will use backup biomes in place of the custom biomes.");
Iris.error("----------------------------------------------------------------------------");
Iris.error(C.UNDERLINE + "IT IS HIGHLY RECOMMENDED YOU RESTART THE SERVER BEFORE GENERATING!");
Iris.error("============================================================================");
for (Player i : Bukkit.getOnlinePlayers()) {
if (i.isOp() || i.hasPermission("iris.all")) {
VolmitSender sender = new VolmitSender(i, Iris.instance.getTag("WARNING"));
sender.sendMessage("There are some Iris Packs that have custom biomes in them");
sender.sendMessage("You need to restart your server to use these packs.");
}
}
J.sleep(3000);
}
} }
} }
@@ -218,7 +170,7 @@ public class ServerConfigurator {
Iris.warn("This will only happen when your pack changes (updates/first time setup)"); Iris.warn("This will only happen when your pack changes (updates/first time setup)");
Iris.warn("(You can disable this auto restart in iris settings)"); Iris.warn("(You can disable this auto restart in iris settings)");
J.s(() -> { J.s(() -> {
Iris.warn("Looks like the restart command diddn't work. Stopping the server instead!"); Iris.warn("Looks like the restart command didn't work. Stopping the server instead!");
Bukkit.shutdown(); Bukkit.shutdown();
}, 100); }, 100);
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "restart"); Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "restart");
@@ -226,22 +178,24 @@ public class ServerConfigurator {
} }
public static boolean verifyDataPackInstalled(IrisDimension dimension) { public static boolean verifyDataPackInstalled(IrisDimension dimension) {
IrisData idm = IrisData.get(Iris.instance.getDataFolder("packs", dimension.getLoadKey()));
KSet<String> keys = new KSet<>(); KSet<String> keys = new KSet<>();
boolean warn = false; boolean warn = false;
for (IrisBiome i : dimension.getAllBiomes(() -> idm)) { for (IrisBiome i : dimension.getAllBiomes(dimension::getLoader)) {
if (i.isCustom()) { if (i.isCustom()) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) { for (IrisBiomeCustom j : i.getCustomDerivitives()) {
keys.add(dimension.getLoadKey() + ":" + j.getId()); keys.add(dimension.getLoadKey() + ":" + j.getId());
} }
} }
} }
String key = getWorld(dimension.getLoader());
if (key == null) key = dimension.getLoadKey();
else key += "/" + dimension.getLoadKey();
if (!INMS.get().supportsDataPacks()) { if (!INMS.get().supportsDataPacks()) {
if (!keys.isEmpty()) { if (!keys.isEmpty()) {
Iris.warn("==================================================================================="); Iris.warn("===================================================================================");
Iris.warn("Pack " + dimension.getLoadKey() + " has " + keys.size() + " custom biome(s). "); Iris.warn("Pack " + key + " has " + keys.size() + " custom biome(s). ");
Iris.warn("Your server version does not yet support datapacks for iris."); Iris.warn("Your server version does not yet support datapacks for iris.");
Iris.warn("The world will generate these biomes as backup biomes."); Iris.warn("The world will generate these biomes as backup biomes.");
Iris.warn("===================================================================================="); Iris.warn("====================================================================================");
@@ -260,10 +214,74 @@ public class ServerConfigurator {
} }
if (warn) { if (warn) {
Iris.error("The Pack " + dimension.getLoadKey() + " is INCAPABLE of generating custom biomes"); Iris.error("The Pack " + key + " is INCAPABLE of generating custom biomes");
Iris.error("If not done automatically, restart your server before generating with this pack!"); Iris.error("If not done automatically, restart your server before generating with this pack!");
} }
return !warn; return !warn;
} }
public static Stream<IrisData> allPacks() {
return Stream.concat(listFiles(new File("plugins/Iris/packs")),
listFiles(Bukkit.getWorldContainer()).map(w -> new File(w, "iris/pack")))
.filter(File::isDirectory)
.map(IrisData::get);
}
@Nullable
public static String getWorld(@NonNull IrisData data) {
String worldContainer = Bukkit.getWorldContainer().getAbsolutePath();
if (!worldContainer.endsWith(File.separator)) worldContainer += File.separator;
String path = data.getDataFolder().getAbsolutePath();
if (!path.startsWith(worldContainer)) return null;
int l = path.endsWith(File.separator) ? 11 : 10;
return path.substring(worldContainer.length(), path.length() - l);
}
private static Stream<File> listFiles(File parent) {
var files = parent.listFiles();
return files == null ? Stream.empty() : Arrays.stream(files);
}
@Data
public static class DimensionHeight {
private final IDataFixer fixer;
private IrisRange overworld = new IrisRange();
private IrisRange nether = new IrisRange();
private IrisRange end = new IrisRange();
private int logicalOverworld = 0;
private int logicalNether = 0;
private int logicalEnd = 0;
public Stream<IrisDimension> merge(IrisData data) {
Iris.verbose("Checking Pack: " + data.getDataFolder().getPath());
var loader = data.getDimensionLoader();
return loader.loadAll(loader.getPossibleKeys())
.stream()
.peek(this::merge);
}
public void merge(IrisDimension dimension) {
overworld.merge(dimension.getDimensionHeight());
nether.merge(dimension.getDimensionHeight());
end.merge(dimension.getDimensionHeight());
logicalOverworld = Math.max(logicalOverworld, dimension.getLogicalHeight());
logicalNether = Math.max(logicalNether, dimension.getLogicalHeightNether());
logicalEnd = Math.max(logicalEnd, dimension.getLogicalHeightEnd());
}
public String overworldType() {
return fixer.createDimension(OVERRWORLD, overworld, logicalOverworld).toString(4);
}
public String netherType() {
return fixer.createDimension(NETHER, nether, logicalNether).toString(4);
}
public String endType() {
return fixer.createDimension(THE_END, end, logicalEnd).toString(4);
}
}
} }
@@ -22,11 +22,14 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.methods.HeadlessPregenMethod;
import com.volmit.iris.core.service.IrisEngineSVC; import com.volmit.iris.core.service.IrisEngineSVC;
import com.volmit.iris.core.tools.IrisPackBenchmarking; import com.volmit.iris.core.tools.IrisPackBenchmarking;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin; import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree; import com.volmit.iris.util.decree.annotations.Decree;
@@ -36,6 +39,7 @@ import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.io.CountingDataInputStream; import com.volmit.iris.util.io.CountingDataInputStream;
import com.volmit.iris.util.io.IO; import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.mantle.TectonicPlate; import com.volmit.iris.util.mantle.TectonicPlate;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.nbt.mca.MCAFile; import com.volmit.iris.util.nbt.mca.MCAFile;
import com.volmit.iris.util.nbt.mca.MCAUtil; import com.volmit.iris.util.nbt.mca.MCAUtil;
import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.parallel.MultiBurst;
@@ -48,6 +52,7 @@ import org.apache.commons.lang.RandomStringUtils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.util.Vector;
import java.io.*; import java.io.*;
import java.net.InetAddress; import java.net.InetAddress;
@@ -140,12 +145,16 @@ public class CommandDeveloper implements DecreeExecutor {
public void packBenchmark( public void packBenchmark(
@Param(description = "The pack to bench", aliases = {"pack"}, defaultValue = "overworld") @Param(description = "The pack to bench", aliases = {"pack"}, defaultValue = "overworld")
IrisDimension dimension, IrisDimension dimension,
@Param(description = "Radius in regions", defaultValue = "5") @Param(description = "Diameter in regions", defaultValue = "2048")
int radius, int diameter,
@Param(description = "Headless", defaultValue = "true")
boolean headless,
@Param(description = "Open GUI while benchmarking", defaultValue = "false") @Param(description = "Open GUI while benchmarking", defaultValue = "false")
boolean gui boolean gui
) { ) {
new IrisPackBenchmarking(dimension, radius, gui); int rb = diameter << 9;
Iris.info("Benchmarking pack " + dimension.getName() + " with diameter: " + rb + "(" + diameter + ")");
new IrisPackBenchmarking(dimension, diameter, headless, gui);
} }
@Decree(description = "Upgrade to another Minecraft version") @Decree(description = "Upgrade to another Minecraft version")
@@ -213,6 +222,42 @@ public class CommandDeveloper implements DecreeExecutor {
sender.sendMessage(C.RED + "Failed to load " + failed.get() + " of " + keys.length + " objects"); sender.sendMessage(C.RED + "Failed to load " + failed.get() + " of " + keys.length + " objects");
} }
@Decree(description = "Pregenerate a world")
public void headless(
@Param(description = "The radius of the pregen in blocks", aliases = "size")
int radius,
@Param(description = "The world to pregen", contextual = true)
World world,
@Param(aliases = "middle", description = "The center location of the pregen. Use \"me\" for your current location", defaultValue = "0,0")
Vector center
) {
try {
var engine = Optional.ofNullable(IrisToolbelt.access(world))
.map(PlatformChunkGenerator::getEngine)
.orElse(null);
if (engine == null) {
sender().sendMessage(C.RED + "The engine access for this world is null!");
sender().sendMessage(C.RED + "Please make sure the world is loaded & the engine is initialized. Generate a new chunk, for example.");
}
radius = Math.max(radius, 1024);
IrisToolbelt.pregenerate(PregenTask
.builder()
.center(new Position2(center.getBlockX(), center.getBlockZ()))
.gui(true)
.radiusX(radius)
.radiusZ(radius)
.build(), new HeadlessPregenMethod(engine), engine);
String msg = C.GREEN + "Headless Pregen started in " + C.GOLD + world.getName() + C.GREEN + " of " + C.GOLD + (radius * 2) + C.GREEN + " by " + C.GOLD + (radius * 2) + C.GREEN + " blocks from " + C.GOLD + center.getX() + "," + center.getZ();
sender().sendMessage(msg);
Iris.info(msg);
} catch (Throwable e) {
sender().sendMessage(C.RED + "Epic fail. See console.");
Iris.reportError(e);
e.printStackTrace();
}
}
@Decree(description = "Test", aliases = {"ip"}) @Decree(description = "Test", aliases = {"ip"})
public void network() { public void network() {
try { try {
File diff suppressed because it is too large Load Diff
@@ -28,6 +28,8 @@ import com.volmit.iris.core.tools.IrisConverter;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.object.*;
import com.volmit.iris.util.data.Cuboid; import com.volmit.iris.util.data.Cuboid;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.data.registry.Materials;
import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin; import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree; import com.volmit.iris.util.decree.annotations.Decree;
@@ -36,12 +38,9 @@ import com.volmit.iris.util.decree.specialhandlers.ObjectHandler;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.Direction; import com.volmit.iris.util.math.Direction;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.misc.E;
import com.volmit.iris.util.scheduling.Queue; import com.volmit.iris.util.scheduling.Queue;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
@@ -54,7 +53,7 @@ import java.util.*;
@Decree(name = "object", aliases = "o", origin = DecreeOrigin.PLAYER, studio = true, description = "Iris object manipulation") @Decree(name = "object", aliases = "o", origin = DecreeOrigin.PLAYER, studio = true, description = "Iris object manipulation")
public class CommandObject implements DecreeExecutor { public class CommandObject implements DecreeExecutor {
private static final Set<Material> skipBlocks = Set.of(E.getOrDefault(Material.class, "GRASS", "SHORT_GRASS"), Material.SNOW, Material.VINE, Material.TORCH, Material.DEAD_BUSH, private static final Set<Material> skipBlocks = Set.of(Materials.GRASS, Material.SNOW, Material.VINE, Material.TORCH, Material.DEAD_BUSH,
Material.POPPY, Material.DANDELION); Material.POPPY, Material.DANDELION);
public static IObjectPlacer createPlacer(World world, Map<Block, BlockData> futureBlockChanges) { public static IObjectPlacer createPlacer(World world, Map<Block, BlockData> futureBlockChanges) {
@@ -79,7 +78,10 @@ public class CommandObject implements DecreeExecutor {
futureBlockChanges.put(block, block.getBlockData()); futureBlockChanges.put(block, block.getBlockData());
block.setBlockData(d); if (d instanceof IrisCustomData data) {
block.setBlockData(data.getBase());
Iris.warn("Tried to place custom block at " + x + ", " + y + ", " + z + " which is not supported!");
} else block.setBlockData(d);
} }
@Override @Override
@@ -19,9 +19,7 @@
package com.volmit.iris.core.commands; package com.volmit.iris.core.commands;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.gui.PregeneratorJob; import com.volmit.iris.core.gui.PregeneratorJob;
import com.volmit.iris.core.pregenerator.LazyPregenerator;
import com.volmit.iris.core.pregenerator.PregenTask; import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeExecutor;
@@ -29,12 +27,9 @@ import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param; import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.Position2;
import org.bukkit.Bukkit;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import java.io.File;
@Decree(name = "pregen", aliases = "pregenerate", description = "Pregenerate your Iris worlds!") @Decree(name = "pregen", aliases = "pregenerate", description = "Pregenerate your Iris worlds!")
public class CommandPregen implements DecreeExecutor { public class CommandPregen implements DecreeExecutor {
@Decree(description = "Pregenerate a world") @Decree(description = "Pregenerate a world")
@@ -52,13 +47,12 @@ public class CommandPregen implements DecreeExecutor {
sender().sendMessage(C.RED + "Please make sure the world is loaded & the engine is initialized. Generate a new chunk, for example."); sender().sendMessage(C.RED + "Please make sure the world is loaded & the engine is initialized. Generate a new chunk, for example.");
} }
radius = Math.max(radius, 1024); radius = Math.max(radius, 1024);
int w = (radius >> 9 + 1) * 2;
IrisToolbelt.pregenerate(PregenTask IrisToolbelt.pregenerate(PregenTask
.builder() .builder()
.center(new Position2(center.getBlockX() >> 9, center.getBlockZ() >> 9)) .center(new Position2(center.getBlockX(), center.getBlockZ()))
.gui(true) .gui(true)
.width(w) .radiusX(radius)
.height(w) .radiusZ(radius)
.build(), world); .build(), world);
String msg = C.GREEN + "Pregen started in " + C.GOLD + world.getName() + C.GREEN + " of " + C.GOLD + (radius * 2) + C.GREEN + " by " + C.GOLD + (radius * 2) + C.GREEN + " blocks from " + C.GOLD + center.getX() + "," + center.getZ(); String msg = C.GREEN + "Pregen started in " + C.GOLD + world.getName() + C.GREEN + " of " + C.GOLD + (radius * 2) + C.GREEN + " by " + C.GOLD + (radius * 2) + C.GREEN + " blocks from " + C.GOLD + center.getX() + "," + center.getZ();
sender().sendMessage(msg); sender().sendMessage(msg);
@@ -172,7 +172,7 @@ public class CommandStudio implements DecreeExecutor {
KList<Runnable> js = new KList<>(); KList<Runnable> js = new KList<>();
BurstExecutor b = MultiBurst.burst.burst(); BurstExecutor b = MultiBurst.burst.burst();
b.setMulticore(false); b.setMulticore(false);
int rad = engine.getMantle().getRealRadius(); int rad = engine.getMantle().getRadius();
for (int i = -(radius + rad); i <= radius + rad; i++) { for (int i = -(radius + rad); i <= radius + rad; i++) {
for (int j = -(radius + rad); j <= radius + rad; j++) { for (int j = -(radius + rad); j <= radius + rad; j++) {
engine.getMantle().getMantle().deleteChunk(i + cx.getX(), j + cx.getZ()); engine.getMantle().getMantle().deleteChunk(i + cx.getX(), j + cx.getZ());
@@ -24,7 +24,6 @@ import com.volmit.iris.core.pregenerator.IrisPregenerator;
import com.volmit.iris.core.pregenerator.PregenListener; import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregenTask; import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.PregeneratorMethod; import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.core.tools.IrisPackBenchmarking;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
@@ -45,8 +44,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer; import java.util.function.Consumer;
import static com.volmit.iris.core.tools.IrisPackBenchmarking.benchmarkInProgress;
public class PregeneratorJob implements PregenListener { public class PregeneratorJob implements PregenListener {
private static final Color COLOR_EXISTS = parseColor("#4d7d5b"); private static final Color COLOR_EXISTS = parseColor("#4d7d5b");
private static final Color COLOR_BLACK = parseColor("#4d7d5b"); private static final Color COLOR_BLACK = parseColor("#4d7d5b");
@@ -81,12 +78,12 @@ public class PregeneratorJob implements PregenListener {
this.task = task; this.task = task;
this.pregenerator = new IrisPregenerator(task, method, this); this.pregenerator = new IrisPregenerator(task, method, this);
max = new Position2(0, 0); max = new Position2(0, 0);
min = new Position2(0, 0); min = new Position2(Integer.MAX_VALUE, Integer.MAX_VALUE);
task.iterateRegions((xx, zz) -> { task.iterateAllChunks((xx, zz) -> {
min.setX(Math.min(xx << 5, min.getX())); min.setX(Math.min(xx, min.getX()));
min.setZ(Math.min(zz << 5, min.getZ())); min.setZ(Math.min(zz, min.getZ()));
max.setX(Math.max((xx << 5) + 31, max.getX())); max.setX(Math.max(xx, max.getX()));
max.setZ(Math.max((zz << 5) + 31, max.getZ())); max.setZ(Math.max(zz, max.getZ()));
}); });
if (IrisSettings.get().getGui().isUseServerLaunchedGuis() && task.isGui()) { if (IrisSettings.get().getGui().isUseServerLaunchedGuis() && task.isGui()) {
@@ -162,7 +159,7 @@ public class PregeneratorJob implements PregenListener {
} }
public void drawRegion(int x, int z, Color color) { public void drawRegion(int x, int z, Color color) {
J.a(() -> PregenTask.iterateRegion(x, z, (xx, zz) -> { J.a(() -> task.iterateChunks(x, z, (xx, zz) -> {
draw(xx, zz, color); draw(xx, zz, color);
J.sleep(3); J.sleep(3);
})); }));
@@ -30,6 +30,7 @@ import com.volmit.iris.engine.object.IrisWorld;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.registry.Attributes;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.math.BlockPosition; import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
@@ -56,6 +57,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import static com.volmit.iris.util.data.registry.Attributes.MAX_HEALTH;
public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener, MouseMotionListener, MouseInputListener { public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener, MouseMotionListener, MouseInputListener {
private static final long serialVersionUID = 2094606939770332040L; private static final long serialVersionUID = 2094606939770332040L;
private final KList<LivingEntity> lastEntities = new KList<>(); private final KList<LivingEntity> lastEntities = new KList<>();
@@ -636,7 +639,7 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
k.add("Pos: " + h.getLocation().getBlockX() + ", " + h.getLocation().getBlockY() + ", " + h.getLocation().getBlockZ()); k.add("Pos: " + h.getLocation().getBlockX() + ", " + h.getLocation().getBlockY() + ", " + h.getLocation().getBlockZ());
k.add("UUID: " + h.getUniqueId()); k.add("UUID: " + h.getUniqueId());
k.add("HP: " + h.getHealth() + " / " + h.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()); k.add("HP: " + h.getHealth() + " / " + h.getAttribute(MAX_HEALTH).getValue());
drawCardTR(g, k); drawCardTR(g, k);
} }
@@ -55,10 +55,10 @@ public class IrisRenderer {
IrisBiome b = renderer.getBiome((int) Math.round(x), renderer.getMaxHeight() - 1, (int) Math.round(z)); IrisBiome b = renderer.getBiome((int) Math.round(x), renderer.getMaxHeight() - 1, (int) Math.round(z));
IrisBiomeGeneratorLink g = b.getGenerators().get(0); IrisBiomeGeneratorLink g = b.getGenerators().get(0);
Color c; Color c;
if (g.getMax(renderer) <= 0) { if (g.getMax() <= 0) {
// Max is below water level, so it is most likely an ocean biome // Max is below water level, so it is most likely an ocean biome
c = Color.BLUE; c = Color.BLUE;
} else if (g.getMin(renderer) < 0) { } else if (g.getMin() < 0) {
// Min is below water level, but max is not, so it is most likely a shore biome // Min is below water level, but max is not, so it is most likely a shore biome
c = Color.YELLOW; c = Color.YELLOW;
} else { } else {
@@ -2,7 +2,7 @@ package com.volmit.iris.core.link;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.data.IrisCustomData;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -49,7 +49,7 @@ public abstract class ExternalDataProvider {
* @param blockId The id of the block to get * @param blockId The id of the block to get
* @param state The state of the block to get * @param state The state of the block to get
* @return Corresponding {@link BlockData} to the blockId * @return Corresponding {@link BlockData} to the blockId
* may return {@link IrisBlockData} for blocks that need a world for placement * may return {@link IrisCustomData} for blocks that need a world for placement
* @throws MissingResourceException when the blockId is invalid * @throws MissingResourceException when the blockId is invalid
*/ */
@NotNull @NotNull
@@ -77,7 +77,7 @@ public abstract class ExternalDataProvider {
/** /**
* This method is used for placing blocks that need to use the plugins api * This method is used for placing blocks that need to use the plugins api
* it will only be called when the {@link ExternalDataProvider#getBlockData(Identifier, KMap)} returned a {@link IrisBlockData} * it will only be called when the {@link ExternalDataProvider#getBlockData(Identifier, KMap)} returned a {@link IrisCustomData}
* *
* @param engine The engine of the world the block is being placed in * @param engine The engine of the world the block is being placed in
* @param block The block where the block should be placed * @param block The block where the block should be placed
@@ -6,7 +6,7 @@ import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.reflect.WrappedField; import com.volmit.iris.util.reflect.WrappedField;
import com.volmit.iris.util.reflect.WrappedReturningMethod; import com.volmit.iris.util.reflect.WrappedReturningMethod;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@@ -64,7 +64,7 @@ public class HMCLeavesDataProvider extends ExternalDataProvider {
BlockData blockData = Bukkit.createBlockData(material); BlockData blockData = Bukkit.createBlockData(material);
if (IrisSettings.get().getGenerator().preventLeafDecay && blockData instanceof Leaves leaves) if (IrisSettings.get().getGenerator().preventLeafDecay && blockData instanceof Leaves leaves)
leaves.setPersistent(true); leaves.setPersistent(true);
return new IrisBlockData(blockData, ExternalDataSVC.buildState(blockId, state)); return new IrisCustomData(blockData, ExternalDataSVC.buildState(blockId, state));
} }
@NotNull @NotNull
@@ -27,7 +27,7 @@ import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import io.lumine.mythic.bukkit.BukkitAdapter; import io.lumine.mythic.bukkit.BukkitAdapter;
import io.lumine.mythic.bukkit.utils.serialize.Chroma; import io.lumine.mythic.bukkit.utils.serialize.Chroma;
@@ -71,7 +71,7 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider {
CustomBlockItemContext blockItemContext = crucibleItem.getBlockData(); CustomBlockItemContext blockItemContext = crucibleItem.getBlockData();
FurnitureItemContext furnitureItemContext = crucibleItem.getFurnitureData(); FurnitureItemContext furnitureItemContext = crucibleItem.getFurnitureData();
if (furnitureItemContext != null) { if (furnitureItemContext != null) {
return new IrisBlockData(B.getAir(), ExternalDataSVC.buildState(blockId, state)); return new IrisCustomData(B.getAir(), ExternalDataSVC.buildState(blockId, state));
} else if (blockItemContext != null) { } else if (blockItemContext != null) {
return blockItemContext.getBlockData(); return blockItemContext.getBlockData();
} }
@@ -26,6 +26,7 @@ import org.bukkit.plugin.Plugin;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collection; import java.util.Collection;
import java.util.List;
public class MythicMobsLink { public class MythicMobsLink {
@@ -54,6 +55,6 @@ public class MythicMobsLink {
} }
public Collection<String> getMythicMobTypes() { public Collection<String> getMythicMobTypes() {
return isEnabled() ? MythicBukkit.inst().getMobManager().getMobNames() : null; return isEnabled() ? MythicBukkit.inst().getMobManager().getMobNames() : List.of();
} }
} }
@@ -11,7 +11,7 @@ import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.block.Block; import org.bukkit.block.Block;
@@ -49,9 +49,9 @@ public class NexoDataProvider extends ExternalDataProvider {
BlockData data = NexoBlocks.blockData(blockId.key()); BlockData data = NexoBlocks.blockData(blockId.key());
if (data == null) if (data == null)
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
return new IrisBlockData(data, blockState); return new IrisCustomData(data, blockState);
} else if (NexoFurniture.isFurniture(blockId.key())) { } else if (NexoFurniture.isFurniture(blockId.key())) {
return new IrisBlockData(B.getAir(), blockState); return new IrisCustomData(B.getAir(), blockState);
} }
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
@@ -125,7 +125,7 @@ public class NexoDataProvider extends ExternalDataProvider {
@NotNull @NotNull
@Override @Override
public Identifier[] getBlockTypes() { public Identifier[] getBlockTypes() {
return Arrays.stream(NexoItems.itemNames()) return NexoItems.itemNames().stream()
.map(i -> new Identifier("nexo", i)) .map(i -> new Identifier("nexo", i))
.filter(i -> { .filter(i -> {
try { try {
@@ -140,7 +140,7 @@ public class NexoDataProvider extends ExternalDataProvider {
@NotNull @NotNull
@Override @Override
public Identifier[] getItemTypes() { public Identifier[] getItemTypes() {
return Arrays.stream(NexoItems.itemNames()) return NexoItems.itemNames().stream()
.map(i -> new Identifier("nexo", i)) .map(i -> new Identifier("nexo", i))
.filter(i -> { .filter(i -> {
try { try {
@@ -23,19 +23,28 @@ import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.nms.v1X.NMSBinding1X; import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import java.util.List;
import java.util.Map; import java.util.Map;
public class INMS { public class INMS {
private static final Map<String, String> REVISION = Map.of( private static final Map<String, String> REVISION = Map.of(
"1.20.5", "v1_20_R4", "1.20.5", "v1_20_R4",
"1.20.6", "v1_20_R4", "1.20.6", "v1_20_R4",
"1.21", "v1_21_R1", "1.21", "v1_21_R1",
"1.21.1", "v1_21_R1", "1.21.1", "v1_21_R1",
"1.21.2", "v1_21_R2", "1.21.2", "v1_21_R2",
"1.21.3", "v1_21_R2" "1.21.3", "v1_21_R2",
"1.21.4", "v1_21_R3"
); );
private static final List<Version> PACKS = List.of(
new Version(21, 4, "31020"),
new Version(21, 2, "31000"),
new Version(20, 1, "3910")
);
//@done //@done
private static final INMSBinding binding = bind(); private static final INMSBinding binding = bind();
public static final String OVERWORLD_TAG = getOverworldTag();
public static INMSBinding get() { public static INMSBinding get() {
return binding; return binding;
@@ -86,4 +95,26 @@ public class INMS {
return new NMSBinding1X(); return new NMSBinding1X();
} }
private static String getOverworldTag() {
var version = Bukkit.getServer().getBukkitVersion().split("-")[0].split("\\.", 3);
int major = 0;
int minor = 0;
if (version.length > 2) {
major = Integer.parseInt(version[1]);
minor = Integer.parseInt(version[2]);
} else if (version.length == 2) {
major = Integer.parseInt(version[1]);
}
for (var p : PACKS) {
if (p.major > major || p.minor > minor)
continue;
return p.tag;
}
return "3910";
}
private record Version(int major, int minor, String tag) {}
} }
@@ -18,8 +18,11 @@
package com.volmit.iris.core.nms; package com.volmit.iris.core.nms;
import com.volmit.iris.core.nms.container.AutoClosing;
import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.core.nms.headless.IRegionStorage;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
@@ -30,15 +33,12 @@ import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess;
import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.nbt.tag.CompoundTag;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.structure.Structure;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.awt.*;
import java.awt.Color; import java.awt.Color;
public interface INMSBinding { public interface INMSBinding {
@@ -91,7 +91,12 @@ public interface INMSBinding {
MCABiomeContainer newBiomeContainer(int min, int max); MCABiomeContainer newBiomeContainer(int min, int max);
default World createWorld(WorldCreator c) { default World createWorld(WorldCreator c) {
return c.createWorld(); if (missingDimensionTypes(true, true, true))
throw new IllegalStateException("Missing dimenstion types to create world");
try (var ignored = injectLevelStems()) {
return c.createWorld();
}
} }
int countCustomBiomes(); int countCustomBiomes();
@@ -124,5 +129,13 @@ public interface INMSBinding {
return 441; return 441;
} }
IRegionStorage createRegionStorage(Engine engine);
KList<String> getStructureKeys(); KList<String> getStructureKeys();
AutoClosing injectLevelStems();
Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end);
boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end);
} }
@@ -0,0 +1,22 @@
package com.volmit.iris.core.nms.container;
import com.volmit.iris.util.function.NastyRunnable;
import lombok.AllArgsConstructor;
import java.util.concurrent.atomic.AtomicBoolean;
@AllArgsConstructor
public class AutoClosing implements AutoCloseable {
private final AtomicBoolean closed = new AtomicBoolean();
private final NastyRunnable action;
@Override
public void close() {
if (closed.getAndSet(true)) return;
try {
action.run();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
@@ -1,11 +1,28 @@
package com.volmit.iris.core.nms.datapack; package com.volmit.iris.core.nms.datapack;
import com.volmit.iris.engine.object.IrisBiomeCustom; import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisRange;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
public interface IDataFixer { public interface IDataFixer {
JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json); default JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) {
return json;
}
JSONObject fixDimension(JSONObject json); JSONObject rawDimension(Dimension dimension);
default JSONObject createDimension(Dimension dimension, IrisRange height, int logicalHeight) {
JSONObject obj = rawDimension(dimension);
obj.put("min_y", height.getMin());
obj.put("height", height.getMax() - height.getMin());
obj.put("logical_height", logicalHeight);
return obj;
}
enum Dimension {
OVERRWORLD,
NETHER,
THE_END
}
} }
@@ -1,18 +1,81 @@
package com.volmit.iris.core.nms.datapack.v1192; package com.volmit.iris.core.nms.datapack.v1192;
import com.volmit.iris.core.nms.datapack.IDataFixer; import com.volmit.iris.core.nms.datapack.IDataFixer;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
import java.util.Map;
public class DataFixerV1192 implements IDataFixer { public class DataFixerV1192 implements IDataFixer {
@Override private static final Map<Dimension, String> DIMENSIONS = Map.of(
public JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) { Dimension.OVERRWORLD, """
return json; {
} "ambient_light": 0.0,
"bed_works": true,
"coordinate_scale": 1.0,
"effects": "minecraft:overworld",
"has_ceiling": false,
"has_raids": true,
"has_skylight": true,
"infiniburn": "#minecraft:infiniburn_overworld",
"monster_spawn_block_light_limit": 0,
"monster_spawn_light_level": {
"type": "minecraft:uniform",
"value": {
"max_inclusive": 7,
"min_inclusive": 0
}
},
"natural": true,
"piglin_safe": false,
"respawn_anchor_works": false,
"ultrawarm": false
}""",
Dimension.NETHER, """
{
"ambient_light": 0.1,
"bed_works": false,
"coordinate_scale": 8.0,
"effects": "minecraft:the_nether",
"fixed_time": 18000,
"has_ceiling": true,
"has_raids": false,
"has_skylight": false,
"infiniburn": "#minecraft:infiniburn_nether",
"monster_spawn_block_light_limit": 15,
"monster_spawn_light_level": 7,
"natural": false,
"piglin_safe": true,
"respawn_anchor_works": true,
"ultrawarm": true
}""",
Dimension.THE_END, """
{
"ambient_light": 0.0,
"bed_works": false,
"coordinate_scale": 1.0,
"effects": "minecraft:the_end",
"fixed_time": 6000,
"has_ceiling": false,
"has_raids": true,
"has_skylight": false,
"infiniburn": "#minecraft:infiniburn_end",
"monster_spawn_block_light_limit": 0,
"monster_spawn_light_level": {
"type": "minecraft:uniform",
"value": {
"max_inclusive": 7,
"min_inclusive": 0
}
},
"natural": false,
"piglin_safe": false,
"respawn_anchor_works": false,
"ultrawarm": false
}"""
);
@Override @Override
public JSONObject fixDimension(JSONObject json) { public JSONObject rawDimension(Dimension dimension) {
return json; return new JSONObject(DIMENSIONS.get(dimension));
} }
} }
@@ -1,6 +1,6 @@
package com.volmit.iris.core.nms.datapack.v1206; package com.volmit.iris.core.nms.datapack.v1206;
import com.volmit.iris.core.nms.datapack.IDataFixer; import com.volmit.iris.core.nms.datapack.v1192.DataFixerV1192;
import com.volmit.iris.engine.object.IrisBiomeCustom; import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisBiomeCustomSpawn; import com.volmit.iris.engine.object.IrisBiomeCustomSpawn;
import com.volmit.iris.engine.object.IrisBiomeCustomSpawnType; import com.volmit.iris.engine.object.IrisBiomeCustomSpawnType;
@@ -10,7 +10,7 @@ import com.volmit.iris.util.json.JSONObject;
import java.util.Locale; import java.util.Locale;
public class DataFixerV1206 implements IDataFixer { public class DataFixerV1206 extends DataFixerV1192 {
@Override @Override
public JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) { public JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) {
int spawnRarity = biome.getSpawnRarity(); int spawnRarity = biome.getSpawnRarity();
@@ -45,7 +45,8 @@ public class DataFixerV1206 implements IDataFixer {
} }
@Override @Override
public JSONObject fixDimension(JSONObject json) { public JSONObject rawDimension(Dimension dimension) {
JSONObject json = super.rawDimension(dimension);
if (!(json.get("monster_spawn_light_level") instanceof JSONObject lightLevel)) if (!(json.get("monster_spawn_light_level") instanceof JSONObject lightLevel))
return json; return json;
var value = (JSONObject) lightLevel.remove("value"); var value = (JSONObject) lightLevel.remove("value");
@@ -0,0 +1,17 @@
package com.volmit.iris.core.nms.headless;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import lombok.NonNull;
import java.io.IOException;
public interface IRegion extends AutoCloseable {
@ChunkCoordinates
boolean exists(int x, int z);
void write(@NonNull SerializableChunk chunk) throws IOException;
@Override
void close();
}
@@ -0,0 +1,27 @@
package com.volmit.iris.core.nms.headless;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.documentation.RegionCoordinates;
import lombok.NonNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
public interface IRegionStorage {
@ChunkCoordinates
boolean exists(int x, int z);
@Nullable
@RegionCoordinates
IRegion getRegion(int x, int z, boolean existingOnly) throws IOException;
@NonNull
@ChunkCoordinates
SerializableChunk createChunk(int x, int z);
void fillBiomes(@NonNull SerializableChunk chunk, @Nullable ChunkContext ctx);
void close();
}
@@ -0,0 +1,12 @@
package com.volmit.iris.core.nms.headless;
import com.volmit.iris.engine.data.chunk.TerrainChunk;
import com.volmit.iris.util.math.Position2;
public interface SerializableChunk extends TerrainChunk {
Position2 getPos();
Object serialize();
void mark();
}
@@ -20,7 +20,10 @@ package com.volmit.iris.core.nms.v1X;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.core.nms.INMSBinding;
import com.volmit.iris.core.nms.container.AutoClosing;
import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.headless.IRegionStorage;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
@@ -109,6 +112,11 @@ public class NMSBinding1X implements INMSBinding {
return Color.GREEN; return Color.GREEN;
} }
@Override
public IRegionStorage createRegionStorage(Engine engine) {
return null;
}
@Override @Override
public KList<String> getStructureKeys() { public KList<String> getStructureKeys() {
var list = StreamSupport.stream(Registry.STRUCTURE.spliterator(), false) var list = StreamSupport.stream(Registry.STRUCTURE.spliterator(), false)
@@ -118,6 +126,21 @@ public class NMSBinding1X implements INMSBinding {
return new KList<>(list); return new KList<>(list);
} }
@Override
public AutoClosing injectLevelStems() {
return new AutoClosing(() -> {});
}
@Override
public Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
return new Pair<>(0, new AutoClosing(() -> {}));
}
@Override
public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) {
return false;
}
@Override @Override
public CompoundTag serializeEntity(Entity location) { public CompoundTag serializeEntity(Entity location) {
return null; return null;
@@ -165,8 +165,11 @@ public class ChunkUpdater {
if (rX < dimensions.min.getX() || rX > dimensions.max.getX() || rZ < dimensions.min.getZ() || rZ > dimensions.max.getZ()) { if (rX < dimensions.min.getX() || rX > dimensions.max.getX() || rZ < dimensions.min.getZ() || rZ > dimensions.max.getZ()) {
return; return;
} }
if (!new File(world.getWorldFolder(), "region" + File.separator + rX + "." + rZ + ".mca").exists()) {
return;
}
PregenTask.iterateRegion(rX, rZ, (x, z) -> { task.iterateChunks(rX, rZ, (x, z) -> {
while (paused.get() && !cancelled.get()) { while (paused.get() && !cancelled.get()) {
J.sleep(50); J.sleep(50);
} }
@@ -348,8 +351,8 @@ public class ChunkUpdater {
int width = maxZ - minZ + 1; int width = maxZ - minZ + 1;
return new Dimensions(new Position2(minX, minZ), new Position2(maxX, maxZ), height * width, PregenTask.builder() return new Dimensions(new Position2(minX, minZ), new Position2(maxX, maxZ), height * width, PregenTask.builder()
.width((int) Math.ceil(width / 2d)) .radiusZ((int) Math.ceil(width / 2d * 512))
.height((int) Math.ceil(height / 2d)) .radiusX((int) Math.ceil(height / 2d * 512))
.center(new Position2(oX, oZ)) .center(new Position2(oX, oZ))
.build()); .build());
} }
@@ -0,0 +1,80 @@
package com.volmit.iris.core.pregenerator;
public class EmptyListener implements PregenListener {
public static PregenListener INSTANCE = new EmptyListener();
@Override
public void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method) {
}
@Override
public void onChunkGenerating(int x, int z) {
}
@Override
public void onChunkGenerated(int x, int z) {
}
@Override
public void onRegionGenerated(int x, int z) {
}
@Override
public void onRegionGenerating(int x, int z) {
}
@Override
public void onChunkCleaned(int x, int z) {
}
@Override
public void onRegionSkipped(int x, int z) {
}
@Override
public void onNetworkStarted(int x, int z) {
}
@Override
public void onNetworkFailed(int x, int z) {
}
@Override
public void onNetworkReclaim(int revert) {
}
@Override
public void onNetworkGeneratedChunk(int x, int z) {
}
@Override
public void onNetworkDownloaded(int x, int z) {
}
@Override
public void onClose() {
}
@Override
public void onSaving() {
}
@Override
public void onChunkExistsInRegionGen(int x, int z) {
}
}
@@ -19,7 +19,6 @@
package com.volmit.iris.core.pregenerator; package com.volmit.iris.core.pregenerator;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.pack.IrisPack;
import com.volmit.iris.core.tools.IrisPackBenchmarking; import com.volmit.iris.core.tools.IrisPackBenchmarking;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.collection.KSet;
@@ -83,7 +82,7 @@ public class IrisPregenerator {
generatedLast = new AtomicInteger(0); generatedLast = new AtomicInteger(0);
generatedLastMinute = new AtomicInteger(0); generatedLastMinute = new AtomicInteger(0);
totalChunks = new AtomicInteger(0); totalChunks = new AtomicInteger(0);
task.iterateRegions((_a, _b) -> totalChunks.addAndGet(1024)); task.iterateAllChunks((_a, _b) -> totalChunks.incrementAndGet());
startTime = new AtomicLong(M.ms()); startTime = new AtomicLong(M.ms());
ticker = new Looper() { ticker = new Looper() {
@Override @Override
@@ -194,7 +193,7 @@ public class IrisPregenerator {
} else if (!regions) { } else if (!regions) {
hit = true; hit = true;
listener.onRegionGenerating(x, z); listener.onRegionGenerating(x, z);
PregenTask.iterateRegion(x, z, (xx, zz) -> { task.iterateChunks(x, z, (xx, zz) -> {
while (paused.get() && !shutdown.get()) { while (paused.get() && !shutdown.get()) {
J.sleep(50); J.sleep(50);
} }
@@ -32,17 +32,26 @@ import java.util.Comparator;
@Data @Data
public class PregenTask { public class PregenTask {
private static final Position2 ZERO = new Position2(0, 0); private static final Position2 ZERO = new Position2(0, 0);
private static final KList<Position2> ORDER_CENTER = computeChunkOrder();
private static final KMap<Position2, KList<Position2>> ORDERS = new KMap<>(); private static final KMap<Position2, KList<Position2>> ORDERS = new KMap<>();
@Builder.Default @Builder.Default
private boolean gui = false; private final boolean gui = false;
@Builder.Default @Builder.Default
private Position2 center = new Position2(0, 0); private final Position2 center = new Position2(0, 0);
@Builder.Default @Builder.Default
private int width = 1; private final int radiusX = 1;
@Builder.Default @Builder.Default
private int height = 1; private final int radiusZ = 1;
private final Bounds bounds = new Bounds();
protected PregenTask(boolean gui, Position2 center, int radiusX, int radiusZ) {
this.gui = gui;
this.center = new ProxiedPos(center);
this.radiusX = radiusX;
this.radiusZ = radiusZ;
bounds.update();
}
public static void iterateRegion(int xr, int zr, Spiraled s, Position2 pull) { public static void iterateRegion(int xr, int zr, Spiraled s, Position2 pull) {
for (Position2 i : ORDERS.computeIfAbsent(pull, PregenTask::computeOrder)) { for (Position2 i : ORDERS.computeIfAbsent(pull, PregenTask::computeOrder)) {
@@ -70,29 +79,72 @@ public class PregenTask {
return p; return p;
} }
private static KList<Position2> computeChunkOrder() { public void iterateRegions(Spiraled s) {
Position2 center = new Position2(15, 15); var bound = bounds.region();
KList<Position2> p = new KList<>(); new Spiraler(bound.sizeX, bound.sizeZ, ((x, z) -> {
new Spiraler(33, 33, (x, z) -> { if (bound.check(x, z)) s.on(x, z);
int xx = x + 15; })).setOffset(center.getX() >> 9, center.getZ() >> 9).drain();
int zz = z + 15;
if (xx < 0 || xx > 31 || zz < 0 || zz > 31) {
return;
}
p.add(new Position2(xx, zz));
}).drain();
p.sort(Comparator.comparing((i) -> i.distance(center)));
return p;
} }
public void iterateRegions(Spiraled s) { public void iterateChunks(int rX, int rZ, Spiraled s) {
new Spiraler(getWidth() * 2, getHeight() * 2, s) var bound = bounds.chunk();
.setOffset(center.getX(), center.getZ()).drain(); iterateRegion(rX, rZ, ((x, z) -> {
if (bound.check(x, z)) s.on(x, z);
}));
} }
public void iterateAllChunks(Spiraled s) { public void iterateAllChunks(Spiraled s) {
new Spiraler(getWidth() * 2, getHeight() * 2, (x, z) -> iterateRegion(x, z, s)) iterateRegions(((rX, rZ) -> iterateChunks(rX, rZ, s)));
.setOffset(center.getX(), center.getZ()).drain(); }
private class Bounds {
private Bound chunk = null;
private Bound region = null;
public void update() {
int maxX = center.getX() + radiusX;
int maxZ = center.getZ() + radiusZ;
int minX = center.getX() - radiusX;
int minZ = center.getZ() - radiusZ;
chunk = new Bound(minX >> 4, minZ >> 4, Math.ceilDiv(maxX, 16), Math.ceilDiv(maxZ, 16));
region = new Bound(minX >> 9, minZ >> 9, Math.ceilDiv(maxX, 512), Math.ceilDiv(maxZ, 512));
}
public Bound chunk() {
if (chunk == null) update();
return chunk;
}
public Bound region() {
if (region == null) update();
return region;
}
}
private record Bound(int minX, int maxX, int minZ, int maxZ, int sizeX, int sizeZ) {
private Bound(int minX, int minZ, int maxX, int maxZ) {
this(minX, maxX, minZ, maxZ, maxZ - minZ + 1, maxZ - minZ + 1);
}
boolean check(int x, int z) {
return x >= minX && x <= maxX && z >= minZ && z <= maxZ;
}
}
private static class ProxiedPos extends Position2 {
public ProxiedPos(Position2 p) {
super(p.getX(), p.getZ());
}
@Override
public void setX(int x) {
throw new IllegalStateException("This Position2 may not be modified");
}
@Override
public void setZ(int z) {
throw new IllegalStateException("This Position2 may not be modified");
}
} }
} }
@@ -0,0 +1,112 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2024 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.pregenerator.methods;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisHeadless;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.parallel.MultiBurst;
import java.io.IOException;
import java.util.concurrent.Semaphore;
public class HeadlessPregenMethod implements PregeneratorMethod {
private final Engine engine;
private final IrisHeadless headless;
private final Semaphore semaphore;
private final int max;
private final MultiBurst burst;
public HeadlessPregenMethod(Engine engine) {
this(engine, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism()));
}
public HeadlessPregenMethod(Engine engine, int threads) {
this.max = Math.max(threads, 4);
this.engine = engine;
this.headless = new IrisHeadless(engine);
burst = new MultiBurst("HeadlessPregen", 8);
this.semaphore = new Semaphore(max);
}
@Override
public void init() {
}
@Override
public void close() {
try {
semaphore.acquire(max);
} catch (InterruptedException ignored) {
}
try {
headless.close();
} catch (IOException e) {
Iris.error("Failed to close headless");
e.printStackTrace();
}
burst.close();
}
@Override
public void save() {
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public String getMethod(int x, int z) {
return "Headless";
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
try {
semaphore.acquire();
} catch (InterruptedException ignored) {
return;
}
burst.complete(() -> {
try {
listener.onChunkGenerating(x, z);
headless.generateChunk(x, z);
listener.onChunkGenerated(x, z);
} finally {
semaphore.release();
}
});
}
@Override
public Mantle getMantle() {
return engine.getMantle().getMantle();
}
}
@@ -1,6 +1,7 @@
package com.volmit.iris.core.safeguard; package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
public class IrisSafeguard { public class IrisSafeguard {
public static boolean unstablemode = false; public static boolean unstablemode = false;
@@ -11,5 +12,13 @@ public class IrisSafeguard {
Iris.info("Enabled Iris SafeGuard"); Iris.info("Enabled Iris SafeGuard");
ServerBootSFG.BootCheck(); ServerBootSFG.BootCheck();
} }
public static void earlySplash() {
if (ServerBootSFG.safeguardPassed || IrisSettings.get().getGeneral().DoomsdayAnnihilationSelfDestructMode)
return;
Iris.instance.splash();
UtilsSFG.splash();
}
} }
@@ -3,6 +3,7 @@ package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.v1X.NMSBinding1X; import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import com.volmit.iris.engine.object.IrisContextInjector;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
@@ -29,6 +30,7 @@ public class ServerBootSFG {
public static boolean isJRE = false; public static boolean isJRE = false;
public static boolean hasPrivileges = true; public static boolean hasPrivileges = true;
public static boolean unsuportedversion = false; public static boolean unsuportedversion = false;
public static boolean missingDimensionTypes = false;
protected static boolean safeguardPassed; protected static boolean safeguardPassed;
public static boolean passedserversoftware = true; public static boolean passedserversoftware = true;
protected static int count; protected static int count;
@@ -110,6 +112,12 @@ public class ServerBootSFG {
severityMedium++; severityMedium++;
} }
if (IrisContextInjector.isMissingDimensionTypes()) {
missingDimensionTypes = true;
joiner.add("Missing Dimension Types");
severityHigh++;
}
allIncompatibilities = joiner.toString(); allIncompatibilities = joiner.toString();
safeguardPassed = (severityHigh == 0 && severityMedium == 0 && severityLow == 0); safeguardPassed = (severityHigh == 0 && severityMedium == 0 && severityLow == 0);
@@ -37,7 +37,12 @@ public class UtilsSFG {
} }
if (ServerBootSFG.unsuportedversion) { if (ServerBootSFG.unsuportedversion) {
Iris.safeguard(C.RED + "Server Version"); Iris.safeguard(C.RED + "Server Version");
Iris.safeguard(C.RED + "- Iris only supports 1.19.2 > 1.21.3"); Iris.safeguard(C.RED + "- Iris only supports 1.20.1 > 1.21.4");
}
if (ServerBootSFG.missingDimensionTypes) {
Iris.safeguard(C.RED + "Dimension Types");
Iris.safeguard(C.RED + "- Required Iris dimension types were not loaded.");
Iris.safeguard(C.RED + "- If this still happens after a restart please contact support.");
} }
if (!ServerBootSFG.passedserversoftware) { if (!ServerBootSFG.passedserversoftware) {
Iris.safeguard(C.YELLOW + "Unsupported Server Software"); Iris.safeguard(C.YELLOW + "Unsupported Server Software");
@@ -40,6 +40,7 @@ import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class BoardSVC implements IrisService, BoardProvider { public class BoardSVC implements IrisService, BoardProvider {
private final KMap<Player, PlayerBoard> boards = new KMap<>(); private final KMap<Player, PlayerBoard> boards = new KMap<>();
@@ -104,11 +105,11 @@ public class BoardSVC implements IrisService, BoardProvider {
@Data @Data
public static class PlayerBoard { public static class PlayerBoard {
private final Player player; private final Player player;
private final KList<String> lines; private final CopyOnWriteArrayList<String> lines;
public PlayerBoard(Player player) { public PlayerBoard(Player player) {
this.player = player; this.player = player;
this.lines = new KList<>(); this.lines = new CopyOnWriteArrayList<>();
update(); update();
} }
@@ -24,6 +24,7 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.pack.IrisPack; import com.volmit.iris.core.pack.IrisPack;
import com.volmit.iris.core.project.IrisProject; import com.volmit.iris.core.project.IrisProject;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
@@ -64,7 +65,7 @@ public class StudioSVC implements IrisService {
if (!f.exists()) { if (!f.exists()) {
Iris.info("Downloading Default Pack " + pack); Iris.info("Downloading Default Pack " + pack);
if (pack.equals("overworld")) { if (pack.equals("overworld")) {
String url = "https://github.com/IrisDimensions/overworld/releases/download/" + Iris.OVERWORLD_TAG + "/overworld.zip"; String url = "https://github.com/IrisDimensions/overworld/releases/download/" + INMS.OVERWORLD_TAG + "/overworld.zip";
Iris.service(StudioSVC.class).downloadRelease(Iris.getSender(), url, false, false); Iris.service(StudioSVC.class).downloadRelease(Iris.getSender(), url, false, false);
} else { } else {
downloadSearch(Iris.getSender(), pack, false); downloadSearch(Iris.getSender(), pack, false);
@@ -27,6 +27,7 @@ import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.Cuboid; import com.volmit.iris.util.data.Cuboid;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.math.BlockPosition; import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.plugin.IrisService; import com.volmit.iris.util.plugin.IrisService;
@@ -34,7 +35,6 @@ import com.volmit.iris.util.scheduling.J;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Sapling; import org.bukkit.block.data.type.Sapling;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@@ -142,7 +142,9 @@ public class TreeSVC implements IrisService {
public void set(int x, int y, int z, BlockData d) { public void set(int x, int y, int z, BlockData d) {
Block b = event.getWorld().getBlockAt(x, y, z); Block b = event.getWorld().getBlockAt(x, y, z);
BlockState state = b.getState(); BlockState state = b.getState();
state.setBlockData(d); if (d instanceof IrisCustomData data)
state.setBlockData(data.getBase());
else state.setBlockData(d);
blockStateList.add(b.getState()); blockStateList.add(b.getState());
dataCache.put(new Location(event.getWorld(), x, y, z), d); dataCache.put(new Location(event.getWorld(), x, y, z), d);
} }
@@ -213,12 +215,17 @@ public class TreeSVC implements IrisService {
block = false; block = false;
if (!iGrow.isCancelled()) { if (!iGrow.isCancelled()) {
for (BlockState block : iGrow.getBlocks()) { for (BlockState state : iGrow.getBlocks()) {
Location l = block.getLocation(); Location l = state.getLocation();
if (dataCache.containsKey(l)) { BlockData d = dataCache.get(l);
l.getBlock().setBlockData(dataCache.get(l), false); if (d == null) continue;
} Block block = l.getBlock();
if (d instanceof IrisCustomData data) {
block.setBlockData(data.getBase(), false);
Iris.service(ExternalDataSVC.class).processUpdate(engine, block, data.getCustom());
} else block.setBlockData(d);
} }
} }
}); });
@@ -30,15 +30,12 @@ import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.matter.Matter; import com.volmit.iris.util.matter.Matter;
import com.volmit.iris.util.matter.WorldMatter; import com.volmit.iris.util.matter.WorldMatter;
import com.volmit.iris.util.misc.E;
import com.volmit.iris.util.plugin.IrisService; import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.S;
import com.volmit.iris.util.scheduling.SR; import com.volmit.iris.util.scheduling.SR;
import com.volmit.iris.util.scheduling.jobs.Job; import com.volmit.iris.util.scheduling.jobs.Job;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@@ -56,11 +53,11 @@ import java.awt.Color;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import static com.volmit.iris.util.data.registry.Particles.CRIT_MAGIC;
import static com.volmit.iris.util.data.registry.Particles.REDSTONE;
public class WandSVC implements IrisService { public class WandSVC implements IrisService {
private static final Particle CRIT_MAGIC = E.getOrDefault(Particle.class, "CRIT_MAGIC", "CRIT");
private static final Particle REDSTONE = E.getOrDefault(Particle.class, "REDSTONE", "DUST");
private static final int MS_PER_TICK = Integer.parseInt(System.getProperty("iris.ms_per_tick", "30")); private static final int MS_PER_TICK = Integer.parseInt(System.getProperty("iris.ms_per_tick", "30"));
private static ItemStack dust; private static ItemStack dust;
@@ -22,6 +22,7 @@ import com.google.common.util.concurrent.AtomicDouble;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.pregenerator.PregenTask; import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisDimension;
@@ -83,7 +84,11 @@ public class IrisCreator {
* Benchmark mode * Benchmark mode
*/ */
private boolean benchmark = false; private boolean benchmark = false;
private boolean smartVanillaHeight = false; /**
* Radius of chunks to pregenerate in the headless mode
* if set to -1, headless mode is disabled
*/
private int headlessRadius = 10;
public static boolean removeFromBukkitYml(String name) throws IOException { public static boolean removeFromBukkitYml(String name) throws IOException {
YamlConfiguration yml = YamlConfiguration.loadConfiguration(BUKKIT_YML); YamlConfiguration yml = YamlConfiguration.loadConfiguration(BUKKIT_YML);
@@ -127,7 +132,6 @@ public class IrisCreator {
Iris.service(StudioSVC.class).installIntoWorld(sender, d.getLoadKey(), new File(Bukkit.getWorldContainer(), name())); Iris.service(StudioSVC.class).installIntoWorld(sender, d.getLoadKey(), new File(Bukkit.getWorldContainer(), name()));
} }
PlatformChunkGenerator access;
AtomicReference<World> world = new AtomicReference<>(); AtomicReference<World> world = new AtomicReference<>();
AtomicDouble pp = new AtomicDouble(0); AtomicDouble pp = new AtomicDouble(0);
O<Boolean> done = new O<>(); O<Boolean> done = new O<>();
@@ -137,34 +141,59 @@ public class IrisCreator {
.name(name) .name(name)
.seed(seed) .seed(seed)
.studio(studio) .studio(studio)
.smartVanillaHeight(smartVanillaHeight)
.create(); .create();
ServerConfigurator.installDataPacks(false); ServerConfigurator.installDataPacks(false);
access = (PlatformChunkGenerator) wc.generator(); PlatformChunkGenerator access = (PlatformChunkGenerator) wc.generator();
PlatformChunkGenerator finalAccess1 = access; if (access == null) {
throw new IrisException("Access is null. Something bad happened.");
}
J.a(() -> if (headlessRadius > 0 && !benchmark) {
{ AtomicBoolean failed = new AtomicBoolean(false);
Supplier<Integer> g = () -> { J.a(() -> {
if (finalAccess1 == null || finalAccess1.getEngine() == null) { int generated = access.getGenerated();
return 0; double total = Math.pow(headlessRadius * 2 + 1, 2);
while (generated < total) {
if (failed.get()) return;
double v = (double) generated / total;
if (sender.isPlayer()) {
sender.sendProgress(v, "Generating headless chunks");
J.sleep(16);
} else {
sender.sendMessage(C.WHITE + "Generating headless chunks " + Form.pc(v) + ((C.GRAY + " (" + ((int) total - generated) + " Left)")));
J.sleep(1000);
}
generated = access.getGenerated();
} }
return finalAccess1.getEngine().getGenerated(); });
};
if(!benchmark) {
if (finalAccess1 == null) return;
int req = finalAccess1.getSpawnChunks().join();
while (g.get() < req) { try {
double v = (double) g.get() / (double) req; access.prepareSpawnChunks(seed, headlessRadius);
} catch (Throwable e) {
Iris.error("Failed to prepare spawn chunks for " + name);
e.printStackTrace();
failed.set(true);
}
}
J.a(() -> {
if(!benchmark) {
int req = access.getSpawnChunks().join();
int generated = access.getGenerated();
while (generated < req) {
double v = (double) generated / (double) req;
if (sender.isPlayer()) { if (sender.isPlayer()) {
sender.sendProgress(v, "Generating"); sender.sendProgress(v, "Generating");
J.sleep(16); J.sleep(16);
} else { } else {
sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - g.get()) + " Left)"))); sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - generated) + " Left)")));
J.sleep(1000); J.sleep(1000);
} }
generated = access.getGenerated();
} }
} }
}); });
@@ -172,7 +201,7 @@ public class IrisCreator {
try { try {
J.sfut(() -> { J.sfut(() -> {
world.set(wc.createWorld()); world.set(INMS.get().createWorld(wc));
}).get(); }).get();
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
@@ -2,13 +2,22 @@ package com.volmit.iris.core.tools;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.pregenerator.PregenTask; import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.methods.HeadlessPregenMethod;
import com.volmit.iris.core.pregenerator.methods.HybridPregenMethod;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.IrisEngine;
import com.volmit.iris.engine.framework.Engine; 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.IrisDimension;
import com.volmit.iris.engine.object.IrisWorld;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.exceptions.IrisException; import com.volmit.iris.util.exceptions.IrisException;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Getter; import lombok.Getter;
@@ -17,11 +26,6 @@ import org.bukkit.Bukkit;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Clock; import java.time.Clock;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Collections; import java.util.Collections;
@@ -33,13 +37,16 @@ public class IrisPackBenchmarking {
public static boolean benchmarkInProgress = false; public static boolean benchmarkInProgress = false;
private final PrecisionStopwatch stopwatch = new PrecisionStopwatch(); private final PrecisionStopwatch stopwatch = new PrecisionStopwatch();
private final IrisDimension dimension; private final IrisDimension dimension;
private final int radius; private final int diameter;
private final boolean gui; private final boolean gui;
private final boolean headless;
private transient Engine engine;
public IrisPackBenchmarking(IrisDimension dimension, int radius, boolean gui) { public IrisPackBenchmarking(IrisDimension dimension, int diameter, boolean headless, boolean gui) {
instance = this; instance = this;
this.dimension = dimension; this.dimension = dimension;
this.radius = radius; this.diameter = diameter;
this.headless = headless;
this.gui = gui; this.gui = gui;
runBenchmark(); runBenchmark();
} }
@@ -50,12 +57,9 @@ public class IrisPackBenchmarking {
.start(() -> { .start(() -> {
Iris.info("Setting up benchmark environment "); Iris.info("Setting up benchmark environment ");
benchmarkInProgress = true; benchmarkInProgress = true;
File file = new File("benchmark"); IO.delete(new File(Bukkit.getWorldContainer(), "benchmark"));
if (file.exists()) {
deleteDirectory(file.toPath());
}
createBenchmark(); createBenchmark();
while (!IrisToolbelt.isIrisWorld(Bukkit.getWorld("benchmark"))) { while (!headless && !IrisToolbelt.isIrisWorld(Bukkit.getWorld("benchmark"))) {
J.sleep(1000); J.sleep(1000);
Iris.debug("Iris PackBenchmark: Waiting..."); Iris.debug("Iris PackBenchmark: Waiting...");
} }
@@ -73,7 +77,6 @@ public class IrisPackBenchmarking {
public void finishedBenchmark(KList<Integer> cps) { public void finishedBenchmark(KList<Integer> cps) {
try { try {
String time = Form.duration(stopwatch.getMillis()); String time = Form.duration(stopwatch.getMillis());
Engine engine = IrisToolbelt.access(Bukkit.getWorld("benchmark")).getEngine();
Iris.info("-----------------"); Iris.info("-----------------");
Iris.info("Results:"); Iris.info("Results:");
Iris.info("- Total time: " + time); Iris.info("- Total time: " + time);
@@ -114,12 +117,16 @@ public class IrisPackBenchmarking {
e.printStackTrace(); e.printStackTrace();
} }
J.s(() -> { if (headless) {
var world = Bukkit.getWorld("benchmark"); engine.close();
if (world == null) return; } else {
IrisToolbelt.evacuate(world); J.s(() -> {
Bukkit.unloadWorld(world, true); var world = Bukkit.getWorld("benchmark");
}); if (world == null) return;
IrisToolbelt.evacuate(world);
Bukkit.unloadWorld(world, true);
});
}
stopwatch.end(); stopwatch.end();
} catch (Exception e) { } catch (Exception e) {
@@ -130,13 +137,34 @@ public class IrisPackBenchmarking {
private void createBenchmark() { private void createBenchmark() {
try { try {
IrisToolbelt.createWorld() if (headless) {
Iris.info("Using headless benchmark!");
IrisWorld world = IrisWorld.builder()
.name("benchmark")
.minHeight(dimension.getMinHeight())
.maxHeight(dimension.getMaxHeight())
.seed(1337)
.worldFolder(new File(Bukkit.getWorldContainer(), "benchmark"))
.environment(dimension.getEnvironment())
.build();
Iris.service(StudioSVC.class).installIntoWorld(
Iris.getSender(),
dimension.getLoadKey(),
world.worldFolder());
var data = IrisData.get(new File(world.worldFolder(), "iris/pack"));
var dim = data.getDimensionLoader().load(dimension.getLoadKey());
engine = new IrisEngine(new EngineTarget(world, dim, data), false);
return;
}
engine = IrisToolbelt.access(IrisToolbelt.createWorld()
.dimension(dimension.getLoadKey()) .dimension(dimension.getLoadKey())
.name("benchmark") .name("benchmark")
.seed(1337) .seed(1337)
.studio(false) .studio(false)
.benchmark(true) .benchmark(true)
.create(); .create())
.getEngine();
} catch (IrisException e) { } catch (IrisException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -146,9 +174,15 @@ public class IrisPackBenchmarking {
IrisToolbelt.pregenerate(PregenTask IrisToolbelt.pregenerate(PregenTask
.builder() .builder()
.gui(gui) .gui(gui)
.width(radius) .radiusX(diameter)
.height(radius) .radiusZ(diameter)
.build(), Bukkit.getWorld("benchmark") .build(), headless ?
new HeadlessPregenMethod(engine) :
new HybridPregenMethod(
engine.getWorld().realWorld(),
IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())
),
engine
); );
} }
@@ -178,26 +212,4 @@ public class IrisPackBenchmarking {
private int findHighest(KList<Integer> list) { private int findHighest(KList<Integer> list) {
return Collections.max(list); return Collections.max(list);
} }
private boolean deleteDirectory(Path dir) {
try {
Files.walkFileTree(dir, new SimpleFileVisitor<>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
} }
@@ -21,10 +21,13 @@ package com.volmit.iris.core.tools;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.platform.BukkitChunkGenerator; import com.volmit.iris.engine.platform.BukkitChunkGenerator;
import com.volmit.iris.util.reflect.WrappedField;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.WorldCreator; import org.bukkit.WorldCreator;
import org.bukkit.WorldType;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import sun.misc.Unsafe;
import java.io.File; import java.io.File;
@@ -32,7 +35,6 @@ public class IrisWorldCreator {
private String name; private String name;
private boolean studio = false; private boolean studio = false;
private String dimensionName = null; private String dimensionName = null;
private boolean smartVanillaHeight = false;
private long seed = 1337; private long seed = 1337;
public IrisWorldCreator() { public IrisWorldCreator() {
@@ -64,11 +66,6 @@ public class IrisWorldCreator {
return this; return this;
} }
public IrisWorldCreator smartVanillaHeight(boolean smartVanillaHeight) {
this.smartVanillaHeight = smartVanillaHeight;
return this;
}
public WorldCreator create() { public WorldCreator create() {
IrisDimension dim = IrisData.loadAnyDimension(dimensionName); IrisDimension dim = IrisData.loadAnyDimension(dimensionName);
@@ -82,7 +79,7 @@ public class IrisWorldCreator {
.build(); .build();
ChunkGenerator g = new BukkitChunkGenerator(w, studio, studio ChunkGenerator g = new BukkitChunkGenerator(w, studio, studio
? dim.getLoader().getDataFolder() : ? dim.getLoader().getDataFolder() :
new File(w.worldFolder(), "iris/pack"), dimensionName, smartVanillaHeight); new File(w.worldFolder(), "iris/pack"), dimensionName);
return new WorldCreator(name) return new WorldCreator(name)
@@ -20,8 +20,6 @@ package com.volmit.iris.core.wand;
import com.volmit.iris.util.data.Cuboid; import com.volmit.iris.util.data.Cuboid;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.misc.E;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Particle; import org.bukkit.Particle;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -29,8 +27,9 @@ import org.bukkit.util.Vector;
import java.awt.*; import java.awt.*;
import static com.volmit.iris.util.data.registry.Particles.REDSTONE;
public class WandSelection { public class WandSelection {
private static final Particle REDSTONE = E.getOrDefault(Particle.class, "REDSTONE", "DUST");
private final Cuboid c; private final Cuboid c;
private final Player p; private final Player p;
private static final double STEP = 0.10; private static final double STEP = 0.10;
@@ -21,10 +21,10 @@ package com.volmit.iris.engine;
import com.google.common.util.concurrent.AtomicDouble; import com.google.common.util.concurrent.AtomicDouble;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.events.IrisEngineHotloadEvent; import com.volmit.iris.core.events.IrisEngineHotloadEvent;
import com.volmit.iris.core.gui.PregeneratorJob; import com.volmit.iris.core.gui.PregeneratorJob;
import com.volmit.iris.core.loader.ResourceLoader;
import com.volmit.iris.core.nms.container.BlockPos; import com.volmit.iris.core.nms.container.BlockPos;
import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.project.IrisProject; import com.volmit.iris.core.project.IrisProject;
@@ -53,7 +53,6 @@ import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
@@ -63,11 +62,10 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Data @Data
@EqualsAndHashCode(exclude = "context") @EqualsAndHashCode(exclude = "context")
@@ -92,6 +90,7 @@ public class IrisEngine implements Engine {
private final AtomicBoolean cleaning; private final AtomicBoolean cleaning;
private final ChronoLatch cleanLatch; private final ChronoLatch cleanLatch;
private final SeedManager seedManager; private final SeedManager seedManager;
private CompletableFuture<Long> hash32;
private EngineMode mode; private EngineMode mode;
private EngineEffects effects; private EngineEffects effects;
private EngineExecutionEnvironment execution; private EngineExecutionEnvironment execution;
@@ -174,8 +173,17 @@ public class IrisEngine implements Engine {
complex = new IrisComplex(this); complex = new IrisComplex(this);
execution = new IrisExecutionEnvironment(this); execution = new IrisExecutionEnvironment(this);
effects = new IrisEngineEffects(this); effects = new IrisEngineEffects(this);
hash32 = new CompletableFuture<>();
setupMode(); setupMode();
J.a(this::computeBiomeMaxes); J.a(this::computeBiomeMaxes);
J.a(() -> {
File[] roots = getData().getLoaders()
.values()
.stream()
.map(ResourceLoader::getRoot)
.toArray(File[]::new);
hash32.complete(IO.hashRecursive(roots));
});
} catch (Throwable e) { } catch (Throwable e) {
Iris.error("FAILED TO SETUP ENGINE!"); Iris.error("FAILED TO SETUP ENGINE!");
e.printStackTrace(); e.printStackTrace();
@@ -296,6 +304,11 @@ public class IrisEngine implements Engine {
return generated.get(); return generated.get();
} }
@Override
public void addGenerated(int x, int z) {
generated.incrementAndGet();
}
@Override @Override
public double getGeneratedPerSecond() { public double getGeneratedPerSecond() {
if (perSecondLatch.flip()) { if (perSecondLatch.flip()) {
@@ -18,7 +18,7 @@
package com.volmit.iris.engine; package com.volmit.iris.engine;
import com.volmit.iris.Iris; import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.mantle.EngineMantle; import com.volmit.iris.engine.mantle.EngineMantle;
@@ -27,23 +27,13 @@ import com.volmit.iris.engine.mantle.components.MantleCarvingComponent;
import com.volmit.iris.engine.mantle.components.MantleFluidBodyComponent; import com.volmit.iris.engine.mantle.components.MantleFluidBodyComponent;
import com.volmit.iris.engine.mantle.components.MantleJigsawComponent; import com.volmit.iris.engine.mantle.components.MantleJigsawComponent;
import com.volmit.iris.engine.mantle.components.MantleObjectComponent; import com.volmit.iris.engine.mantle.components.MantleObjectComponent;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.parallel.BurstExecutor; import lombok.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.bukkit.util.BlockVector;
import java.io.File; import java.io.File;
import java.io.IOException; import java.util.stream.Collectors;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
@Data @Data
@EqualsAndHashCode(exclude = "engine") @EqualsAndHashCode(exclude = "engine")
@@ -51,8 +41,9 @@ import java.util.concurrent.atomic.AtomicInteger;
public class IrisEngineMantle implements EngineMantle { public class IrisEngineMantle implements EngineMantle {
private final Engine engine; private final Engine engine;
private final Mantle mantle; private final Mantle mantle;
private final KList<MantleComponent> components; @Getter(AccessLevel.NONE)
private final int radius; private final KMap<Integer, KList<MantleComponent>> components;
private final AtomicCache<KList<Pair<KList<MantleComponent>, Integer>>> componentsCache = new AtomicCache<>();
private final AtomicCache<Integer> radCache = new AtomicCache<>(); private final AtomicCache<Integer> radCache = new AtomicCache<>();
private final MantleObjectComponent object; private final MantleObjectComponent object;
private final MantleJigsawComponent jigsaw; private final MantleJigsawComponent jigsaw;
@@ -60,8 +51,7 @@ public class IrisEngineMantle implements EngineMantle {
public IrisEngineMantle(Engine engine) { public IrisEngineMantle(Engine engine) {
this.engine = engine; this.engine = engine;
this.mantle = new Mantle(new File(engine.getWorld().worldFolder(), "mantle"), engine.getTarget().getHeight()); this.mantle = new Mantle(new File(engine.getWorld().worldFolder(), "mantle"), engine.getTarget().getHeight());
radius = radCache.aquire(this::computeParallaxSize); components = new KMap<>();
components = new KList<>();
registerComponent(new MantleCarvingComponent(this)); registerComponent(new MantleCarvingComponent(this));
registerComponent(new MantleFluidBodyComponent(this)); registerComponent(new MantleFluidBodyComponent(this));
jigsaw = new MantleJigsawComponent(this); jigsaw = new MantleJigsawComponent(this);
@@ -70,9 +60,49 @@ public class IrisEngineMantle implements EngineMantle {
registerComponent(object); registerComponent(object);
} }
@Override
public int getRadius() {
if (components.isEmpty()) return 0;
return getComponents().getFirst().getB();
}
@Override
public int getRealRadius() {
if (components.isEmpty()) return 0;
return getComponents().getLast().getB();
}
@Override
public KList<Pair<KList<MantleComponent>, Integer>> getComponents() {
return componentsCache.aquire(() -> {
var list = components.keySet()
.stream()
.sorted()
.map(components::get)
.map(components -> {
int radius = components.stream()
.mapToInt(MantleComponent::getRadius)
.max()
.orElse(0);
return new Pair<>(components, radius);
})
.collect(Collectors.toCollection(KList::new));
int radius = 0;
for (var pair : list.reversed()) {
radius += pair.getB();
pair.setB(Math.ceilDiv(radius, 16));
}
return list;
});
}
@Override @Override
public void registerComponent(MantleComponent c) { public void registerComponent(MantleComponent c) {
components.add(c); components.computeIfAbsent(c.getPriority(), k -> new KList<>()).add(c);
componentsCache.reset();
} }
@Override @Override
@@ -84,243 +114,4 @@ public class IrisEngineMantle implements EngineMantle {
public MantleObjectComponent getObjectComponent() { public MantleObjectComponent getObjectComponent() {
return object; return object;
} }
private KList<IrisRegion> getAllRegions() {
KList<IrisRegion> r = new KList<>();
for (String i : getEngine().getDimension().getRegions()) {
r.add(getEngine().getData().getRegionLoader().load(i));
}
return r;
}
private KList<IrisBiome> getAllBiomes() {
KList<IrisBiome> r = new KList<>();
for (IrisRegion i : getAllRegions()) {
r.addAll(i.getAllBiomes(getEngine()));
}
return r;
}
private void warn(String ob, BlockVector bv) {
if (Math.max(bv.getBlockX(), bv.getBlockZ()) > 128) {
Iris.warn("Object " + ob + " has a large size (" + bv + ") and may increase memory usage!");
}
}
private void warnScaled(String ob, BlockVector bv, double ms) {
if (Math.max(bv.getBlockX(), bv.getBlockZ()) > 128) {
Iris.warn("Object " + ob + " has a large size (" + bv + ") and may increase memory usage! (Object scaled up to " + Form.pc(ms, 2) + ")");
}
}
private int computeParallaxSize() {
Iris.verbose("Calculating the Parallax Size in Parallel");
AtomicInteger xg = new AtomicInteger(0);
AtomicInteger zg = new AtomicInteger();
xg.set(0);
zg.set(0);
int jig = 0;
KSet<String> objects = new KSet<>();
KMap<IrisObjectScale, KList<String>> scalars = new KMap<>();
int x = xg.get();
int z = zg.get();
if (getEngine().getDimension().isUseMantle()) {
KList<IrisRegion> r = getAllRegions();
KList<IrisBiome> b = getAllBiomes();
for (IrisBiome i : b) {
for (IrisObjectPlacement j : i.getObjects()) {
if (j.getScale().canScaleBeyond()) {
scalars.put(j.getScale(), j.getPlace());
} else {
objects.addAll(j.getPlace());
}
}
for (IrisJigsawStructurePlacement j : i.getJigsawStructures()) {
jig = Math.max(jig, getData().getJigsawStructureLoader().load(j.getStructure()).getMaxDimension());
}
}
for (IrisRegion i : r) {
for (IrisObjectPlacement j : i.getObjects()) {
if (j.getScale().canScaleBeyond()) {
scalars.put(j.getScale(), j.getPlace());
} else {
objects.addAll(j.getPlace());
}
}
for (IrisJigsawStructurePlacement j : i.getJigsawStructures()) {
jig = Math.max(jig, getData().getJigsawStructureLoader().load(j.getStructure()).getMaxDimension());
}
}
for (IrisJigsawStructurePlacement j : getEngine().getDimension().getJigsawStructures()) {
jig = Math.max(jig, getData().getJigsawStructureLoader().load(j.getStructure()).getMaxDimension());
}
if (getEngine().getDimension().getStronghold() != null) {
try {
jig = Math.max(jig, getData().getJigsawStructureLoader().load(getEngine().getDimension().getStronghold()).getMaxDimension());
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
}
Iris.verbose("Checking sizes for " + Form.f(objects.size()) + " referenced objects.");
BurstExecutor e = getEngine().getTarget().getBurster().burst(objects.size());
KMap<String, BlockVector> sizeCache = new KMap<>();
for (String i : objects) {
e.queue(() -> {
try {
BlockVector bv = sizeCache.computeIfAbsent(i, (k) -> {
try {
return IrisObject.sampleSize(getData().getObjectLoader().findFile(i));
} catch (IOException ex) {
Iris.reportError(ex);
ex.printStackTrace();
}
return null;
});
if (bv == null) {
throw new RuntimeException();
}
warn(i, bv);
synchronized (xg) {
xg.getAndSet(Math.max(bv.getBlockX(), xg.get()));
}
synchronized (zg) {
zg.getAndSet(Math.max(bv.getBlockZ(), zg.get()));
}
} catch (Throwable ed) {
Iris.reportError(ed);
}
});
}
for (Map.Entry<IrisObjectScale, KList<String>> entry : scalars.entrySet()) {
double ms = entry.getKey().getMaximumScale();
for (String j : entry.getValue()) {
e.queue(() -> {
try {
BlockVector bv = sizeCache.computeIfAbsent(j, (k) -> {
try {
return IrisObject.sampleSize(getData().getObjectLoader().findFile(j));
} catch (IOException ioException) {
Iris.reportError(ioException);
ioException.printStackTrace();
}
return null;
});
if (bv == null) {
throw new RuntimeException();
}
warnScaled(j, bv, ms);
synchronized (xg) {
xg.getAndSet((int) Math.max(Math.ceil(bv.getBlockX() * ms), xg.get()));
}
synchronized (zg) {
zg.getAndSet((int) Math.max(Math.ceil(bv.getBlockZ() * ms), zg.get()));
}
} catch (Throwable ee) {
Iris.reportError(ee);
}
});
}
}
e.complete();
x = xg.get();
z = zg.get();
for (IrisDepositGenerator i : getEngine().getDimension().getDeposits()) {
int max = i.getMaxDimension();
x = Math.max(max, x);
z = Math.max(max, z);
}
for (IrisRegion v : r) {
for (IrisDepositGenerator i : v.getDeposits()) {
int max = i.getMaxDimension();
x = Math.max(max, x);
z = Math.max(max, z);
}
}
for (IrisBiome v : b) {
for (IrisDepositGenerator i : v.getDeposits()) {
int max = i.getMaxDimension();
x = Math.max(max, x);
z = Math.max(max, z);
}
}
} else {
return 0;
}
x = Math.max(z, x);
int u = x;
int c = Math.max(computeCarvingRange(), computeBodyRange());
x = Math.max(jig, x);
x = Math.max(x, c);
x = (Math.max(x, 16) + 16) >> 4;
x = x % 2 == 0 ? x + 1 : x;
Iris.info("Mantle Size: " + x + " Chunks");
Iris.info(" Object Mantle Size: " + u + " (" + ((Math.max(u, 16) + 16) >> 4) + ")");
Iris.info(" Jigsaw Mantle Size: " + jig + " (" + ((Math.max(jig, 16) + 16) >> 4) + ")");
Iris.info(" Carving Mantle Size: " + c + " (" + ((Math.max(c, 16) + 16) >> 4) + ")");
return x;
}
private int computeBodyRange() {
int m = 0;
m = Math.max(m, getDimension().getFluidBodies().getMaxRange(getData()));
for (IrisRegion i : getDimension().getAllRegions(getEngine())) {
m = Math.max(m, i.getFluidBodies().getMaxRange(getData()));
}
for (IrisBiome i : getDimension().getAllBiomes(getEngine())) {
m = Math.max(m, i.getFluidBodies().getMaxRange(getData()));
}
return m;
}
private int computeCarvingRange() {
int m = 0;
m = Math.max(m, getDimension().getCarving().getMaxRange(getData()));
for (IrisRegion i : getDimension().getAllRegions(getEngine())) {
m = Math.max(m, i.getCarving().getMaxRange(getData()));
}
for (IrisBiome i : getDimension().getAllBiomes(getEngine())) {
m = Math.max(m, i.getCarving().getMaxRange(getData()));
}
return m;
}
} }
@@ -62,6 +62,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -299,28 +300,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
energy += 1.2; energy += 1.2;
} }
//@builder
IrisBiome biome = IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()
? getEngine().getSurfaceBiome(c) : null;
IrisEntitySpawn v = IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()
? spawnRandomly(Stream.concat(getData().getSpawnerLoader()
.loadAll(getDimension().getEntitySpawners())
.shuffleCopy(RNG.r).stream()
.filter(this::canSpawn)
.filter((i) -> i.isValid(biome))
.flatMap((i) -> stream(i, initial)),
Stream.concat(getData().getSpawnerLoader()
.loadAll(getEngine().getRegion(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
.shuffleCopy(RNG.r).stream().filter(this::canSpawn)
.flatMap((i) -> stream(i, initial)),
getData().getSpawnerLoader()
.loadAll(getEngine().getSurfaceBiome(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
.shuffleCopy(RNG.r).stream().filter(this::canSpawn)
.flatMap((i) -> stream(i, initial))))
.collect(Collectors.toList()))
.popRandom(RNG.r) : null;
//@done
if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) { if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) {
getSpawnersFromMarkers(c).forEach((blockf, spawners) -> { getSpawnersFromMarkers(c).forEach((blockf, spawners) -> {
if (spawners.isEmpty()) { if (spawners.isEmpty()) {
@@ -335,94 +314,67 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
}); });
} }
if (v != null && v.getReferenceSpawner() != null) { if (!IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()) {
int maxEntCount = v.getReferenceSpawner().getMaxEntitiesPerChunk(); return;
}
for (Entity i : c.getEntities()) { //@builder
if (i instanceof LivingEntity) { Predicate<IrisSpawner> filter = i -> i.canSpawn(getEngine(), c.getX(), c.getZ());
if (-maxEntCount <= 0) { ChunkCounter counter = new ChunkCounter(c.getEntities());
return;
}
}
}
try { IrisBiome biome = getEngine().getSurfaceBiome(c);
spawn(c, v); IrisEntitySpawn v = spawnRandomly(Stream.concat(getData().getSpawnerLoader()
} catch (Throwable e) { .loadAll(getDimension().getEntitySpawners())
J.s(() -> spawn(c, v)); .shuffleCopy(RNG.r)
} .stream()
.filter(filter)
.filter((i) -> i.isValid(biome)),
Stream.concat(getData()
.getSpawnerLoader()
.loadAll(getEngine().getRegion(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
.shuffleCopy(RNG.r)
.stream()
.filter(filter),
getData().getSpawnerLoader()
.loadAll(getEngine().getSurfaceBiome(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
.shuffleCopy(RNG.r)
.stream()
.filter(filter)))
.filter(counter)
.flatMap((i) -> stream(i, initial))
.collect(Collectors.toList()))
.getRandom();
//@done
if (v == null || v.getReferenceSpawner() == null)
return;
try {
spawn(c, v);
} catch (Throwable e) {
J.s(() -> spawn(c, v));
} }
} }
private void spawn(Chunk c, IrisEntitySpawn i) { private void spawn(Chunk c, IrisEntitySpawn i) {
boolean allow = true; IrisSpawner ref = i.getReferenceSpawner();
int s = i.spawn(getEngine(), c, RNG.r);
if (!i.getReferenceSpawner().getMaximumRatePerChunk().isInfinite()) { actuallySpawned += s;
allow = false; if (s > 0) {
IrisEngineChunkData cd = getEngine().getEngineData().getChunk(c.getX(), c.getZ()); ref.spawn(getEngine(), c.getX(), c.getZ());
IrisEngineSpawnerCooldown sc = null; energy -= s * ((i.getEnergyMultiplier() * ref.getEnergyMultiplier() * 1));
for (IrisEngineSpawnerCooldown j : cd.getCooldowns()) {
if (j.getSpawner().equals(i.getReferenceSpawner().getLoadKey())) {
sc = j;
break;
}
}
if (sc == null) {
sc = new IrisEngineSpawnerCooldown();
sc.setSpawner(i.getReferenceSpawner().getLoadKey());
cd.getCooldowns().add(sc);
}
if (sc.canSpawn(i.getReferenceSpawner().getMaximumRatePerChunk())) {
sc.spawn(getEngine());
allow = true;
}
}
if (allow) {
int s = i.spawn(getEngine(), c, RNG.r);
actuallySpawned += s;
if (s > 0) {
getCooldown(i.getReferenceSpawner()).spawn(getEngine());
energy -= s * ((i.getEnergyMultiplier() * i.getReferenceSpawner().getEnergyMultiplier() * 1));
}
} }
} }
private void spawn(IrisPosition c, IrisEntitySpawn i) { private void spawn(IrisPosition pos, IrisEntitySpawn i) {
boolean allow = true; IrisSpawner ref = i.getReferenceSpawner();
if (!ref.canSpawn(getEngine(), pos.getX() >> 4, pos.getZ()))
return;
if (!i.getReferenceSpawner().getMaximumRatePerChunk().isInfinite()) { int s = i.spawn(getEngine(), pos, RNG.r);
allow = false; actuallySpawned += s;
IrisEngineChunkData cd = getEngine().getEngineData().getChunk(c.getX() >> 4, c.getZ() >> 4); if (s > 0) {
IrisEngineSpawnerCooldown sc = null; ref.spawn(getEngine(), pos.getX() >> 4, pos.getZ() >> 4);
for (IrisEngineSpawnerCooldown j : cd.getCooldowns()) { energy -= s * ((i.getEnergyMultiplier() * ref.getEnergyMultiplier() * 1));
if (j.getSpawner().equals(i.getReferenceSpawner().getLoadKey())) {
sc = j;
break;
}
}
if (sc == null) {
sc = new IrisEngineSpawnerCooldown();
sc.setSpawner(i.getReferenceSpawner().getLoadKey());
cd.getCooldowns().add(sc);
}
if (sc.canSpawn(i.getReferenceSpawner().getMaximumRatePerChunk())) {
sc.spawn(getEngine());
allow = true;
}
}
if (allow) {
int s = i.spawn(getEngine(), c, RNG.r);
actuallySpawned += s;
if (s > 0) {
getCooldown(i.getReferenceSpawner()).spawn(getEngine());
energy -= s * ((i.getEnergyMultiplier() * i.getReferenceSpawner().getEnergyMultiplier() * 1));
}
} }
} }
@@ -450,31 +402,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
return rarityTypes; return rarityTypes;
} }
public boolean canSpawn(IrisSpawner i) {
return i.isValid(getEngine().getWorld().realWorld())
&& getCooldown(i).canSpawn(i.getMaximumRate());
}
private IrisEngineSpawnerCooldown getCooldown(IrisSpawner i) {
IrisEngineData ed = getEngine().getEngineData();
IrisEngineSpawnerCooldown cd = null;
for (IrisEngineSpawnerCooldown j : ed.getSpawnerCooldowns().copy()) {
if (j.getSpawner().equals(i.getLoadKey())) {
cd = j;
}
}
if (cd == null) {
cd = new IrisEngineSpawnerCooldown();
cd.setSpawner(i.getLoadKey());
cd.setLastSpawn(M.ms() - i.getMaximumRate().getInterval());
ed.getSpawnerCooldowns().add(cd);
}
return cd;
}
@Override @Override
public void onTick() { public void onTick() {
@@ -708,4 +635,27 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
return (double) entityCount / (getEngine().getWorld().realWorld().getLoadedChunks().length + 1) * 1.28; return (double) entityCount / (getEngine().getWorld().realWorld().getLoadedChunks().length + 1) * 1.28;
} }
@Data
private static class ChunkCounter implements Predicate<IrisSpawner> {
private final Entity[] entities;
private transient int index = 0;
private transient int count = 0;
@Override
public boolean test(IrisSpawner spawner) {
int max = spawner.getMaxEntitiesPerChunk();
if (max <= count)
return false;
while (index < entities.length) {
if (entities[index++] instanceof LivingEntity) {
if (++count >= max)
return false;
}
}
return true;
}
}
} }
@@ -21,7 +21,7 @@ package com.volmit.iris.engine.data.chunk;
import com.volmit.iris.core.nms.BiomeBaseInjector; import com.volmit.iris.core.nms.BiomeBaseInjector;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.util.data.IrisBiomeStorage; import com.volmit.iris.util.data.IrisBiomeStorage;
import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.data.IrisCustomData;
import lombok.Setter; import lombok.Setter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
@@ -121,7 +121,7 @@ public class LinkedTerrainChunk implements TerrainChunk {
@Override @Override
public synchronized void setBlock(int x, int y, int z, BlockData blockData) { public synchronized void setBlock(int x, int y, int z, BlockData blockData) {
if (blockData instanceof IrisBlockData d) if (blockData instanceof IrisCustomData d)
blockData = d.getBase(); blockData = d.getBase();
rawChunkData.setBlock(x, y, z, blockData); rawChunkData.setBlock(x, y, z, blockData);
} }
@@ -20,7 +20,7 @@ package com.volmit.iris.engine.data.chunk;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.BiomeBaseInjector; import com.volmit.iris.core.nms.BiomeBaseInjector;
import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.nbt.mca.Chunk; import com.volmit.iris.util.nbt.mca.Chunk;
import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.mca.NBTWorld;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@@ -89,7 +89,7 @@ public class MCATerrainChunk implements TerrainChunk {
if (blockData == null) { if (blockData == null) {
Iris.error("NULL BD"); Iris.error("NULL BD");
} }
if (blockData instanceof IrisBlockData data) if (blockData instanceof IrisCustomData data)
blockData = data.getBase(); blockData = data.getBase();
mcaChunk.setBlockStateAt(xx, y, zz, NBTWorld.getCompound(blockData), false); mcaChunk.setBlockStateAt(xx, y, zz, NBTWorld.getCompound(blockData), false);
@@ -18,18 +18,16 @@
package com.volmit.iris.engine.decorator; package com.volmit.iris.engine.decorator;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorationPart; import com.volmit.iris.engine.object.IrisDecorationPart;
import com.volmit.iris.engine.object.IrisDecorator; import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.math.RNG;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing;
import org.bukkit.block.data.type.PointedDripstone; import org.bukkit.block.data.type.PointedDripstone;
public class IrisCeilingDecorator extends IrisEngineDecorator { public class IrisCeilingDecorator extends IrisEngineDecorator {
@@ -40,12 +38,14 @@ public class IrisCeilingDecorator extends IrisEngineDecorator {
@BlockCoordinates @BlockCoordinates
@Override @Override
public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max) { public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max) {
IrisDecorator decorator = getDecorator(biome, realX, realZ); RNG rng = getRNG(realX, realZ);
IrisDecorator decorator = getDecorator(rng, biome, realX, realZ);
if (decorator != null) { if (decorator != null) {
if (!decorator.isStacking()) { if (!decorator.isStacking()) {
data.set(x, height, z, fixFaces(decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()), realX, height, realZ)); data.set(x, height, z, fixFaces(decorator.getBlockData100(biome, rng, realX, height, realZ, getData()), data, x, z, realX, height, realZ));
} else { } else {
int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData()); int stack = decorator.getHeight(rng, realX, realZ, getData());
if (decorator.isScaleStack()) { if (decorator.isScaleStack()) {
stack = Math.min((int) Math.ceil((double) max * ((double) stack / 100)), decorator.getAbsoluteMaxStack()); stack = Math.min((int) Math.ceil((double) max * ((double) stack / 100)), decorator.getAbsoluteMaxStack());
} else { } else {
@@ -53,7 +53,7 @@ public class IrisCeilingDecorator extends IrisEngineDecorator {
} }
if (stack == 1) { if (stack == 1) {
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())); data.set(x, height, z, decorator.getBlockDataForTop(biome, rng, realX, height, realZ, getData()));
return; return;
} }
@@ -66,8 +66,8 @@ public class IrisCeilingDecorator extends IrisEngineDecorator {
double threshold = (((double) i) / (double) (stack - 1)); double threshold = (((double) i) / (double) (stack - 1));
BlockData bd = threshold >= decorator.getTopThreshold() ? BlockData bd = threshold >= decorator.getTopThreshold() ?
decorator.getBlockDataForTop(biome, getRng(), realX, h, realZ, getData()) : decorator.getBlockDataForTop(biome, rng, realX, h, realZ, getData()) :
decorator.getBlockData100(biome, getRng(), realX, h, realZ, getData()); decorator.getBlockData100(biome, rng, realX, h, realZ, getData());
if (bd instanceof PointedDripstone) { if (bd instanceof PointedDripstone) {
PointedDripstone.Thickness th = PointedDripstone.Thickness.BASE; PointedDripstone.Thickness th = PointedDripstone.Thickness.BASE;
@@ -97,24 +97,4 @@ public class IrisCeilingDecorator extends IrisEngineDecorator {
} }
} }
} }
private BlockData fixFaces(BlockData b, int x, int y, int z) {
if (B.isVineBlock(b)) {
MultipleFacing data = (MultipleFacing) b.clone();
boolean found = false;
for (BlockFace f : BlockFace.values()) {
if (!f.isCartesian())
continue;
Material m = getEngine().getMantle().get(x + f.getModX(), y + f.getModY(), z + f.getModZ()).getMaterial();
if (m.isSolid()) {
found = true;
data.setFace(f, m.isSolid());
}
}
if (!found)
data.setFace(BlockFace.UP, true);
return data;
}
return b;
}
} }
@@ -19,7 +19,6 @@
package com.volmit.iris.engine.decorator; package com.volmit.iris.engine.decorator;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineAssignedComponent; import com.volmit.iris.engine.framework.EngineAssignedComponent;
import com.volmit.iris.engine.framework.EngineDecorator; import com.volmit.iris.engine.framework.EngineDecorator;
@@ -27,30 +26,42 @@ import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorationPart; import com.volmit.iris.engine.object.IrisDecorationPart;
import com.volmit.iris.engine.object.IrisDecorator; import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import lombok.Getter; import lombok.Getter;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockSupport;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing;
public abstract class IrisEngineDecorator extends EngineAssignedComponent implements EngineDecorator { public abstract class IrisEngineDecorator extends EngineAssignedComponent implements EngineDecorator {
@Getter
private final RNG rng;
@Getter @Getter
private final IrisDecorationPart part; private final IrisDecorationPart part;
private final long seed;
private final long modX, modZ;
public IrisEngineDecorator(Engine engine, String name, IrisDecorationPart part) { public IrisEngineDecorator(Engine engine, String name, IrisDecorationPart part) {
super(engine, name + " Decorator"); super(engine, name + " Decorator");
this.part = part; this.part = part;
this.rng = new RNG(getSeed() + 29356788 - (part.ordinal() * 10439677L)); this.seed = getSeed() + 29356788 - (part.ordinal() * 10439677L);
this.modX = 29356788 ^ (part.ordinal() + 6);
this.modZ = 10439677 ^ (part.ordinal() + 1);
} }
protected IrisDecorator getDecorator(IrisBiome biome, double realX, double realZ) { @BlockCoordinates
KList<IrisDecorator> v = new KList<>(); protected RNG getRNG(int x, int z) {
RNG rng = new RNG(Cache.key((int) realX, (int) realZ)); return new RNG(x * modX + z * modZ + seed);
}
protected IrisDecorator getDecorator(RNG rng, IrisBiome biome, double realX, double realZ) {
KList<IrisDecorator> v = new KList<>();
RNG gRNG = new RNG(seed);
for (IrisDecorator i : biome.getDecorators()) { for (IrisDecorator i : biome.getDecorators()) {
try { try {
if (i.getPartOf().equals(part) && i.getBlockData(biome, this.rng, realX, realZ, getData()) != null) { if (i.getPartOf().equals(part) && i.getBlockData(biome, gRNG, realX, realZ, getData()) != null) {
v.add(i); v.add(i);
} }
} catch (Throwable e) { } catch (Throwable e) {
@@ -65,4 +76,40 @@ public abstract class IrisEngineDecorator extends EngineAssignedComponent implem
return null; return null;
} }
protected BlockData fixFaces(BlockData b, Hunk<BlockData> hunk, int rX, int rZ, int x, int y, int z) {
if (B.isVineBlock(b)) {
MultipleFacing data = (MultipleFacing) b.clone();
data.getFaces().forEach(f -> data.setFace(f, false));
boolean found = false;
for (BlockFace f : BlockFace.values()) {
if (!f.isCartesian())
continue;
int yy = y + f.getModY();
BlockData r = getEngine().getMantle().get(x + f.getModX(), yy, z + f.getModZ());
if (r.isFaceSturdy(f.getOppositeFace(), BlockSupport.FULL)) {
found = true;
data.setFace(f, true);
continue;
}
int xx = rX + f.getModX();
int zz = rZ + f.getModZ();
if (xx < 0 || xx > 15 || zz < 0 || zz > 15 || yy < 0 || yy > hunk.getHeight())
continue;
r = hunk.get(xx, yy, zz);
if (r.isFaceSturdy(f.getOppositeFace(), BlockSupport.FULL)) {
found = true;
data.setFace(f, true);
}
}
if (!found)
data.setFace(BlockFace.DOWN, true);
return data;
}
return b;
}
} }
@@ -18,13 +18,13 @@
package com.volmit.iris.engine.decorator; package com.volmit.iris.engine.decorator;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorationPart; import com.volmit.iris.engine.object.IrisDecorationPart;
import com.volmit.iris.engine.object.IrisDecorator; import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.math.RNG;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
public class IrisSeaFloorDecorator extends IrisEngineDecorator { public class IrisSeaFloorDecorator extends IrisEngineDecorator {
@@ -35,7 +35,8 @@ public class IrisSeaFloorDecorator extends IrisEngineDecorator {
@BlockCoordinates @BlockCoordinates
@Override @Override
public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max) { public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max) {
IrisDecorator decorator = getDecorator(biome, realX, realZ); RNG rng = getRNG(realX, realZ);
IrisDecorator decorator = getDecorator(rng, biome, realX, realZ);
if (decorator != null) { if (decorator != null) {
if (!decorator.isStacking()) { if (!decorator.isStacking()) {
@@ -44,17 +45,17 @@ public class IrisSeaFloorDecorator extends IrisEngineDecorator {
return; return;
} }
if (height >= 0 || height < getEngine().getHeight()) { if (height >= 0 || height < getEngine().getHeight()) {
data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData())); data.set(x, height, z, decorator.getBlockData100(biome, rng, realX, height, realZ, getData()));
} }
} else { } else {
int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData()); int stack = decorator.getHeight(rng, realX, realZ, getData());
if (decorator.isScaleStack()) { if (decorator.isScaleStack()) {
int maxStack = max - height; int maxStack = max - height;
stack = (int) Math.ceil((double) maxStack * ((double) stack / 100)); stack = (int) Math.ceil((double) maxStack * ((double) stack / 100));
} else stack = Math.min(stack, max - height); } else stack = Math.min(stack, max - height);
if (stack == 1) { if (stack == 1) {
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())); data.set(x, height, z, decorator.getBlockDataForTop(biome, rng, realX, height, realZ, getData()));
return; return;
} }
@@ -66,8 +67,8 @@ public class IrisSeaFloorDecorator extends IrisEngineDecorator {
double threshold = ((double) i) / (stack - 1); double threshold = ((double) i) / (stack - 1);
data.set(x, h, z, threshold >= decorator.getTopThreshold() ? data.set(x, h, z, threshold >= decorator.getTopThreshold() ?
decorator.getBlockDataForTop(biome, getRng(), realX, h, realZ, getData()) : decorator.getBlockDataForTop(biome, rng, realX, h, realZ, getData()) :
decorator.getBlockData100(biome, getRng(), realX, h, realZ, getData())); decorator.getBlockData100(biome, rng, realX, h, realZ, getData()));
} }
} }
} }
@@ -18,13 +18,13 @@
package com.volmit.iris.engine.decorator; package com.volmit.iris.engine.decorator;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorationPart; import com.volmit.iris.engine.object.IrisDecorationPart;
import com.volmit.iris.engine.object.IrisDecorator; import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.math.RNG;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
public class IrisSeaSurfaceDecorator extends IrisEngineDecorator { public class IrisSeaSurfaceDecorator extends IrisEngineDecorator {
@@ -35,22 +35,23 @@ public class IrisSeaSurfaceDecorator extends IrisEngineDecorator {
@BlockCoordinates @BlockCoordinates
@Override @Override
public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max) { public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max) {
IrisDecorator decorator = getDecorator(biome, realX, realZ); RNG rng = getRNG(realX, realZ);
IrisDecorator decorator = getDecorator(rng, biome, realX, realZ);
if (decorator != null) { if (decorator != null) {
if (!decorator.isStacking()) { if (!decorator.isStacking()) {
if (height >= 0 || height < getEngine().getHeight()) { if (height >= 0 || height < getEngine().getHeight()) {
data.set(x, height + 1, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData())); data.set(x, height + 1, z, decorator.getBlockData100(biome, rng, realX, height, realZ, getData()));
} }
} else { } else {
int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData()); int stack = decorator.getHeight(rng, realX, realZ, getData());
if (decorator.isScaleStack()) { if (decorator.isScaleStack()) {
int maxStack = max - height; int maxStack = max - height;
stack = (int) Math.ceil((double) maxStack * ((double) stack / 100)); stack = (int) Math.ceil((double) maxStack * ((double) stack / 100));
} }
if (stack == 1) { if (stack == 1) {
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())); data.set(x, height, z, decorator.getBlockDataForTop(biome, rng, realX, height, realZ, getData()));
return; return;
} }
@@ -62,8 +63,8 @@ public class IrisSeaSurfaceDecorator extends IrisEngineDecorator {
double threshold = ((double) i) / (stack - 1); double threshold = ((double) i) / (stack - 1);
data.set(x, h + 1, z, threshold >= decorator.getTopThreshold() ? data.set(x, h + 1, z, threshold >= decorator.getTopThreshold() ?
decorator.getBlockDataForTop(biome, getRng().nextParallelRNG(i), realX, h, realZ, getData()) : decorator.getBlockDataForTop(biome, rng, realX, h, realZ, getData()) :
decorator.getBlockData100(biome, getRng().nextParallelRNG(i), realX, h, realZ, getData())); decorator.getBlockData100(biome, rng, realX, h, realZ, getData()));
} }
} }
} }
@@ -18,13 +18,13 @@
package com.volmit.iris.engine.decorator; package com.volmit.iris.engine.decorator;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorationPart; import com.volmit.iris.engine.object.IrisDecorationPart;
import com.volmit.iris.engine.object.IrisDecorator; import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.math.RNG;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
public class IrisShoreLineDecorator extends IrisEngineDecorator { public class IrisShoreLineDecorator extends IrisEngineDecorator {
@@ -42,7 +42,8 @@ public class IrisShoreLineDecorator extends IrisEngineDecorator {
Math.round(getComplex().getHeightStream().get(realX, realZ1)) < getComplex().getFluidHeight() || Math.round(getComplex().getHeightStream().get(realX, realZ1)) < getComplex().getFluidHeight() ||
Math.round(getComplex().getHeightStream().get(realX, realZ_1)) < getComplex().getFluidHeight() Math.round(getComplex().getHeightStream().get(realX, realZ_1)) < getComplex().getFluidHeight()
) { ) {
IrisDecorator decorator = getDecorator(biome, realX, realZ); RNG rng = getRNG(realX, realZ);
IrisDecorator decorator = getDecorator(rng, biome, realX, realZ);
if (decorator != null) { if (decorator != null) {
if (!decorator.isForcePlace() && !decorator.getSlopeCondition().isDefault() if (!decorator.isForcePlace() && !decorator.getSlopeCondition().isDefault()
@@ -51,16 +52,16 @@ public class IrisShoreLineDecorator extends IrisEngineDecorator {
} }
if (!decorator.isStacking()) { if (!decorator.isStacking()) {
data.set(x, height + 1, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData())); data.set(x, height + 1, z, decorator.getBlockData100(biome, rng, realX, height, realZ, getData()));
} else { } else {
int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData()); int stack = decorator.getHeight(rng, realX, realZ, getData());
if (decorator.isScaleStack()) { if (decorator.isScaleStack()) {
int maxStack = max - height; int maxStack = max - height;
stack = (int) Math.ceil((double) maxStack * ((double) stack / 100)); stack = (int) Math.ceil((double) maxStack * ((double) stack / 100));
} else stack = Math.min(max - height, stack); } else stack = Math.min(max - height, stack);
if (stack == 1) { if (stack == 1) {
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())); data.set(x, height, z, decorator.getBlockDataForTop(biome, rng, realX, height, realZ, getData()));
return; return;
} }
@@ -68,8 +69,8 @@ public class IrisShoreLineDecorator extends IrisEngineDecorator {
int h = height + i; int h = height + i;
double threshold = ((double) i) / (stack - 1); double threshold = ((double) i) / (stack - 1);
data.set(x, h + 1, z, threshold >= decorator.getTopThreshold() ? data.set(x, h + 1, z, threshold >= decorator.getTopThreshold() ?
decorator.getBlockDataForTop(biome, getRng(), realX, h, realZ, getData()) : decorator.getBlockDataForTop(biome, rng, realX, h, realZ, getData()) :
decorator.getBlockData100(biome, getRng(), realX, h, realZ, getData())); decorator.getBlockData100(biome, rng, realX, h, realZ, getData()));
} }
} }
} }
@@ -19,7 +19,6 @@
package com.volmit.iris.engine.decorator; package com.volmit.iris.engine.decorator;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.InferredType; import com.volmit.iris.engine.object.InferredType;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
@@ -28,11 +27,11 @@ import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.B;
import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.math.RNG;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Bisected; import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing;
import org.bukkit.block.data.type.PointedDripstone; import org.bukkit.block.data.type.PointedDripstone;
public class IrisSurfaceDecorator extends IrisEngineDecorator { public class IrisSurfaceDecorator extends IrisEngineDecorator {
@@ -48,7 +47,8 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
} }
BlockData bd, bdx; BlockData bd, bdx;
IrisDecorator decorator = getDecorator(biome, realX, realZ); RNG rng = getRNG(realX, realZ);
IrisDecorator decorator = getDecorator(rng, biome, realX, realZ);
bdx = data.get(x, height, z); bdx = data.get(x, height, z);
boolean underwater = height < getDimension().getFluidHeight(); boolean underwater = height < getDimension().getFluidHeight();
@@ -59,7 +59,7 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
} }
if (!decorator.isStacking()) { if (!decorator.isStacking()) {
bd = decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()); bd = decorator.getBlockData100(biome, rng, realX, height, realZ, getData());
if (!underwater) { if (!underwater) {
if (!canGoOn(bd, bdx) && (!decorator.isForcePlace() && decorator.getForceBlock() == null)) { if (!canGoOn(bd, bdx) && (!decorator.isForcePlace() && decorator.getForceBlock() == null)) {
@@ -68,12 +68,12 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
} }
if (decorator.getForceBlock() != null) { if (decorator.getForceBlock() != null) {
data.set(x, height, z, fixFaces(decorator.getForceBlock().getBlockData(getData()), x, height, z)); data.set(x, height, z, fixFaces(decorator.getForceBlock().getBlockData(getData()), data, x, z, realX, height, realZ));
} else if (!decorator.isForcePlace()) { } else if (!decorator.isForcePlace()) {
if (decorator.getWhitelist() != null && decorator.getWhitelist().stream().noneMatch(d -> d.getBlockData(getData()).equals(bdx))) { if (decorator.getWhitelist() != null && decorator.getWhitelist().stream().noneMatch(d -> d.getBlockData(getData()).equals(bdx))) {
return; return;
} }
if (decorator.getBlacklist() != null && decorator.getWhitelist().stream().anyMatch(d -> d.getBlockData(getData()).equals(bdx))) { if (decorator.getBlacklist() != null && decorator.getBlacklist().stream().anyMatch(d -> d.getBlockData(getData()).equals(bdx))) {
return; return;
} }
} }
@@ -91,14 +91,14 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
} }
if (B.isAir(data.get(x, height + 1, z))) { if (B.isAir(data.get(x, height + 1, z))) {
data.set(x, height + 1, z, fixFaces(bd, x, height + 1, z)); data.set(x, height + 1, z, fixFaces(bd, data, x, z, realX, height + 1, realZ));
} }
} else { } else {
if (height < getDimension().getFluidHeight()) { if (height < getDimension().getFluidHeight()) {
max = getDimension().getFluidHeight(); max = getDimension().getFluidHeight();
} }
int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData()); int stack = decorator.getHeight(rng, realX, realZ, getData());
if (decorator.isScaleStack()) { if (decorator.isScaleStack()) {
stack = Math.min((int) Math.ceil((double) max * ((double) stack / 100)), decorator.getAbsoluteMaxStack()); stack = Math.min((int) Math.ceil((double) max * ((double) stack / 100)), decorator.getAbsoluteMaxStack());
@@ -107,7 +107,7 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
} }
if (stack == 1) { if (stack == 1) {
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())); data.set(x, height, z, decorator.getBlockDataForTop(biome, rng, realX, height, realZ, getData()));
return; return;
} }
@@ -115,8 +115,8 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
int h = height + i; int h = height + i;
double threshold = ((double) i) / (stack - 1); double threshold = ((double) i) / (stack - 1);
bd = threshold >= decorator.getTopThreshold() ? bd = threshold >= decorator.getTopThreshold() ?
decorator.getBlockDataForTop(biome, getRng(), realX, h, realZ, getData()) : decorator.getBlockDataForTop(biome, rng, realX, h, realZ, getData()) :
decorator.getBlockData100(biome, getRng(), realX, h, realZ, getData()); decorator.getBlockData100(biome, rng, realX, h, realZ, getData());
if (bd == null) { if (bd == null) {
break; break;
@@ -158,24 +158,4 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
} }
} }
} }
private BlockData fixFaces(BlockData b, int x, int y, int z) {
if (B.isVineBlock(b)) {
MultipleFacing data = (MultipleFacing) b.clone();
boolean found = false;
for (BlockFace f : BlockFace.values()) {
if (!f.isCartesian())
continue;
Material m = getEngine().getMantle().get(x + f.getModX(), y + f.getModY(), z + f.getModZ()).getMaterial();
if (m.isSolid()) {
found = true;
data.setFace(f, m.isSolid());
}
}
if (!found)
data.setFace(BlockFace.UP, true);
return data;
}
return b;
}
} }
@@ -42,7 +42,7 @@ import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.context.IrisContext; import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.DataProvider; import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
@@ -80,6 +80,7 @@ import java.awt.Color;
import java.util.Arrays; import java.util.Arrays;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@@ -258,10 +259,8 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
if (B.isUpdatable(data)) { if (B.isUpdatable(data)) {
getMantle().updateBlock(x, y, z); getMantle().updateBlock(x, y, z);
} }
if (data instanceof IrisBlockData d) { if (data instanceof IrisCustomData) {
getMantle().getMantle().set(x, y, z, d.getCustom()); getMantle().getMantle().flag(x >> 4, z >> 4, MantleFlag.CUSTOM, true);
} else {
getMantle().getMantle().remove(x, y, z, Identifier.class);
} }
} }
@@ -611,6 +610,11 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
int getGenerated(); int getGenerated();
@ChunkCoordinates
void addGenerated(int x, int z);
CompletableFuture<Long> getHash32();
default <T> IrisPosition lookForStreamResult(T find, ProceduralStream<T> stream, Function2<T, T, Boolean> matcher, long timeout) { default <T> IrisPosition lookForStreamResult(T find, ProceduralStream<T> stream, Function2<T, T, Boolean> matcher, long timeout) {
AtomicInteger checked = new AtomicInteger(); AtomicInteger checked = new AtomicInteger();
AtomicLong time = new AtomicLong(M.ms()); AtomicLong time = new AtomicLong(M.ms());
@@ -13,6 +13,7 @@ import com.volmit.iris.engine.object.IrisLootTable;
import com.volmit.iris.engine.object.TileData; import com.volmit.iris.engine.object.TileData;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@@ -78,7 +79,11 @@ public class WorldObjectPlacer implements IObjectPlacer {
} }
} }
block.setBlockData(d);
if (d instanceof IrisCustomData data) {
block.setBlockData(data.getBase());
Iris.warn("Tried to place custom block at " + x + ", " + y + ", " + z + " which is not supported!");
} else block.setBlockData(d);
} }
@Override @Override
@@ -25,7 +25,6 @@ import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.placer.WorldObjectPlacer; import com.volmit.iris.engine.framework.placer.WorldObjectPlacer;
import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.object.*;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.data.IrisBlockData;
import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
@@ -155,9 +154,6 @@ public class PlannedStructure {
return v.place(xx, height, zz, placer, options, rng, (b, data) -> { return v.place(xx, height, zz, placer, options, rng, (b, data) -> {
e.set(b.getX(), b.getY(), b.getZ(), v.getLoadKey() + "@" + id); e.set(b.getX(), b.getY(), b.getZ(), v.getLoadKey() + "@" + id);
e.set(b.getX(), b.getY(), b.getZ(), container); e.set(b.getX(), b.getY(), b.getZ(), container);
if (data instanceof IrisBlockData d) {
e.set(b.getX(), b.getY(), b.getZ(), d.getCustom());
}
}, null, getData().getEngine() != null ? getData() : eng.getData()) != -1; }, null, getData().getEngine() != null ? getData() : eng.getData()) != -1;
} }
@@ -20,10 +20,10 @@ package com.volmit.iris.engine.mantle;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.IrisComplex; import com.volmit.iris.engine.IrisComplex;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineTarget; import com.volmit.iris.engine.framework.EngineTarget;
import com.volmit.iris.engine.framework.SeedManager;
import com.volmit.iris.engine.mantle.components.MantleJigsawComponent; import com.volmit.iris.engine.mantle.components.MantleJigsawComponent;
import com.volmit.iris.engine.mantle.components.MantleObjectComponent; import com.volmit.iris.engine.mantle.components.MantleObjectComponent;
import com.volmit.iris.engine.object.IObjectPlacer; import com.volmit.iris.engine.object.IObjectPlacer;
@@ -34,6 +34,7 @@ import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.context.IrisContext; import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
@@ -44,7 +45,6 @@ import com.volmit.iris.util.matter.*;
import com.volmit.iris.util.matter.slices.UpdateMatter; import com.volmit.iris.util.matter.slices.UpdateMatter;
import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.parallel.MultiBurst;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -59,7 +59,9 @@ public interface EngineMantle extends IObjectPlacer {
int getRadius(); int getRadius();
KList<MantleComponent> getComponents(); int getRealRadius();
KList<Pair<KList<MantleComponent>, Integer>> getComponents();
void registerComponent(MantleComponent c); void registerComponent(MantleComponent c);
@@ -103,7 +105,10 @@ public interface EngineMantle extends IObjectPlacer {
@Override @Override
default void set(int x, int y, int z, BlockData d) { default void set(int x, int y, int z, BlockData d) {
getMantle().set(x, y, z, d == null ? AIR : d); if (d instanceof IrisCustomData data) {
getMantle().set(x, y, z, data.getBase());
getMantle().set(x, y, z, data.getCustom());
} else getMantle().set(x, y, z, d == null ? AIR : d);
} }
@Override @Override
@@ -187,39 +192,37 @@ public interface EngineMantle extends IObjectPlacer {
return getEngine().burst(); return getEngine().burst();
} }
default int getRealRadius() {
return (int) Math.ceil(getRadius() / 2D);
}
@ChunkCoordinates @ChunkCoordinates
default void generateMatter(int x, int z, boolean multicore, ChunkContext context) { default void generateMatter(int x, int z, boolean multicore, ChunkContext context) {
synchronized (this) { if (!getEngine().getDimension().isUseMantle()) {
if (!getEngine().getDimension().isUseMantle()) { return;
return; }
}
int s = getRealRadius(); try (MantleWriter writer = getMantle().write(this, x, z, getRadius() * 2)) {
BurstExecutor burst = burst().burst(multicore); var iterator = getComponents().iterator();
MantleWriter writer = getMantle().write(this, x, z, s * 2); while (iterator.hasNext()) {
for (int i = -s; i <= s; i++) { var pair = iterator.next();
for (int j = -s; j <= s; j++) { int radius = pair.getB();
int xx = i + x; boolean last = !iterator.hasNext();
int zz = j + z; BurstExecutor burst = burst().burst(radius * 2 + 1);
burst.queue(() -> { burst.setMulticore(multicore);
IrisContext.touch(getEngine().getContext());
getMantle().raiseFlag(xx, zz, MantleFlag.PLANNED, () -> {
MantleChunk mc = getMantle().getChunk(xx, zz);
for (MantleComponent k : getComponents()) { for (int i = -radius; i <= radius; i++) {
generateMantleComponent(writer, xx, zz, k, mc, context); for (int j = -radius; j <= radius; j++) {
} int xx = x + i;
int zz = z + j;
MantleChunk mc = getMantle().getChunk(xx, zz);
burst.queue(() -> {
IrisContext.touch(getEngine().getContext());
pair.getA().forEach(k -> generateMantleComponent(writer, xx, zz, k, mc, context));
if (last) mc.flag(MantleFlag.PLANNED, true);
}); });
}); }
} }
}
burst.complete(); burst.complete();
}
} }
} }
@@ -29,4 +29,5 @@ import lombok.ToString;
public abstract class IrisMantleComponent implements MantleComponent { public abstract class IrisMantleComponent implements MantleComponent {
private final EngineMantle engineMantle; private final EngineMantle engineMantle;
private final MantleFlag flag; private final MantleFlag flag;
private final int priority;
} }
@@ -26,11 +26,12 @@ import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.BurstExecutor;
import org.jetbrains.annotations.NotNull;
public interface MantleComponent { public interface MantleComponent extends Comparable<MantleComponent> {
default int getRadius() { int getPriority();
return getEngineMantle().getRealRadius();
} int getRadius();
default IrisData getData() { default IrisData getData() {
return getEngineMantle().getData(); return getEngineMantle().getData();
@@ -62,4 +63,9 @@ public interface MantleComponent {
@ChunkCoordinates @ChunkCoordinates
void generateLayer(MantleWriter writer, int x, int z, ChunkContext context); void generateLayer(MantleWriter writer, int x, int z, ChunkContext context);
@Override
default int compareTo(@NotNull MantleComponent o) {
return Integer.compare(getPriority(), o.getPriority());
}
} }
@@ -29,13 +29,13 @@ import com.volmit.iris.engine.object.IrisPosition;
import com.volmit.iris.engine.object.TileData; import com.volmit.iris.engine.object.TileData;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.function.Function3; import com.volmit.iris.util.function.Function3;
import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.mantle.MantleChunk; import com.volmit.iris.util.mantle.MantleChunk;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.Matter; import com.volmit.iris.util.matter.Matter;
import lombok.Data; import lombok.Data;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
@@ -44,7 +44,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
@Data @Data
public class MantleWriter implements IObjectPlacer { public class MantleWriter implements IObjectPlacer, AutoCloseable {
private final EngineMantle engineMantle; private final EngineMantle engineMantle;
private final Mantle mantle; private final Mantle mantle;
private final KMap<Long, MantleChunk> cachedChunks; private final KMap<Long, MantleChunk> cachedChunks;
@@ -62,7 +62,7 @@ public class MantleWriter implements IObjectPlacer {
for (int i = -radius; i <= radius; i++) { for (int i = -radius; i <= radius; i++) {
for (int j = -radius; j <= radius; j++) { for (int j = -radius; j <= radius; j++) {
cachedChunks.put(Cache.key(i + x, j + z), mantle.getChunk(i + x, j + z)); cachedChunks.put(Cache.key(i + x, j + z), mantle.getChunk(i + x, j + z).use());
} }
} }
} }
@@ -167,7 +167,10 @@ public class MantleWriter implements IObjectPlacer {
@Override @Override
public void set(int x, int y, int z, BlockData d) { public void set(int x, int y, int z, BlockData d) {
setData(x, y, z, d); if (d instanceof IrisCustomData data) {
setData(x, y, z, data.getBase());
setData(x, y, z, data.getCustom());
} else setData(x, y, z, d);
} }
@Override @Override
@@ -633,4 +636,12 @@ public class MantleWriter implements IObjectPlacer {
return cx >= this.x - radius && cx <= this.x + radius return cx >= this.x - radius && cx <= this.x + radius
&& cz >= this.z - radius && cz <= this.z + radius; && cz >= this.z - radius && cz <= this.z + radius;
} }
@Override
public void close() {
cachedChunks.values().removeIf(c -> {
c.release();
return true;
});
}
} }
@@ -29,10 +29,14 @@ import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import lombok.Getter;
@Getter
public class MantleCarvingComponent extends IrisMantleComponent { public class MantleCarvingComponent extends IrisMantleComponent {
private final int radius = computeRadius();
public MantleCarvingComponent(EngineMantle engineMantle) { public MantleCarvingComponent(EngineMantle engineMantle) {
super(engineMantle, MantleFlag.CARVED); super(engineMantle, MantleFlag.CARVED, 0);
} }
@Override @Override
@@ -56,4 +60,21 @@ public class MantleCarvingComponent extends IrisMantleComponent {
private void carve(IrisCarving carving, MantleWriter writer, RNG rng, int cx, int cz) { private void carve(IrisCarving carving, MantleWriter writer, RNG rng, int cx, int cz) {
carving.doCarving(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4); carving.doCarving(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4);
} }
private int computeRadius() {
var dimension = getDimension();
int max = 0;
max = Math.max(max, dimension.getCarving().getMaxRange(getData()));
for (var i : dimension.getAllRegions(this::getData)) {
max = Math.max(max, i.getCarving().getMaxRange(getData()));
}
for (var i : dimension.getAllBiomes(this::getData)) {
max = Math.max(max, i.getCarving().getMaxRange(getData()));
}
return max;
}
} }
@@ -29,10 +29,14 @@ import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import lombok.Getter;
@Getter
public class MantleFluidBodyComponent extends IrisMantleComponent { public class MantleFluidBodyComponent extends IrisMantleComponent {
private final int radius = computeRadius();
public MantleFluidBodyComponent(EngineMantle engineMantle) { public MantleFluidBodyComponent(EngineMantle engineMantle) {
super(engineMantle, MantleFlag.FLUID_BODIES); super(engineMantle, MantleFlag.FLUID_BODIES, 0);
} }
@Override @Override
@@ -56,4 +60,20 @@ public class MantleFluidBodyComponent extends IrisMantleComponent {
private void generate(IrisFluidBodies bodies, MantleWriter writer, RNG rng, int cx, int cz) { private void generate(IrisFluidBodies bodies, MantleWriter writer, RNG rng, int cx, int cz) {
bodies.generate(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4); bodies.generate(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4);
} }
private int computeRadius() {
int max = 0;
max = Math.max(max, getDimension().getFluidBodies().getMaxRange(getData()));
for (IrisRegion i : getDimension().getAllRegions(this::getData)) {
max = Math.max(max, i.getFluidBodies().getMaxRange(getData()));
}
for (IrisBiome i : getDimension().getAllBiomes(this::getData)) {
max = Math.max(max, i.getFluidBodies().getMaxRange(getData()));
}
return max;
}
} }
@@ -34,15 +34,18 @@ import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.slices.container.JigsawStructuresContainer; import com.volmit.iris.util.matter.slices.container.JigsawStructuresContainer;
import com.volmit.iris.util.noise.CNG; import com.volmit.iris.util.noise.CNG;
import lombok.Getter;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
public class MantleJigsawComponent extends IrisMantleComponent { public class MantleJigsawComponent extends IrisMantleComponent {
@Getter
private final int radius = computeRadius();
private final CNG cng; private final CNG cng;
public MantleJigsawComponent(EngineMantle engineMantle) { public MantleJigsawComponent(EngineMantle engineMantle) {
super(engineMantle, MantleFlag.JIGSAW); super(engineMantle, MantleFlag.JIGSAW, 1);
cng = NoiseStyle.STATIC.create(new RNG(jigsaw())); cng = NoiseStyle.STATIC.create(new RNG(jigsaw()));
} }
@@ -87,8 +90,10 @@ public class MantleJigsawComponent extends IrisMantleComponent {
private boolean placeStructures(MantleWriter writer, long seed, int x, int z, KList<IrisJigsawStructurePlacement> structures, private boolean placeStructures(MantleWriter writer, long seed, int x, int z, KList<IrisJigsawStructurePlacement> structures,
KSet<Position2> cachedRegions, KMap<String, KSet<Position2>> cache, KMap<Position2, Double> distanceCache) { KSet<Position2> cachedRegions, KMap<String, KSet<Position2>> cache, KMap<Position2, Double> distanceCache) {
IrisJigsawStructurePlacement i = pick(structures, seed, x, z); IrisJigsawStructurePlacement i = pick(structures, seed, x, z);
if (i == null || checkMinDistances(i.collectMinDistances(), x, z, cachedRegions, cache, distanceCache)) try {
return false; if (i == null || checkMinDistances(i.collectMinDistances(), x, z, cachedRegions, cache, distanceCache))
return false;
} catch (Throwable ignored) {}
RNG rng = new RNG(seed); RNG rng = new RNG(seed);
IrisPosition position = new IrisPosition((x << 4) + rng.nextInt(15), 0, (z << 4) + rng.nextInt(15)); IrisPosition position = new IrisPosition((x << 4) + rng.nextInt(15), 0, (z << 4) + rng.nextInt(15));
IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(i.getStructure()); IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(i.getStructure());
@@ -156,7 +161,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
@ChunkCoordinates @ChunkCoordinates
private IrisJigsawStructurePlacement pick(List<IrisJigsawStructurePlacement> structures, long seed, int x, int z) { private IrisJigsawStructurePlacement pick(List<IrisJigsawStructurePlacement> structures, long seed, int x, int z) {
return IRare.pick(structures.stream() return IRare.pick(structures.stream()
.filter(p -> p.shouldPlace(getDimension().getJigsawStructureDivisor(), jigsaw(), x, z)) .filter(p -> p.shouldPlace(getData(), getDimension().getJigsawStructureDivisor(), jigsaw(), x, z))
.toList(), new RNG(seed).nextDouble()); .toList(), new RNG(seed).nextDouble());
} }
@@ -168,4 +173,29 @@ public class MantleJigsawComponent extends IrisMantleComponent {
private long jigsaw() { private long jigsaw() {
return getEngineMantle().getEngine().getSeedManager().getJigsaw(); return getEngineMantle().getEngine().getSeedManager().getJigsaw();
} }
private int computeRadius() {
var dimension = getDimension();
KSet<String> structures = new KSet<>();
for (var placement : dimension.getJigsawStructures()) {
structures.add(placement.getStructure());
}
for (var region : dimension.getAllRegions(this::getData)) {
for (var placement : region.getJigsawStructures()) {
structures.add(placement.getStructure());
}
}
for (var biome : dimension.getAllBiomes(this::getData)) {
for (var placement : biome.getJigsawStructures()) {
structures.add(placement.getStructure());
}
}
int max = 0;
for (var structure : structures) {
max = Math.max(max, getData().getJigsawStructureLoader().load(structure).getMaxDimension());
}
return max;
}
} }
@@ -24,23 +24,34 @@ import com.volmit.iris.engine.mantle.EngineMantle;
import com.volmit.iris.engine.mantle.IrisMantleComponent; import com.volmit.iris.engine.mantle.IrisMantleComponent;
import com.volmit.iris.engine.mantle.MantleWriter; import com.volmit.iris.engine.mantle.MantleWriter;
import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.object.*;
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.collection.KSet;
import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisBlockData;
import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.MatterStructurePOI; import com.volmit.iris.util.matter.MatterStructurePOI;
import com.volmit.iris.util.noise.CNG; import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.noise.NoiseType; import com.volmit.iris.util.noise.NoiseType;
import com.volmit.iris.util.parallel.BurstExecutor;
import lombok.Getter;
import org.bukkit.util.BlockVector;
import java.io.IOException;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
@Getter
public class MantleObjectComponent extends IrisMantleComponent { public class MantleObjectComponent extends IrisMantleComponent {
private final int radius = computeRadius();
public MantleObjectComponent(EngineMantle engineMantle) { public MantleObjectComponent(EngineMantle engineMantle) {
super(engineMantle, MantleFlag.OBJECT); super(engineMantle, MantleFlag.OBJECT, 1);
} }
@Override @Override
@@ -104,9 +115,6 @@ public class MantleObjectComponent extends IrisMantleComponent {
if (objectPlacement.isDolphinTarget() && objectPlacement.isUnderwater() && B.isStorageChest(data)) { if (objectPlacement.isDolphinTarget() && objectPlacement.isUnderwater() && B.isStorageChest(data)) {
writer.setData(b.getX(), b.getY(), b.getZ(), MatterStructurePOI.BURIED_TREASURE); writer.setData(b.getX(), b.getY(), b.getZ(), MatterStructurePOI.BURIED_TREASURE);
} }
if (data instanceof IrisBlockData d) {
writer.setData(b.getX(), b.getY(), b.getZ(), d.getCustom());
}
}, null, getData()); }, null, getData());
} }
} }
@@ -146,4 +154,112 @@ public class MantleObjectComponent extends IrisMantleComponent {
return v; return v;
} }
private int computeRadius() {
var dimension = getDimension();
AtomicInteger xg = new AtomicInteger();
AtomicInteger zg = new AtomicInteger();
KSet<String> objects = new KSet<>();
KMap<IrisObjectScale, KList<String>> scalars = new KMap<>();
for (var region : dimension.getAllRegions(this::getData)) {
for (var j : region.getObjects()) {
if (j.getScale().canScaleBeyond()) {
scalars.put(j.getScale(), j.getPlace());
} else {
objects.addAll(j.getPlace());
}
}
}
for (var biome : dimension.getAllBiomes(this::getData)) {
for (var j : biome.getObjects()) {
if (j.getScale().canScaleBeyond()) {
scalars.put(j.getScale(), j.getPlace());
} else {
objects.addAll(j.getPlace());
}
}
}
BurstExecutor e = getEngineMantle().getTarget().getBurster().burst(objects.size());
KMap<String, BlockVector> sizeCache = new KMap<>();
for (String i : objects) {
e.queue(() -> {
try {
BlockVector bv = sizeCache.computeIfAbsent(i, (k) -> {
try {
return IrisObject.sampleSize(getData().getObjectLoader().findFile(i));
} catch (IOException ex) {
Iris.reportError(ex);
ex.printStackTrace();
}
return null;
});
if (bv == null) {
throw new RuntimeException();
}
if (Math.max(bv.getBlockX(), bv.getBlockZ()) > 128) {
Iris.warn("Object " + i + " has a large size (" + bv + ") and may increase memory usage!");
}
synchronized (xg) {
xg.getAndSet(Math.max(bv.getBlockX(), xg.get()));
}
synchronized (zg) {
zg.getAndSet(Math.max(bv.getBlockZ(), zg.get()));
}
} catch (Throwable ed) {
Iris.reportError(ed);
}
});
}
for (Map.Entry<IrisObjectScale, KList<String>> entry : scalars.entrySet()) {
double ms = entry.getKey().getMaximumScale();
for (String j : entry.getValue()) {
e.queue(() -> {
try {
BlockVector bv = sizeCache.computeIfAbsent(j, (k) -> {
try {
return IrisObject.sampleSize(getData().getObjectLoader().findFile(j));
} catch (IOException ioException) {
Iris.reportError(ioException);
ioException.printStackTrace();
}
return null;
});
if (bv == null) {
throw new RuntimeException();
}
if (Math.max(bv.getBlockX(), bv.getBlockZ()) > 128) {
Iris.warn("Object " + j + " has a large size (" + bv + ") and may increase memory usage! (Object scaled up to " + Form.pc(ms, 2) + ")");
}
synchronized (xg) {
xg.getAndSet((int) Math.max(Math.ceil(bv.getBlockX() * ms), xg.get()));
}
synchronized (zg) {
zg.getAndSet((int) Math.max(Math.ceil(bv.getBlockZ() * ms), zg.get()));
}
} catch (Throwable ee) {
Iris.reportError(ee);
}
});
}
}
e.complete();
return Math.max(xg.get(), zg.get());
}
} }
@@ -25,10 +25,7 @@ import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineMode; import com.volmit.iris.engine.framework.EngineMode;
import com.volmit.iris.engine.framework.EngineStage; import com.volmit.iris.engine.framework.EngineStage;
import com.volmit.iris.engine.framework.IrisEngineMode; import com.volmit.iris.engine.framework.IrisEngineMode;
import com.volmit.iris.engine.modifier.IrisCarveModifier; import com.volmit.iris.engine.modifier.*;
import com.volmit.iris.engine.modifier.IrisDepositModifier;
import com.volmit.iris.engine.modifier.IrisPerfectionModifier;
import com.volmit.iris.engine.modifier.IrisPostModifier;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
public class ModeOverworld extends IrisEngineMode implements EngineMode { public class ModeOverworld extends IrisEngineMode implements EngineMode {
@@ -41,6 +38,7 @@ public class ModeOverworld extends IrisEngineMode implements EngineMode {
var post = new IrisPostModifier(getEngine()); var post = new IrisPostModifier(getEngine());
var deposit = new IrisDepositModifier(getEngine()); var deposit = new IrisDepositModifier(getEngine());
var perfection = new IrisPerfectionModifier(getEngine()); var perfection = new IrisPerfectionModifier(getEngine());
var custom = new IrisCustomModifier(getEngine());
EngineStage sBiome = (x, z, k, p, m, c) -> biome.actuate(x, z, p, m, c); EngineStage sBiome = (x, z, k, p, m, c) -> biome.actuate(x, z, p, m, c);
EngineStage sGenMatter = (x, z, k, p, m, c) -> generateMatter(x >> 4, z >> 4, m, c); EngineStage sGenMatter = (x, z, k, p, m, c) -> generateMatter(x >> 4, z >> 4, m, c);
EngineStage sTerrain = (x, z, k, p, m, c) -> terrain.actuate(x, z, k, m, c); EngineStage sTerrain = (x, z, k, p, m, c) -> terrain.actuate(x, z, k, m, c);
@@ -50,6 +48,7 @@ public class ModeOverworld extends IrisEngineMode implements EngineMode {
EngineStage sPost = (x, z, k, p, m, c) -> post.modify(x, z, k, m, c); EngineStage sPost = (x, z, k, p, m, c) -> post.modify(x, z, k, m, c);
EngineStage sInsertMatter = (x, z, K, p, m, c) -> getMantle().insertMatter(x >> 4, z >> 4, BlockData.class, K, m); EngineStage sInsertMatter = (x, z, K, p, m, c) -> getMantle().insertMatter(x >> 4, z >> 4, BlockData.class, K, m);
EngineStage sPerfection = (x, z, k, p, m, c) -> perfection.modify(x, z, k, m, c); EngineStage sPerfection = (x, z, k, p, m, c) -> perfection.modify(x, z, k, m, c);
EngineStage sCustom = (x, z, k, p, m, c) -> custom.modify(x, z, k, m, c);
registerStage(burst( registerStage(burst(
sGenMatter, sGenMatter,
@@ -65,6 +64,6 @@ public class ModeOverworld extends IrisEngineMode implements EngineMode {
sDecorant sDecorant
)); ));
registerStage(sPerfection); registerStage(sPerfection);
registerStage(sCustom);
} }
} }
@@ -57,7 +57,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
public void onModify(int x, int z, Hunk<BlockData> output, boolean multicore, ChunkContext context) { public void onModify(int x, int z, Hunk<BlockData> output, boolean multicore, ChunkContext context) {
PrecisionStopwatch p = PrecisionStopwatch.start(); PrecisionStopwatch p = PrecisionStopwatch.start();
Mantle mantle = getEngine().getMantle().getMantle(); Mantle mantle = getEngine().getMantle().getMantle();
MantleChunk mc = getEngine().getMantle().getMantle().getChunk(x, z); MantleChunk mc = getEngine().getMantle().getMantle().getChunk(x, z).use();
KMap<Long, KList<Integer>> positions = new KMap<>(); KMap<Long, KList<Integer>> positions = new KMap<>();
KMap<IrisPosition, MatterCavern> walls = new KMap<>(); KMap<IrisPosition, MatterCavern> walls = new KMap<>();
Consumer4<Integer, Integer, Integer, MatterCavern> iterator = (xx, yy, zz, c) -> { Consumer4<Integer, Integer, Integer, MatterCavern> iterator = (xx, yy, zz, c) -> {
@@ -166,6 +166,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
}); });
getEngine().getMetrics().getDeposit().put(p.getMilliseconds()); getEngine().getMetrics().getDeposit().put(p.getMilliseconds());
mc.release();
} }
private void processZone(Hunk<BlockData> output, MantleChunk mc, Mantle mantle, CaveZone zone, int rx, int rz, int xx, int zz) { private void processZone(Hunk<BlockData> output, MantleChunk mc, Mantle mantle, CaveZone zone, int rx, int rz, int xx, int zz) {
@@ -211,14 +212,6 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
biome.setInferredType(InferredType.CAVE); biome.setInferredType(InferredType.CAVE);
for (IrisDecorator i : biome.getDecorators()) {
if (i.getPartOf().equals(IrisDecorationPart.NONE) && B.isSolid(output.get(rx, zone.getFloor() - 1, rz))) {
decorant.getSurfaceDecorator().decorate(rx, rz, xx, xx, xx, zz, zz, zz, output, biome, zone.getFloor() - 1, zone.airThickness());
} else if (i.getPartOf().equals(IrisDecorationPart.CEILING) && B.isSolid(output.get(rx, zone.getCeiling() + 1, rz))) {
decorant.getCeilingDecorator().decorate(rx, rz, xx, xx, xx, zz, zz, zz, output, biome, zone.getCeiling(), zone.airThickness());
}
}
KList<BlockData> blocks = biome.generateLayers(getDimension(), xx, zz, rng, 3, zone.floor, getData(), getComplex()); KList<BlockData> blocks = biome.generateLayers(getDimension(), xx, zz, rng, 3, zone.floor, getData(), getComplex());
for (int i = 0; i < zone.floor - 1; i++) { for (int i = 0; i < zone.floor - 1; i++) {
@@ -260,6 +253,14 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
output.set(rx, zone.ceiling + i + 1, rz, b); output.set(rx, zone.ceiling + i + 1, rz, b);
} }
} }
for (IrisDecorator i : biome.getDecorators()) {
if (i.getPartOf().equals(IrisDecorationPart.NONE) && B.isSolid(output.get(rx, zone.getFloor() - 1, rz))) {
decorant.getSurfaceDecorator().decorate(rx, rz, xx, xx, xx, zz, zz, zz, output, biome, zone.getFloor() - 1, zone.airThickness());
} else if (i.getPartOf().equals(IrisDecorationPart.CEILING) && B.isSolid(output.get(rx, zone.getCeiling() + 1, rz))) {
decorant.getCeilingDecorator().decorate(rx, rz, xx, xx, xx, zz, zz, zz, output, biome, zone.getCeiling(), zone.airThickness());
}
}
} }
@Data @Data
@@ -0,0 +1,43 @@
package com.volmit.iris.engine.modifier;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineAssignedModifier;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import org.bukkit.block.data.BlockData;
public class IrisCustomModifier extends EngineAssignedModifier<BlockData> {
public IrisCustomModifier(Engine engine) {
super(engine, "Custom");
}
@Override
public void onModify(int x, int z, Hunk<BlockData> output, boolean multicore, ChunkContext context) {
var mc = getEngine().getMantle().getMantle().getChunk(x >> 4, z >> 4);
if (!mc.isFlagged(MantleFlag.CUSTOM_ACTIVE)) return;
mc.use();
BurstExecutor burst = MultiBurst.burst.burst(output.getHeight());
burst.setMulticore(multicore);
for (int y = 0; y < output.getHeight(); y++) {
int finalY = y;
burst.queue(() -> {
for (int rX = 0; rX < output.getWidth(); rX++) {
for (int rZ = 0; rZ < output.getDepth(); rZ++) {
BlockData b = output.get(rX, finalY, rZ);
if (!(b instanceof IrisCustomData d)) continue;
mc.getOrCreate(finalY >> 4)
.slice(Identifier.class)
.set(rX, finalY & 15, rZ, d.getCustom());
output.set(rX, finalY, rZ, d.getBase());
}
}
});
}
burst.complete();
mc.release();
}
}
@@ -20,10 +20,7 @@ package com.volmit.iris.engine.modifier;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineAssignedModifier; import com.volmit.iris.engine.framework.EngineAssignedModifier;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.object.IrisDepositGenerator;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.HeightMap; import com.volmit.iris.util.data.HeightMap;
@@ -45,30 +42,26 @@ public class IrisDepositModifier extends EngineAssignedModifier<BlockData> {
@Override @Override
public void onModify(int x, int z, Hunk<BlockData> output, boolean multicore, ChunkContext context) { public void onModify(int x, int z, Hunk<BlockData> output, boolean multicore, ChunkContext context) {
PrecisionStopwatch p = PrecisionStopwatch.start(); PrecisionStopwatch p = PrecisionStopwatch.start();
generateDeposits(rng, output, Math.floorDiv(x, 16), Math.floorDiv(z, 16), multicore, context); generateDeposits(output, Math.floorDiv(x, 16), Math.floorDiv(z, 16), multicore, context);
getEngine().getMetrics().getDeposit().put(p.getMilliseconds()); getEngine().getMetrics().getDeposit().put(p.getMilliseconds());
} }
public void generateDeposits(RNG rx, Hunk<BlockData> terrain, int x, int z, boolean multicore, ChunkContext context) { public void generateDeposits(Hunk<BlockData> terrain, int x, int z, boolean multicore, ChunkContext context) {
RNG ro = rx.nextParallelRNG(x * x).nextParallelRNG(z * z);
IrisRegion region = context.getRegion().get(7, 7); IrisRegion region = context.getRegion().get(7, 7);
IrisBiome biome = context.getBiome().get(7, 7); IrisBiome biome = context.getBiome().get(7, 7);
BurstExecutor burst = burst().burst(multicore); BurstExecutor burst = burst().burst(multicore);
long seed = x * 341873128712L + z * 132897987541L;
for (IrisDepositGenerator k : getDimension().getDeposits()) { for (IrisDepositGenerator k : getDimension().getDeposits()) {
burst.queue(() -> generate(k, terrain, ro, x, z, false, context)); burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(seed), x, z, false, context));
} }
for (IrisDepositGenerator k : region.getDeposits()) { for (IrisDepositGenerator k : region.getDeposits()) {
for (int l = 0; l < ro.i(k.getMinPerChunk(), k.getMaxPerChunk()); l++) { burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(seed), x, z, false, context));
burst.queue(() -> generate(k, terrain, ro, x, z, false, context));
}
} }
for (IrisDepositGenerator k : biome.getDeposits()) { for (IrisDepositGenerator k : biome.getDeposits()) {
for (int l = 0; l < ro.i(k.getMinPerChunk(), k.getMaxPerChunk()); l++) { burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(seed), x, z, false, context));
burst.queue(() -> generate(k, terrain, ro, x, z, false, context));
}
} }
burst.complete(); burst.complete();
} }
@@ -78,45 +71,48 @@ public class IrisDepositModifier extends EngineAssignedModifier<BlockData> {
} }
public void generate(IrisDepositGenerator k, Hunk<BlockData> data, RNG rng, int cx, int cz, boolean safe, HeightMap he, ChunkContext context) { public void generate(IrisDepositGenerator k, Hunk<BlockData> data, RNG rng, int cx, int cz, boolean safe, HeightMap he, ChunkContext context) {
for (int l = 0; l < rng.i(k.getMinPerChunk(), k.getMaxPerChunk()); l++) { if (k.getSpawnChance() < rng.d())
return;
for (int l = 0; l < rng.i(k.getMinPerChunk(), k.getMaxPerChunk() + 1); l++) {
if (k.getPerClumpSpawnChance() < rng.d())
continue;
IrisObject clump = k.getClump(rng, getData()); IrisObject clump = k.getClump(rng, getData());
int af = (int) Math.floor(clump.getW() / 2D); int dim = clump.getW();
int bf = (int) Math.floor(16D - (clump.getW() / 2D)); int min = dim / 2;
int max = (int) (16D - dim / 2D);
if (af > bf || af < 0 || bf > 15) { if (min > max || min < 0 || max > 15) {
af = 6; min = 6;
bf = 9; max = 9;
} }
af = Math.max(af - 1, 0); int x = rng.i(min, max + 1);
int x = rng.i(af, bf); int z = rng.i(min, max + 1);
int z = rng.i(af, bf);
int height = (he != null ? he.getHeight((cx << 4) + x, (cz << 4) + z) : (int) (Math.round( int height = (he != null ? he.getHeight((cx << 4) + x, (cz << 4) + z) : (int) (Math.round(
context.getHeight().get(x, z) context.getHeight().get(x, z)
))) - 7; ))) - 7;
if (height <= 0) { if (height <= 0)
return; continue;
}
int i = Math.max(0, k.getMinHeight()); int minY = Math.max(0, k.getMinHeight());
// TODO: WARNING HEIGHT // TODO: WARNING HEIGHT
int a = Math.min(height, Math.min(getEngine().getHeight(), k.getMaxHeight())); int maxY = Math.min(height, Math.min(getEngine().getHeight(), k.getMaxHeight()));
if (i >= a) { if (minY >= maxY)
return; continue;
}
int h = rng.i(i, a); int y = rng.i(minY, maxY + 1);
if (h > k.getMaxHeight() || h < k.getMinHeight() || h > height - 2) { if (y > k.getMaxHeight() || y < k.getMinHeight() || y > height - 2)
return; continue;
}
for (BlockVector j : clump.getBlocks().keySet()) { for (BlockVector j : clump.getBlocks().keySet()) {
int nx = j.getBlockX() + x; int nx = j.getBlockX() + x;
int ny = j.getBlockY() + h; int ny = j.getBlockY() + y;
int nz = j.getBlockZ() + z; int nz = j.getBlockZ() + z;
if (ny > height || nx > 15 || nx < 0 || ny > getEngine().getHeight() || ny < 0 || nz < 0 || nz > 15) { if (ny > height || nx > 15 || nx < 0 || ny > getEngine().getHeight() || ny < 0 || nz < 0 || nz > 15) {
@@ -200,7 +200,7 @@ public class IrisBiome extends IrisRegistrant implements IRare {
KMap<String, Integer> l = new KMap<>(); KMap<String, Integer> l = new KMap<>();
for (IrisBiomeGeneratorLink i : getGenerators()) { for (IrisBiomeGeneratorLink i : getGenerators()) {
l.put(i.getGenerator(), i.getMax(engine)); l.put(i.getGenerator(), i.getMax());
} }
@@ -216,7 +216,7 @@ public class IrisBiome extends IrisRegistrant implements IRare {
KMap<String, Integer> l = new KMap<>(); KMap<String, Integer> l = new KMap<>();
for (IrisBiomeGeneratorLink i : getGenerators()) { for (IrisBiomeGeneratorLink i : getGenerators()) {
l.put(i.getGenerator(), i.getMin(engine)); l.put(i.getGenerator(), i.getMin());
} }
return l; return l;
@@ -457,7 +457,7 @@ public class IrisBiome extends IrisRegistrant implements IRare {
int maxHeight = 0; int maxHeight = 0;
for (IrisBiomeGeneratorLink i : getGenerators()) { for (IrisBiomeGeneratorLink i : getGenerators()) {
maxHeight += i.getMax(engine); maxHeight += i.getMax();
} }
return maxHeight; return maxHeight;
@@ -470,7 +470,7 @@ public class IrisBiome extends IrisRegistrant implements IRare {
int maxHeight = 0; int maxHeight = 0;
for (IrisBiomeGeneratorLink i : getGenerators()) { for (IrisBiomeGeneratorLink i : getGenerators()) {
maxHeight += i.getMax(engine); maxHeight += i.getMax();
} }
int gg = 0; int gg = 0;
@@ -18,9 +18,7 @@
package com.volmit.iris.engine.object; package com.volmit.iris.engine.object;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.util.data.DataProvider; import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.interpolation.IrisInterpolation; import com.volmit.iris.util.interpolation.IrisInterpolation;
@@ -39,18 +37,16 @@ public class IrisBiomeGeneratorLink {
@RegistryListResource(IrisGenerator.class) @RegistryListResource(IrisGenerator.class)
@Desc("The generator id") @Desc("The generator id")
private String generator = "default"; private String generator = "default";
@DependsOn({ "min", "max" }) @DependsOn({"min", "max"})
@Required @Required
@MinNumber(-2032) // TODO: WARNING HEIGHT @MinNumber(-2032) // TODO: WARNING HEIGHT
@MaxNumber(2032) // TODO: WARNING HEIGHT @MaxNumber(2032) // TODO: WARNING HEIGHT
@Desc("The min block value (value + fluidHeight)") @Desc("The min block value (value + fluidHeight)")
@Getter(AccessLevel.NONE)
private int min = 0; private int min = 0;
@DependsOn({ "min", "max" }) @DependsOn({"min", "max"})
@Required @Required
@MinNumber(-2032) // TODO: WARNING HEIGHT @MinNumber(-2032) // TODO: WARNING HEIGHT
@MaxNumber(2032) // TODO: WARNING HEIGHT @MaxNumber(2032) // TODO: WARNING HEIGHT
@Getter(AccessLevel.NONE)
@Desc("The max block value (value + fluidHeight)") @Desc("The max block value (value + fluidHeight)")
private int max = 0; private int max = 0;
@@ -66,70 +62,6 @@ public class IrisBiomeGeneratorLink {
}); });
} }
private int[] getBiomeGeneratorsRaw(Engine engine) {
int max = engine.getDimension().getMinHeight();
int min = engine.getDimension().getMaxHeight();
for (IrisBiome biome : engine.getAllBiomes()) {
for (IrisBiomeGeneratorLink i : biome.getGenerators()) {
int biomeRawMax = i.getMaxRaw();
int biomeRawMin = i.getMinRaw();
if (max < biomeRawMax)
max = biomeRawMax;
if (min > biomeRawMin)
min = biomeRawMin;
}
}
return new int[] { min, max };
}
private int calculateHeight(Engine engine, int option) {
int dmx = engine.getDimension().getMaxHeight();
int dmn = engine.getDimension().getMinHeight();
int[] heights = getBiomeGeneratorsRaw(engine);
int gmx = heights[1];
int gmn = heights[0];
int mx = getMaxRaw();
int mn = getMinRaw();
if (engine.getDimension().isSmartVanillaHeight()) {
if (mx > 0)
mx = Math.min((int) (((float) mx / (float) gmx) * 300.0f), 300);
if (mx < 0)
mx = Math.min((int) (((float) mx / (float) gmn) * 300.0f), 56);
if (mn > 0)
mn = Math.min((int) (((float) mn / (float) gmx) * 300.0f), 300);
if (mn < 0)
mn = Math.min((int) (((float) mn / (float) gmn) * 300.0f), 56);
}
if (option == 1) {
return mx;
}
if (option == 0) {
return mn;
}
Iris.error("Fatal Generator error!");
return 0;
}
public int getMax(Engine engine) {
return calculateHeight(engine, 1);
}
public int getMin(Engine engine) {
return calculateHeight(engine, 0);
}
private int getMaxRaw() {
return max;
}
private int getMinRaw() {
return min;
}
public double getHeight(DataProvider xg, double x, double z, long seed) { public double getHeight(DataProvider xg, double x, double z, long seed) {
double g = getCachedGenerator(xg).getHeight(x, z, seed); double g = getCachedGenerator(xg).getHeight(x, z, seed);
g = g < 0 ? 0 : g; g = g < 0 ? 0 : g;
@@ -0,0 +1,77 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.AutoClosing;
import com.volmit.iris.util.misc.ServerProperties;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
import java.util.List;
import static com.volmit.iris.Iris.instance;
public class IrisContextInjector implements Listener {
@Getter
private static boolean missingDimensionTypes = false;
private AutoClosing autoClosing = null;
private final int totalWorlds;
private int worldCounter = 0;
public IrisContextInjector() {
if (!Bukkit.getWorlds().isEmpty()) {
totalWorlds = 0;
return;
}
String levelName = ServerProperties.LEVEL_NAME;
List<String> irisWorlds = irisWorlds();
boolean overworld = irisWorlds.contains(levelName);
boolean nether = irisWorlds.contains(levelName + "_nether");
boolean end = irisWorlds.contains(levelName + "_end");
int i = 1;
if (Bukkit.getAllowNether()) i++;
if (Bukkit.getAllowEnd()) i++;
if (INMS.get().missingDimensionTypes(overworld, nether, end)) {
missingDimensionTypes = true;
totalWorlds = 0;
return;
}
if (overworld || nether || end) {
var pair = INMS.get().injectUncached(overworld, nether, end);
i += pair.getA() - 3;
autoClosing = pair.getB();
}
totalWorlds = i;
instance.registerListener(this);
}
@EventHandler
public void on(WorldInitEvent event) {
if (++worldCounter < totalWorlds) return;
if (autoClosing != null) {
autoClosing.close();
autoClosing = null;
}
instance.unregisterListener(this);
}
private List<String> irisWorlds() {
var config = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML);
ConfigurationSection section = config.getConfigurationSection("worlds");
if (section == null) return List.of();
return section.getKeys(false)
.stream()
.filter(k -> section.getString(k + ".generator", "").startsWith("Iris"))
.toList();
}
}
@@ -22,13 +22,14 @@ import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.util.BlockVector;
@Snippet("deposit") @Snippet("deposit")
@Accessors(chain = true) @Accessors(chain = true)
@@ -69,6 +70,14 @@ public class IrisDepositGenerator {
@MaxNumber(2048) @MaxNumber(2048)
@Desc("The minimum amount of clumps per chunk") @Desc("The minimum amount of clumps per chunk")
private int minPerChunk = 0; private int minPerChunk = 0;
@MinNumber(0)
@MaxNumber(1)
@Desc("The change of the deposit spawning in a chunk")
private double spawnChance = 1;
@MinNumber(0)
@MaxNumber(1)
@Desc("The change of the a clump spawning in a chunk")
private double perClumpSpawnChance = 1;
@Required @Required
@ArrayType(min = 1, type = IrisBlockData.class) @ArrayType(min = 1, type = IrisBlockData.class)
@Desc("The palette of blocks to be used in this deposit generator") @Desc("The palette of blocks to be used in this deposit generator")
@@ -90,35 +99,62 @@ public class IrisDepositGenerator {
return objectsf; return objectsf;
}); });
return objects.get(rng.i(0, objects.size() - 1)); return objects.get(rng.i(0, objects.size()));
} }
public int getMaxDimension() { public int getMaxDimension() {
return Math.min(11, (int) Math.round(Math.pow(maxSize, 1D / 3D))); return Math.min(11, (int) Math.ceil(Math.cbrt(maxSize)));
} }
private IrisObject generateClumpObject(RNG rngv, IrisData rdata) { private IrisObject generateClumpObject(RNG rngv, IrisData rdata) {
int s = rngv.i(minSize, maxSize); int s = rngv.i(minSize, maxSize + 1);
int dim = Math.min(11, (int) Math.round(Math.pow(maxSize, 1D / 3D))); if (s == 1) {
int w = dim / 2; IrisObject o = new IrisObject(1, 1, 1);
o.getBlocks().put(o.getCenter(), nextBlock(rngv, rdata));
return o;
}
int dim = Math.min(11, (int) Math.ceil(Math.cbrt(s)));
IrisObject o = new IrisObject(dim, dim, dim); IrisObject o = new IrisObject(dim, dim, dim);
if (s == 1) { int volume = dim * dim * dim;
o.getBlocks().put(o.getCenter(), nextBlock(rngv, rdata)); if (s >= volume) {
} else { int x = 0, y = 0, z = 0;
while (s > 0) {
s--; while (z < dim) {
BlockVector ang = new BlockVector(rngv.i(-w, w), rngv.i(-w, w), rngv.i(-w, w)); o.setUnsigned(x++, y, z, nextBlock(rngv, rdata));
BlockVector pos = o.getCenter().clone().add(ang).toBlockVector();
o.getBlocks().put(pos, nextBlock(rngv, rdata)); if (x == dim) {
x = 0;
y++;
}
if (y == dim) {
y = 0;
z++;
}
} }
return o;
}
KSet<BlockPosition> set = new KSet<>();
while (s > 0) {
BlockPosition ang = new BlockPosition(
rngv.i(0, dim),
rngv.i(0, dim),
rngv.i(0, dim)
);
if (!set.add(ang)) continue;
s--;
o.setUnsigned(ang.getX(), ang.getY(), ang.getZ(), nextBlock(rngv, rdata));
} }
return o; return o;
} }
private BlockData nextBlock(RNG rngv, IrisData rdata) { private BlockData nextBlock(RNG rngv, IrisData rdata) {
return getBlockData(rdata).get(rngv.i(0, getBlockData(rdata).size() - 1)); return getBlockData(rdata).get(rngv.i(0, getBlockData(rdata).size()));
} }
public KList<BlockData> getBlockData(IrisData rdata) { public KList<BlockData> getBlockData(IrisData rdata) {
@@ -19,6 +19,8 @@
package com.volmit.iris.engine.object; package com.volmit.iris.engine.object;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.ServerConfigurator.DimensionHeight;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
@@ -26,6 +28,7 @@ import com.volmit.iris.core.nms.datapack.IDataFixer;
import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.DataProvider; import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.io.IO; import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
@@ -54,73 +57,6 @@ import java.io.IOException;
public class IrisDimension extends IrisRegistrant { public class IrisDimension extends IrisRegistrant {
public static final BlockData STONE = Material.STONE.createBlockData(); public static final BlockData STONE = Material.STONE.createBlockData();
public static final BlockData WATER = Material.WATER.createBlockData(); public static final BlockData WATER = Material.WATER.createBlockData();
private static final String DP_OVERWORLD_DEFAULT = """
{
"ambient_light": 0.0,
"bed_works": true,
"coordinate_scale": 1.0,
"effects": "minecraft:overworld",
"has_ceiling": false,
"has_raids": true,
"has_skylight": true,
"infiniburn": "#minecraft:infiniburn_overworld",
"monster_spawn_block_light_limit": 0,
"monster_spawn_light_level": {
"type": "minecraft:uniform",
"value": {
"max_inclusive": 7,
"min_inclusive": 0
}
},
"natural": true,
"piglin_safe": false,
"respawn_anchor_works": false,
"ultrawarm": false
}""";
private static final String DP_NETHER_DEFAULT = """
{
"ambient_light": 0.1,
"bed_works": false,
"coordinate_scale": 8.0,
"effects": "minecraft:the_nether",
"fixed_time": 18000,
"has_ceiling": true,
"has_raids": false,
"has_skylight": false,
"infiniburn": "#minecraft:infiniburn_nether",
"monster_spawn_block_light_limit": 15,
"monster_spawn_light_level": 7,
"natural": false,
"piglin_safe": true,
"respawn_anchor_works": true,
"ultrawarm": true
}""";
private static final String DP_END_DEFAULT = """
{
"ambient_light": 0.0,
"bed_works": false,
"coordinate_scale": 1.0,
"effects": "minecraft:the_end",
"fixed_time": 6000,
"has_ceiling": false,
"has_raids": true,
"has_skylight": false,
"infiniburn": "#minecraft:infiniburn_end",
"monster_spawn_block_light_limit": 0,
"monster_spawn_light_level": {
"type": "minecraft:uniform",
"value": {
"max_inclusive": 7,
"min_inclusive": 0
}
},
"natural": false,
"piglin_safe": false,
"respawn_anchor_works": false,
"ultrawarm": false
}""";
private final transient AtomicCache<Position2> parallaxSize = new AtomicCache<>(); private final transient AtomicCache<Position2> parallaxSize = new AtomicCache<>();
private final transient AtomicCache<CNG> rockLayerGenerator = new AtomicCache<>(); private final transient AtomicCache<CNG> rockLayerGenerator = new AtomicCache<>();
private final transient AtomicCache<CNG> fluidLayerGenerator = new AtomicCache<>(); private final transient AtomicCache<CNG> fluidLayerGenerator = new AtomicCache<>();
@@ -234,8 +170,6 @@ public class IrisDimension extends IrisRegistrant {
private IrisRange dimensionHeightEnd = new IrisRange(-64, 320); private IrisRange dimensionHeightEnd = new IrisRange(-64, 320);
@Desc("Define the min and max Y bounds of this dimension. Please keep in mind that Iris internally generates from 0 to (max - min). \n\nFor example at -64 to 320, Iris is internally generating to 0 to 384, then on outputting chunks, it shifts it down by the min height (64 blocks). The default is -64 to 320. \n\nThe fluid height is placed at (fluid height + min height). So a fluid height of 63 would actually show up in the world at 1.") @Desc("Define the min and max Y bounds of this dimension. Please keep in mind that Iris internally generates from 0 to (max - min). \n\nFor example at -64 to 320, Iris is internally generating to 0 to 384, then on outputting chunks, it shifts it down by the min height (64 blocks). The default is -64 to 320. \n\nThe fluid height is placed at (fluid height + min height). So a fluid height of 63 would actually show up in the world at 1.")
private IrisRange dimensionHeightNether = new IrisRange(-64, 320); private IrisRange dimensionHeightNether = new IrisRange(-64, 320);
@Desc("Enable smart vanilla height")
private boolean smartVanillaHeight = false;
@RegistryListResource(IrisBiome.class) @RegistryListResource(IrisBiome.class)
@Desc("Keep this either undefined or empty. Setting any biome name into this will force iris to only generate the specified biome. Great for testing.") @Desc("Keep this either undefined or empty. Setting any biome name into this will force iris to only generate the specified biome. Great for testing.")
private String focus = ""; private String focus = "";
@@ -445,61 +379,35 @@ public class IrisDimension extends IrisRegistrant {
return landBiomeStyle; return landBiomeStyle;
} }
public boolean installDataPack(IDataFixer fixer, DataProvider data, File datapacks, double ultimateMaxHeight, double ultimateMinHeight) { public void installBiomes(IDataFixer fixer, DataProvider data, KList<File> folders, KSet<String> biomes) {
boolean write = false; getAllBiomes(data)
boolean changed = false; .stream()
.filter(IrisBiome::isCustom)
IO.delete(new File(datapacks, "iris/data/" + getLoadKey().toLowerCase())); .map(IrisBiome::getCustomDerivitives)
.flatMap(KList::stream)
for (IrisBiome i : getAllBiomes(data)) { .parallel()
if (i.isCustom()) { .forEach(j -> {
write = true; String json = j.generateJson(fixer);
synchronized (biomes) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) { if (!biomes.add(j.getId())) {
File output = new File(datapacks, "iris/data/" + getLoadKey().toLowerCase() + "/worldgen/biome/" + j.getId() + ".json"); Iris.verbose("Duplicate Data Pack Biome: " + getLoadKey() + "/" + j.getId());
return;
if (!output.exists()) {
changed = true;
}
Iris.verbose(" Installing Data Pack Biome: " + output.getPath());
output.getParentFile().mkdirs();
try {
IO.writeAll(output, j.generateJson(fixer));
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
}
}
}
if (!dimensionHeight.equals(new IrisRange(-64, 320)) && this.name.equalsIgnoreCase("overworld")) {
Iris.verbose(" Installing Data Pack Dimension Types: \"minecraft:overworld\", \"minecraft:the_nether\", \"minecraft:the_end\"");
dimensionHeight.setMax(ultimateMaxHeight);
dimensionHeight.setMin(ultimateMinHeight);
changed = writeDimensionType(fixer, changed, datapacks);
}
if (write) {
File mcm = new File(datapacks, "iris/pack.mcmeta");
try {
IO.writeAll(mcm, """
{
"pack": {
"description": "Iris Data Pack. This pack contains all installed Iris Packs' resources.",
"pack_format": {}
}
} }
""".replace("{}", INMS.get().getDataVersion().getPackFormat() + "")); }
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
Iris.verbose(" Installing Data Pack MCMeta: " + mcm.getPath());
}
return changed; for (File datapacks : folders) {
File output = new File(datapacks, "iris/data/" + getLoadKey().toLowerCase() + "/worldgen/biome/" + j.getId() + ".json");
Iris.verbose(" Installing Data Pack Biome: " + output.getPath());
output.getParentFile().mkdirs();
try {
IO.writeAll(output, json);
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
}
});
} }
@Override @Override
@@ -517,66 +425,55 @@ public class IrisDimension extends IrisRegistrant {
} }
public boolean writeDimensionType(IDataFixer fixer, boolean changed, File datapacks) { public static void writeShared(KList<File> folders, DimensionHeight height) {
File dimTypeOverworld = new File(datapacks, "iris/data/minecraft/dimension_type/overworld.json"); Iris.verbose(" Installing Data Pack Dimension Types: \"iris:overworld\", \"iris:the_nether\", \"iris:the_end\"");
if (!dimTypeOverworld.exists()) for (File datapacks : folders) {
changed = true; write(datapacks, "overworld", height.overworldType());
dimTypeOverworld.getParentFile().mkdirs(); write(datapacks, "the_nether", height.netherType());
write(datapacks, "the_end", height.endType());
}
String raw = """
{
"pack": {
"description": "Iris Data Pack. This pack contains all installed Iris Packs' resources.",
"pack_format": {}
}
}
""".replace("{}", INMS.get().getDataVersion().getPackFormat() + "");
for (File datapacks : folders) {
File mcm = new File(datapacks, "iris/pack.mcmeta");
try {
IO.writeAll(mcm, raw);
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
Iris.verbose(" Installing Data Pack MCMeta: " + mcm.getPath());
}
}
private static void write(File datapacks, String type, String json) {
File dimType = new File(datapacks, "iris/data/iris/dimension_type/" + type + ".json");
File dimTypeVanilla = new File(datapacks, "iris/data/minecraft/dimension_type/" + type + ".json");
dimType.getParentFile().mkdirs();
try { try {
IO.writeAll(dimTypeOverworld, generateDatapackJsonOverworld(fixer)); IO.writeAll(dimType, json);
} catch (IOException e) { } catch (IOException e) {
Iris.reportError(e); Iris.reportError(e);
e.printStackTrace(); e.printStackTrace();
} }
if (IrisSettings.get().getGeneral().adjustVanillaHeight || dimTypeVanilla.exists()) {
File dimTypeNether = new File(datapacks, "iris/data/minecraft/dimension_type/the_nether.json"); dimTypeVanilla.getParentFile().mkdirs();
if (!dimTypeNether.exists()) try {
changed = true; IO.writeAll(dimTypeVanilla, json);
dimTypeNether.getParentFile().mkdirs(); } catch (IOException e) {
try { Iris.reportError(e);
IO.writeAll(dimTypeNether, generateDatapackJsonNether(fixer)); e.printStackTrace();
} catch (IOException e) { }
Iris.reportError(e);
e.printStackTrace();
} }
File dimTypeEnd = new File(datapacks, "iris/data/minecraft/dimension_type/the_end.json");
if (!dimTypeEnd.exists())
changed = true;
dimTypeEnd.getParentFile().mkdirs();
try {
IO.writeAll(dimTypeEnd, generateDatapackJsonEnd(fixer));
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
return changed;
}
private String generateDatapackJsonOverworld(IDataFixer fixer) {
JSONObject obj = new JSONObject(DP_OVERWORLD_DEFAULT);
obj.put("min_y", dimensionHeight.getMin());
obj.put("height", dimensionHeight.getMax() - dimensionHeight.getMin());
obj.put("logical_height", logicalHeight);
return fixer.fixDimension(obj).toString(4);
}
private String generateDatapackJsonNether(IDataFixer fixer) {
JSONObject obj = new JSONObject(DP_NETHER_DEFAULT);
obj.put("min_y", dimensionHeightNether.getMin());
obj.put("height", dimensionHeightNether.getMax() - dimensionHeightNether.getMin());
obj.put("logical_height", logicalHeightNether);
return fixer.fixDimension(obj).toString(4);
}
private String generateDatapackJsonEnd(IDataFixer fixer) {
JSONObject obj = new JSONObject(DP_END_DEFAULT);
obj.put("min_y", dimensionHeightEnd.getMin());
obj.put("height", dimensionHeightEnd.getMax() - dimensionHeightEnd.getMin());
obj.put("logical_height", logicalHeightEnd);
return fixer.fixDimension(obj).toString(4);
} }
} }
@@ -1,43 +0,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.engine.object;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
import lombok.Data;
@Data
public class IrisEngineChunkData {
private long chunk;
private KList<IrisEngineSpawnerCooldown> cooldowns = new KList<>();
public void cleanup(Engine engine) {
for (IrisEngineSpawnerCooldown i : getCooldowns().copy()) {
IrisSpawner sp = engine.getData().getSpawnerLoader().load(i.getSpawner());
if (sp == null || i.canSpawn(sp.getMaximumRate())) {
getCooldowns().remove(i);
}
}
}
public boolean isEmpty() {
return cooldowns.isEmpty();
}
}
@@ -20,51 +20,31 @@ package com.volmit.iris.engine.object;
import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
@Data @Data
public class IrisEngineData { @EqualsAndHashCode(callSuper = true)
public class IrisEngineData extends IrisSpawnerCooldowns {
private IrisEngineStatistics statistics = new IrisEngineStatistics(); private IrisEngineStatistics statistics = new IrisEngineStatistics();
private KList<IrisEngineSpawnerCooldown> spawnerCooldowns = new KList<>(); private KMap<Long, IrisSpawnerCooldowns> chunks = new KMap<>();
private KList<IrisEngineChunkData> chunks = new KList<>();
private Long seed = null; private Long seed = null;
public void removeChunk(int x, int z) { public void removeChunk(int x, int z) {
long k = Cache.key(x, z); chunks.remove(Cache.key(x, z));
chunks.removeWhere((i) -> i.getChunk() == k);
} }
public IrisEngineChunkData getChunk(int x, int z) { public IrisSpawnerCooldowns getChunk(int x, int z) {
long k = Cache.key(x, z); return chunks.computeIfAbsent(Cache.key(x, z), k -> new IrisSpawnerCooldowns());
for (IrisEngineChunkData i : chunks) {
if (i.getChunk() == k) {
return i;
}
}
IrisEngineChunkData c = new IrisEngineChunkData();
c.setChunk(k);
chunks.add(c);
return c;
} }
public void cleanup(Engine engine) { public void cleanup(Engine engine) {
for (IrisEngineSpawnerCooldown i : getSpawnerCooldowns().copy()) { super.cleanup(engine);
IrisSpawner sp = engine.getData().getSpawnerLoader().load(i.getSpawner());
if (sp == null || i.canSpawn(sp.getMaximumRate())) { chunks.values().removeIf(chunk -> {
getSpawnerCooldowns().remove(i); chunk.cleanup(engine);
} return chunk.isEmpty();
} });
for (IrisEngineChunkData i : chunks.copy()) {
i.cleanup(engine);
if (i.isEmpty()) {
getChunks().remove(i);
}
}
} }
} }
@@ -29,7 +29,6 @@ import com.volmit.iris.util.format.C;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.misc.E;
import com.volmit.iris.util.plugin.Chunks; import com.volmit.iris.util.plugin.Chunks;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
@@ -57,6 +56,8 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import static com.volmit.iris.util.data.registry.Particles.ITEM;
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
@Accessors(chain = true) @Accessors(chain = true)
@NoArgsConstructor @NoArgsConstructor
@@ -66,7 +67,6 @@ import java.util.concurrent.atomic.AtomicReference;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public class IrisEntity extends IrisRegistrant { public class IrisEntity extends IrisRegistrant {
private static final Particle ITEM = E.getOrDefault(Particle.class, "ITEM_CRACK", "ITEM");
@Required @Required
@Desc("The type of entity to spawn. To spawn a mythic mob, set this type to unknown and define mythic type.") @Desc("The type of entity to spawn. To spawn a mythic mob, set this type to unknown and define mythic type.")
private EntityType type = EntityType.UNKNOWN; private EntityType type = EntityType.UNKNOWN;
@@ -24,6 +24,7 @@ import com.dfsek.paralithic.eval.parser.Scope;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.IrisExpressionFunction.FunctionContext;
import com.volmit.iris.engine.object.annotations.ArrayType; import com.volmit.iris.engine.object.annotations.ArrayType;
import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.Required; import com.volmit.iris.engine.object.annotations.Required;
@@ -46,12 +47,14 @@ import lombok.experimental.Accessors;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public class IrisExpression extends IrisRegistrant { public class IrisExpression extends IrisRegistrant {
private static final Parser parser = new Parser();
@ArrayType(type = IrisExpressionLoad.class, min = 1) @ArrayType(type = IrisExpressionLoad.class, min = 1)
@Desc("Variables to use in this expression") @Desc("Variables to use in this expression")
private KList<IrisExpressionLoad> variables = new KList<>(); private KList<IrisExpressionLoad> variables = new KList<>();
@ArrayType(type = IrisExpressionFunction.class, min = 1)
@Desc("Functions to use in this expression")
private KList<IrisExpressionFunction> functions = new KList<>();
@Required @Required
@Desc("The expression. Inherited variables are x, y and z. Avoid using those variable names.") @Desc("The expression. Inherited variables are x, y and z. Avoid using those variable names.")
private String expression; private String expression;
@@ -62,6 +65,7 @@ public class IrisExpression extends IrisRegistrant {
private Expression expression() { private Expression expression() {
return expressionCache.aquire(() -> { return expressionCache.aquire(() -> {
Scope scope = new Scope(); // Create variable scope. This scope can hold both constants and invocation variables. Scope scope = new Scope(); // Create variable scope. This scope can hold both constants and invocation variables.
Parser parser = new Parser();
try { try {
for (IrisExpressionLoad i : variables) { for (IrisExpressionLoad i : variables) {
@@ -76,6 +80,12 @@ public class IrisExpression extends IrisRegistrant {
Iris.error("Script Variable load error in " + getLoadFile().getPath()); Iris.error("Script Variable load error in " + getLoadFile().getPath());
} }
for (IrisExpressionFunction f : functions) {
if (!f.isValid()) continue;
f.setData(getLoader());
parser.registerFunction(f.getName(), f);
}
try { try {
return parser.parse(getExpression(), scope); return parser.parse(getExpression(), scope);
} catch (Throwable e) { } catch (Throwable e) {
@@ -103,7 +113,7 @@ public class IrisExpression extends IrisRegistrant {
g[m++] = z; g[m++] = z;
g[m] = -1; g[m] = -1;
return expression().evaluate(g); return expression().evaluate(new FunctionContext(rng), g);
} }
public double evaluate(RNG rng, double x, double y, double z) { public double evaluate(RNG rng, double x, double y, double z) {
@@ -117,7 +127,7 @@ public class IrisExpression extends IrisRegistrant {
g[m++] = y; g[m++] = y;
g[m] = z; g[m] = z;
return expression().evaluate(g); return expression().evaluate(new FunctionContext(rng), g);
} }
@Override @Override
@@ -0,0 +1,101 @@
package com.volmit.iris.engine.object;
import com.dfsek.paralithic.functions.dynamic.Context;
import com.dfsek.paralithic.functions.dynamic.DynamicFunction;
import com.dfsek.paralithic.node.Statefulness;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.MinNumber;
import com.volmit.iris.engine.object.annotations.Required;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.math.RNG;
import lombok.*;
import lombok.experimental.Accessors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@Snippet("expression-function")
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Desc("Represents a function to use in your expression. Do not set the name to x, y, or z, also don't duplicate names.")
@Data
@EqualsAndHashCode(callSuper = false)
public class IrisExpressionFunction implements DynamicFunction {
@Required
@Desc("The function to assign this value to. Do not set the name to x, y, or z")
private String name;
@Desc("If defined, this variable will use a generator style as it's value")
private IrisGeneratorStyle styleValue = null;
@Desc("If defined, iris will use an internal stream from the engine as it's value")
private IrisEngineStreamType engineStreamValue = null;
@MinNumber(2)
@Desc("Number of arguments for the function")
private int args = 2;
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private transient final KMap<FunctionContext, Provider> cache = new KMap<>();
private transient IrisData data;
public boolean isValid() {
return styleValue != null || engineStreamValue != null;
}
@Override
public int getArgNumber() {
if (engineStreamValue != null) return 2;
return Math.max(args, 2);
}
@NotNull
@Override
public Statefulness statefulness() {
return Statefulness.STATEFUL;
}
@Override
public double eval(double... doubles) {
return 0;
}
@Override
public double eval(@Nullable Context raw, double... args) {
return cache.computeIfAbsent((FunctionContext) raw, context -> {
assert context != null;
if (engineStreamValue != null) {
var stream = engineStreamValue.get(data.getEngine());
return d -> stream.get(d[0], d[1]);
}
if (styleValue != null) {
return styleValue.createNoCache(context.rng, data)::noise;
}
return d -> Double.NaN;
}).eval(args);
}
public record FunctionContext(@NonNull RNG rng) implements Context {
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
FunctionContext that = (FunctionContext) o;
return rng.getSeed() == that.rng.getSeed();
}
@Override
public int hashCode() {
return Long.hashCode(rng.getSeed());
}
}
@FunctionalInterface
private interface Provider {
double eval(double... args);
}
}
@@ -23,12 +23,11 @@ import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.Required; import com.volmit.iris.engine.object.annotations.Required;
import com.volmit.iris.engine.object.annotations.Snippet; import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.stream.ProceduralStream; import com.volmit.iris.util.stream.ProceduralStream;
import lombok.AllArgsConstructor; import lombok.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
@Snippet("expression-load") @Snippet("expression-load")
@@ -57,6 +56,9 @@ public class IrisExpressionLoad {
private transient AtomicCache<ProceduralStream<Double>> streamCache = new AtomicCache<>(); private transient AtomicCache<ProceduralStream<Double>> streamCache = new AtomicCache<>();
private transient AtomicCache<Double> valueCache = new AtomicCache<>(); private transient AtomicCache<Double> valueCache = new AtomicCache<>();
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private transient final KMap<Long, CNG> styleCache = new KMap<>();
public double getValue(RNG rng, IrisData data, double x, double z) { public double getValue(RNG rng, IrisData data, double x, double z) {
if (engineValue != null) { if (engineValue != null) {
@@ -68,7 +70,8 @@ public class IrisExpressionLoad {
} }
if (styleValue != null) { if (styleValue != null) {
return styleValue.create(rng, data).noise(x, z); return styleCache.computeIfAbsent(rng.getSeed(), k -> styleValue.createNoCache(new RNG(k), data))
.noise(x, z);
} }
return staticValue; return staticValue;
@@ -84,7 +87,8 @@ public class IrisExpressionLoad {
} }
if (styleValue != null) { if (styleValue != null) {
return styleValue.create(rng, data).noise(x, y, z); return styleCache.computeIfAbsent(rng.getSeed(), k -> styleValue.createNoCache(new RNG(k), data))
.noise(x, y, z);
} }
return staticValue; return staticValue;
@@ -0,0 +1,325 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2024 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.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.headless.IRegion;
import com.volmit.iris.core.nms.headless.IRegionStorage;
import com.volmit.iris.core.nms.headless.SerializableChunk;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineStage;
import com.volmit.iris.engine.framework.WrongEngineBroException;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.RegionCoordinates;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder;
import com.volmit.iris.util.hunk.view.SyncChunkDataHunkHolder;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.Looper;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import java.io.IOException;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.function.Consumer;
public class IrisHeadless {
private final long KEEP_ALIVE = TimeUnit.SECONDS.toMillis(10L);
private final Engine engine;
private final IRegionStorage storage;
private final ExecutorService executor = Executors.newCachedThreadPool();
private final KMap<Long, Region> regions = new KMap<>();
private final AtomicInteger loadedChunks = new AtomicInteger();
private transient CompletingThread regionThread;
private transient boolean closed = false;
public IrisHeadless(Engine engine) {
this.engine = engine;
this.storage = INMS.get().createRegionStorage(engine);
if (storage == null) throw new IllegalStateException("Failed to create region storage!");
engine.getWorld().headless(this);
startRegionCleaner();
}
private void startRegionCleaner() {
var cleaner = new Looper() {
@Override
protected long loop() {
if (closed) return -1;
long time = M.ms() - KEEP_ALIVE;
regions.values()
.stream()
.filter(r -> r.lastEntry < time)
.forEach(Region::submit);
return closed ? -1 : 1000;
}
};
cleaner.setName("Iris Region Cleaner - " + engine.getWorld().name());
cleaner.setPriority(Thread.MIN_PRIORITY);
cleaner.start();
}
public int getLoadedChunks() {
return loadedChunks.get();
}
/**
* Checks if the mca plate is fully generated or not.
*
* @param x coord of the chunk
* @param z coord of the chunk
* @return true if the chunk exists in .mca
*/
public boolean exists(int x, int z) {
if (closed) return false;
if (engine.getWorld().hasRealWorld() && engine.getWorld().realWorld().isChunkLoaded(x, z))
return true;
return storage.exists(x, z);
}
public synchronized CompletableFuture<Void> generateRegion(MultiBurst burst, int x, int z, int maxConcurrent, PregenListener listener) {
if (closed) return CompletableFuture.completedFuture(null);
if (regionThread != null && !regionThread.future.isDone())
throw new IllegalStateException("Region generation already in progress");
regionThread = new CompletingThread(() -> {
boolean listening = listener != null;
Semaphore semaphore = new Semaphore(maxConcurrent);
CountDownLatch latch = new CountDownLatch(1024);
iterateRegion(x, z, pos -> {
try {
semaphore.acquire();
} catch (InterruptedException e) {
semaphore.release();
return;
}
burst.complete(() -> {
try {
if (listening) listener.onChunkGenerating(pos.getX(), pos.getZ());
generateChunk(pos.getX(), pos.getZ());
if (listening) listener.onChunkGenerated(pos.getX(), pos.getZ());
} finally {
semaphore.release();
latch.countDown();
}
});
});
try {
latch.await();
} catch (InterruptedException ignored) {}
if (listening) listener.onRegionGenerated(x, z);
}, "Region Generator - " + x + "," + z, Thread.MAX_PRIORITY);
return regionThread.future;
}
@RegionCoordinates
private static void iterateRegion(int x, int z, Consumer<Position2> chunkPos) {
int cX = x << 5;
int cZ = z << 5;
for (int xx = 0; xx < 32; xx++) {
for (int zz = 0; zz < 32; zz++) {
chunkPos.accept(new Position2(cX + xx, cZ + zz));
}
}
}
public void generateChunk(int x, int z) {
if (closed || exists(x, z)) return;
try {
var chunk = storage.createChunk(x, z);
loadedChunks.incrementAndGet();
SyncChunkDataHunkHolder blocks = new SyncChunkDataHunkHolder(chunk);
BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(chunk, chunk.getMinHeight(), chunk.getMaxHeight());
ChunkContext ctx = generate(engine, x << 4, z << 4, blocks, biomes);
blocks.apply();
biomes.apply();
storage.fillBiomes(chunk, ctx);
chunk.mark();
long key = Cache.key(x >> 5, z >> 5);
regions.computeIfAbsent(key, Region::new)
.add(chunk);
} catch (Throwable e) {
loadedChunks.decrementAndGet();
Iris.error("Failed to generate " + x + ", " + z);
e.printStackTrace();
}
}
@BlockCoordinates
private ChunkContext generate(Engine engine, int x, int z, Hunk<BlockData> vblocks, Hunk<org.bukkit.block.Biome> vbiomes) throws WrongEngineBroException {
if (engine.isClosed()) {
throw new WrongEngineBroException();
}
engine.getContext().touch();
engine.getEngineData().getStatistics().generatedChunk();
ChunkContext ctx = null;
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
Hunk<BlockData> blocks = vblocks.listen((xx, y, zz, t) -> engine.catchBlockUpdates(x + xx, y + engine.getMinHeight(), z + zz, t));
var dimension = engine.getDimension();
if (dimension.isDebugChunkCrossSections() && ((x >> 4) % dimension.getDebugCrossSectionsMod() == 0 || (z >> 4) % dimension.getDebugCrossSectionsMod() == 0)) {
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
blocks.set(i, 0, j, Material.CRYING_OBSIDIAN.createBlockData());
}
}
} else {
ctx = new ChunkContext(x, z, engine.getComplex());
IrisContext.getOr(engine).setChunkContext(ctx);
for (EngineStage i : engine.getMode().getStages()) {
i.generate(x, z, blocks, vbiomes, false, ctx);
}
}
engine.getMantle().getMantle().flag(x >> 4, z >> 4, MantleFlag.REAL, true);
engine.getMetrics().getTotal().put(p.getMilliseconds());
engine.addGenerated(x,z);
} catch (Throwable e) {
Iris.reportError(e);
engine.fail("Failed to generate " + x + ", " + z, e);
}
return ctx;
}
public void close() throws IOException {
if (closed) return;
try {
if (regionThread != null) {
regionThread.future.join();
regionThread = null;
}
regions.v().forEach(Region::submit);
Iris.info("Waiting for " + loadedChunks.get() + " chunks to unload...");
while (loadedChunks.get() > 0)
J.sleep(1);
Iris.info("All chunks unloaded");
executor.shutdown();
storage.close();
engine.getWorld().headless(null);
} finally {
closed = true;
}
}
private class Region implements Runnable {
private final int x, z;
private final long key;
private final AtomicReferenceArray<SerializableChunk> chunks = new AtomicReferenceArray<>(1024);
private final AtomicReference<Future<?>> full = new AtomicReference<>();
private transient int size;
private transient long lastEntry = M.ms();
public Region(long key) {
this.x = Cache.keyX(key);
this.z = Cache.keyZ(key);
this.key = key;
}
@Override
public void run() {
try (IRegion region = storage.getRegion(x, z, false)) {
assert region != null;
for (int i = 0; i < 1024; i++) {
SerializableChunk chunk = chunks.get(i);
if (chunk == null)
continue;
try {
region.write(chunk);
} catch (Throwable e) {
Iris.error("Failed to save chunk " + chunk.getPos());
e.printStackTrace();
}
loadedChunks.decrementAndGet();
}
} catch (Throwable e) {
Iris.error("Failed to load region file " + x + ", " + z);
e.printStackTrace();
loadedChunks.addAndGet(-size);
}
}
public synchronized void add(SerializableChunk chunk) {
lastEntry = M.ms();
if (chunks.getAndSet(index(chunk.getPos()), chunk) != null)
throw new IllegalStateException("Chunk " + chunk.getPos() + " already exists");
if (++size < 1024)
return;
submit();
}
public void submit() {
regions.remove(key);
full.getAndUpdate(future -> {
if (future != null) return future;
return executor.submit(this);
});
}
private int index(Position2 chunk) {
int x = chunk.getX() & 31;
int z = chunk.getZ() & 31;
return z * 32 + x;
}
}
private static class CompletingThread extends Thread {
private final CompletableFuture<Void> future = new CompletableFuture<>();
private CompletingThread(Runnable task, String name, int priority) {
super(task, name);
setPriority(priority);
start();
}
@Override
public void run() {
try {
super.run();
} finally {
future.complete(null);
}
}
}
}
@@ -139,6 +139,14 @@ public class IrisJigsawStructure extends IrisRegistrant {
loadPiece(i, pools, pieces); loadPiece(i, pools, pieces);
} }
if (pieces.isEmpty()) {
int max = 0;
for (String i : getPieces()) {
max = Math.max(max, getLoader().getJigsawPieceLoader().load(i).getMax2dDimension());
}
return max;
}
int avg = 0; int avg = 0;
for (String i : pieces) { for (String i : pieces) {
@@ -19,13 +19,8 @@
package com.volmit.iris.engine.object; package com.volmit.iris.engine.object;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.engine.object.annotations.ArrayType; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.engine.object.annotations.MaxNumber;
import com.volmit.iris.engine.object.annotations.MinNumber;
import com.volmit.iris.engine.object.annotations.RegistryListResource;
import com.volmit.iris.engine.object.annotations.Required;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates;
@@ -54,6 +49,7 @@ public class IrisJigsawStructurePlacement implements IRare {
private int rarity = 100; private int rarity = 100;
@Required @Required
@DependsOn({"spacing", "separation"})
@Desc("The salt to use when generating the structure (to differentiate structures)") @Desc("The salt to use when generating the structure (to differentiate structures)")
@MinNumber(Long.MIN_VALUE) @MinNumber(Long.MIN_VALUE)
@MaxNumber(Long.MAX_VALUE) @MaxNumber(Long.MAX_VALUE)
@@ -61,16 +57,26 @@ public class IrisJigsawStructurePlacement implements IRare {
@Required @Required
@MinNumber(0) @MinNumber(0)
@DependsOn({"salt", "separation"})
@Desc("Average distance in chunks between two neighboring generation attempts") @Desc("Average distance in chunks between two neighboring generation attempts")
private int spacing = -1; private int spacing = -1;
@Required @Required
@MinNumber(0) @MinNumber(0)
@DependsOn({"salt", "spacing"})
@Desc("Minimum distance in chunks between two neighboring generation attempts\nThe maximum distance of two neighboring generation attempts is 2*spacing - separation") @Desc("Minimum distance in chunks between two neighboring generation attempts\nThe maximum distance of two neighboring generation attempts is 2*spacing - separation")
private int separation = -1; private int separation = -1;
@Desc("The method used to spread the structure") @Desc("The method used to spread the structure")
private SpreadType spreadType = SpreadType.TRIANGULAR; private SpreadType spreadType = SpreadType.LINEAR;
@DependsOn({"spreadType"})
@Desc("The noise style to use when spreadType is set to 'NOISE'\nThis ignores the spacing and separation parameters")
private IrisGeneratorStyle style = new IrisGeneratorStyle();
@DependsOn({"spreadType", "style"})
@Desc("Threshold for noise style")
private double threshold = 0.5;
@ArrayType(type = IrisJigsawMinDistance.class) @ArrayType(type = IrisJigsawMinDistance.class)
@Desc("List of minimum distances to check for") @Desc("List of minimum distances to check for")
@@ -89,20 +95,29 @@ public class IrisJigsawStructurePlacement implements IRare {
} }
private void calculateMissing(double divisor, long seed) { private void calculateMissing(double divisor, long seed) {
seed = seed + hashCode(); if (salt != 0 && separation > 0 && spacing > 0)
return;
seed *= (long) structure.hashCode() * rarity;
if (salt == 0) { if (salt == 0) {
salt = new RNG(seed).nextLong(Integer.MIN_VALUE, Integer.MAX_VALUE); salt = new RNG(seed).l(Integer.MIN_VALUE, Integer.MAX_VALUE);
} }
if (separation == -1 || spacing == -1) { if (separation == -1 || spacing == -1) {
separation = (int) Math.round(rarity / divisor); separation = (int) Math.round(rarity / divisor);
spacing = new RNG(seed).nextInt(separation, separation * 2); spacing = new RNG(seed).i(separation, separation * 2);
} }
} }
@ChunkCoordinates @ChunkCoordinates
public boolean shouldPlace(double divisor, long seed, int x, int z) { public boolean shouldPlace(IrisData data, double divisor, long seed, int x, int z) {
calculateMissing(divisor, seed); calculateMissing(divisor, seed);
if (spreadType != SpreadType.NOISE)
return shouldPlaceSpread(seed, x, z);
return style.create(new RNG(seed + salt), data).noise(x, z) > threshold;
}
private boolean shouldPlaceSpread(long seed, int x, int z) {
if (separation > spacing) { if (separation > spacing) {
separation = spacing; separation = spacing;
Iris.warn("JigsawStructurePlacement: separation must be less than or equal to spacing"); Iris.warn("JigsawStructurePlacement: separation must be less than or equal to spacing");
@@ -123,7 +138,9 @@ public class IrisJigsawStructurePlacement implements IRare {
@Desc("Linear spread") @Desc("Linear spread")
LINEAR(RNG::i), LINEAR(RNG::i),
@Desc("Triangular spread") @Desc("Triangular spread")
TRIANGULAR((rng, bound) -> (rng.i(bound) + rng.i(bound)) / 2); TRIANGULAR((rng, bound) -> (rng.i(bound) + rng.i(bound)) / 2),
@Desc("Noise based spread\nThis ignores the spacing and separation parameters")
NOISE((rng, bound) -> 0);
private final SpreadMethod method; private final SpreadMethod method;
SpreadType(SpreadMethod method) { SpreadType(SpreadMethod method) {
@@ -29,7 +29,7 @@ import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.context.IrisContext; import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.interpolation.IrisInterpolation; import com.volmit.iris.util.interpolation.IrisInterpolation;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
@@ -53,8 +53,6 @@ import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing; import org.bukkit.block.data.MultipleFacing;
import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.Waterlogged;
@@ -943,7 +941,7 @@ public class IrisObject extends IrisRegistrant {
if (j.isExact() ? k.matches(data) : k.getMaterial().equals(data.getMaterial())) { if (j.isExact() ? k.matches(data) : k.getMaterial().equals(data.getMaterial())) {
BlockData newData = j.getReplace(rng, i.getX() + x, i.getY() + y, i.getZ() + z, rdata).clone(); BlockData newData = j.getReplace(rng, i.getX() + x, i.getY() + y, i.getZ() + z, rdata).clone();
if (newData.getMaterial() == data.getMaterial() && !(newData instanceof IrisBlockData || data instanceof IrisBlockData)) if (newData.getMaterial() == data.getMaterial() && !(newData instanceof IrisCustomData || data instanceof IrisCustomData))
data = data.merge(newData); data = data.merge(newData);
else else
data = newData; data = newData;
@@ -1012,8 +1010,9 @@ public class IrisObject extends IrisRegistrant {
} }
boolean wouldReplace = B.isSolid(placer.get(xx, yy, zz)) && B.isVineBlock(data); boolean wouldReplace = B.isSolid(placer.get(xx, yy, zz)) && B.isVineBlock(data);
boolean place = !data.getMaterial().equals(Material.AIR) && !data.getMaterial().equals(Material.CAVE_AIR) && !wouldReplace;
if (!data.getMaterial().equals(Material.AIR) && !data.getMaterial().equals(Material.CAVE_AIR) && !wouldReplace) { if (data instanceof IrisCustomData || place) {
placer.set(xx, yy, zz, data); placer.set(xx, yy, zz, data);
if (tile != null) { if (tile != null) {
placer.setTile(xx, yy, zz, tile); placer.setTile(xx, yy, zz, tile);
@@ -50,4 +50,10 @@ public class IrisRange {
public boolean contains(int v) { public boolean contains(int v) {
return v >= min && v <= max; return v >= min && v <= max;
} }
public IrisRange merge(IrisRange other) {
min = Math.min(min, other.min);
max = Math.max(max, other.max);
return this;
}
} }
@@ -43,7 +43,7 @@ public class IrisRate {
} }
public long getInterval() { public long getInterval() {
long t = per.getMilliseconds() / (amount == 0 ? 1 : amount); long t = per.toMilliseconds() / (amount == 0 ? 1 : amount);
return Math.abs(t <= 0 ? 1 : t); return Math.abs(t <= 0 ? 1 : t);
} }
@@ -19,6 +19,7 @@
package com.volmit.iris.engine.object; package com.volmit.iris.engine.object;
import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.annotations.ArrayType; import com.volmit.iris.engine.object.annotations.ArrayType;
import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
@@ -95,6 +96,37 @@ public class IrisSpawner extends IrisRegistrant {
return timeBlock.isWithin(world) && weather.is(world); return timeBlock.isWithin(world) && weather.is(world);
} }
public boolean canSpawn(Engine engine) {
if (!isValid(engine.getWorld().realWorld()))
return false;
var rate = getMaximumRate();
return rate.isInfinite() || engine.getEngineData().getCooldown(this).canSpawn(rate);
}
public boolean canSpawn(Engine engine, int x, int z) {
if (!canSpawn(engine))
return false;
var rate = getMaximumRatePerChunk();
return rate.isInfinite() || engine.getEngineData().getChunk(x, z).getCooldown(this).canSpawn(rate);
}
public void spawn(Engine engine) {
if (getMaximumRate().isInfinite())
return;
engine.getEngineData().getCooldown(this).spawn(engine);
}
public void spawn(Engine engine, int x, int z) {
spawn(engine);
if (getMaximumRatePerChunk().isInfinite())
return;
engine.getEngineData().getChunk(x, z).getCooldown(this).spawn(engine);
}
@Override @Override
public String getFolderName() { public String getFolderName() {
return "spawners"; return "spawners";
@@ -0,0 +1,34 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
@EqualsAndHashCode
public class IrisSpawnerCooldowns {
private final KMap<String, IrisEngineSpawnerCooldown> cooldowns = new KMap<>();
public IrisEngineSpawnerCooldown getCooldown(@NonNull IrisSpawner spawner) {
return getCooldown(spawner.getLoadKey());
}
public IrisEngineSpawnerCooldown getCooldown(@NonNull String loadKey) {
return cooldowns.computeIfAbsent(loadKey, k -> {
IrisEngineSpawnerCooldown cd = new IrisEngineSpawnerCooldown();
cd.setSpawner(loadKey);
return cd;
});
}
public void cleanup(Engine engine) {
cooldowns.values().removeIf(cd -> {
IrisSpawner sp = engine.getData().getSpawnerLoader().load(cd.getSpawner());
return sp == null || cd.canSpawn(sp.getMaximumRate());
});
}
public boolean isEmpty() {
return cooldowns.isEmpty();
}
}
@@ -48,6 +48,7 @@ public class IrisWorld {
private long seed; private long seed;
private World.Environment environment; private World.Environment environment;
private World realWorld; private World realWorld;
private IrisHeadless headless;
private int minHeight; private int minHeight;
private int maxHeight; private int maxHeight;
@@ -35,7 +35,6 @@ import java.io.IOException;
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
@Getter @Getter
@ToString
@EqualsAndHashCode @EqualsAndHashCode
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED) @NoArgsConstructor(access = AccessLevel.PROTECTED)
@@ -137,4 +136,9 @@ public class TileData implements Cloneable {
clone.properties = properties.copy(); //TODO make a deep copy clone.properties = properties.copy(); //TODO make a deep copy
return clone; return clone;
} }
@Override
public String toString() {
return material.getKey() + gson.toJson(properties);
}
} }
@@ -21,6 +21,8 @@ package com.volmit.iris.engine.platform;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.pregenerator.EmptyListener;
import com.volmit.iris.core.pregenerator.methods.HeadlessPregenMethod;
import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.IrisEngine; import com.volmit.iris.engine.IrisEngine;
import com.volmit.iris.engine.data.chunk.TerrainChunk; import com.volmit.iris.engine.data.chunk.TerrainChunk;
@@ -32,10 +34,13 @@ import com.volmit.iris.engine.object.StudioMode;
import com.volmit.iris.engine.platform.studio.StudioGenerator; import com.volmit.iris.engine.platform.studio.StudioGenerator;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.data.IrisBiomeStorage; import com.volmit.iris.util.data.IrisBiomeStorage;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder; import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder;
import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder; import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder;
import com.volmit.iris.util.io.ReactiveFolder; import com.volmit.iris.util.io.ReactiveFolder;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.Looper; import com.volmit.iris.util.scheduling.Looper;
@@ -58,8 +63,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
@@ -86,7 +89,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
private final boolean studio; private final boolean studio;
private final AtomicInteger a = new AtomicInteger(0); private final AtomicInteger a = new AtomicInteger(0);
private final CompletableFuture<Integer> spawnChunks = new CompletableFuture<>(); private final CompletableFuture<Integer> spawnChunks = new CompletableFuture<>();
private final boolean smartVanillaHeight;
private Engine engine; private Engine engine;
private Looper hotloader; private Looper hotloader;
private StudioMode lastMode; private StudioMode lastMode;
@@ -96,7 +98,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
private boolean initialized = false; private boolean initialized = false;
public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey, boolean smartVanillaHeight) { public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) {
setup = new AtomicBoolean(false); setup = new AtomicBoolean(false);
studioGenerator = null; studioGenerator = null;
dummyBiomeProvider = new DummyBiomeProvider(); dummyBiomeProvider = new DummyBiomeProvider();
@@ -108,7 +110,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
this.dataLocation = dataLocation; this.dataLocation = dataLocation;
this.dimensionKey = dimensionKey; this.dimensionKey = dimensionKey;
this.folder = new ReactiveFolder(dataLocation, (_a, _b, _c) -> hotload()); this.folder = new ReactiveFolder(dataLocation, (_a, _b, _c) -> hotload());
this.smartVanillaHeight = smartVanillaHeight;
Bukkit.getServer().getPluginManager().registerEvents(this, Iris.instance); Bukkit.getServer().getPluginManager().registerEvents(this, Iris.instance);
} }
@@ -186,14 +187,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
throw new RuntimeException("Missing Dimension: " + dimensionKey); throw new RuntimeException("Missing Dimension: " + dimensionKey);
} }
} }
if (smartVanillaHeight) {
dimension.setSmartVanillaHeight(true);
try (FileWriter writer = new FileWriter(data.getDimensionLoader().fileFor(dimension))) {
writer.write(data.getGson().toJson(dimension));
} catch (IOException e) {
e.printStackTrace();
}
}
lastMode = StudioMode.NORMAL; lastMode = StudioMode.NORMAL;
engine = new IrisEngine(new EngineTarget(world, dimension, data), studio); engine = new IrisEngine(new EngineTarget(world, dimension, data), studio);
@@ -264,6 +257,10 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
} }
private Engine getEngine(WorldInfo world) { private Engine getEngine(WorldInfo world) {
return getEngine(world.getSeed());
}
private Engine getEngine(long seed) {
if (setup.get()) { if (setup.get()) {
return getEngine(); return getEngine();
} }
@@ -276,7 +273,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
} }
getWorld().setRawWorldSeed(world.getSeed()); getWorld().setRawWorldSeed(seed);
setupEngine(); setupEngine();
setup.set(true); setup.set(true);
this.hotloader = studio ? new Looper() { this.hotloader = studio ? new Looper() {
@@ -347,6 +344,21 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
getEngine(world); getEngine(world);
} }
@Override
public void prepareSpawnChunks(long seed, int radius) {
if (radius < 0 || new File(world.worldFolder(), "level.dat").exists())
return;
var engine = getEngine(seed);
var headless = new HeadlessPregenMethod(engine, 4);
for (int x = -radius; x <= radius; x++) {
for (int z = -radius; z <= radius; z++) {
headless.generateChunk(x, z, EmptyListener.INSTANCE);
}
}
headless.close();
}
@Override @Override
public void generateNoise(@NotNull WorldInfo world, @NotNull Random random, int x, int z, @NotNull ChunkGenerator.ChunkData d) { public void generateNoise(@NotNull WorldInfo world, @NotNull Random random, int x, int z, @NotNull ChunkGenerator.ChunkData d) {
try { try {
@@ -49,4 +49,12 @@ public interface PlatformChunkGenerator extends Hotloadable, DataProvider {
void touch(World world); void touch(World world);
CompletableFuture<Integer> getSpawnChunks(); CompletableFuture<Integer> getSpawnChunks();
void prepareSpawnChunks(long seed, int radius);
default int getGenerated() {
Engine engine = getEngine();
if (engine == null) return 0;
return engine.getGenerated();
}
} }
@@ -22,10 +22,9 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.object.IrisCompat;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.misc.E; import com.volmit.iris.util.data.registry.Materials;
import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.ChronoLatch;
import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.ints.*;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@@ -47,7 +46,7 @@ public class B {
private static final KMap<String, BlockData> custom = new KMap<>(); private static final KMap<String, BlockData> custom = new KMap<>();
private static final Material AIR_MATERIAL = Material.AIR; private static final Material AIR_MATERIAL = Material.AIR;
private static final Material SHORT_GRASS = E.getOrDefault(Material.class, "GRASS", "SHORT_GRASS"); private static final Material SHORT_GRASS = Materials.GRASS;
private static final BlockData AIR = AIR_MATERIAL.createBlockData(); private static final BlockData AIR = AIR_MATERIAL.createBlockData();
private static final IntSet foliageCache = buildFoliageCache(); private static final IntSet foliageCache = buildFoliageCache();
private static final IntSet deepslateCache = buildDeepslateCache(); private static final IntSet deepslateCache = buildDeepslateCache();
@@ -15,7 +15,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@Data @Data
public class IrisBlockData implements BlockData { public class IrisCustomData implements BlockData {
private final @NonNull BlockData base; private final @NonNull BlockData base;
private final @NotNull Identifier custom; private final @NotNull Identifier custom;
@@ -40,12 +40,12 @@ public class IrisBlockData implements BlockData {
@NotNull @NotNull
@Override @Override
public BlockData merge(@NotNull BlockData blockData) { public BlockData merge(@NotNull BlockData blockData) {
return new IrisBlockData(base.merge(blockData), custom); return new IrisCustomData(base.merge(blockData), custom);
} }
@Override @Override
public boolean matches(@Nullable BlockData blockData) { public boolean matches(@Nullable BlockData blockData) {
if (blockData instanceof IrisBlockData b) if (blockData instanceof IrisCustomData b)
return custom.equals(b.custom) && base.matches(b.base); return custom.equals(b.custom) && base.matches(b.base);
return base.matches(blockData); return base.matches(blockData);
} }
@@ -53,7 +53,7 @@ public class IrisBlockData implements BlockData {
@NotNull @NotNull
@Override @Override
public BlockData clone() { public BlockData clone() {
return new IrisBlockData(base.clone(), custom); return new IrisCustomData(base.clone(), custom);
} }
@NotNull @NotNull
@@ -0,0 +1,7 @@
package com.volmit.iris.util.data.registry;
import org.bukkit.attribute.Attribute;
public class Attributes {
public static final Attribute MAX_HEALTH = RegistryUtil.find(Attribute.class, "generic_max_health", "max_health");
}
@@ -0,0 +1,9 @@
package com.volmit.iris.util.data.registry;
import org.bukkit.Material;
import static com.volmit.iris.util.data.registry.RegistryUtil.find;
public class Materials {
public static final Material GRASS = find(Material.class, "grass", "short_grass");
}
@@ -0,0 +1,11 @@
package com.volmit.iris.util.data.registry;
import org.bukkit.Particle;
import static com.volmit.iris.util.data.registry.RegistryUtil.find;
public class Particles {
public static final Particle CRIT_MAGIC = find(Particle.class, "crit_magic", "crit");
public static final Particle REDSTONE = find(Particle.class, "redstone", "dust");
public static final Particle ITEM = find(Particle.class, "item_crack", "item");
}
@@ -0,0 +1,209 @@
package com.volmit.iris.util.data.registry;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.data.cache.AtomicCache;
import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
@SuppressWarnings("unchecked")
public class RegistryUtil {
private static final AtomicCache<RegistryLookup> registryLookup = new AtomicCache<>();
private static final Map<Class<?>, Map<NamespacedKey, Keyed>> KEYED_REGISTRY = new HashMap<>();
private static final Map<Class<?>, Map<NamespacedKey, Object>> ENUM_REGISTRY = new HashMap<>();
private static final Map<Class<?>, Registry<Keyed>> REGISTRY = new HashMap<>();
@NonNull
public static <T> T find(@NonNull Class<T> typeClass, @NonNull String... keys) {
return find(typeClass, defaultLookup(), keys);
}
@NonNull
public static <T> T find(@NonNull Class<T> typeClass, @Nullable Lookup<T> lookup, @NonNull String... keys) {
return find(typeClass, lookup, Arrays.stream(keys).map(NamespacedKey::minecraft).toArray(NamespacedKey[]::new));
}
public static <T> T find(@NonNull Class<T> typeClass, @NonNull NamespacedKey... keys) {
return find(typeClass, defaultLookup(), keys);
}
@NonNull
public static <T> T find(@NonNull Class<T> typeClass, @Nullable Lookup<T> lookup, @NonNull NamespacedKey... keys) {
if (keys.length == 0) throw new IllegalArgumentException("Need at least one key");
Registry<Keyed> registry = null;
if (Keyed.class.isAssignableFrom(typeClass)) {
registry = getRegistry(typeClass.asSubclass(Keyed.class));
}
if (registry == null) {
registry = REGISTRY.computeIfAbsent(typeClass, t -> Arrays.stream(Registry.class.getDeclaredFields())
.filter(field -> Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers()))
.filter(field -> Registry.class.isAssignableFrom(field.getType()))
.filter(field -> ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0].equals(t))
.map(field -> {
try {
return (Registry<Keyed>) field.get(null);
} catch (IllegalAccessException e) {
return null;
}
})
.filter(Objects::nonNull)
.findFirst()
.orElse(null));
}
if (registry != null) {
for (NamespacedKey key : keys) {
Keyed value = registry.get(key);
if (value != null)
return (T) value;
}
}
if (lookup != null)
return lookup.find(typeClass, keys);
throw new IllegalArgumentException("No element found for keys: " + Arrays.toString(keys));
}
@NonNull
public static <T> T findByField(@NonNull Class<T> typeClass, @NonNull NamespacedKey... keys) {
var values = KEYED_REGISTRY.computeIfAbsent(typeClass, RegistryUtil::getKeyedValues);
for (NamespacedKey key : keys) {
var value = values.get(key);
if (value != null)
return (T) value;
}
throw new IllegalArgumentException("No element found for keys: " + Arrays.toString(keys));
}
@NonNull
public static <T> T findByEnum(@NonNull Class<T> typeClass, @NonNull NamespacedKey... keys) {
var values = ENUM_REGISTRY.computeIfAbsent(typeClass, RegistryUtil::getEnumValues);
for (NamespacedKey key : keys) {
var value = values.get(key);
if (value != null)
return (T) value;
}
throw new IllegalArgumentException("No element found for keys: " + Arrays.toString(keys));
}
@NonNull
public static <T> Lookup<T> defaultLookup() {
return Lookup.combine(RegistryUtil::findByField, RegistryUtil::findByEnum);
}
private static Map<NamespacedKey, Keyed> getKeyedValues(@NonNull Class<?> typeClass) {
return Arrays.stream(typeClass.getDeclaredFields())
.filter(field -> Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers()))
.filter(field -> Keyed.class.isAssignableFrom(field.getType()))
.map(field -> {
try {
return (Keyed) field.get(null);
} catch (Throwable e) {
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toMap(Keyed::getKey, Function.identity()));
}
private static Map<NamespacedKey, Object> getEnumValues(@NonNull Class<?> typeClass) {
return Arrays.stream(typeClass.getDeclaredFields())
.filter(field -> Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers()))
.filter(field -> typeClass.isAssignableFrom(field.getType()))
.map(field -> {
try {
return new Pair<>(NamespacedKey.minecraft(field.getName().toLowerCase()), field.get(null));
} catch (Throwable e) {
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toMap(Pair::getA, Pair::getB));
}
@FunctionalInterface
public interface Lookup<T> {
@NonNull
T find(@NonNull Class<T> typeClass, @NonNull NamespacedKey... keys);
static <T> Lookup<T> combine(@NonNull Lookup<T>... lookups) {
if (lookups.length == 0) throw new IllegalArgumentException("Need at least one lookup");
return (typeClass, keys) -> {
for (Lookup<T> lookup : lookups) {
try {
return lookup.find(typeClass, keys);
} catch (IllegalArgumentException ignored) {}
}
throw new IllegalArgumentException("No element found for keys: " + Arrays.toString(keys));
};
}
}
@Nullable
private static <T extends Keyed> Registry<T> getRegistry(@NotNull Class<T> type) {
RegistryLookup lookup = registryLookup.aquire(() -> {
RegistryLookup bukkit;
try {
bukkit = Bukkit::getRegistry;
} catch (Throwable ignored) {
bukkit = null;
}
return new DefaultRegistryLookup(bukkit);
});
return lookup.find(type);
}
private interface RegistryLookup {
@Nullable
<T extends Keyed> Registry<T> find(@NonNull Class<T> type);
}
private static class DefaultRegistryLookup implements RegistryLookup {
private final RegistryLookup bukkit;
private final Map<Type, Object> registries;
private DefaultRegistryLookup(RegistryLookup bukkit) {
this.bukkit = bukkit;
registries = Arrays.stream(Registry.class.getDeclaredFields())
.filter(field -> Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers()))
.filter(field -> Registry.class.isAssignableFrom(field.getType()))
.map(field -> {
var type = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
try {
return new Pair<>(type, field.get(null));
} catch (Throwable e) {
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toMap(Pair::getA, Pair::getB, (a, b) -> a));
}
@Nullable
@Override
public <T extends Keyed> Registry<T> find(@NonNull Class<T> type) {
if (bukkit == null) return (Registry<T>) registries.get(type);
try {
return bukkit.find(type);
} catch (Throwable e) {
return (Registry<T>) registries.get(type);
}
}
}
}

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