Merge pull request #1115 from VolmitSoftware/v3.4.3

V3.5.0
This commit is contained in:
Julian Krings 2025-01-02 19:37:22 +01:00 committed by GitHub
commit 5cf0ac9315
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
134 changed files with 7179 additions and 3564 deletions

View File

@ -32,7 +32,7 @@ plugins {
id "de.undercouch.download" version "5.0.1" id "de.undercouch.download" version "5.0.1"
} }
version '3.4.1-1.19.2-1.21.1' version '3.5.0-1.19.2-1.21.3'
// 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 =============================
@ -43,7 +43,8 @@ registerCustomOutputTask('Coco', 'D://mcsm/plugins')
registerCustomOutputTask('Strange', 'D://Servers/1.17 Test Server/plugins') registerCustomOutputTask('Strange', 'D://Servers/1.17 Test Server/plugins')
registerCustomOutputTask('Vatuu', 'D://Minecraft/Servers/1.19.4/plugins') registerCustomOutputTask('Vatuu', 'D://Minecraft/Servers/1.19.4/plugins')
registerCustomOutputTask('CrazyDev22', 'C://Users/Julian/Desktop/server/plugins') registerCustomOutputTask('CrazyDev22', 'C://Users/Julian/Desktop/server/plugins')
registerCustomOutputTask('Pixel', 'C://Users/repix/Iris Dimension Engine/1.20.4 - Development/plugins') registerCustomOutputTask('PixelFury', 'C://Users/repix/workplace/Iris/1.21.3 - Development-Public-v3/plugins')
registerCustomOutputTask('PixelFuryDev', 'C://Users/repix/workplace/Iris/1.21 - Development-v3/plugins')
// ========================== UNIX ============================== // ========================== UNIX ==============================
registerCustomOutputTaskUnix('CyberpwnLT', '/Users/danielmills/development/server/plugins') registerCustomOutputTaskUnix('CyberpwnLT', '/Users/danielmills/development/server/plugins')
registerCustomOutputTaskUnix('PsychoLT', '/Users/brianfopiano/Developer/RemoteGit/Server/plugins') registerCustomOutputTaskUnix('PsychoLT', '/Users/brianfopiano/Developer/RemoteGit/Server/plugins')
@ -52,7 +53,8 @@ registerCustomOutputTaskUnix('CrazyDev22LT', '/home/julian/Desktop/server/plugin
// ============================================================== // ==============================================================
def NMS_BINDINGS = Map.of( def NMS_BINDINGS = Map.of(
"v1_21_R1", "1.21-R0.1-SNAPSHOT", "v1_21_R2", "1.21.3-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",
@ -61,17 +63,14 @@ def NMS_BINDINGS = Map.of(
"v1_19_R2", "1.19.3-R0.1-SNAPSHOT", "v1_19_R2", "1.19.3-R0.1-SNAPSHOT",
"v1_19_R1", "1.19.2-R0.1-SNAPSHOT" "v1_19_R1", "1.19.2-R0.1-SNAPSHOT"
) )
def JVM_VERSION = Map.of( def JVM_VERSION = Map.of()
"v1_21_R1", 21,
"v1_20_R4", 21,
)
NMS_BINDINGS.each { nms -> NMS_BINDINGS.each { nms ->
project(":nms:${nms.key}") { project(":nms:${nms.key}") {
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'com.volmit.nmstools' apply plugin: 'com.volmit.nmstools'
nmsTools { nmsTools {
it.jvm = JVM_VERSION.getOrDefault(nms.key, 17) it.jvm = JVM_VERSION.getOrDefault(nms.key, 21)
it.version = nms.value it.version = nms.value
} }
@ -92,6 +91,7 @@ shadowJar {
relocate 'com.dfsek.paralithic', 'com.volmit.iris.util.paralithic' relocate 'com.dfsek.paralithic', 'com.volmit.iris.util.paralithic'
relocate 'io.papermc.lib', 'com.volmit.iris.util.paper' relocate 'io.papermc.lib', 'com.volmit.iris.util.paper'
relocate 'net.kyori', 'com.volmit.iris.util.kyori' relocate 'net.kyori', 'com.volmit.iris.util.kyori'
relocate 'org.bstats', 'com.volmit.util.metrics'
archiveFileName.set("Iris-${project.version}.jar") archiveFileName.set("Iris-${project.version}.jar")
} }
@ -119,23 +119,26 @@ allprojects {
maven { url "https://repo.triumphteam.dev/snapshots" } maven { url "https://repo.triumphteam.dev/snapshots" }
maven { url "https://repo.mineinabyss.com/releases" } maven { url "https://repo.mineinabyss.com/releases" }
maven { url 'https://hub.jeff-media.com/nexus/repository/jeff-media-public/' } maven { url 'https://hub.jeff-media.com/nexus/repository/jeff-media-public/' }
maven { url "https://repo.oraxen.com/releases" } maven { url "https://repo.nexomc.com/snapshots/" }
maven { url "https://libraries.minecraft.net" }
} }
dependencies { dependencies {
// Provided or Classpath // Provided or Classpath
compileOnly 'org.projectlombok:lombok:1.18.24' compileOnly 'org.projectlombok:lombok:1.18.36'
annotationProcessor 'org.projectlombok:lombok:1.18.24' annotationProcessor 'org.projectlombok:lombok:1.18.36'
// Shaded // Shaded
implementation 'com.dfsek:Paralithic:0.4.0' implementation 'com.dfsek:Paralithic:0.4.0'
implementation 'io.papermc:paperlib:1.0.5' implementation 'io.papermc:paperlib:1.0.5'
implementation "net.kyori:adventure-text-minimessage:4.13.1" implementation "net.kyori:adventure-text-minimessage:4.17.0"
implementation 'net.kyori:adventure-platform-bukkit:4.3.2' implementation 'net.kyori:adventure-platform-bukkit:4.3.4'
implementation 'net.kyori:adventure-api:4.13.1' implementation 'net.kyori:adventure-api:4.17.0'
implementation 'org.bstats:bstats-bukkit:3.1.0'
//implementation 'org.bytedeco:javacpp:1.5.10' //implementation 'org.bytedeco:javacpp:1.5.10'
//implementation 'org.bytedeco:cuda-platform:12.3-8.9-1.5.10' //implementation 'org.bytedeco:cuda-platform:12.3-8.9-1.5.10'
compileOnly 'io.lumine:Mythic-Dist:5.2.1' compileOnly 'io.lumine:Mythic-Dist:5.2.1'
compileOnly 'io.lumine:MythicCrucible-Dist:2.0.0'
// Dynamically Loaded // Dynamically Loaded
compileOnly 'io.timeandspace:smoothie-map:2.0.2' compileOnly 'io.timeandspace:smoothie-map:2.0.2'
@ -149,6 +152,7 @@ allprojects {
compileOnly 'rhino:js:1.7R2' compileOnly 'rhino:js:1.7R2'
compileOnly 'com.github.ben-manes.caffeine:caffeine:3.0.6' compileOnly 'com.github.ben-manes.caffeine:caffeine:3.0.6'
compileOnly 'org.apache.commons:commons-lang3:3.12.0' compileOnly 'org.apache.commons:commons-lang3:3.12.0'
compileOnly 'com.github.oshi:oshi-core:6.6.5'
} }
/** /**
@ -175,18 +179,18 @@ allprojects {
} }
} }
if (JavaVersion.current().toString() != "17") { if (JavaVersion.current().toString() != "21") {
System.err.println() System.err.println()
System.err.println("=========================================================================================================") System.err.println("=========================================================================================================")
System.err.println("You must run gradle on Java 17. You are using " + JavaVersion.current()) System.err.println("You must run gradle on Java 21. You are using " + JavaVersion.current())
System.err.println() System.err.println()
System.err.println("=== For IDEs ===") System.err.println("=== For IDEs ===")
System.err.println("1. Configure the project for Java 17") System.err.println("1. Configure the project for Java 21")
System.err.println("2. Configure the bundled gradle to use Java 17 in settings") System.err.println("2. Configure the bundled gradle to use Java 21 in settings")
System.err.println() System.err.println()
System.err.println("=== For Command Line (gradlew) ===") System.err.println("=== For Command Line (gradlew) ===")
System.err.println("1. Install JDK 17 from https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html") System.err.println("1. Install JDK 21 from https://www.oracle.com/java/technologies/javase/jdk21-archive-downloads.html")
System.err.println("2. Set JAVA_HOME environment variable to the new jdk installation folder such as C:\\Program Files\\Java\\jdk-17.0.1") System.err.println("2. Set JAVA_HOME environment variable to the new jdk installation folder such as C:\\Program Files\\Java\\jdk-21.0.4")
System.err.println("3. Open a new command prompt window to get the new environment variables if need be.") System.err.println("3. Open a new command prompt window to get the new environment variables if need be.")
System.err.println("=========================================================================================================") System.err.println("=========================================================================================================")
System.err.println() System.err.println()

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 'io.th0rgal:oraxen:1.173.0' compileOnly 'com.nexomc:nexo:0.6.0-dev.0'
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'
@ -71,6 +71,9 @@ dependencies {
//implementation files('libs/CustomItems.jar') //implementation files('libs/CustomItems.jar')
} }
java {
disableAutoTargetJvm()
}
/** /**
* Gradle is weird sometimes, we need to delete the plugin yml from the build folder to actually filter properly. * Gradle is weird sometimes, we need to delete the plugin yml from the build folder to actually filter properly.

View File

@ -40,6 +40,7 @@ import com.volmit.iris.engine.platform.BukkitChunkGenerator;
import com.volmit.iris.engine.platform.DummyChunkGenerator; import com.volmit.iris.engine.platform.DummyChunkGenerator;
import com.volmit.iris.core.safeguard.IrisSafeguard; import com.volmit.iris.core.safeguard.IrisSafeguard;
import com.volmit.iris.core.safeguard.UtilsSFG; import com.volmit.iris.core.safeguard.UtilsSFG;
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.exceptions.IrisException; import com.volmit.iris.util.exceptions.IrisException;
@ -55,7 +56,6 @@ import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.misc.getHardware; import com.volmit.iris.util.misc.getHardware;
import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.IrisService; import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.Metrics;
import com.volmit.iris.util.plugin.VolmitPlugin; import com.volmit.iris.util.plugin.VolmitPlugin;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.reflect.ShadeFix; import com.volmit.iris.util.reflect.ShadeFix;
@ -63,13 +63,13 @@ import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.Queue; import com.volmit.iris.util.scheduling.Queue;
import com.volmit.iris.util.scheduling.ShurikenQueue; import com.volmit.iris.util.scheduling.ShurikenQueue;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import lombok.Getter;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.serializer.ComponentSerializer; import net.kyori.adventure.text.serializer.ComponentSerializer;
import org.bukkit.Bukkit; import org.bstats.bukkit.Metrics;
import org.bukkit.GameMode; import org.bstats.charts.DrilldownPie;
import org.bukkit.Location; import org.bstats.charts.SimplePie;
import org.bukkit.WorldCreator; import org.bstats.charts.SingleLineChart;
import org.bukkit.*;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -77,33 +77,31 @@ import org.bukkit.configuration.ConfigurationSection;
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.bukkit.event.Event; import org.bukkit.event.*;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.IllegalPluginAccessException; import org.bukkit.plugin.IllegalPluginAccessException;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import oshi.SystemInfo;
import java.io.*; import java.io.*;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.management.ManagementFactory; import java.math.RoundingMode;
import java.lang.management.OperatingSystemMXBean;
import java.net.URL; import java.net.URL;
import java.util.Date; import java.text.NumberFormat;
import java.util.Map; import java.util.*;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.volmit.iris.core.safeguard.IrisSafeguard.*; import static com.volmit.iris.core.safeguard.IrisSafeguard.*;
import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware; import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware;
import static com.volmit.iris.util.misc.getHardware.getCPUModel;
@SuppressWarnings("CanBeFinal") @SuppressWarnings("CanBeFinal")
public class Iris extends VolmitPlugin implements Listener { public class Iris extends VolmitPlugin implements Listener {
public static final String OVERWORLD_TAG = "3800"; public static final String OVERWORLD_TAG = "31000";
private static final Queue<Runnable> syncJobs = new ShurikenQueue<>(); private static final Queue<Runnable> syncJobs = new ShurikenQueue<>();
@ -512,11 +510,10 @@ public class Iris extends VolmitPlugin implements Listener {
continue; continue;
} }
Iris.info("2 World: %s | Generator: %s", s, generator); if (Bukkit.getWorld(s) != null)
if (Bukkit.getWorlds().stream().anyMatch(w -> w.getName().equals(s))) {
continue; continue;
}
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) new WorldCreator(s)
@ -664,7 +661,48 @@ public class Iris extends VolmitPlugin implements Listener {
private void bstats() { private void bstats() {
if (IrisSettings.get().getGeneral().isPluginMetrics()) { if (IrisSettings.get().getGeneral().isPluginMetrics()) {
J.s(() -> new Metrics(Iris.instance, 8757)); J.s(() -> {
var metrics = new Metrics(Iris.instance, 24220);
metrics.addCustomChart(new SingleLineChart("custom_dimensions", () -> Bukkit.getWorlds()
.stream()
.filter(IrisToolbelt::isIrisWorld)
.mapToInt(w -> 1)
.sum()));
metrics.addCustomChart(new DrilldownPie("used_packs", () -> Bukkit.getWorlds().stream()
.map(IrisToolbelt::access)
.filter(Objects::nonNull)
.map(PlatformChunkGenerator::getTarget)
.collect(Collectors.toMap(target -> target.getDimension().getLoadKey(), target -> {
int version = target.getDimension().getVersion();
String checksum = IO.hashRecursive(target.getData().getDataFolder());
return Map.of("v" + version + " (" + checksum + ")", 1);
}, (a, b) -> {
Map<String, Integer> merged = new HashMap<>(a);
b.forEach((k, v) -> merged.merge(k, v, Integer::sum));
return merged;
}))));
var info = new SystemInfo().getHardware();
var cpu = info.getProcessor().getProcessorIdentifier();
var mem = info.getMemory();
metrics.addCustomChart(new SimplePie("cpu_model", cpu::getName));
var nf = NumberFormat.getInstance(Locale.ENGLISH);
nf.setMinimumFractionDigits(0);
nf.setMaximumFractionDigits(2);
nf.setRoundingMode(RoundingMode.HALF_UP);
metrics.addCustomChart(new DrilldownPie("memory", () -> {
double total = mem.getTotal() * 1E-9;
double alloc = Math.min(total, Runtime.getRuntime().maxMemory() * 1E-9);
return Map.of(nf.format(alloc), Map.of(nf.format(total), 1));
}));
postShutdown.add(metrics::shutdown);
});
} }
} }

View File

@ -25,7 +25,9 @@ import com.volmit.iris.util.json.JSONException;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.ChronoLatch;
import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -42,6 +44,7 @@ public class IrisSettings {
private IrisSettingsConcurrency concurrency = new IrisSettingsConcurrency(); private IrisSettingsConcurrency concurrency = new IrisSettingsConcurrency();
private IrisSettingsStudio studio = new IrisSettingsStudio(); private IrisSettingsStudio studio = new IrisSettingsStudio();
private IrisSettingsPerformance performance = new IrisSettingsPerformance(); private IrisSettingsPerformance performance = new IrisSettingsPerformance();
private IrisSettingsUpdater updater = new IrisSettingsUpdater();
public static int getThreadCount(int c) { public static int getThreadCount(int c) {
return switch (c) { return switch (c) {
@ -144,6 +147,30 @@ public class IrisSettings {
public int scriptLoaderCacheSize = 512; public int scriptLoaderCacheSize = 512;
} }
@Data
public static class IrisSettingsUpdater {
public double threadMultiplier = 2;
public double chunkLoadSensitivity = 0.7;
public MsRange emptyMsRange = new MsRange(80, 100);
public MsRange defaultMsRange = new MsRange(20, 40);
public double getThreadMultiplier() {
return Math.min(Math.abs(threadMultiplier), 0.1);
}
public double getChunkLoadSensitivity() {
return Math.min(chunkLoadSensitivity, 0.9);
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class MsRange {
public int min = 20;
public int max = 40;
}
@Data @Data
public static class IrisSettingsGeneral { public static class IrisSettingsGeneral {
public boolean DoomsdayAnnihilationSelfDestructMode = false; public boolean DoomsdayAnnihilationSelfDestructMode = false;
@ -171,6 +198,7 @@ public class IrisSettings {
public static class IrisSettingsGUI { public static class IrisSettingsGUI {
public boolean useServerLaunchedGuis = true; public boolean useServerLaunchedGuis = true;
public boolean maximumPregenGuiFPS = false; public boolean maximumPregenGuiFPS = false;
public boolean colorMode = true;
} }
@Data @Data

View File

@ -21,34 +21,25 @@ package com.volmit.iris.core.commands;
import com.volmit.iris.Iris; 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.INMS;
import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import com.volmit.iris.core.pregenerator.ChunkUpdater;
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.mantle.components.MantleObjectComponent;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisCave;
import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisEntity;
import com.volmit.iris.util.data.Dimension;
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;
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.format.Form; import com.volmit.iris.util.format.Form;
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.Spiraler;
import com.volmit.iris.util.math.Vector3d;
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.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
import io.lumine.mythic.bukkit.adapters.BukkitEntity;
import net.jpountz.lz4.LZ4BlockInputStream; import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream; import net.jpountz.lz4.LZ4BlockOutputStream;
import net.jpountz.lz4.LZ4FrameInputStream; import net.jpountz.lz4.LZ4FrameInputStream;
@ -56,10 +47,7 @@ import net.jpountz.lz4.LZ4FrameOutputStream;
import org.apache.commons.lang.RandomStringUtils; 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.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.EntityType;
import java.io.*; import java.io.*;
import java.net.InetAddress; import java.net.InetAddress;
@ -150,12 +138,14 @@ public class CommandDeveloper implements DecreeExecutor {
@Decree(description = "Test") @Decree(description = "Test")
public void packBenchmark( public void packBenchmark(
@Param(description = "The pack to bench", aliases = {"pack"}) @Param(description = "The pack to bench", aliases = {"pack"}, defaultValue = "overworld")
IrisDimension dimension IrisDimension dimension,
@Param(description = "Radius in regions", defaultValue = "5")
int radius,
@Param(description = "Open GUI while benchmarking", defaultValue = "false")
boolean gui
) { ) {
Iris.info("test"); new IrisPackBenchmarking(dimension, radius, gui);
IrisPackBenchmarking benchmark = new IrisPackBenchmarking(dimension, 1);
} }
@Decree(description = "Upgrade to another Minecraft version") @Decree(description = "Upgrade to another Minecraft version")
@ -206,6 +196,23 @@ public class CommandDeveloper implements DecreeExecutor {
} }
@Decree
public void objects(@Param(defaultValue = "overworld") IrisDimension dimension) {
var loader = dimension.getLoader().getObjectLoader();
var sender = sender();
var keys = loader.getPossibleKeys();
var burst = MultiBurst.burst.burst(keys.length);
AtomicInteger failed = new AtomicInteger();
for (String key : keys) {
burst.queue(() -> {
if (loader.load(key) == null)
failed.incrementAndGet();
});
}
burst.complete();
sender.sendMessage(C.RED + "Failed to load " + failed.get() + " of " + keys.length + " objects");
}
@Decree(description = "Test", aliases = {"ip"}) @Decree(description = "Test", aliases = {"ip"})
public void network() { public void network() {
try { try {
@ -243,7 +250,7 @@ public class CommandDeveloper implements DecreeExecutor {
VolmitSender sender = sender(); VolmitSender sender = sender();
service.submit(() -> { service.submit(() -> {
try { try {
DataInputStream raw = new DataInputStream(new FileInputStream(file)); CountingDataInputStream raw = CountingDataInputStream.wrap(new FileInputStream(file));
TectonicPlate plate = new TectonicPlate(height, raw); TectonicPlate plate = new TectonicPlate(height, raw);
raw.close(); raw.close();
@ -262,7 +269,7 @@ public class CommandDeveloper implements DecreeExecutor {
if (size == 0) if (size == 0)
size = tmp.length(); size = tmp.length();
start = System.currentTimeMillis(); start = System.currentTimeMillis();
DataInputStream din = createInput(tmp, algorithm); CountingDataInputStream din = createInput(tmp, algorithm);
new TectonicPlate(height, din); new TectonicPlate(height, din);
din.close(); din.close();
d2 += System.currentTimeMillis() - start; d2 += System.currentTimeMillis() - start;
@ -282,10 +289,10 @@ public class CommandDeveloper implements DecreeExecutor {
} }
} }
private DataInputStream createInput(File file, String algorithm) throws Throwable { private CountingDataInputStream createInput(File file, String algorithm) throws Throwable {
FileInputStream in = new FileInputStream(file); FileInputStream in = new FileInputStream(file);
return new DataInputStream(switch (algorithm) { return CountingDataInputStream.wrap(switch (algorithm) {
case "gzip" -> new GZIPInputStream(in); case "gzip" -> new GZIPInputStream(in);
case "lz4f" -> new LZ4FrameInputStream(in); case "lz4f" -> new LZ4FrameInputStream(in);
case "lz4b" -> new LZ4BlockInputStream(in); case "lz4b" -> new LZ4BlockInputStream(in);

View File

@ -60,7 +60,7 @@ public class CommandJigsaw implements DecreeExecutor {
try { try {
var world = world(); var world = world();
WorldObjectPlacer placer = new WorldObjectPlacer(world); WorldObjectPlacer placer = new WorldObjectPlacer(world);
PlannedStructure ps = new PlannedStructure(structure, new IrisPosition(player().getLocation().add(0, world.getMinHeight(), 0)), new RNG()); PlannedStructure ps = new PlannedStructure(structure, new IrisPosition(player().getLocation().add(0, world.getMinHeight(), 0)), new RNG(), true);
VolmitSender sender = sender(); VolmitSender sender = sender();
sender.sendMessage(C.GREEN + "Generated " + ps.getPieces().size() + " pieces in " + Form.duration(p.getMilliseconds(), 2)); sender.sendMessage(C.GREEN + "Generated " + ps.getPieces().size() + " pieces in " + Form.duration(p.getMilliseconds(), 2));
ps.place(placer, failed -> sender.sendMessage(failed ? C.GREEN + "Placed the structure!" : C.RED + "Failed to place the structure!")); ps.place(placer, failed -> sender.sendMessage(failed ? C.GREEN + "Placed the structure!" : C.RED + "Failed to place the structure!"));

View File

@ -24,6 +24,7 @@ import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.service.ObjectSVC; import com.volmit.iris.core.service.ObjectSVC;
import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.service.WandSVC; import com.volmit.iris.core.service.WandSVC;
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;
@ -117,10 +118,8 @@ public class CommandObject implements DecreeExecutor {
} }
@Override @Override
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) { public void setTile(int xx, int yy, int zz, TileData tile) {
BlockState state = world.getBlockAt(xx, yy, zz).getState(); tile.toBukkitTry(world.getBlockAt(xx, yy, zz));
tile.toBukkitTry(state);
state.update();
} }
@Override @Override
@ -212,6 +211,16 @@ public class CommandObject implements DecreeExecutor {
} }
} }
@Decree(description = "Convert .schem files in the 'convert' folder to .iob files.")
public void convert () {
try {
IrisConverter.convertSchematics(sender());
} catch (Exception e) {
e.printStackTrace();
}
}
@Decree(description = "Get a powder that reveals objects", studio = true, aliases = "d") @Decree(description = "Get a powder that reveals objects", studio = true, aliases = "d")
public void dust() { public void dust() {
player().getInventory().addItem(WandSVC.createDust()); player().getInventory().addItem(WandSVC.createDust());
@ -367,9 +376,11 @@ public class CommandObject implements DecreeExecutor {
@Param(description = "The file to store it in, can use / for subfolders") @Param(description = "The file to store it in, can use / for subfolders")
String name, String name,
@Param(description = "Overwrite existing object files", defaultValue = "false", aliases = "force") @Param(description = "Overwrite existing object files", defaultValue = "false", aliases = "force")
boolean overwrite boolean overwrite,
@Param(description = "Use legacy TileState serialization if possible", defaultValue = "true")
boolean legacy
) { ) {
IrisObject o = WandSVC.createSchematic(player()); IrisObject o = WandSVC.createSchematic(player(), legacy);
if (o == null) { if (o == null) {
sender().sendMessage(C.YELLOW + "You need to hold your wand!"); sender().sendMessage(C.YELLOW + "You need to hold your wand!");
@ -383,7 +394,7 @@ public class CommandObject implements DecreeExecutor {
return; return;
} }
try { try {
o.write(file); o.write(file, sender());
} catch (IOException e) { } catch (IOException e) {
sender().sendMessage(C.RED + "Failed to save object because of an IOException: " + e.getMessage()); sender().sendMessage(C.RED + "Failed to save object because of an IOException: " + e.getMessage());
Iris.reportError(e); Iris.reportError(e);

View File

@ -26,7 +26,6 @@ import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.project.IrisProject; import com.volmit.iris.core.project.IrisProject;
import com.volmit.iris.core.service.ConversionSVC; import com.volmit.iris.core.service.ConversionSVC;
import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.tools.IrisConverter;
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.*; import com.volmit.iris.engine.object.*;
@ -303,7 +302,7 @@ public class CommandStudio implements DecreeExecutor {
Inventory inv = Bukkit.createInventory(null, 27 * 2); Inventory inv = Bukkit.createInventory(null, 27 * 2);
try { try {
engine().addItems(true, inv, RNG.r, tables, InventorySlotType.STORAGE, player().getLocation().getBlockX(), player().getLocation().getBlockY(), player().getLocation().getBlockZ(), 1); engine().addItems(true, inv, RNG.r, tables, InventorySlotType.STORAGE, player().getWorld(), player().getLocation().getBlockX(), player().getLocation().getBlockY(), player().getLocation().getBlockZ(), 1);
} catch (Throwable e) { } catch (Throwable e) {
Iris.reportError(e); Iris.reportError(e);
sender().sendMessage(C.RED + "Cannot add items to virtual inventory because of: " + e.getMessage()); sender().sendMessage(C.RED + "Cannot add items to virtual inventory because of: " + e.getMessage());
@ -326,7 +325,7 @@ public class CommandStudio implements DecreeExecutor {
inv.clear(); inv.clear();
} }
engine().addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player().getLocation().getBlockX(), player().getLocation().getBlockY(), player().getLocation().getBlockZ(), 1); engine().addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player().getWorld(), player().getLocation().getBlockX(), player().getLocation().getBlockY(), player().getLocation().getBlockZ(), 1);
}, 0, fast ? 5 : 35)); }, 0, fast ? 5 : 35));
sender().sendMessage(C.GREEN + "Opening inventory now!"); sender().sendMessage(C.GREEN + "Opening inventory now!");
@ -335,29 +334,38 @@ public class CommandStudio implements DecreeExecutor {
@Decree(description = "Get all structures in a radius of chunks", aliases = "dist", origin = DecreeOrigin.PLAYER) @Decree(description = "Get all structures in a radius of chunks", aliases = "dist", origin = DecreeOrigin.PLAYER)
public void distances(@Param(description = "The radius") int radius) { public void distances(@Param(description = "The radius in chunks") int radius) {
var engine = engine(); var engine = engine();
if (engine == null) { if (engine == null) {
sender().sendMessage(C.RED + "Only works in an Iris world!"); sender().sendMessage(C.RED + "Only works in an Iris world!");
return; return;
} }
var sender = sender(); var sender = sender();
int d = radius*2; int d = radius * 2;
KMap<String, KList<Position2>> data = new KMap<>(); KMap<String, KList<Position2>> data = new KMap<>();
var multiBurst = new MultiBurst("Distance Sampler", Thread.MIN_PRIORITY); var multiBurst = new MultiBurst("Distance Sampler", Thread.MIN_PRIORITY);
var executor = multiBurst.burst(radius * radius); var executor = multiBurst.burst(radius * radius);
sender.sendMessage(C.GRAY + "Generating data..."); sender.sendMessage(C.GRAY + "Generating data...");
var loc = player().getLocation(); var loc = player().getLocation();
int totalTasks = d * d;
AtomicInteger completedTasks = new AtomicInteger(0);
int c = J.ar(() -> {
sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding structures");
}, 0);
new Spiraler(d, d, (x, z) -> executor.queue(() -> { new Spiraler(d, d, (x, z) -> executor.queue(() -> {
var struct = engine.getStructureAt(x, z); var struct = engine.getStructureAt(x, z);
if (struct != null) { if (struct != null) {
data.computeIfAbsent(struct.getLoadKey(), (k) -> new KList<>()).add(new Position2(x, z)); data.computeIfAbsent(struct.getLoadKey(), (k) -> new KList<>()).add(new Position2(x, z));
} }
completedTasks.incrementAndGet();
})).setOffset(loc.getBlockX(), loc.getBlockZ()).drain(); })).setOffset(loc.getBlockX(), loc.getBlockZ()).drain();
executor.complete(); executor.complete();
multiBurst.close(); multiBurst.close();
J.car(c);
for (var key : data.keySet()) { for (var key : data.keySet()) {
var list = data.get(key); var list = data.get(key);
KList<Long> distances = new KList<>(list.size() - 1); KList<Long> distances = new KList<>(list.size() - 1);
@ -390,6 +398,7 @@ public class CommandStudio implements DecreeExecutor {
} }
} }
@Decree(description = "Render a world map (External GUI)", aliases = "render") @Decree(description = "Render a world map (External GUI)", aliases = "render")
public void map( public void map(
@Param(name = "world", description = "The world to open the generator for", contextual = true) @Param(name = "world", description = "The world to open the generator for", contextual = true)

View File

@ -43,6 +43,10 @@ public class CommandUpdater implements DecreeExecutor {
sender().sendMessage(C.GOLD + "This is not an Iris world"); sender().sendMessage(C.GOLD + "This is not an Iris world");
return; return;
} }
if (chunkUpdater != null) {
chunkUpdater.stop();
}
chunkUpdater = new ChunkUpdater(world); chunkUpdater = new ChunkUpdater(world);
if (sender().isPlayer()) { if (sender().isPlayer()) {
sender().sendMessage(C.GREEN + "Updating " + world.getName() + C.GRAY + " Total chunks: " + Form.f(chunkUpdater.getChunks())); sender().sendMessage(C.GREEN + "Updating " + world.getName() + C.GRAY + " Total chunks: " + Form.f(chunkUpdater.getChunks()));
@ -53,14 +57,7 @@ public class CommandUpdater implements DecreeExecutor {
} }
@Decree(description = "Pause the updater") @Decree(description = "Pause the updater")
public void pause( public void pause( ) {
@Param(description = "World to pause the Updater at")
World world
) {
if (!IrisToolbelt.isIrisWorld(world)) {
sender().sendMessage(C.GOLD + "This is not an Iris world");
return;
}
if (chunkUpdater == null) { if (chunkUpdater == null) {
sender().sendMessage(C.GOLD + "You cant pause something that doesnt exist?"); sender().sendMessage(C.GOLD + "You cant pause something that doesnt exist?");
return; return;
@ -68,40 +65,32 @@ public class CommandUpdater implements DecreeExecutor {
boolean status = chunkUpdater.pause(); boolean status = chunkUpdater.pause();
if (sender().isPlayer()) { if (sender().isPlayer()) {
if (status) { if (status) {
sender().sendMessage(C.IRIS + "Paused task for: " + C.GRAY + world.getName()); sender().sendMessage(C.IRIS + "Paused task for: " + C.GRAY + chunkUpdater.getName());
} else { } else {
sender().sendMessage(C.IRIS + "Unpause task for: " + C.GRAY + world.getName()); sender().sendMessage(C.IRIS + "Unpause task for: " + C.GRAY + chunkUpdater.getName());
} }
} else { } else {
if (status) { if (status) {
Iris.info(C.IRIS + "Paused task for: " + C.GRAY + world.getName()); Iris.info(C.IRIS + "Paused task for: " + C.GRAY + chunkUpdater.getName());
} else { } else {
Iris.info(C.IRIS + "Unpause task for: " + C.GRAY + world.getName()); Iris.info(C.IRIS + "Unpause task for: " + C.GRAY + chunkUpdater.getName());
} }
} }
} }
@Decree(description = "Stops the updater") @Decree(description = "Stops the updater")
public void stop( public void stop() {
@Param(description = "World to stop the Updater at")
World world
) {
if (!IrisToolbelt.isIrisWorld(world)) {
sender().sendMessage(C.GOLD + "This is not an Iris world");
return;
}
if (chunkUpdater == null) { if (chunkUpdater == null) {
sender().sendMessage(C.GOLD + "You cant stop something that doesnt exist?"); sender().sendMessage(C.GOLD + "You cant stop something that doesnt exist?");
return; return;
} }
if (sender().isPlayer()) { if (sender().isPlayer()) {
sender().sendMessage("Stopping Updater for: " + C.GRAY + world.getName()); sender().sendMessage("Stopping Updater for: " + C.GRAY + chunkUpdater.getName());
} else { } else {
Iris.info("Stopping Updater for: " + C.GRAY + world.getName()); Iris.info("Stopping Updater for: " + C.GRAY + chunkUpdater.getName());
} }
chunkUpdater.stop(); chunkUpdater.stop();
} }
} }

View File

@ -0,0 +1,113 @@
package com.volmit.iris.core.events;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.InventorySlotType;
import com.volmit.iris.engine.object.IrisLootTable;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.scheduling.J;
import lombok.Getter;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.world.LootGenerateEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.loot.LootContext;
import org.bukkit.loot.LootTable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Random;
@Getter
public class IrisLootEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private static final LootTable EMPTY = new LootTable() {
@NotNull
@Override
public NamespacedKey getKey() {
return new NamespacedKey(Iris.instance, "empty");
}
@NotNull
@Override
public Collection<ItemStack> populateLoot(@Nullable Random random, @NotNull LootContext context) {
return List.of();
}
@Override
public void fillInventory(@NotNull Inventory inventory, @Nullable Random random, @NotNull LootContext context) {
}
};
private final Engine engine;
private final Block block;
private final InventorySlotType slot;
private final KList<IrisLootTable> tables;
/**
* Constructor for IrisLootEvent with mode selection.
*
* @param engine The engine instance.
* @param block The block associated with the event.
* @param slot The inventory slot type.
* @param tables The list of IrisLootTables. (mutable*)
*/
public IrisLootEvent(Engine engine, Block block, InventorySlotType slot, KList<IrisLootTable> tables) {
this.engine = engine;
this.block = block;
this.slot = slot;
this.tables = tables;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
/**
* Required method to get the HandlerList for this event.
*
* @return The HandlerList.
*/
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Triggers the corresponding Bukkit loot event.
* This method integrates your custom IrisLootTables with Bukkit's LootGenerateEvent,
* allowing other plugins to modify or cancel the loot generation.
*
* @return true when the event was canceled
*/
public static boolean callLootEvent(KList<ItemStack> loot, Inventory inv, World world, int x, int y, int z) {
InventoryHolder holder = inv.getHolder();
Location loc = new Location(world, x, y, z);
if (holder == null) {
holder = new InventoryHolder() {
@NotNull
@Override
public Inventory getInventory() {
return inv;
}
};
}
LootContext context = new LootContext.Builder(loc).build();
LootGenerateEvent event = new LootGenerateEvent(world, null, holder, EMPTY, context, loot, true);
if (!Bukkit.isPrimaryThread()) {
Iris.warn("LootGenerateEvent was not called on the main thread, please report this issue.");
Thread.dumpStack();
J.sfut(() -> Bukkit.getPluginManager().callEvent(event)).join();
} else Bukkit.getPluginManager().callEvent(event);
return event.isCancelled();
}
}

View File

@ -19,6 +19,7 @@
package com.volmit.iris.core.gui; package com.volmit.iris.core.gui;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.events.IrisEngineHotloadEvent; import com.volmit.iris.core.events.IrisEngineHotloadEvent;
import com.volmit.iris.engine.object.NoiseStyle; import com.volmit.iris.engine.object.NoiseStyle;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
@ -61,7 +62,7 @@ public class NoiseExplorerGUI extends JPanel implements MouseWheelListener, List
@SuppressWarnings("CanBeFinal") @SuppressWarnings("CanBeFinal")
RollingSequence r = new RollingSequence(20); RollingSequence r = new RollingSequence(20);
@SuppressWarnings("CanBeFinal") @SuppressWarnings("CanBeFinal")
boolean colorMode = true; boolean colorMode = IrisSettings.get().getGui().colorMode;
double scale = 1; double scale = 1;
CNG cng = NoiseStyle.STATIC.create(new RNG(RNG.r.nextLong())); CNG cng = NoiseStyle.STATIC.create(new RNG(RNG.r.nextLong()));
@SuppressWarnings("CanBeFinal") @SuppressWarnings("CanBeFinal")
@ -274,7 +275,8 @@ public class NoiseExplorerGUI extends JPanel implements MouseWheelListener, List
n = n > 1 ? 1 : n < 0 ? 0 : n; n = n > 1 ? 1 : n < 0 ? 0 : n;
try { try {
Color color = colorMode ? Color.getHSBColor((float) (n), 1f - (float) (n * n * n * n * n * n), 1f - (float) n) : Color.getHSBColor(0f, 0f, (float) n); //Color color = colorMode ? Color.getHSBColor((float) (n), 1f - (float) (n * n * n * n * n * n), 1f - (float) n) : Color.getHSBColor(0f, 0f, (float) n);
Color color = colorMode ? Color.getHSBColor((float) (0.666f - n * 0.666f), 1f, (float) (1f - n * 0.8f)) : Color.getHSBColor(0f, 0f, (float) n);
int rgb = color.getRGB(); int rgb = color.getRGB();
img.setRGB(xx, z, rgb); img.setRGB(xx, z, rgb);
} catch (Throwable ignored) { } catch (Throwable ignored) {

View File

@ -93,7 +93,12 @@ public class PregeneratorJob implements PregenListener {
open(); open();
} }
J.a(this.pregenerator::start, 20); var t = new Thread(() -> {
J.sleep(1000);
this.pregenerator.start();
}, "Iris Pregenerator");
t.setPriority(Thread.MIN_PRIORITY);
t.start();
} }
public static boolean shutdownInstance() { public static boolean shutdownInstance() {

View File

@ -9,6 +9,7 @@ import com.willfp.ecoitems.items.EcoItems;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.MissingResourceException; import java.util.MissingResourceException;
@ -33,23 +34,27 @@ public class EcoItemsDataProvider extends ExternalDataProvider {
} }
} }
@NotNull
@Override @Override
public BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException { public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
} }
@NotNull
@Override @Override
public ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException { public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
EcoItem item = EcoItems.INSTANCE.getByID(itemId.key()); EcoItem item = EcoItems.INSTANCE.getByID(itemId.key());
if (item == null) throw new MissingResourceException("Failed to find Item!", itemId.namespace(), itemId.key()); if (item == null) throw new MissingResourceException("Failed to find Item!", itemId.namespace(), itemId.key());
return itemStack.get(item).clone(); return itemStack.get(item).clone();
} }
@NotNull
@Override @Override
public Identifier[] getBlockTypes() { public Identifier[] getBlockTypes() {
return new Identifier[0]; return new Identifier[0];
} }
@NotNull
@Override @Override
public Identifier[] getItemTypes() { public Identifier[] getItemTypes() {
KList<Identifier> names = new KList<>(); KList<Identifier> names = new KList<>();
@ -66,7 +71,7 @@ public class EcoItemsDataProvider extends ExternalDataProvider {
} }
@Override @Override
public boolean isValidProvider(Identifier id, boolean isItem) { public boolean isValidProvider(@NotNull Identifier id, boolean isItem) {
return id.namespace().equalsIgnoreCase("ecoitems") && isItem; return id.namespace().equalsIgnoreCase("ecoitems") && isItem;
} }
} }

View File

@ -6,6 +6,7 @@ import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.Optional; import java.util.Optional;
@ -20,23 +21,27 @@ public class ExecutableItemsDataProvider extends ExternalDataProvider {
Iris.info("Setting up ExecutableItems Link..."); Iris.info("Setting up ExecutableItems Link...");
} }
@NotNull
@Override @Override
public BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException { public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
} }
@NotNull
@Override @Override
public ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException { public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
return ExecutableItemsAPI.getExecutableItemsManager().getExecutableItem(itemId.key()) return ExecutableItemsAPI.getExecutableItemsManager().getExecutableItem(itemId.key())
.map(item -> item.buildItem(1, Optional.empty())) .map(item -> item.buildItem(1, Optional.empty()))
.orElseThrow(() -> new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key())); .orElseThrow(() -> new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()));
} }
@NotNull
@Override @Override
public Identifier[] getBlockTypes() { public Identifier[] getBlockTypes() {
return new Identifier[0]; return new Identifier[0];
} }
@NotNull
@Override @Override
public Identifier[] getItemTypes() { public Identifier[] getItemTypes() {
KList<Identifier> names = new KList<>(); KList<Identifier> names = new KList<>();
@ -53,7 +58,7 @@ public class ExecutableItemsDataProvider extends ExternalDataProvider {
} }
@Override @Override
public boolean isValidProvider(Identifier key, boolean isItem) { public boolean isValidProvider(@NotNull Identifier key, boolean isItem) {
return key.namespace().equalsIgnoreCase("executable_items") && isItem; return key.namespace().equalsIgnoreCase("executable_items") && isItem;
} }
} }

View File

@ -2,22 +2,28 @@ 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 lombok.Getter; import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.block.Block; import org.bukkit.block.Block;
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.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.MissingResourceException; import java.util.MissingResourceException;
@Getter
@RequiredArgsConstructor @RequiredArgsConstructor
public abstract class ExternalDataProvider { public abstract class ExternalDataProvider {
@Getter @NonNull
private final String pluginId; private final String pluginId;
@Nullable
public Plugin getPlugin() { public Plugin getPlugin() {
return Bukkit.getPluginManager().getPlugin(pluginId); return Bukkit.getPluginManager().getPlugin(pluginId);
} }
@ -28,23 +34,60 @@ public abstract class ExternalDataProvider {
public abstract void init(); public abstract void init();
public BlockData getBlockData(Identifier blockId) throws MissingResourceException { /**
* @see ExternalDataProvider#getBlockData(Identifier, KMap)
*/
@NotNull
public BlockData getBlockData(@NotNull Identifier blockId) throws MissingResourceException {
return getBlockData(blockId, new KMap<>()); return getBlockData(blockId, new KMap<>());
} }
public abstract BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException; /**
* This method returns a {@link BlockData} corresponding to the blockID
* it is used in any place Iris accepts {@link BlockData}
*
* @param blockId The id of the block to get
* @param state The state of the block to get
* @return Corresponding {@link BlockData} to the blockId
* may return {@link IrisBlockData} for blocks that need a world for placement
* @throws MissingResourceException when the blockId is invalid
*/
@NotNull
public abstract BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException;
public ItemStack getItemStack(Identifier itemId) throws MissingResourceException { /**
* @see ExternalDataProvider#getItemStack(Identifier)
*/
@NotNull
public ItemStack getItemStack(@NotNull Identifier itemId) throws MissingResourceException {
return getItemStack(itemId, new KMap<>()); return getItemStack(itemId, new KMap<>());
} }
public abstract ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException; /**
* This method returns a {@link ItemStack} corresponding to the itemID
* it is used in loot tables
*
* @param itemId The id of the item to get
* @param customNbt Custom nbt to apply to the item
* @return Corresponding {@link ItemStack} to the itemId
* @throws MissingResourceException when the itemId is invalid
*/
@NotNull
public abstract ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException;
public void processUpdate(Engine engine, Block block, Identifier blockId) {} /**
* 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}
*
* @param engine The engine of the world the block is being placed in
* @param block The block where the block should be placed
* @param blockId The blockId to place
*/
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {}
public abstract Identifier[] getBlockTypes(); public abstract @NotNull Identifier[] getBlockTypes();
public abstract Identifier[] getItemTypes(); public abstract @NotNull Identifier[] getItemTypes();
public abstract boolean isValidProvider(Identifier id, boolean isItem); public abstract boolean isValidProvider(@NotNull Identifier id, boolean isItem);
} }

View File

@ -16,6 +16,7 @@ import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Leaves; import org.bukkit.block.data.type.Leaves;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Map; import java.util.Map;
import java.util.MissingResourceException; import java.util.MissingResourceException;
@ -51,8 +52,9 @@ public class HMCLeavesDataProvider extends ExternalDataProvider {
} }
} }
@NotNull
@Override @Override
public BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException { public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
Object o = blockDataMap.get(blockId.key()); Object o = blockDataMap.get(blockId.key());
if (o == null) if (o == null)
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
@ -65,15 +67,16 @@ public class HMCLeavesDataProvider extends ExternalDataProvider {
return new IrisBlockData(blockData, ExternalDataSVC.buildState(blockId, state)); return new IrisBlockData(blockData, ExternalDataSVC.buildState(blockId, state));
} }
@NotNull
@Override @Override
public ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException { public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
if (!itemDataField.containsKey(itemId.key())) if (!itemDataField.containsKey(itemId.key()))
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()); throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
return itemDataField.get(itemId.key()).get(); return itemDataField.get(itemId.key()).get();
} }
@Override @Override
public void processUpdate(Engine engine, Block block, Identifier blockId) { public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
var pair = ExternalDataSVC.parseState(blockId); var pair = ExternalDataSVC.parseState(blockId);
blockId = pair.getA(); blockId = pair.getA();
Boolean result = setCustomBlock.invoke(apiInstance, new Object[]{block.getLocation(), blockId.key(), false}); Boolean result = setCustomBlock.invoke(apiInstance, new Object[]{block.getLocation(), blockId.key(), false});
@ -86,6 +89,7 @@ public class HMCLeavesDataProvider extends ExternalDataProvider {
} }
} }
@NotNull
@Override @Override
public Identifier[] getBlockTypes() { public Identifier[] getBlockTypes() {
KList<Identifier> names = new KList<>(); KList<Identifier> names = new KList<>();
@ -101,6 +105,7 @@ public class HMCLeavesDataProvider extends ExternalDataProvider {
return names.toArray(new Identifier[0]); return names.toArray(new Identifier[0]);
} }
@NotNull
@Override @Override
public Identifier[] getItemTypes() { public Identifier[] getItemTypes() {
KList<Identifier> names = new KList<>(); KList<Identifier> names = new KList<>();
@ -117,7 +122,7 @@ public class HMCLeavesDataProvider extends ExternalDataProvider {
} }
@Override @Override
public boolean isValidProvider(Identifier id, boolean isItem) { public boolean isValidProvider(@NotNull Identifier id, boolean isItem) {
return (isItem ? itemDataField.keySet() : blockDataMap.keySet()).contains(id.key()); return (isItem ? itemDataField.keySet() : blockDataMap.keySet()).contains(id.key());
} }

View File

@ -7,6 +7,7 @@ import dev.lone.itemsadder.api.CustomBlock;
import dev.lone.itemsadder.api.CustomStack; import dev.lone.itemsadder.api.CustomStack;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.MissingResourceException; import java.util.MissingResourceException;
@ -32,13 +33,15 @@ public class ItemAdderDataProvider extends ExternalDataProvider {
} }
} }
@NotNull
@Override @Override
public BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException { public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
return CustomBlock.getBaseBlockData(blockId.toString()); return CustomBlock.getBaseBlockData(blockId.toString());
} }
@NotNull
@Override @Override
public ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException { public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
CustomStack stack = CustomStack.getInstance(itemId.toString()); CustomStack stack = CustomStack.getInstance(itemId.toString());
if (stack == null) { if (stack == null) {
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()); throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
@ -46,6 +49,7 @@ public class ItemAdderDataProvider extends ExternalDataProvider {
return stack.getItemStack(); return stack.getItemStack();
} }
@NotNull
@Override @Override
public Identifier[] getBlockTypes() { public Identifier[] getBlockTypes() {
KList<Identifier> keys = new KList<>(); KList<Identifier> keys = new KList<>();
@ -55,6 +59,7 @@ public class ItemAdderDataProvider extends ExternalDataProvider {
return keys.toArray(new Identifier[0]); return keys.toArray(new Identifier[0]);
} }
@NotNull
@Override @Override
public Identifier[] getItemTypes() { public Identifier[] getItemTypes() {
KList<Identifier> keys = new KList<>(); KList<Identifier> keys = new KList<>();
@ -65,7 +70,7 @@ public class ItemAdderDataProvider extends ExternalDataProvider {
} }
@Override @Override
public boolean isValidProvider(Identifier id, boolean isItem) { public boolean isValidProvider(@NotNull Identifier id, boolean isItem) {
return isItem ? this.itemNamespaces.contains(id.namespace()) : this.blockNamespaces.contains(id.namespace()); return isItem ? this.itemNamespaces.contains(id.namespace()) : this.blockNamespaces.contains(id.namespace());
} }
} }

View File

@ -5,11 +5,13 @@ 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.scheduling.J; import com.volmit.iris.util.scheduling.J;
import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.ItemTier;
import net.Indyuce.mmoitems.api.Type; import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.block.CustomBlock; import net.Indyuce.mmoitems.api.block.CustomBlock;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -26,8 +28,9 @@ public class MMOItemsDataProvider extends ExternalDataProvider {
Iris.info("Setting up MMOItems Link..."); Iris.info("Setting up MMOItems Link...");
} }
@NotNull
@Override @Override
public BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException { public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
int id = -1; int id = -1;
try { try {
id = Integer.parseInt(blockId.key()); id = Integer.parseInt(blockId.key());
@ -37,8 +40,9 @@ public class MMOItemsDataProvider extends ExternalDataProvider {
return block.getState().getBlockData(); return block.getState().getBlockData();
} }
@NotNull
@Override @Override
public ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException { public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
String[] parts = itemId.namespace().split("_", 2); String[] parts = itemId.namespace().split("_", 2);
if (parts.length != 2) if (parts.length != 2)
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()); throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
@ -46,8 +50,13 @@ public class MMOItemsDataProvider extends ExternalDataProvider {
Runnable run = () -> { Runnable run = () -> {
try { try {
var type = api().getTypes().get(parts[1]); var type = api().getTypes().get(parts[1]);
int level = customNbt.containsKey("level") ? (int) customNbt.get("level") : -1; int level = -1;
var tier = api().getTiers().get(String.valueOf(customNbt.get("tier"))); ItemTier tier = null;
if (customNbt != null) {
level = (int) customNbt.getOrDefault("level", -1);
tier = api().getTiers().get(String.valueOf(customNbt.get("tier")));
}
ItemStack itemStack; ItemStack itemStack;
if (type == null) { if (type == null) {
@ -76,6 +85,7 @@ public class MMOItemsDataProvider extends ExternalDataProvider {
return item; return item;
} }
@NotNull
@Override @Override
public Identifier[] getBlockTypes() { public Identifier[] getBlockTypes() {
KList<Identifier> names = new KList<>(); KList<Identifier> names = new KList<>();
@ -90,6 +100,7 @@ public class MMOItemsDataProvider extends ExternalDataProvider {
return names.toArray(new Identifier[0]); return names.toArray(new Identifier[0]);
} }
@NotNull
@Override @Override
public Identifier[] getItemTypes() { public Identifier[] getItemTypes() {
KList<Identifier> names = new KList<>(); KList<Identifier> names = new KList<>();
@ -118,7 +129,7 @@ public class MMOItemsDataProvider extends ExternalDataProvider {
} }
@Override @Override
public boolean isValidProvider(Identifier id, boolean isItem) { public boolean isValidProvider(@NotNull Identifier id, boolean isItem) {
return isItem ? id.namespace().split("_", 2).length == 2 : id.namespace().equals("mmoitems"); return isItem ? id.namespace().split("_", 2).length == 2 : id.namespace().equals("mmoitems");
} }

View File

@ -0,0 +1,171 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.link;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisBlockData;
import com.volmit.iris.util.math.RNG;
import io.lumine.mythic.bukkit.BukkitAdapter;
import io.lumine.mythic.bukkit.utils.serialize.Chroma;
import io.lumine.mythiccrucible.MythicCrucible;
import io.lumine.mythiccrucible.items.CrucibleItem;
import io.lumine.mythiccrucible.items.ItemManager;
import io.lumine.mythiccrucible.items.blocks.CustomBlockItemContext;
import io.lumine.mythiccrucible.items.furniture.FurnitureItemContext;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.MissingResourceException;
import java.util.Optional;
public class MythicCrucibleDataProvider extends ExternalDataProvider {
private ItemManager itemManager;
public MythicCrucibleDataProvider() {
super("MythicCrucible");
}
@Override
public void init() {
Iris.info("Setting up MythicCrucible Link...");
try {
this.itemManager = MythicCrucible.inst().getItemManager();
} catch (Exception e) {
Iris.error("Failed to set up MythicCrucible Link: Unable to fetch MythicCrucible instance!");
}
}
@NotNull
@Override
public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
CrucibleItem crucibleItem = this.itemManager.getItem(blockId.key())
.orElseThrow(() -> new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()));
CustomBlockItemContext blockItemContext = crucibleItem.getBlockData();
FurnitureItemContext furnitureItemContext = crucibleItem.getFurnitureData();
if (furnitureItemContext != null) {
return new IrisBlockData(B.getAir(), ExternalDataSVC.buildState(blockId, state));
} else if (blockItemContext != null) {
return blockItemContext.getBlockData();
}
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@NotNull
@Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
Optional<CrucibleItem> opt = this.itemManager.getItem(itemId.key());
return BukkitAdapter.adapt(opt.orElseThrow(() ->
new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()))
.getMythicItem()
.generateItemStack(1));
}
@NotNull
@Override
public Identifier[] getBlockTypes() {
KList<Identifier> names = new KList<>();
for (CrucibleItem item : this.itemManager.getItems()) {
if (item.getBlockData() == null) continue;
try {
Identifier key = new Identifier("crucible", item.getInternalName());
if (getBlockData(key) != null) {
Iris.info("getBlockTypes: Block loaded '" + item.getInternalName() + "'");
names.add(key);
}
} catch (MissingResourceException ignored) {}
}
return names.toArray(new Identifier[0]);
}
@NotNull
@Override
public Identifier[] getItemTypes() {
KList<Identifier> names = new KList<>();
for (CrucibleItem item : this.itemManager.getItems()) {
try {
Identifier key = new Identifier("crucible", item.getInternalName());
if (getItemStack(key) != null) {
Iris.info("getItemTypes: Item loaded '" + item.getInternalName() + "'");
names.add(key);
}
} catch (MissingResourceException ignored) {}
}
return names.toArray(new Identifier[0]);
}
@Override
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
var pair = ExternalDataSVC.parseState(blockId);
var state = pair.getB();
blockId = pair.getA();
Optional<CrucibleItem> item = itemManager.getItem(blockId.key());
if (item.isEmpty()) return;
FurnitureItemContext furniture = item.get().getFurnitureData();
if (furniture == null) return;
float yaw = 0;
BlockFace face = BlockFace.NORTH;
long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY();
RNG rng = new RNG(seed);
if ("true".equals(state.get("randomYaw"))) {
yaw = rng.f(0, 360);
} else if (state.containsKey("yaw")) {
yaw = Float.parseFloat(state.get("yaw"));
}
if ("true".equals(state.get("randomFace"))) {
BlockFace[] faces = BlockFace.values();
face = faces[rng.i(0, faces.length - 1)];
} else if (state.containsKey("face")) {
face = BlockFace.valueOf(state.get("face").toUpperCase());
}
if (face == BlockFace.SELF) {
face = BlockFace.NORTH;
}
BiomeColor type = null;
Chroma color = null;
try {
type = BiomeColor.valueOf(state.get("matchBiome").toUpperCase());
} catch (NullPointerException | IllegalArgumentException ignored) {}
if (type != null) {
var biomeColor = INMS.get().getBiomeColor(block.getLocation(), type);
if (biomeColor == null) return;
color = Chroma.of(biomeColor.getRGB());
}
furniture.place(block, face, yaw, color);
}
@Override
public boolean isValidProvider(@NotNull Identifier key, boolean isItem) {
return key.namespace().equalsIgnoreCase("crucible");
}
}

View File

@ -0,0 +1,164 @@
package com.volmit.iris.core.link;
import com.nexomc.nexo.api.NexoBlocks;
import com.nexomc.nexo.api.NexoFurniture;
import com.nexomc.nexo.api.NexoItems;
import com.nexomc.nexo.items.ItemBuilder;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisBlockData;
import com.volmit.iris.util.math.RNG;
import org.bukkit.Color;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.MissingResourceException;
import java.util.concurrent.atomic.AtomicBoolean;
public class NexoDataProvider extends ExternalDataProvider {
private final AtomicBoolean failed = new AtomicBoolean(false);
public NexoDataProvider() {
super("Nexo");
}
@Override
public void init() {
}
@NotNull
@Override
public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
if (!NexoItems.exists(blockId.key())) {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
Identifier blockState = ExternalDataSVC.buildState(blockId, state);
if (NexoBlocks.isCustomBlock(blockId.key())) {
BlockData data = NexoBlocks.blockData(blockId.key());
if (data == null)
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
return new IrisBlockData(data, blockState);
} else if (NexoFurniture.isFurniture(blockId.key())) {
return new IrisBlockData(B.getAir(), blockState);
}
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@NotNull
@Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
ItemBuilder builder = NexoItems.itemFromId(itemId.key());
if (builder == null) {
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
}
return builder.build();
}
@Override
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
var pair = ExternalDataSVC.parseState(blockId);
var state = pair.getB();
blockId = pair.getA();
if (NexoBlocks.isCustomBlock(blockId.key())) {
NexoBlocks.place(blockId.key(), block.getLocation());
return;
}
if (!NexoFurniture.isFurniture(blockId.key()))
return;
float yaw = 0;
BlockFace face = BlockFace.NORTH;
long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY();
RNG rng = new RNG(seed);
if ("true".equals(state.get("randomYaw"))) {
yaw = rng.f(0, 360);
} else if (state.containsKey("yaw")) {
yaw = Float.parseFloat(state.get("yaw"));
}
if ("true".equals(state.get("randomFace"))) {
BlockFace[] faces = BlockFace.values();
face = faces[rng.i(0, faces.length - 1)];
} else if (state.containsKey("face")) {
face = BlockFace.valueOf(state.get("face").toUpperCase());
}
if (face == BlockFace.SELF) {
face = BlockFace.NORTH;
}
ItemDisplay display = NexoFurniture.place(blockId.key(), block.getLocation(), yaw, face);
if (display == null) return;
ItemStack itemStack = display.getItemStack();
if (itemStack == null) return;
BiomeColor type = null;
try {
type = BiomeColor.valueOf(state.get("matchBiome").toUpperCase());
} catch (NullPointerException | IllegalArgumentException ignored) {}
if (type != null) {
var biomeColor = INMS.get().getBiomeColor(block.getLocation(), type);
if (biomeColor == null) return;
var potionColor = Color.fromARGB(biomeColor.getAlpha(), biomeColor.getRed(), biomeColor.getGreen(), biomeColor.getBlue());
if (itemStack.getItemMeta() instanceof PotionMeta meta) {
meta.setColor(potionColor);
itemStack.setItemMeta(meta);
}
}
display.setItemStack(itemStack);
}
@NotNull
@Override
public Identifier[] getBlockTypes() {
return Arrays.stream(NexoItems.itemNames())
.map(i -> new Identifier("nexo", i))
.filter(i -> {
try {
return getBlockData(i) != null;
} catch (MissingResourceException e) {
return false;
}
})
.toArray(Identifier[]::new);
}
@NotNull
@Override
public Identifier[] getItemTypes() {
return Arrays.stream(NexoItems.itemNames())
.map(i -> new Identifier("nexo", i))
.filter(i -> {
try {
return getItemStack(i) != null;
} catch (MissingResourceException e) {
return false;
}
})
.toArray(Identifier[]::new);
}
@Override
public boolean isValidProvider(@NotNull Identifier id, boolean isItem) {
return "nexo".equalsIgnoreCase(id.namespace());
}
@Override
public boolean isReady() {
return super.isReady() && !failed.get();
}
}

View File

@ -1,213 +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.core.link;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisBlockData;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.reflect.WrappedField;
import io.th0rgal.oraxen.api.OraxenItems;
import io.th0rgal.oraxen.items.ItemBuilder;
import io.th0rgal.oraxen.mechanics.Mechanic;
import io.th0rgal.oraxen.mechanics.MechanicFactory;
import io.th0rgal.oraxen.mechanics.MechanicsManager;
import io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanic;
import io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanicFactory;
import io.th0rgal.oraxen.mechanics.provided.gameplay.furniture.FurnitureFactory;
import io.th0rgal.oraxen.mechanics.provided.gameplay.furniture.FurnitureMechanic;
import io.th0rgal.oraxen.mechanics.provided.gameplay.noteblock.NoteBlockMechanicFactory;
import io.th0rgal.oraxen.mechanics.provided.gameplay.stringblock.StringBlockMechanicFactory;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.entity.ItemFrame;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Optional;
import java.util.function.Consumer;
public class OraxenDataProvider extends ExternalDataProvider {
private static final String FIELD_FACTORIES_MAP = "FACTORIES_BY_MECHANIC_ID";
private WrappedField<MechanicsManager, Map<String, MechanicFactory>> factories;
public OraxenDataProvider() {
super("Oraxen");
}
@Override
public void init() {
Iris.info("Setting up Oraxen Link...");
this.factories = new WrappedField<>(MechanicsManager.class, FIELD_FACTORIES_MAP);
if (this.factories.hasFailed()) {
Iris.error("Failed to set up Oraxen Link: Unable to fetch MechanicFactoriesMap!");
}
}
@Override
public BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException {
MechanicFactory factory = getFactory(blockId);
if (factory instanceof NoteBlockMechanicFactory f)
return f.createNoteBlockData(blockId.key());
else if (factory instanceof BlockMechanicFactory f) {
MultipleFacing newBlockData = (MultipleFacing) Bukkit.createBlockData(Material.MUSHROOM_STEM);
BlockMechanic.setBlockFacing(newBlockData, ((BlockMechanic) f.getMechanic(blockId.key())).getCustomVariation());
return newBlockData;
} else if (factory instanceof StringBlockMechanicFactory f) {
return f.createTripwireData(blockId.key());
} else if (factory instanceof FurnitureFactory) {
return new IrisBlockData(B.getAir(), ExternalDataSVC.buildState(blockId, state));
} else
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@Override
public ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException {
Optional<ItemBuilder> opt = OraxenItems.getOptionalItemById(itemId.key());
return opt.orElseThrow(() -> new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key())).build();
}
@Override
public void processUpdate(Engine engine, Block block, Identifier blockId) {
var pair = ExternalDataSVC.parseState(blockId);
var state = pair.getB();
blockId = pair.getA();
Mechanic mechanic = getFactory(blockId).getMechanic(blockId.key());
if (mechanic instanceof FurnitureMechanic f) {
float yaw = 0;
BlockFace face = BlockFace.NORTH;
long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY();
RNG rng = new RNG(seed);
if ("true".equals(state.get("randomYaw"))) {
yaw = rng.f(0, 360);
} else if (state.containsKey("yaw")) {
yaw = Float.parseFloat(state.get("yaw"));
}
if ("true".equals(state.get("randomFace"))) {
BlockFace[] faces = BlockFace.values();
face = faces[rng.i(0, faces.length - 1)];
} else if (state.containsKey("face")) {
face = BlockFace.valueOf(state.get("face").toUpperCase());
}
if (face == BlockFace.SELF) {
face = BlockFace.NORTH;
}
ItemStack itemStack = OraxenItems.getItemById(f.getItemID()).build();
Entity entity = f.place(block.getLocation(), itemStack, yaw, face, false);
Consumer<ItemStack> setter = null;
if (entity instanceof ItemFrame frame) {
itemStack = frame.getItem();
setter = frame::setItem;
} else if (entity instanceof ItemDisplay display) {
itemStack = display.getItemStack();
setter = display::setItemStack;
}
if (setter == null || itemStack == null) return;
BiomeColor type = null;
try {
type = BiomeColor.valueOf(state.get("matchBiome").toUpperCase());
} catch (NullPointerException | IllegalArgumentException ignored) {}
if (type != null) {
var biomeColor = INMS.get().getBiomeColor(block.getLocation(), type);
if (biomeColor == null) return;
var potionColor = Color.fromARGB(biomeColor.getAlpha(), biomeColor.getRed(), biomeColor.getGreen(), biomeColor.getBlue());
if (itemStack.getItemMeta() instanceof PotionMeta meta) {
meta.setColor(potionColor);
itemStack.setItemMeta(meta);
}
}
setter.accept(itemStack);
}
}
@Override
public Identifier[] getBlockTypes() {
KList<Identifier> names = new KList<>();
for (String name : OraxenItems.getItemNames()) {
try {
Identifier key = new Identifier("oraxen", name);
if (getBlockData(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
return names.toArray(new Identifier[0]);
}
@Override
public Identifier[] getItemTypes() {
KList<Identifier> names = new KList<>();
for (String name : OraxenItems.getItemNames()) {
try {
Identifier key = new Identifier("oraxen", name);
if (getItemStack(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
return names.toArray(new Identifier[0]);
}
@Override
public boolean isReady() {
if (super.isReady()) {
if (factories == null) {
this.factories = new WrappedField<>(MechanicsManager.class, FIELD_FACTORIES_MAP);
}
return super.isReady() && !factories.hasFailed();
}
return false;
}
@Override
public boolean isValidProvider(Identifier key, boolean isItem) {
return key.namespace().equalsIgnoreCase("oraxen");
}
private MechanicFactory getFactory(Identifier key) throws MissingResourceException {
return factories.get().values().stream()
.filter(i -> i.getItems().contains(key.key()))
.findFirst()
.orElseThrow(() -> new MissingResourceException("Failed to find BlockData!", key.namespace(), key.key()));
}
}

View File

@ -36,6 +36,7 @@ import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
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 com.volmit.iris.util.reflect.OldEnum;
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 lombok.Data; import lombok.Data;
@ -337,6 +338,15 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
this.imageLoader = registerLoader(IrisImage.class); this.imageLoader = registerLoader(IrisImage.class);
this.scriptLoader = registerLoader(IrisScript.class); this.scriptLoader = registerLoader(IrisScript.class);
this.matterObjectLoader = registerLoader(IrisMatterObject.class); this.matterObjectLoader = registerLoader(IrisMatterObject.class);
if (OldEnum.exists()) {
builder.registerTypeAdapterFactory(new TypeAdapterFactory() {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
return (TypeAdapter<T>) OldEnum.create(type.getRawType());
}
});
}
gson = builder.create(); gson = builder.create();
} }
@ -434,6 +444,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
return adapter.read(reader); return adapter.read(reader);
} catch (Throwable e) { } catch (Throwable e) {
Iris.error("Failed to read " + typeToken.getRawType().getCanonicalName() + "... faking objects a little to load the file at least."); Iris.error("Failed to read " + typeToken.getRawType().getCanonicalName() + "... faking objects a little to load the file at least.");
Iris.reportError(e);
try { try {
return (T) typeToken.getRawType().getConstructor().newInstance(); return (T) typeToken.getRawType().getConstructor().newInstance();
} catch (Throwable ignored) { } catch (Throwable ignored) {

View File

@ -50,10 +50,10 @@ public class ObjectResourceLoader extends ResourceLoader<IrisObject> {
try { try {
PrecisionStopwatch p = PrecisionStopwatch.start(); PrecisionStopwatch p = PrecisionStopwatch.start();
IrisObject t = new IrisObject(0, 0, 0); IrisObject t = new IrisObject(0, 0, 0);
t.read(j);
t.setLoadKey(name); t.setLoadKey(name);
t.setLoader(manager); t.setLoader(manager);
t.setLoadFile(j); t.setLoadFile(j);
t.read(j);
logLoad(j, t); logLoad(j, t);
tlt.addAndGet(p.getMilliseconds()); tlt.addAndGet(p.getMilliseconds());
return t; return t;

View File

@ -30,7 +30,9 @@ public class INMS {
"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.3", "v1_21_R2"
); );
//@done //@done
private static final INMSBinding binding = bind(); private static final INMSBinding binding = bind();

View File

@ -28,26 +28,27 @@ import com.volmit.iris.util.math.Vector3d;
import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer; import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer;
import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess; 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.Chunk; import org.bukkit.*;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.entity.Dolphin; 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.*;
import java.awt.Color;
public interface INMSBinding { public interface INMSBinding {
boolean hasTile(Material material);
boolean hasTile(Location l); boolean hasTile(Location l);
CompoundTag serializeTile(Location location); KMap<String, Object> serializeTile(Location location);
void deserializeTile(CompoundTag s, Location newPosition); void deserializeTile(KMap<String, Object> s, Location newPosition);
CompoundTag serializeEntity(Entity location); CompoundTag serializeEntity(Entity location);
@ -107,8 +108,6 @@ public interface INMSBinding {
ItemStack applyCustomNbt(ItemStack itemStack, KMap<String, Object> customNbt) throws IllegalArgumentException; ItemStack applyCustomNbt(ItemStack itemStack, KMap<String, Object> customNbt) throws IllegalArgumentException;
void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos);
void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException; void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException;
Vector3d getBoundingbox(org.bukkit.entity.EntityType entity); Vector3d getBoundingbox(org.bukkit.entity.EntityType entity);
@ -124,4 +123,6 @@ public interface INMSBinding {
default int getSpawnChunkCount(World world) { default int getSpawnChunkCount(World world) {
return 441; return 441;
} }
KList<String> getStructureKeys();
} }

View File

@ -3,6 +3,7 @@ package com.volmit.iris.core.nms.datapack;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.datapack.v1192.DataFixerV1192; import com.volmit.iris.core.nms.datapack.v1192.DataFixerV1192;
import com.volmit.iris.core.nms.datapack.v1206.DataFixerV1206; import com.volmit.iris.core.nms.datapack.v1206.DataFixerV1206;
import com.volmit.iris.core.nms.datapack.v1213.DataFixerV1213;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
@ -13,7 +14,8 @@ import java.util.function.Supplier;
@Getter @Getter
public enum DataVersion { public enum DataVersion {
V1192("1.19.2", 10, DataFixerV1192::new), V1192("1.19.2", 10, DataFixerV1192::new),
V1205("1.20.6", 41, DataFixerV1206::new); V1205("1.20.6", 41, DataFixerV1206::new),
V1213("1.21.3", 57, DataFixerV1213::new);
private static final KMap<DataVersion, IDataFixer> cache = new KMap<>(); private static final KMap<DataVersion, IDataFixer> cache = new KMap<>();
@Getter(AccessLevel.NONE) @Getter(AccessLevel.NONE)
private final Supplier<IDataFixer> constructor; private final Supplier<IDataFixer> constructor;

View File

@ -16,6 +16,8 @@ public class DataFixerV1206 implements IDataFixer {
int spawnRarity = biome.getSpawnRarity(); int spawnRarity = biome.getSpawnRarity();
if (spawnRarity > 0) { if (spawnRarity > 0) {
json.put("creature_spawn_probability", Math.min(spawnRarity/20d, 0.9999999)); json.put("creature_spawn_probability", Math.min(spawnRarity/20d, 0.9999999));
} else {
json.remove("creature_spawn_probability");
} }
var spawns = biome.getSpawns(); var spawns = biome.getSpawns();
@ -26,10 +28,10 @@ public class DataFixerV1206 implements IDataFixer {
for (IrisBiomeCustomSpawn i : spawns) { for (IrisBiomeCustomSpawn i : spawns) {
JSONArray g = groups.computeIfAbsent(i.getGroup(), (k) -> new JSONArray()); JSONArray g = groups.computeIfAbsent(i.getGroup(), (k) -> new JSONArray());
JSONObject o = new JSONObject(); JSONObject o = new JSONObject();
o.put("type", "minecraft:" + i.getType().name().toLowerCase()); o.put("type", i.getType().getKey());
o.put("weight", i.getWeight()); o.put("weight", i.getWeight());
o.put("minCount", Math.min(i.getMinCount()/20d, 0)); o.put("minCount", i.getMinCount());
o.put("maxCount", Math.min(i.getMaxCount()/20d, 0.9999999)); o.put("maxCount", i.getMaxCount());
g.put(o); g.put(o);
} }

View File

@ -0,0 +1,16 @@
package com.volmit.iris.core.nms.datapack.v1213;
import com.volmit.iris.core.nms.datapack.v1206.DataFixerV1206;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject;
public class DataFixerV1213 extends DataFixerV1206 {
@Override
public JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) {
json = super.fixCustomBiome(biome, json);
json.put("carvers", new JSONArray());
return json;
}
}

View File

@ -21,7 +21,6 @@ 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.BiomeColor; import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockPos;
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,18 +29,17 @@ import com.volmit.iris.util.math.Vector3d;
import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer; import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer;
import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess; 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.Chunk; import org.bukkit.*;
import org.bukkit.Location;
import org.bukkit.World;
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.util.stream.StreamSupport;
public class NMSBinding1X implements INMSBinding { public class NMSBinding1X implements INMSBinding {
private static final boolean supportsCustomHeight = testCustomHeight(); private static final boolean supportsCustomHeight = testCustomHeight();
@ -61,16 +59,27 @@ public class NMSBinding1X implements INMSBinding {
return false; return false;
} }
@Override
public boolean hasTile(Material material) {
return false;
}
@Override @Override
public boolean hasTile(Location l) { public boolean hasTile(Location l) {
return false; return false;
} }
@Override @Override
public CompoundTag serializeTile(Location location) { public KMap<String, Object> serializeTile(Location location) {
return null; return null;
} }
@Override
public void deserializeTile(KMap<String, Object> s, Location newPosition) {
}
@Override @Override
public void injectBiomesFromMantle(Chunk e, Mantle mantle) { public void injectBiomesFromMantle(Chunk e, Mantle mantle) {
@ -81,11 +90,6 @@ public class NMSBinding1X implements INMSBinding {
return itemStack; return itemStack;
} }
@Override
public void setTreasurePos(Dolphin dolphin, BlockPos pos) {
}
@Override @Override
public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
@ -106,8 +110,12 @@ public class NMSBinding1X implements INMSBinding {
} }
@Override @Override
public void deserializeTile(CompoundTag s, Location newPosition) { public KList<String> getStructureKeys() {
var list = StreamSupport.stream(Registry.STRUCTURE.spliterator(), false)
.map(Structure::getKey)
.map(NamespacedKey::toString)
.toList();
return new KList<>(list);
} }
@Override @Override

View File

@ -1,16 +1,21 @@
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.IrisSettings;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
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 com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RollingSequence; import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.math.Spiraler; import com.volmit.iris.util.profile.LoadBalancer;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.World;
@ -23,53 +28,40 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
public class ChunkUpdater { public class ChunkUpdater {
private AtomicBoolean paused; private final AtomicBoolean paused = new AtomicBoolean();
private AtomicBoolean cancelled; private final AtomicBoolean cancelled = new AtomicBoolean();
private KMap<Chunk, Long> lastUse; private final KMap<Long, Pair<Long, AtomicInteger>> lastUse = new KMap<>();
private final RollingSequence chunksPerSecond; private final RollingSequence chunksPerSecond = new RollingSequence(5);
private final AtomicInteger worldheightsize; private final AtomicInteger totalMaxChunks = new AtomicInteger();
private final AtomicInteger worldwidthsize; private final AtomicInteger chunksProcessed = new AtomicInteger();
private final AtomicInteger totalChunks; private final AtomicInteger chunksProcessedLast = new AtomicInteger();
private final AtomicInteger totalMaxChunks; private final AtomicInteger chunksUpdated = new AtomicInteger();
private final AtomicInteger totalMcaregions; private final AtomicBoolean serverEmpty = new AtomicBoolean(true);
private final AtomicInteger position; private final AtomicLong lastCpsTime = new AtomicLong(M.ms());
private AtomicInteger chunksProcessed; private final int coreLimit = (int) Math.max(Runtime.getRuntime().availableProcessors() * IrisSettings.get().getUpdater().getThreadMultiplier(), 1);
private AtomicInteger chunksUpdated; private final Semaphore semaphore = new Semaphore(256);
private AtomicLong startTime; private final LoadBalancer loadBalancer = new LoadBalancer(semaphore, 256, IrisSettings.get().getUpdater().emptyMsRange);
private ExecutorService executor; private final AtomicLong startTime = new AtomicLong();
private ExecutorService chunkExecutor; private final Dimensions dimensions;
private ScheduledExecutorService scheduler; private final PregenTask task;
private CompletableFuture future; private final ExecutorService executor = Executors.newFixedThreadPool(coreLimit);
private CountDownLatch latch; private final ExecutorService chunkExecutor = Executors.newFixedThreadPool(coreLimit);
private final Object pauseLock; private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private final CountDownLatch latch;
private final Engine engine; private final Engine engine;
private final World world; private final World world;
public ChunkUpdater(World world) { public ChunkUpdater(World world) {
this.engine = IrisToolbelt.access(world).getEngine(); this.engine = IrisToolbelt.access(world).getEngine();
this.chunksPerSecond = new RollingSequence(5);
this.world = world; this.world = world;
this.lastUse = new KMap(); this.dimensions = calculateWorldDimensions(new File(world.getWorldFolder(), "region"));
this.worldheightsize = new AtomicInteger(calculateWorldDimensions(new File(world.getWorldFolder(), "region"), 1)); this.task = dimensions.task();
this.worldwidthsize = new AtomicInteger(calculateWorldDimensions(new File(world.getWorldFolder(), "region"), 0)); this.totalMaxChunks.set(dimensions.count * 1024);
int m = Math.max(worldheightsize.get(), worldwidthsize.get());
this.executor = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors() / 3, 1));
this.chunkExecutor = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors() / 3, 1));
this.scheduler = Executors.newScheduledThreadPool(1);
this.future = new CompletableFuture<>();
this.startTime = new AtomicLong();
this.worldheightsize.set(m);
this.worldwidthsize.set(m);
this.totalMaxChunks = new AtomicInteger((worldheightsize.get() / 16) * (worldwidthsize.get() / 16));
this.chunksProcessed = new AtomicInteger();
this.chunksUpdated = new AtomicInteger();
this.position = new AtomicInteger(0);
this.latch = new CountDownLatch(totalMaxChunks.get()); this.latch = new CountDownLatch(totalMaxChunks.get());
this.paused = new AtomicBoolean(false); }
this.pauseLock = new Object();
this.cancelled = new AtomicBoolean(false); public String getName() {
this.totalChunks = new AtomicInteger(0); return world.getName();
this.totalMcaregions = new AtomicInteger(0);
} }
public int getChunks() { public int getChunks() {
@ -97,7 +89,6 @@ public class ChunkUpdater {
cancelled.set(true); cancelled.set(true);
} }
private void update() { private void update() {
Iris.info("Updating.."); Iris.info("Updating..");
try { try {
@ -106,11 +97,11 @@ public class ChunkUpdater {
try { try {
if (!paused.get()) { if (!paused.get()) {
long eta = computeETA(); long eta = computeETA();
long elapsedSeconds = (System.currentTimeMillis() - startTime.get()) / 1000;
int processed = chunksProcessed.get(); int processed = chunksProcessed.get();
double cps = elapsedSeconds > 0 ? processed / (double) elapsedSeconds : 0; double last = processed - chunksProcessedLast.getAndSet(processed);
double cps = last / ((M.ms() - lastCpsTime.getAndSet(M.ms())) / 1000d);
chunksPerSecond.put(cps); chunksPerSecond.put(cps);
double percentage = ((double) chunksProcessed.get() / (double) totalMaxChunks.get()) * 100; double percentage = ((double) processed / (double) totalMaxChunks.get()) * 100;
if (!cancelled.get()) { if (!cancelled.get()) {
Iris.info("Updated: " + Form.f(processed) + " of " + Form.f(totalMaxChunks.get()) + " (%.0f%%) " + Form.f(chunksPerSecond.getAverage()) + "/s, ETA: " + Form.duration(eta, Iris.info("Updated: " + Form.f(processed) + " of " + Form.f(totalMaxChunks.get()) + " (%.0f%%) " + Form.f(chunksPerSecond.getAverage()) + "/s, ETA: " + Form.duration(eta,
2), percentage); 2), percentage);
@ -120,35 +111,20 @@ public class ChunkUpdater {
e.printStackTrace(); e.printStackTrace();
} }
}, 0, 3, TimeUnit.SECONDS); }, 0, 3, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(this::unloadChunks, 0, 1, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(() -> {
boolean empty = Bukkit.getOnlinePlayers().isEmpty();
if (serverEmpty.getAndSet(empty) == empty)
return;
loadBalancer.setRange(empty ? IrisSettings.get().getUpdater().emptyMsRange : IrisSettings.get().getUpdater().defaultMsRange);
}, 0, 10, TimeUnit.SECONDS);
CompletableFuture.runAsync(() -> { var t = new Thread(() -> {
for (int i = 0; i < totalMaxChunks.get(); i++) { run();
if (paused.get()) { close();
synchronized (pauseLock) { }, "Iris Chunk Updater - " + world.getName());
try { t.setPriority(Thread.MAX_PRIORITY);
pauseLock.wait(); t.start();
} catch (InterruptedException e) {
Iris.error("Interrupted while waiting for executor: ");
e.printStackTrace();
break;
}
}
}
executor.submit(() -> {
if (!cancelled.get()) {
processNextChunk();
}
latch.countDown();
});
}
}).thenRun(() -> {
try {
latch.await();
close();
} catch (Exception e) {
Thread.currentThread().interrupt();
}
});
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -157,14 +133,16 @@ public class ChunkUpdater {
public void close() { public void close() {
try { try {
unloadAndSaveAllChunks(); loadBalancer.close();
semaphore.acquire(256);
executor.shutdown(); executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS); executor.awaitTermination(5, TimeUnit.SECONDS);
chunkExecutor.shutdown(); chunkExecutor.shutdown();
chunkExecutor.awaitTermination(5, TimeUnit.SECONDS); chunkExecutor.awaitTermination(5, TimeUnit.SECONDS);
scheduler.shutdownNow(); scheduler.shutdownNow();
} catch (Exception ignored) { unloadAndSaveAllChunks();
} } catch (Exception ignored) {}
if (cancelled.get()) { if (cancelled.get()) {
Iris.info("Updated: " + Form.f(chunksUpdated.get()) + " Chunks"); Iris.info("Updated: " + Form.f(chunksUpdated.get()) + " Chunks");
Iris.info("Irritated: " + Form.f(chunksProcessed.get()) + " of " + Form.f(totalMaxChunks.get())); Iris.info("Irritated: " + Form.f(chunksProcessed.get()) + " of " + Form.f(totalMaxChunks.get()));
@ -175,18 +153,69 @@ public class ChunkUpdater {
} }
} }
private void processNextChunk() { private void run() {
int pos = position.getAndIncrement(); task.iterateRegions((rX, rZ) -> {
int[] coords = getChunk(pos); if (cancelled.get())
if (loadChunksIfGenerated(coords[0], coords[1])) { return;
Chunk c = world.getChunkAt(coords[0], coords[1]);
engine.updateChunk(c); while (paused.get()) {
chunksUpdated.incrementAndGet(); J.sleep(50);
}
if (rX < dimensions.min.getX() || rX > dimensions.max.getX() || rZ < dimensions.min.getZ() || rZ > dimensions.max.getZ()) {
return;
}
PregenTask.iterateRegion(rX, rZ, (x, z) -> {
while (paused.get() && !cancelled.get()) {
J.sleep(50);
}
try {
semaphore.acquire();
} catch (InterruptedException ignored) {
return;
}
chunkExecutor.submit(() -> {
try {
if (!cancelled.get())
processChunk(x, z);
} finally {
latch.countDown();
semaphore.release();
}
});
});
});
}
private void processChunk(int x, int z) {
if (!loadChunksIfGenerated(x, z)) {
chunksProcessed.getAndIncrement();
return;
}
try {
Chunk c = world.getChunkAt(x, z);
engine.getMantle().getMantle().getChunk(c);
engine.updateChunk(c);
for (int xx = -1; xx <= 1; xx++) {
for (int zz = -1; zz <= 1; zz++) {
var counter = lastUse.get(Cache.key(x + xx, z + zz));
if (counter != null) counter.getB().decrementAndGet();
}
}
} finally {
chunksUpdated.incrementAndGet();
chunksProcessed.getAndIncrement();
} }
chunksProcessed.getAndIncrement();
} }
private boolean loadChunksIfGenerated(int x, int z) { private boolean loadChunksIfGenerated(int x, int z) {
if (engine.getMantle().getMantle().hasFlag(x, z, MantleFlag.ETCHED))
return false;
for (int dx = -1; dx <= 1; dx++) { for (int dx = -1; dx <= 1; dx++) {
for (int dz = -1; dz <= 1; dz++) { for (int dz = -1; dz <= 1; dz++) {
if (!PaperLib.isChunkGenerated(world, x + dx, z + dz)) { if (!PaperLib.isChunkGenerated(world, x + dx, z + dz)) {
@ -196,45 +225,79 @@ public class ChunkUpdater {
} }
AtomicBoolean generated = new AtomicBoolean(true); AtomicBoolean generated = new AtomicBoolean(true);
KList<Future<?>> futures = new KList<>(9); CountDownLatch latch = new CountDownLatch(9);
for (int dx = -1; dx <= 1; dx++) { for (int dx = -1; dx <= 1; dx++) {
for (int dz = -1; dz <= 1; dz++) { for (int dz = -1; dz <= 1; dz++) {
int xx = x + dx; int xx = x + dx;
int zz = z + dz; int zz = z + dz;
futures.add(chunkExecutor.submit(() -> { executor.submit(() -> {
Chunk c;
try { try {
c = PaperLib.getChunkAtAsync(world, xx, zz, false).get(); Chunk c;
} catch (InterruptedException | ExecutionException e) {
generated.set(false);
return;
}
if (!c.isLoaded()) {
CountDownLatch latch = new CountDownLatch(1);
J.s(() -> {
c.load(false);
latch.countDown();
});
try { try {
latch.await(); c = PaperLib.getChunkAtAsync(world, xx, zz, false, true)
} catch (InterruptedException ignored) {} .thenApply(chunk -> {
if (chunk != null)
chunk.addPluginChunkTicket(Iris.instance);
return chunk;
}).get();
} catch (InterruptedException | ExecutionException e) {
generated.set(false);
return;
}
if (c == null) {
generated.set(false);
return;
}
if (!c.isLoaded()) {
var future = J.sfut(() -> c.load(false));
if (future != null) future.join();
}
if (!PaperLib.isChunkGenerated(c.getWorld(), xx, zz))
generated.set(false);
var pair = lastUse.computeIfAbsent(Cache.key(c), k -> new Pair<>(0L, new AtomicInteger(-1)));
pair.setA(M.ms());
pair.getB().updateAndGet(i -> i == -1 ? 1 : ++i);
} finally {
latch.countDown();
} }
if (!c.isGenerated()) { });
generated.set(false);
}
lastUse.put(c, M.ms());
}));
} }
} }
while (!futures.isEmpty()) {
futures.removeIf(Future::isDone); try {
try { latch.await();
Thread.sleep(50); } catch (InterruptedException e) {
} catch (InterruptedException ignored) {} Iris.info("Interrupted while waiting for chunks to load");
} }
return generated.get(); return generated.get();
} }
private synchronized void unloadChunks() {
for (var key : new ArrayList<>(lastUse.keySet())) {
if (key == null) continue;
var pair = lastUse.get(key);
if (pair == null) continue;
var lastUseTime = pair.getA();
var counter = pair.getB();
if (lastUseTime == null || counter == null)
continue;
if (M.ms() - lastUseTime >= 5000 && counter.get() == 0) {
int x = Cache.keyX(key);
int z = Cache.keyZ(key);
J.s(() -> {
world.removePluginChunkTicket(x, z, Iris.instance);
world.unloadChunk(x, z);
lastUse.remove(key);
});
}
}
}
private void unloadAndSaveAllChunks() { private void unloadAndSaveAllChunks() {
try { try {
J.sfut(() -> { J.sfut(() -> {
@ -243,13 +306,7 @@ public class ChunkUpdater {
return; return;
} }
for (Chunk i : new ArrayList<>(lastUse.keySet())) { unloadChunks();
Long lastUseTime = lastUse.get(i);
if (lastUseTime != null && M.ms() - lastUseTime >= 5000) {
i.unload();
lastUse.remove(i);
}
}
world.save(); world.save();
}).get(); }).get();
} catch (Throwable e) { } catch (Throwable e) {
@ -266,7 +323,7 @@ public class ChunkUpdater {
); );
} }
public int calculateWorldDimensions(File regionDir, Integer o) { private Dimensions calculateWorldDimensions(File regionDir) {
File[] files = regionDir.listFiles((dir, name) -> name.endsWith(".mca")); File[] files = regionDir.listFiles((dir, name) -> name.endsWith(".mca"));
int minX = Integer.MAX_VALUE; int minX = Integer.MAX_VALUE;
@ -279,40 +336,23 @@ public class ChunkUpdater {
int x = Integer.parseInt(parts[1]); int x = Integer.parseInt(parts[1]);
int z = Integer.parseInt(parts[2]); int z = Integer.parseInt(parts[2]);
if (x < minX) minX = x; minX = Math.min(minX, x);
if (x > maxX) maxX = x; maxX = Math.max(maxX, x);
if (z < minZ) minZ = z; minZ = Math.min(minZ, z);
if (z > maxZ) maxZ = z; maxZ = Math.max(maxZ, z);
} }
int oX = minX + ((maxX - minX) / 2);
int oZ = minZ + ((maxZ - minZ) / 2);
int height = (maxX - minX + 1) * 32 * 16; int height = maxX - minX + 1;
int width = (maxZ - minZ + 1) * 32 * 16; int width = maxZ - minZ + 1;
if (o == 1) { return new Dimensions(new Position2(minX, minZ), new Position2(maxX, maxZ), height * width, PregenTask.builder()
return height; .width((int) Math.ceil(width / 2d))
} .height((int) Math.ceil(height / 2d))
if (o == 0) { .center(new Position2(oX, oZ))
return width; .build());
}
return 0;
} }
public int[] getChunk(int position) { private record Dimensions(Position2 min, Position2 max, int count, PregenTask task) { }
int p = -1;
AtomicInteger xx = new AtomicInteger();
AtomicInteger zz = new AtomicInteger();
Spiraler s = new Spiraler(worldheightsize.get() * 2, worldwidthsize.get() * 2, (x, z) -> {
xx.set(x);
zz.set(z);
});
while (s.hasNext() && p++ < position) {
s.next();
}
int[] coords = new int[2];
coords[0] = xx.get();
coords[1] = zz.get();
return coords;
}
} }

View File

@ -15,7 +15,6 @@ import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.math.Spiraler; import com.volmit.iris.util.math.Spiraler;
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 lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -261,14 +260,14 @@ public class DeepSearchPregenerator extends Thread implements Listener {
} }
@Data @Data
@Builder @lombok.Builder
public static class DeepSearchJob { public static class DeepSearchJob {
private World world; private World world;
@Builder.Default @lombok.Builder.Default
private int radiusBlocks = 5000; private int radiusBlocks = 5000;
@Builder.Default @lombok.Builder.Default
private int position = 0; private int position = 0;
@Builder.Default @lombok.Builder.Default
boolean paused = false; boolean paused = false;
} }
} }

View File

@ -12,7 +12,6 @@ import com.volmit.iris.util.math.Spiraler;
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 io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -264,22 +263,22 @@ public class LazyPregenerator extends Thread implements Listener {
} }
@Data @Data
@Builder @lombok.Builder
public static class LazyPregenJob { public static class LazyPregenJob {
private String world; private String world;
@Builder.Default @lombok.Builder.Default
private int healingPosition = 0; private int healingPosition = 0;
@Builder.Default @lombok.Builder.Default
private boolean healing = false; private boolean healing = false;
@Builder.Default @lombok.Builder.Default
private int chunksPerMinute = 32; private int chunksPerMinute = 32;
@Builder.Default @lombok.Builder.Default
private int radiusBlocks = 5000; private int radiusBlocks = 5000;
@Builder.Default @lombok.Builder.Default
private int position = 0; private int position = 0;
@Builder.Default @lombok.Builder.Default
boolean silent = false; boolean silent = false;
@Builder.Default @lombok.Builder.Default
boolean paused = false; boolean paused = false;
} }
} }

View File

@ -18,7 +18,6 @@ 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.PrecisionStopwatch; import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.Getter; import lombok.Getter;
import org.apache.logging.log4j.core.util.ExecutorServices; import org.apache.logging.log4j.core.util.ExecutorServices;
@ -328,14 +327,14 @@ public class TurboPregenerator extends Thread implements Listener {
} }
@Data @Data
@Builder @lombok.Builder
public static class TurboPregenJob { public static class TurboPregenJob {
private String world; private String world;
@Builder.Default @lombok.Builder.Default
private int radiusBlocks = 5000; private int radiusBlocks = 5000;
@Builder.Default @lombok.Builder.Default
private int position = 0; private int position = 0;
@Builder.Default @lombok.Builder.Default
boolean paused = false; boolean paused = false;
} }
} }

View File

@ -22,28 +22,23 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.pregenerator.PregenListener; import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod; import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
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.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.World;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.concurrent.Semaphore;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
public class AsyncPregenMethod implements PregeneratorMethod { public class AsyncPregenMethod implements PregeneratorMethod {
private final World world; private final World world;
private final MultiBurst burst; private final MultiBurst burst;
private final KList<Future<?>> future; private final Semaphore semaphore;
private final Map<Chunk, Long> lastUse; private final Map<Chunk, Long> lastUse;
public AsyncPregenMethod(World world, int threads) { public AsyncPregenMethod(World world, int threads) {
@ -52,8 +47,8 @@ public class AsyncPregenMethod implements PregeneratorMethod {
} }
this.world = world; this.world = world;
burst = MultiBurst.burst; burst = new MultiBurst("Iris Async Pregen", Thread.MIN_PRIORITY);
future = new KList<>(1024); semaphore = new Semaphore(256);
this.lastUse = new KMap<>(); this.lastUse = new KMap<>();
} }
@ -67,7 +62,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
for (Chunk i : new ArrayList<>(lastUse.keySet())) { for (Chunk i : new ArrayList<>(lastUse.keySet())) {
Long lastUseTime = lastUse.get(i); Long lastUseTime = lastUse.get(i);
if (lastUseTime != null && M.ms() - lastUseTime >= 10000) { if (!i.isLoaded() || (lastUseTime != null && M.ms() - lastUseTime >= 10000)) {
i.unload(); i.unload();
lastUse.remove(i); lastUse.remove(i);
} }
@ -81,56 +76,19 @@ public class AsyncPregenMethod implements PregeneratorMethod {
private void completeChunk(int x, int z, PregenListener listener) { private void completeChunk(int x, int z, PregenListener listener) {
try { try {
future.add(PaperLib.getChunkAtAsync(world, x, z, true).thenApply((i) -> { PaperLib.getChunkAtAsync(world, x, z, true).thenAccept((i) -> {
if (i == null) { lastUse.put(i, M.ms());
}
Chunk c = Bukkit.getWorld(world.getUID()).getChunkAt(x, z);
lastUse.put(c, M.ms());
listener.onChunkGenerated(x, z); listener.onChunkGenerated(x, z);
listener.onChunkCleaned(x, z); listener.onChunkCleaned(x, z);
return 0; }).get();
})); } catch (InterruptedException ignored) {
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
} finally {
semaphore.release();
} }
} }
private void waitForChunksPartial(int maxWaiting) {
future.removeWhere(Objects::isNull);
while (future.size() > maxWaiting) {
try {
Future<?> i = future.remove(0);
if (i == null) {
continue;
}
i.get();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
private void waitForChunks() {
for (Future<?> i : future.copy()) {
if (i == null) {
continue;
}
try {
i.get();
future.remove(i);
} catch (Throwable e) {
e.printStackTrace();
}
}
future.removeWhere(Objects::isNull);
}
@Override @Override
public void init() { public void init() {
unloadAndSaveAllChunks(); unloadAndSaveAllChunks();
@ -143,13 +101,13 @@ public class AsyncPregenMethod implements PregeneratorMethod {
@Override @Override
public void close() { public void close() {
waitForChunks(); semaphore.acquireUninterruptibly(256);
unloadAndSaveAllChunks(); unloadAndSaveAllChunks();
burst.close();
} }
@Override @Override
public void save() { public void save() {
waitForChunksPartial(256);
unloadAndSaveAllChunks(); unloadAndSaveAllChunks();
} }
@ -166,10 +124,12 @@ public class AsyncPregenMethod implements PregeneratorMethod {
@Override @Override
public void generateChunk(int x, int z, PregenListener listener) { public void generateChunk(int x, int z, PregenListener listener) {
listener.onChunkGenerating(x, z); listener.onChunkGenerating(x, z);
if (future.size() > 256) { try {
waitForChunksPartial(256); semaphore.acquire();
} catch (InterruptedException e) {
return;
} }
future.add(burst.complete(() -> completeChunk(x, z, listener))); burst.complete(() -> completeChunk(x, z, listener));
} }
@Override @Override

View File

@ -28,14 +28,17 @@ 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.json.JSONArray; import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.reflect.OldEnum;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import java.awt.*; import java.awt.*;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class SchemaBuilder { public class SchemaBuilder {
@ -43,7 +46,6 @@ public class SchemaBuilder {
private static final String SYMBOL_TYPE__N = ""; private static final String SYMBOL_TYPE__N = "";
private static final JSONArray POTION_TYPES = getPotionTypes(); private static final JSONArray POTION_TYPES = getPotionTypes();
private static final JSONArray ENCHANT_TYPES = getEnchantTypes(); private static final JSONArray ENCHANT_TYPES = getEnchantTypes();
private static final JSONArray ITEM_TYPES = new JSONArray(B.getItemTypes());
private static final JSONArray FONT_TYPES = new JSONArray(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()); private static final JSONArray FONT_TYPES = new JSONArray(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames());
private final KMap<String, JSONObject> definitions; private final KMap<String, JSONObject> definitions;
private final Class<?> root; private final Class<?> root;
@ -261,7 +263,7 @@ public class SchemaBuilder {
if (!definitions.containsKey(key)) { if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject(); JSONObject j = new JSONObject();
j.put("enum", ITEM_TYPES); j.put("enum", B.getItemTypes());
definitions.put(key, j); definitions.put(key, j);
} }
@ -309,6 +311,24 @@ public class SchemaBuilder {
fancyType = "Enchantment Type"; fancyType = "Enchantment Type";
prop.put("$ref", "#/definitions/" + key); prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Enchantment Type (use ctrl+space for auto complete!)"); description.add(SYMBOL_TYPE__N + " Must be a valid Enchantment Type (use ctrl+space for auto complete!)");
} else if (k.isAnnotationPresent(RegistryListFunction.class)) {
var functionClass = k.getDeclaredAnnotation(RegistryListFunction.class).value();
try {
var instance = functionClass.getDeclaredConstructor().newInstance();
String key = instance.key();
fancyType = instance.fancyName();
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", instance.apply(data));
definitions.put(key, j);
}
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid " + fancyType + " (use ctrl+space for auto complete!)");
} catch (Throwable e) {
Iris.error("Could not execute apply method in " + functionClass.getName());
}
} else if (k.getType().equals(PotionEffectType.class)) { } else if (k.getType().equals(PotionEffectType.class)) {
String key = "enum-potion-effect-type"; String key = "enum-potion-effect-type";
@ -323,38 +343,9 @@ public class SchemaBuilder {
description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)"); description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)");
} else if (k.getType().isEnum()) { } else if (k.getType().isEnum()) {
fancyType = k.getType().getSimpleName().replaceAll("\\QIris\\E", ""); fancyType = addEnum(k.getType(), prop, description, k.getType().getEnumConstants(), o -> ((Enum<?>) o).name());
JSONArray a = new JSONArray(); } else if (OldEnum.isOldEnum(k.getType())) {
boolean advanced = k.getType().isAnnotationPresent(Desc.class); fancyType = addEnum(k.getType(), prop, description, OldEnum.values(k.getType()), OldEnum::name);
for (Object gg : k.getType().getEnumConstants()) {
if (advanced) {
try {
JSONObject j = new JSONObject();
String name = ((Enum<?>) gg).name();
j.put("const", name);
Desc dd = k.getType().getField(name).getAnnotation(Desc.class);
j.put("description", dd == null ? ("No Description for " + name) : dd.value());
a.put(j);
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
} else {
a.put(((Enum<?>) gg).name());
}
}
String key = (advanced ? "oneof-" : "") + "enum-" + k.getType().getCanonicalName().replaceAll("\\Q.\\E", "-").toLowerCase();
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put(advanced ? "oneOf" : "enum", a);
definitions.put(key, j);
}
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid " + k.getType().getSimpleName().replaceAll("\\QIris\\E", "") + " (use ctrl+space for auto complete!)");
} }
} }
case "object" -> { case "object" -> {
@ -449,7 +440,7 @@ public class SchemaBuilder {
if (!definitions.containsKey(key)) { if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject(); JSONObject j = new JSONObject();
j.put("enum", ITEM_TYPES); j.put("enum", B.getItemTypes());
definitions.put(key, j); definitions.put(key, j);
} }
@ -500,39 +491,9 @@ public class SchemaBuilder {
prop.put("items", items); prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)"); description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)");
} else if (t.type().isEnum()) { } else if (t.type().isEnum()) {
fancyType = "List of " + t.type().getSimpleName().replaceAll("\\QIris\\E", "") + "s"; fancyType = addEnumList(prop, description, t, t.type().getEnumConstants(), o -> ((Enum<?>) o).name());
JSONArray a = new JSONArray(); } else if (OldEnum.isOldEnum(t.type())) {
boolean advanced = t.type().isAnnotationPresent(Desc.class); fancyType = addEnumList(prop, description, t, OldEnum.values(t.type()), OldEnum::name);
for (Object gg : t.type().getEnumConstants()) {
if (advanced) {
try {
JSONObject j = new JSONObject();
String name = ((Enum<?>) gg).name();
j.put("const", name);
Desc dd = t.type().getField(name).getAnnotation(Desc.class);
j.put("description", dd == null ? ("No Description for " + name) : dd.value());
a.put(j);
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
} else {
a.put(((Enum<?>) gg).name());
}
}
String key = (advanced ? "oneof-" : "") + "enum-" + t.type().getCanonicalName().replaceAll("\\Q.\\E", "-").toLowerCase();
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put(advanced ? "oneOf" : "enum", a);
definitions.put(key, j);
}
JSONObject items = new JSONObject();
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid " + t.type().getSimpleName().replaceAll("\\QIris\\E", "") + " (use ctrl+space for auto complete!)");
} }
} }
} }
@ -565,7 +526,7 @@ public class SchemaBuilder {
if (value instanceof List) { if (value instanceof List) {
d.add(" "); d.add(" ");
d.add("* Default Value is an empty list"); d.add("* Default Value is an empty list");
} else if (!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum())) { } else if (!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum()) && !OldEnum.isOldEnum(cl)) {
d.add(" "); d.add(" ");
d.add("* Default Value is a default object (create this object to see default properties)"); d.add("* Default Value is a default object (create this object to see default properties)");
} else { } else {
@ -611,6 +572,50 @@ public class SchemaBuilder {
return prop; return prop;
} }
@NotNull
private String addEnumList(JSONObject prop, KList<String> description, ArrayType t, Object[] values, Function<Object, String> function) {
JSONObject items = new JSONObject();
var s = addEnum(t.type(), items, description, values, function);
prop.put("items", items);
return "List of " + s + "s";
}
@NotNull
private String addEnum(Class<?> type, JSONObject prop, KList<String> description, Object[] values, Function<Object, String> function) {
JSONArray a = new JSONArray();
boolean advanced = type.isAnnotationPresent(Desc.class);
for (Object gg : values) {
if (advanced) {
try {
JSONObject j = new JSONObject();
String name = function.apply(gg);
j.put("const", name);
Desc dd = type.getField(name).getAnnotation(Desc.class);
j.put("description", dd == null ? ("No Description for " + name) : dd.value());
a.put(j);
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
} else {
a.put(function.apply(gg));
}
}
String key = (advanced ? "oneof-" : "") + "enum-" + type.getCanonicalName().replaceAll("\\Q.\\E", "-").toLowerCase();
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put(advanced ? "oneOf" : "enum", a);
definitions.put(key, j);
}
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid " + type.getSimpleName().replaceAll("\\QIris\\E", "") + " (use ctrl+space for auto complete!)");
return type.getSimpleName().replaceAll("\\QIris\\E", "");
}
private String getType(Class<?> c) { private String getType(Class<?> c) {
if (c.equals(int.class) || c.equals(Integer.class) || c.equals(long.class) || c.equals(Long.class)) { if (c.equals(int.class) || c.equals(Integer.class) || c.equals(long.class) || c.equals(Long.class)) {
return "integer"; return "integer";
@ -624,7 +629,7 @@ public class SchemaBuilder {
return "boolean"; return "boolean";
} }
if (c.equals(String.class) || c.isEnum() || c.equals(Enchantment.class) || c.equals(PotionEffectType.class)) { if (c.equals(String.class) || c.isEnum() || OldEnum.isOldEnum(c) || c.equals(Enchantment.class) || c.equals(PotionEffectType.class)) {
return "string"; return "string";
} }

View File

@ -20,12 +20,11 @@ import java.util.Map;
import java.util.StringJoiner; import java.util.StringJoiner;
import static com.volmit.iris.Iris.getJavaVersion; import static com.volmit.iris.Iris.getJavaVersion;
import static com.volmit.iris.Iris.instance;
import static com.volmit.iris.core.safeguard.IrisSafeguard.*; import static com.volmit.iris.core.safeguard.IrisSafeguard.*;
public class ServerBootSFG { public class ServerBootSFG {
public static final Map<String, Boolean> incompatibilities = new HashMap<>(); public static final Map<String, Boolean> incompatibilities = new HashMap<>();
public static boolean isJDK17 = true; public static boolean isCorrectJDK = true;
public static boolean hasEnoughDiskSpace = true; public static boolean hasEnoughDiskSpace = true;
public static boolean isJRE = false; public static boolean isJRE = false;
public static boolean hasPrivileges = true; public static boolean hasPrivileges = true;
@ -87,8 +86,8 @@ public class ServerBootSFG {
severityHigh++; severityHigh++;
} }
if (!List.of(17, 21).contains(getJavaVersion())) { if (!List.of(21).contains(getJavaVersion())) {
isJDK17 = false; isCorrectJDK = false;
joiner.add("Unsupported Java version"); joiner.add("Unsupported Java version");
severityMedium++; severityMedium++;
} }

View File

@ -37,7 +37,7 @@ 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.1"); Iris.safeguard(C.RED + "- Iris only supports 1.19.2 > 1.21.3");
} }
if (!ServerBootSFG.passedserversoftware) { if (!ServerBootSFG.passedserversoftware) {
Iris.safeguard(C.YELLOW + "Unsupported Server Software"); Iris.safeguard(C.YELLOW + "Unsupported Server Software");
@ -51,13 +51,13 @@ public class UtilsSFG {
Iris.safeguard(C.YELLOW + "Insufficient Disk Space"); Iris.safeguard(C.YELLOW + "Insufficient Disk Space");
Iris.safeguard(C.YELLOW + "- The server has insufficient Free DiskSpace to run iris required 3GB+."); Iris.safeguard(C.YELLOW + "- The server has insufficient Free DiskSpace to run iris required 3GB+.");
} }
if (!ServerBootSFG.isJDK17) { if (!ServerBootSFG.isCorrectJDK) {
Iris.safeguard(C.YELLOW + "Unsupported java version"); Iris.safeguard(C.YELLOW + "Unsupported java version");
Iris.safeguard(C.YELLOW + "- Please consider using JDK 17 (or 21 for 1.20.6) Instead of JDK " + Iris.getJavaVersion()); Iris.safeguard(C.YELLOW + "- Please consider using JDK 21 Instead of JDK " + Iris.getJavaVersion());
} }
if (ServerBootSFG.isJRE) { if (ServerBootSFG.isJRE) {
Iris.safeguard(C.YELLOW + "Unsupported Server JDK"); Iris.safeguard(C.YELLOW + "Unsupported Server JDK");
Iris.safeguard(C.YELLOW + "- Please consider using JDK 17 (or 21 for 1.20.6) Instead of JRE " + Iris.getJavaVersion()); Iris.safeguard(C.YELLOW + "- Please consider using JDK 21 Instead of JRE " + Iris.getJavaVersion());
} }
} }
} }

View File

@ -1,93 +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.core.service;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.BlockPos;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.function.Consumer4;
import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.matter.MatterStructurePOI;
import com.volmit.iris.util.plugin.IrisService;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.entity.Dolphin;
import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.generator.structure.StructureType;
import java.util.concurrent.atomic.AtomicReference;
public class DolphinSVC implements IrisService {
@Override
public void onEnable() {
}
@Override
public void onDisable() {
}
@EventHandler
public void on(PlayerInteractEntityEvent event) {
if (!IrisToolbelt.isIrisWorld(event.getPlayer().getWorld())) {
return;
}
Material hand = event.getPlayer().getInventory().getItem(event.getHand()).getType();
if (event.getRightClicked().getType().equals(EntityType.DOLPHIN) && (hand.equals(Material.TROPICAL_FISH) || hand.equals(Material.PUFFERFISH) || hand.equals(Material.COD) || hand.equals(Material.SALMON))) {
Engine e = IrisToolbelt.access(event.getPlayer().getWorld()).getEngine();
searchNearestTreasure(e, event.getPlayer().getLocation().getBlockX() >> 4, event.getPlayer().getLocation().getBlockZ() >> 4, e.getMantle().getRadius() - 1, StructureType.BURIED_TREASURE, (x, y, z, p) -> {
event.setCancelled(true);
Dolphin d = (Dolphin) event.getRightClicked();
INMS.get().setTreasurePos(d, new BlockPos(x, y, z));
d.getWorld().playSound(d, Sound.ENTITY_DOLPHIN_EAT, SoundCategory.NEUTRAL, 1, 1);
});
}
}
@ChunkCoordinates
public void findTreasure(Engine engine, int chunkX, int chunkY, StructureType type, Consumer4<Integer, Integer, Integer, MatterStructurePOI> consumer) {
AtomicReference<MatterStructurePOI> ref = new AtomicReference<>();
engine.getMantle().getMantle().iterateChunk(chunkX, chunkY, MatterStructurePOI.class, ref.get() == null ? (x, y, z, d) -> {
if (d.getType().equals(type.getKey().getKey())) {
ref.set(d);
consumer.accept(x, y, z, d);
}
} : (x, y, z, d) -> {
});
}
@ChunkCoordinates
public void searchNearestTreasure(Engine engine, int chunkX, int chunkY, int radius, StructureType type, Consumer4<Integer, Integer, Integer, MatterStructurePOI> consumer) {
AtomicReference<MatterStructurePOI> ref = new AtomicReference<>();
new Spiraler(radius * 2, radius * 2, (x, z) -> findTreasure(engine, x, z, type, ref.get() == null ? (i, d, g, a) -> {
ref.set(a);
consumer.accept(i, d, g, a);
} : (i, d, g, a) -> {
})).setOffset(chunkX, chunkY).drain();
}
}

View File

@ -26,6 +26,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.plugin.IrisService; import com.volmit.iris.util.plugin.IrisService;
import lombok.Data; import lombok.Data;
import lombok.NonNull;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
@ -46,9 +47,13 @@ public class ExternalDataSVC implements IrisService {
Iris.info("Loading ExternalDataProvider..."); Iris.info("Loading ExternalDataProvider...");
Bukkit.getPluginManager().registerEvents(this, Iris.instance); Bukkit.getPluginManager().registerEvents(this, Iris.instance);
providers.add(new OraxenDataProvider()); providers.add(new NexoDataProvider());
if (Bukkit.getPluginManager().getPlugin("Oraxen") != null) { if (Bukkit.getPluginManager().getPlugin("Nexo") != null) {
Iris.info("Oraxen found, loading OraxenDataProvider..."); Iris.info("Nexo found, loading NexoDataProvider...");
}
providers.add(new MythicCrucibleDataProvider());
if (Bukkit.getPluginManager().getPlugin("MythicCrucible") != null) {
Iris.info("MythicCrucible found, loading MythicCrucibleDataProvider...");
} }
providers.add(new ItemAdderDataProvider()); providers.add(new ItemAdderDataProvider());
if (Bukkit.getPluginManager().getPlugin("ItemAdder") != null) { if (Bukkit.getPluginManager().getPlugin("ItemAdder") != null) {
@ -95,6 +100,18 @@ public class ExternalDataSVC implements IrisService {
} }
} }
public void registerProvider(@NonNull ExternalDataProvider provider) {
String plugin = provider.getPluginId();
if (providers.stream().map(ExternalDataProvider::getPluginId).anyMatch(plugin::equals))
throw new IllegalArgumentException("A provider with the same plugin id already exists.");
providers.add(provider);
if (provider.isReady()) {
activeProviders.add(provider);
provider.init();
}
}
public Optional<BlockData> getBlockData(final Identifier key) { public Optional<BlockData> getBlockData(final Identifier key) {
var pair = parseState(key); var pair = parseState(key);
Identifier mod = pair.getA(); Identifier mod = pair.getA();

View File

@ -63,7 +63,12 @@ public class StudioSVC implements IrisService {
if (!f.exists()) { if (!f.exists()) {
Iris.info("Downloading Default Pack " + pack); Iris.info("Downloading Default Pack " + pack);
downloadSearch(Iris.getSender(), pack, false); if (pack.equals("overworld")) {
String url = "https://github.com/IrisDimensions/overworld/releases/download/" + Iris.OVERWORLD_TAG + "/overworld.zip";
Iris.service(StudioSVC.class).downloadRelease(Iris.getSender(), url, false, false);
} else {
downloadSearch(Iris.getSender(), pack, false);
}
} }
}); });
} }

View File

@ -183,7 +183,7 @@ public class TreeSVC implements IrisService {
} }
@Override @Override
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) { public void setTile(int xx, int yy, int zz, TileData tile) {
} }

View File

@ -1,127 +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.core.service;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.VolmitSender;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.entity.Villager;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.VillagerCareerChangeEvent;
import java.util.List;
public class VillageSVC implements IrisService {
@Override
public void onEnable() {
}
@Override
public void onDisable() {
}
@EventHandler
public void on(VillagerCareerChangeEvent event) {
if (!IrisToolbelt.isIrisWorld(event.getEntity().getWorld())) {
return;
}
IrisDimension dim = IrisToolbelt.access(event.getEntity().getWorld())
.getEngine().getDimension();
if (!dim.isRemoveCartographersDueToCrash()) {
return;
}
if (event.getProfession().equals(Villager.Profession.CARTOGRAPHER)) {
event.setCancelled(true);
Location eventLocation = event.getEntity().getLocation();
int radius = dim.getNotifyPlayersOfCartographerCancelledRadius();
if (radius == -1) {
return;
}
List<Player> playersInWorld = event.getEntity().getWorld().getPlayers();
String message = C.GOLD + IrisSettings.get().getGeneral().cartographerMessage;
Iris.info("Cancelled Cartographer Villager to prevent server crash at " + eventLocation + "!");
if (radius == -2) {
playersInWorld.stream().map(VolmitSender::new).forEach(v -> v.sendMessage(message));
} else {
playersInWorld.forEach(p -> {
if (p.getLocation().distance(eventLocation) < radius) {
new VolmitSender(p).sendMessage(message);
}
});
}
}
}
/*
* Replace or disable villager trade add event to prevent explorer map
*/
/* Removed due to MC breaking stuff again. This event is now called after the cartographer maps are made,
so it can fuck right off.
@EventHandler
public void on(VillagerAcquireTradeEvent event) {
if(!IrisToolbelt.isIrisWorld((event.getEntity().getWorld()))) {
return;
}
// Iris.info("Trade event: type " + event.getRecipe().getResult().getType() + " / meta " + event.getRecipe().getResult().getItemMeta() + " / data " + event.getRecipe().getResult().getData());
if(!event.getRecipe().getResult().getType().equals(Material.FILLED_MAP)) {
return;
}
IrisVillagerOverride override = IrisToolbelt.access(event.getEntity().getWorld()).getEngine()
.getDimension().getPatchCartographers();
if(override.isDisableTrade()) {
event.setCancelled(true);
Iris.debug("Cancelled cartographer trade @ " + event.getEntity().getLocation());
return;
}
if(override.getValidItems() == null) {
event.setCancelled(true);
Iris.debug("Cancelled cartographer trade because no override items are valid @ " + event.getEntity().getLocation());
return;
}
IrisVillagerTrade trade = override.getValidItems().getRandom();
event.setRecipe(trade.convert());
Iris.debug("Overrode cartographer trade with: " + trade + " to prevent allowing cartography map trades");
}
*/
}

View File

@ -35,6 +35,8 @@ 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.S;
import com.volmit.iris.util.scheduling.SR;
import com.volmit.iris.util.scheduling.jobs.Job;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
@ -53,10 +55,13 @@ import org.bukkit.util.Vector;
import java.awt.Color; 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.atomic.AtomicInteger;
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 CRIT_MAGIC = E.getOrDefault(Particle.class, "CRIT_MAGIC", "CRIT");
private static final Particle REDSTONE = E.getOrDefault(Particle.class, "REDSTONE", "DUST"); 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 ItemStack dust; private static ItemStack dust;
private static ItemStack wand; private static ItemStack wand;
@ -71,7 +76,7 @@ public class WandSVC implements IrisService {
* @param p The wand player * @param p The wand player
* @return The new object * @return The new object
*/ */
public static IrisObject createSchematic(Player p) { public static IrisObject createSchematic(Player p, boolean legacy) {
if (!isHoldingWand(p)) { if (!isHoldingWand(p)) {
return null; return null;
} }
@ -80,14 +85,81 @@ public class WandSVC implements IrisService {
Location[] f = getCuboid(p); Location[] f = getCuboid(p);
Cuboid c = new Cuboid(f[0], f[1]); Cuboid c = new Cuboid(f[0], f[1]);
IrisObject s = new IrisObject(c.getSizeX(), c.getSizeY(), c.getSizeZ()); IrisObject s = new IrisObject(c.getSizeX(), c.getSizeY(), c.getSizeZ());
for (Block b : c) {
if (b.getType().equals(Material.AIR)) { var it = c.chunkedIterator();
continue;
int total = c.getSizeX() * c.getSizeY() * c.getSizeZ();
var latch = new CountDownLatch(1);
new Job() {
private int i;
private Chunk chunk;
@Override
public String getName() {
return "Scanning Selection";
} }
BlockVector bv = b.getLocation().subtract(c.getLowerNE().toVector()).toVector().toBlockVector(); @Override
s.setUnsigned(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), b); public void execute() {
} new SR() {
@Override
public void run() {
var time = M.ms() + MS_PER_TICK;
while (time > M.ms()) {
if (!it.hasNext()) {
if (chunk != null) {
chunk.removePluginChunkTicket(Iris.instance);
chunk = null;
}
cancel();
latch.countDown();
return;
}
try {
var b = it.next();
var bChunk = b.getChunk();
if (chunk == null) {
chunk = bChunk;
chunk.addPluginChunkTicket(Iris.instance);
} else if (chunk != bChunk) {
chunk.removePluginChunkTicket(Iris.instance);
chunk = bChunk;
}
if (b.getType().equals(Material.AIR))
continue;
BlockVector bv = b.getLocation().subtract(c.getLowerNE().toVector()).toVector().toBlockVector();
s.setUnsigned(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), b, legacy);
} finally {
i++;
}
}
}
};
try {
latch.await();
} catch (InterruptedException ignored) {}
}
@Override
public void completeWork() {}
@Override
public int getTotalWork() {
return total;
}
@Override
public int getWorkCompleted() {
return i;
}
}.execute(new VolmitSender(p), true, () -> {});
try {
latch.await();
} catch (InterruptedException ignored) {}
return s; return s;
} catch (Throwable e) { } catch (Throwable e) {

View File

@ -12,9 +12,11 @@ import com.volmit.iris.util.reflect.V;
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 it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import org.apache.commons.io.FileUtils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.util.FileUtil;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import java.io.File; import java.io.File;
@ -33,11 +35,15 @@ public class IrisConverter {
FilenameFilter filter = (dir, name) -> name.endsWith(".schem"); FilenameFilter filter = (dir, name) -> name.endsWith(".schem");
File[] fileList = folder.listFiles(filter); File[] fileList = folder.listFiles(filter);
if (fileList == null) {
sender.sendMessage("No schematic files to convert found in " + folder.getAbsolutePath());
return;
}
ExecutorService executorService = Executors.newFixedThreadPool(1); ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.submit(() -> { executorService.submit(() -> {
for (File schem : fileList) { for (File schem : fileList) {
try { try {
PrecisionStopwatch p = new PrecisionStopwatch(); PrecisionStopwatch p = PrecisionStopwatch.start();
boolean largeObject = false; boolean largeObject = false;
NamedTag tag = null; NamedTag tag = null;
try { try {
@ -52,21 +58,17 @@ public class IrisConverter {
int objW = ((ShortTag) compound.get("Width")).getValue(); int objW = ((ShortTag) compound.get("Width")).getValue();
int objH = ((ShortTag) compound.get("Height")).getValue(); int objH = ((ShortTag) compound.get("Height")).getValue();
int objD = ((ShortTag) compound.get("Length")).getValue(); int objD = ((ShortTag) compound.get("Length")).getValue();
int i = -1;
int mv = objW * objH * objD; int mv = objW * objH * objD;
AtomicInteger v = new AtomicInteger(0); AtomicInteger v = new AtomicInteger(0);
AtomicInteger fv = new AtomicInteger(0);
if (mv > 500_000) { if (mv > 500_000) {
largeObject = true; largeObject = true;
Iris.info(C.GRAY + "Converting.. "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob")); Iris.info(C.GRAY + "Converting.. "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
Iris.info(C.GRAY + "- It may take a while"); Iris.info(C.GRAY + "- It may take a while");
if (sender.isPlayer()) { if (sender.isPlayer()) {
J.a(() -> { i = J.ar(() -> {
// while (v.get() != mv) { sender.sendProgress((double) v.get() / mv, "Converting");
// double pr = ((double) v.get() / (double ) mv); }, 0);
// sender.sendProgress(pr, "Converting");
// J.sleep(16);
// }
});
} }
} }
@ -82,165 +84,8 @@ public class IrisConverter {
ByteArrayTag byteArray = (ByteArrayTag) compound.get("BlockData"); ByteArrayTag byteArray = (ByteArrayTag) compound.get("BlockData");
byte[] originalBlockArray = byteArray.getValue(); byte[] originalBlockArray = byteArray.getValue();
int b = 0;
int a = 0;
Map<Integer, Byte> y = new HashMap<>();
Map<Integer, Byte> x = new HashMap<>();
Map<Integer, Byte> z = new HashMap<>();
// Height adjustments
for (int h = 0; h < objH; h++) {
if (b == 0) {
y.put(h, (byte) 0);
}
if (b > 0) {
y.put(h, (byte) 1);
}
a = 0;
b = 0;
for (int d = 0; d < objD; d++) {
for (int w = 0; w < objW; w++) {
BlockData db = blockmap.get((int) originalBlockArray[fv.get()]);
if(db.getAsString().contains("minecraft:air")) {
a++;
} else {
b++;
}
fv.getAndAdd(1);
}
}
}
fv.set(0);
// Width adjustments
for (int w = 0; w < objW; w++) {
if (b == 0) {
x.put(w, (byte) 0);
}
if (b > 0) {
x.put(w, (byte) 1);
}
a = 0;
b = 0;
for (int h = 0; h < objH; h++) {
for (int d = 0; d < objD; d++) {
BlockData db = blockmap.get((int) originalBlockArray[fv.get()]);
if(db.getAsString().contains("minecraft:air")) {
a++;
} else {
b++;
}
fv.getAndAdd(1);
}
}
}
fv.set(0);
// Depth adjustments
for (int d = 0; d < objD; d++) {
if (b == 0) {
z.put(d, (byte) 0);
}
if (b > 0) {
z.put(d, (byte) 1);
}
a = 0;
b = 0;
for (int h = 0; h < objH; h++) {
for (int w = 0; w < objW; w++) {
BlockData db = blockmap.get((int) originalBlockArray[fv.get()]);
if(db.getAsString().contains("minecraft:air")) {
a++;
} else {
b++;
}
fv.getAndAdd(1);
}
}
}
fv.set(0);
int CorrectObjH = getCorrectY(y, objH);
int CorrectObjW = getCorrectX(x, objW);
int CorrectObjD = getCorrectZ(z, objD);
//IrisObject object = new IrisObject(CorrectObjW, CorrectObjH, CorrectObjH);
IrisObject object = new IrisObject(objW, objH, objD); IrisObject object = new IrisObject(objW, objH, objD);
Vector originalVector = new Vector(objW,objH,objD);
int[] yc = null;
int[] xc = null;
int[] zc = null;
int fo = 0;
int so = 0;
int o = 0;
int c = 0;
for (Integer i : y.keySet()) {
if (y.get(i) == 0) {
o++;
}
if (y.get(i) == 1) {
c++;
if (c == 1) {
fo = o;
}
o = 0;
}
}
so = o;
yc = new int[]{fo, so};
fo = 0;
so = 0;
o = 0;
c = 0;
for (Integer i : x.keySet()) {
if (x.get(i) == 0) {
o++;
}
if (x.get(i) == 1) {
c++;
if (c == 1) {
fo = o;
}
o = 0;
}
}
so = o;
xc = new int[]{fo, so};
fo = 0;
so = 0;
o = 0;
c = 0;
for (Integer i : z.keySet()) {
if (z.get(i) == 0) {
o++;
}
if (z.get(i) == 1) {
c++;
if (c == 1) {
fo = o;
}
o = 0;
}
}
so = o;
zc = new int[]{fo, so};
int h1, h2, w1, w2, v1 = 0, volume = objW * objH * objD;
Map<Integer, Integer> blockLocationMap = new LinkedHashMap<>();
boolean hasAir = false;
int pos = 0;
for (int i : originalBlockArray) {
blockLocationMap.put(pos, i);
pos++;
}
for (int h = 0; h < objH; h++) { for (int h = 0; h < objH; h++) {
for (int d = 0; d < objD; d++) { for (int d = 0; d < objD; d++) {
for (int w = 0; w < objW; w++) { for (int w = 0; w < objW; w++) {
@ -252,9 +97,9 @@ public class IrisConverter {
} }
} }
} }
if (i != -1) J.car(i);
try { try {
object.shrinkwrap();
object.write(new File(folder, schem.getName().replace(".schem", ".iob"))); object.write(new File(folder, schem.getName().replace(".schem", ".iob")));
} catch (IOException e) { } catch (IOException e) {
Iris.info(C.RED + "Failed to save: " + schem.getName()); Iris.info(C.RED + "Failed to save: " + schem.getName());
@ -272,7 +117,7 @@ public class IrisConverter {
} else { } else {
Iris.info(C.GRAY + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob")); Iris.info(C.GRAY + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
} }
// schem.delete(); FileUtils.delete(schem);
} }
} catch (Exception e) { } catch (Exception e) {
Iris.info(C.RED + "Failed to convert: " + schem.getName()); Iris.info(C.RED + "Failed to convert: " + schem.getName());
@ -283,112 +128,10 @@ public class IrisConverter {
Iris.reportError(e); Iris.reportError(e);
} }
} }
sender.sendMessage(C.GRAY + "converted: " + fileList.length);
}); });
} }
public static boolean isNewPointFurther(int[] originalPoint, int[] oldPoint, int[] newPoint) {
int oX = oldPoint[1];
int oY = oldPoint[2];
int oZ = oldPoint[3];
int nX = newPoint[1];
int nY = newPoint[2];
int nZ = newPoint[3];
int orX = originalPoint[1];
int orY = originalPoint[2];
int orZ = originalPoint[3];
double oldDistance = Math.sqrt(Math.pow(oX - orX, 2) + Math.pow(oY - orY, 2) + Math.pow(oZ - orZ, 2));
double newDistance = Math.sqrt(Math.pow(nX - orX, 2) + Math.pow(nY - orY, 2) + Math.pow(nZ - orZ, 2));
if (newDistance > oldDistance) {
return true;
}
return false;
}
public static int[] getCoordinates(int pos, int obX, int obY, int obZ) {
int z = 0;
int[] coords = new int[4];
for (int h = 0; h < obY; h++) {
for (int d = 0; d < obZ; d++) {
for (int w = 0; w < obX; w++) {
if (z == pos) {
coords[1] = w;
coords[2] = h;
coords[3] = d;
return coords;
}
z++;
}
}
}
return null;
}
public static int getCorrectY(Map<Integer, Byte> y, int H) {
int fo = 0;
int so = 0;
int o = 0;
int c = 0;
for (Integer i : y.keySet()) {
if (y.get(i) == 0) {
o++;
}
if (y.get(i) == 1) {
c++;
if(c == 1){
fo = o;
}
o = 0;
}
}
so = o;
return H = H - (fo + so);
}
public static int getCorrectX(Map<Integer, Byte> x, int W) {
int fo = 0;
int so = 0;
int o = 0;
int c = 0;
for (Integer i : x.keySet()) {
if (x.get(i) == 0) {
o++;
}
if (x.get(i) == 1) {
c++;
if(c == 1){
fo = o;
}
o = 0;
}
}
so = o;
return W = W - (fo + so);
}
public static int getCorrectZ(Map<Integer, Byte> z, int D) {
int fo = 0;
int so = 0;
int o = 0;
int c = 0;
for (Integer i : z.keySet()) {
if (z.get(i) == 0) {
o++;
}
if (z.get(i) == 1) {
c++;
if(c == 1){
fo = o;
}
o = 0;
}
}
so = o;
return D = D - (fo + so);
}
} }

View File

@ -24,10 +24,8 @@ import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.ServerConfigurator;
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.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.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.core.safeguard.UtilsSFG;
import com.volmit.iris.util.exceptions.IrisException; import com.volmit.iris.util.exceptions.IrisException;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
@ -46,7 +44,6 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier; import java.util.function.Supplier;
import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode;
/** /**
* Makes it a lot easier to setup an engine, world, studio or whatever * Makes it a lot easier to setup an engine, world, studio or whatever
@ -126,14 +123,11 @@ public class IrisCreator {
if (sender == null) if (sender == null)
sender = Iris.getSender(); sender = Iris.getSender();
if (!studio()) { if (!studio() || benchmark) {
Iris.service(StudioSVC.class).installIntoWorld(sender, d.getLoadKey(), new File(Bukkit.getWorldContainer(), name()));
}
if (benchmark) {
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 = null; 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<>();

View File

@ -9,8 +9,6 @@ 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.math.Position2;
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;
@ -27,44 +25,44 @@ 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;
import java.util.concurrent.*;
public class IrisPackBenchmarking { public class IrisPackBenchmarking {
@Getter @Getter
public static IrisPackBenchmarking instance; public static IrisPackBenchmarking instance;
public static boolean benchmarkInProgress = false; public static boolean benchmarkInProgress = false;
private IrisDimension IrisDimension; private final PrecisionStopwatch stopwatch = new PrecisionStopwatch();
private int radius; private final IrisDimension dimension;
private boolean finished = false; private final int radius;
PrecisionStopwatch stopwatch; private final boolean gui;
public IrisPackBenchmarking(IrisDimension dimension, int r) { public IrisPackBenchmarking(IrisDimension dimension, int radius, boolean gui) {
instance = this; instance = this;
this.IrisDimension = dimension; this.dimension = dimension;
this.radius = r; this.radius = radius;
this.gui = gui;
runBenchmark(); runBenchmark();
} }
private void runBenchmark() { private void runBenchmark() {
this.stopwatch = new PrecisionStopwatch(); Thread.ofVirtual()
ExecutorService service = Executors.newSingleThreadExecutor(); .name("PackBenchmarking")
service.submit(() -> { .start(() -> {
Iris.info("Setting up benchmark environment "); Iris.info("Setting up benchmark environment ");
benchmarkInProgress = true; benchmarkInProgress = true;
File file = new File("benchmark"); File file = new File("benchmark");
if (file.exists()) { if (file.exists()) {
deleteDirectory(file.toPath()); deleteDirectory(file.toPath());
} }
createBenchmark(); createBenchmark();
while (!IrisToolbelt.isIrisWorld(Bukkit.getWorld("benchmark"))) { while (!IrisToolbelt.isIrisWorld(Bukkit.getWorld("benchmark"))) {
J.sleep(1000); J.sleep(1000);
Iris.debug("Iris PackBenchmark: Waiting..."); Iris.debug("Iris PackBenchmark: Waiting...");
} }
Iris.info("Starting Benchmark!"); Iris.info("Starting Benchmark!");
stopwatch.begin(); stopwatch.begin();
startBenchmark(); startBenchmark();
}); });
} }
@ -88,14 +86,14 @@ public class IrisPackBenchmarking {
File profilers = new File("plugins" + File.separator + "Iris" + File.separator + "packbenchmarks"); File profilers = new File("plugins" + File.separator + "Iris" + File.separator + "packbenchmarks");
profilers.mkdir(); profilers.mkdir();
File results = new File("plugins " + File.separator + "Iris", IrisDimension.getName() + LocalDateTime.now(Clock.systemDefaultZone()) + ".txt"); File results = new File(profilers, dimension.getName() + " " + LocalDateTime.now(Clock.systemDefaultZone()).toString().replace(':', '-') + ".txt");
results.createNewFile(); results.getParentFile().mkdirs();
KMap<String, Double> metrics = engine.getMetrics().pull(); KMap<String, Double> metrics = engine.getMetrics().pull();
try (FileWriter writer = new FileWriter(results)) { try (FileWriter writer = new FileWriter(results)) {
writer.write("-----------------\n"); writer.write("-----------------\n");
writer.write("Results:\n"); writer.write("Results:\n");
writer.write("Dimension: " + IrisDimension.getName() + "\n"); writer.write("Dimension: " + dimension.getName() + "\n");
writer.write("- Date of Benchmark: " + LocalDateTime.now(Clock.systemDefaultZone()) + "\n"); writer.write("- Date of Benchmark: " + LocalDateTime.now(Clock.systemDefaultZone()) + "\n");
writer.write("\n"); writer.write("\n");
writer.write("Metrics"); writer.write("Metrics");
for (String m : metrics.k()) { for (String m : metrics.k()) {
@ -103,7 +101,7 @@ public class IrisPackBenchmarking {
writer.write("- " + m + ": " + i); writer.write("- " + m + ": " + i);
} }
writer.write("- " + metrics); writer.write("- " + metrics);
writer.write("Benchmark: " + LocalDateTime.now(Clock.systemDefaultZone()) + "\n"); writer.write("Benchmark: " + LocalDateTime.now(Clock.systemDefaultZone()) + "\n");
writer.write("- Total time: " + time + "\n"); writer.write("- Total time: " + time + "\n");
writer.write("- Average CPS: " + calculateAverage(cps) + "\n"); writer.write("- Average CPS: " + calculateAverage(cps) + "\n");
writer.write(" - Median CPS: " + calculateMedian(cps) + "\n"); writer.write(" - Median CPS: " + calculateMedian(cps) + "\n");
@ -116,17 +114,24 @@ public class IrisPackBenchmarking {
e.printStackTrace(); e.printStackTrace();
} }
Bukkit.getServer().unloadWorld("benchmark", true); J.s(() -> {
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) {
Iris.error("Something has gone wrong!"); Iris.error("Something has gone wrong!");
e.printStackTrace(); e.printStackTrace();
} }
} }
private void createBenchmark(){
private void createBenchmark() {
try { try {
IrisToolbelt.createWorld() IrisToolbelt.createWorld()
.dimension(IrisDimension.getName()) .dimension(dimension.getLoadKey())
.name("benchmark") .name("benchmark")
.seed(1337) .seed(1337)
.studio(false) .studio(false)
@ -137,17 +142,14 @@ public class IrisPackBenchmarking {
} }
} }
private void startBenchmark(){ private void startBenchmark() {
int x = 0; IrisToolbelt.pregenerate(PregenTask
int z = 0; .builder()
IrisToolbelt.pregenerate(PregenTask .gui(gui)
.builder() .width(radius)
.gui(false) .height(radius)
.center(new Position2(x, z)) .build(), Bukkit.getWorld("benchmark")
.width(5) );
.height(5)
.build(), Bukkit.getWorld("benchmark")
);
} }
private double calculateAverage(KList<Integer> list) { private double calculateAverage(KList<Integer> list) {
@ -179,7 +181,7 @@ public class IrisPackBenchmarking {
private boolean deleteDirectory(Path dir) { private boolean deleteDirectory(Path dir) {
try { try {
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { Files.walkFileTree(dir, new SimpleFileVisitor<>() {
@Override @Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file); Files.delete(file);

View File

@ -30,9 +30,10 @@ import org.bukkit.util.Vector;
import java.awt.*; import java.awt.*;
public class WandSelection { public class WandSelection {
private static final Particle REDSTONE = E.getOrDefault(Particle.class, "REDSTONE", "DUST"); 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;
public WandSelection(Cuboid c, Player p) { public WandSelection(Cuboid c, Player p) {
this.c = c; this.c = c;
@ -40,77 +41,58 @@ public class WandSelection {
} }
public void draw() { public void draw() {
double accuracy; Location playerLoc = p.getLocation();
double dist; double maxDistanceSquared = 256 * 256;
int particleCount = 0;
for (double i = c.getLowerX() - 1; i < c.getUpperX() + 1; i += 0.25) { // cube!
for (double j = c.getLowerY() - 1; j < c.getUpperY() + 1; j += 0.25) { Location[][] edges = {
for (double k = c.getLowerZ() - 1; k < c.getUpperZ() + 1; k += 0.25) { {c.getLowerNE(), new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getLowerZ())},
boolean ii = i == c.getLowerX() || i == c.getUpperX(); {c.getLowerNE(), new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getLowerZ())},
boolean jj = j == c.getLowerY() || j == c.getUpperY(); {c.getLowerNE(), new Location(c.getWorld(), c.getLowerX(), c.getLowerY(), c.getUpperZ() + 1)},
boolean kk = k == c.getLowerZ() || k == c.getUpperZ(); {new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getLowerZ()), new Location(c.getWorld(), c.getUpperX() + 1, c.getUpperY() + 1, c.getLowerZ())},
{new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getLowerZ()), new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getUpperZ() + 1)},
{new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getLowerZ()), new Location(c.getWorld(), c.getUpperX() + 1, c.getUpperY() + 1, c.getLowerZ())},
{new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getLowerZ()), new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getUpperZ() + 1)},
{new Location(c.getWorld(), c.getLowerX(), c.getLowerY(), c.getUpperZ() + 1), new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getUpperZ() + 1)},
{new Location(c.getWorld(), c.getLowerX(), c.getLowerY(), c.getUpperZ() + 1), new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getUpperZ() + 1)},
{new Location(c.getWorld(), c.getUpperX() + 1, c.getUpperY() + 1, c.getLowerZ()), new Location(c.getWorld(), c.getUpperX() + 1, c.getUpperY() + 1, c.getUpperZ() + 1)},
{new Location(c.getWorld(), c.getLowerX(), c.getUpperY() + 1, c.getUpperZ() + 1), new Location(c.getWorld(), c.getUpperX() + 1, c.getUpperY() + 1, c.getUpperZ() + 1)},
{new Location(c.getWorld(), c.getUpperX() + 1, c.getLowerY(), c.getUpperZ() + 1), new Location(c.getWorld(), c.getUpperX() + 1, c.getUpperY() + 1, c.getUpperZ() + 1)}
};
if ((ii && jj) || (ii && kk) || (kk && jj)) { for (Location[] edge : edges) {
Vector push = new Vector(0, 0, 0); Vector direction = edge[1].toVector().subtract(edge[0].toVector());
double length = direction.length();
direction.normalize();
if (i == c.getLowerX()) { for (double d = 0; d <= length; d += STEP) {
push.add(new Vector(-0.55, 0, 0)); Location particleLoc = edge[0].clone().add(direction.clone().multiply(d));
}
if (j == c.getLowerY()) { if (playerLoc.distanceSquared(particleLoc) > maxDistanceSquared) {
push.add(new Vector(0, -0.55, 0)); continue;
}
if (k == c.getLowerZ()) {
push.add(new Vector(0, 0, -0.55));
}
if (i == c.getUpperX()) {
push.add(new Vector(0.55, 0, 0));
}
if (j == c.getUpperY()) {
push.add(new Vector(0, 0.55, 0));
}
if (k == c.getUpperZ()) {
push.add(new Vector(0, 0, 0.55));
}
Location a = new Location(c.getWorld(), i, j, k).add(0.5, 0.5, 0.5).add(push);
accuracy = M.lerpInverse(0, 64 * 64, p.getLocation().distanceSquared(a));
dist = M.lerp(0.125, 3.5, accuracy);
if (M.r(M.min(dist * 5, 0.9D) * 0.995)) {
continue;
}
if (ii && jj) {
a.add(0, 0, RNG.r.d(-0.3, 0.3));
}
if (kk && jj) {
a.add(RNG.r.d(-0.3, 0.3), 0, 0);
}
if (ii && kk) {
a.add(0, RNG.r.d(-0.3, 0.3), 0);
}
if (p.getLocation().distanceSquared(a) < 256 * 256) {
Color color = Color.getHSBColor((float) (0.5f + (Math.sin((i + j + k + (p.getTicksLived() / 2f)) / (20f)) / 2)), 1, 1);
int r = color.getRed();
int g = color.getGreen();
int b = color.getBlue();
p.spawnParticle(REDSTONE, a.getX(), a.getY(), a.getZ(),
1, 0, 0, 0, 0,
new Particle.DustOptions(org.bukkit.Color.fromRGB(r, g, b),
(float) dist * 3f));
}
}
} }
spawnParticle(particleLoc, playerLoc);
particleCount++;
} }
} }
} }
private void spawnParticle(Location particleLoc, Location playerLoc) {
double accuracy = M.lerpInverse(0, 64 * 64, playerLoc.distanceSquared(particleLoc));
double dist = M.lerp(0.125, 3.5, accuracy);
if (M.r(Math.min(dist * 5, 0.9D) * 0.995)) {
return;
}
float hue = (float) (0.5f + (Math.sin((particleLoc.getX() + particleLoc.getY() + particleLoc.getZ() + (p.getTicksLived() / 2f)) / 20f) / 2));
Color color = Color.getHSBColor(hue, 1, 1);
p.spawnParticle(REDSTONE, particleLoc,
0, 0, 0, 0, 1,
new Particle.DustOptions(org.bukkit.Color.fromRGB(color.getRed(), color.getGreen(), color.getBlue()),
(float) dist * 3f));
}
} }

View File

@ -29,6 +29,7 @@ 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.IrisContext; import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.DataProvider; import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.interpolation.IrisInterpolation.NoiseKey;
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.noise.CNG; import com.volmit.iris.util.noise.CNG;
@ -292,9 +293,11 @@ public class IrisComplex implements DataProvider {
return 0; return 0;
} }
KMap<NoiseKey, IrisBiome> cache = new KMap<>();
double hi = interpolator.interpolate(x, z, (xx, zz) -> { double hi = interpolator.interpolate(x, z, (xx, zz) -> {
try { try {
IrisBiome bx = baseBiomeStream.get(xx, zz); IrisBiome bx = baseBiomeStream.get(xx, zz);
cache.put(new NoiseKey(xx, zz), bx);
double b = 0; double b = 0;
for (IrisGenerator gen : generators) { for (IrisGenerator gen : generators) {
@ -313,7 +316,11 @@ public class IrisComplex implements DataProvider {
double lo = interpolator.interpolate(x, z, (xx, zz) -> { double lo = interpolator.interpolate(x, z, (xx, zz) -> {
try { try {
IrisBiome bx = baseBiomeStream.get(xx, zz); IrisBiome bx = cache.get(new NoiseKey(xx, zz));
if (bx == null) {
bx = baseBiomeStream.get(xx, zz);
cache.put(new NoiseKey(xx, zz), bx);
}
double b = 0; double b = 0;
for (IrisGenerator gen : generators) { for (IrisGenerator gen : generators) {

View File

@ -76,6 +76,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
private final ChronoLatch ecl; private final ChronoLatch ecl;
private final ChronoLatch cln; private final ChronoLatch cln;
private final ChronoLatch chunkUpdater; private final ChronoLatch chunkUpdater;
private final ChronoLatch chunkDiscovery;
private double energy = 25; private double energy = 25;
private int entityCount = 0; private int entityCount = 0;
private long charge = 0; private long charge = 0;
@ -92,12 +93,14 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
clw = null; clw = null;
looper = null; looper = null;
chunkUpdater = null; chunkUpdater = null;
chunkDiscovery = null;
id = -1; id = -1;
} }
public IrisWorldManager(Engine engine) { public IrisWorldManager(Engine engine) {
super(engine); super(engine);
chunkUpdater = new ChronoLatch(3000); chunkUpdater = new ChronoLatch(3000);
chunkDiscovery = new ChronoLatch(5000);
cln = new ChronoLatch(60000); cln = new ChronoLatch(60000);
cl = new ChronoLatch(3000); cl = new ChronoLatch(3000);
ecl = new ChronoLatch(250); ecl = new ChronoLatch(250);
@ -128,6 +131,10 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
updateChunks(); updateChunks();
} }
if (chunkDiscovery.flip()) {
discoverChunks();
}
if (getDimension().isInfiniteEnergy()) { if (getDimension().isInfiniteEnergy()) {
energy += 1000; energy += 1000;
@ -174,6 +181,19 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
looper.start(); looper.start();
} }
private void discoverChunks() {
var mantle = getEngine().getMantle().getMantle();
for (Player i : getEngine().getWorld().realWorld().getPlayers()) {
int r = 1;
for (int x = -r; x <= r; x++) {
for (int z = -r; z <= r; z++) {
mantle.getChunk(i.getLocation().getChunk()).flag(MantleFlag.DISCOVERED, true);
}
}
}
}
private void updateChunks() { private void updateChunks() {
for (Player i : getEngine().getWorld().realWorld().getPlayers()) { for (Player i : getEngine().getWorld().realWorld().getPlayers()) {
int r = 1; int r = 1;
@ -439,7 +459,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
IrisEngineData ed = getEngine().getEngineData(); IrisEngineData ed = getEngine().getEngineData();
IrisEngineSpawnerCooldown cd = null; IrisEngineSpawnerCooldown cd = null;
for (IrisEngineSpawnerCooldown j : ed.getSpawnerCooldowns()) { for (IrisEngineSpawnerCooldown j : ed.getSpawnerCooldowns().copy()) {
if (j.getSpawner().equals(i.getLoadKey())) { if (j.getSpawner().equals(i.getLoadKey())) {
cd = j; cd = j;
} }

View File

@ -43,15 +43,7 @@ public class IrisCeilingDecorator extends IrisEngineDecorator {
IrisDecorator decorator = getDecorator(biome, realX, realZ); IrisDecorator decorator = getDecorator(biome, realX, realZ);
if (decorator != null) { if (decorator != null) {
if (!decorator.isStacking()) { if (!decorator.isStacking()) {
if (height >= 0 || height < getEngine().getHeight()) { data.set(x, height, z, fixFaces(decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()), realX, height, realZ));
if (null != decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())) {
data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
height--;
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData()));
} else {
data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
}
}
} else { } else {
int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData()); int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData());
if (decorator.isScaleStack()) { if (decorator.isScaleStack()) {

View File

@ -44,15 +44,7 @@ public class IrisSeaFloorDecorator extends IrisEngineDecorator {
return; return;
} }
if (height >= 0 || height < getEngine().getHeight()) { if (height >= 0 || height < getEngine().getHeight()) {
if (null != decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())) { data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
if (height == getDimension().getFluidHeight() - 1) {
data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
height++;
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData()));
}
} else {
data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
}
} }
} else { } else {
int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData()); int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData());

View File

@ -40,13 +40,7 @@ public class IrisSeaSurfaceDecorator extends IrisEngineDecorator {
if (decorator != null) { if (decorator != null) {
if (!decorator.isStacking()) { if (!decorator.isStacking()) {
if (height >= 0 || height < getEngine().getHeight()) { if (height >= 0 || height < getEngine().getHeight()) {
if (null != decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())) { data.set(x, height + 1, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
height++;
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData()));
} else {
data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
}
} }
} else { } else {
int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData()); int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData());

View File

@ -51,13 +51,7 @@ public class IrisShoreLineDecorator extends IrisEngineDecorator {
} }
if (!decorator.isStacking()) { if (!decorator.isStacking()) {
if (null != decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())) { data.set(x, height + 1, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
height++;
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData()));
} else {
data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
}
} else { } else {
int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData()); int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData());
if (decorator.isScaleStack()) { if (decorator.isScaleStack()) {

View File

@ -20,6 +20,7 @@ package com.volmit.iris.engine.framework;
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.events.IrisLootEvent;
import com.volmit.iris.core.gui.components.RenderType; import com.volmit.iris.core.gui.components.RenderType;
import com.volmit.iris.core.gui.components.Renderer; import com.volmit.iris.core.gui.components.Renderer;
import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.link.Identifier;
@ -27,6 +28,7 @@ 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.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.pregenerator.ChunkUpdater;
import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.IrisComplex; import com.volmit.iris.engine.IrisComplex;
import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.data.cache.Cache;
@ -57,15 +59,13 @@ import com.volmit.iris.util.matter.TileWrapper;
import com.volmit.iris.util.matter.slices.container.JigsawPieceContainer; import com.volmit.iris.util.matter.slices.container.JigsawPieceContainer;
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 com.volmit.iris.util.reflect.W;
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.PrecisionStopwatch; import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.stream.ProceduralStream; import com.volmit.iris.util.stream.ProceduralStream;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit; import org.bukkit.*;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
@ -76,10 +76,11 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.awt.*; 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.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;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
@ -273,33 +274,43 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
for (int z = -1; z <= 1; z++) { for (int z = -1; z <= 1; z++) {
if (c.getWorld().isChunkLoaded(c.getX() + x, c.getZ() + z)) if (c.getWorld().isChunkLoaded(c.getX() + x, c.getZ() + z))
continue; continue;
Iris.debug("Chunk %s, %s [%s, %s] is not loaded".formatted(c.getX() + x, c.getZ() + z, x, z)); var msg = "Chunk %s, %s [%s, %s] is not loaded".formatted(c.getX() + x, c.getZ() + z, x, z);
if (W.getStack().getCallerClass().equals(ChunkUpdater.class)) Iris.warn(msg);
else Iris.debug(msg);
return; return;
} }
} }
if (!getMantle().getMantle().isLoaded(c)) { var mantle = getMantle().getMantle();
Iris.debug("Mantle Chunk " + c.getX() + c.getX() + " is not loaded"); if (!mantle.isLoaded(c)) {
var msg = "Mantle Chunk " + c.getX() + c.getX() + " is not loaded";
if (W.getStack().getCallerClass().equals(ChunkUpdater.class)) Iris.warn(msg);
else Iris.debug(msg);
return; return;
} }
getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.TILE, () -> J.s(() -> { var chunk = mantle.getChunk(c);
getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, tile) -> { if (chunk.isFlagged(MantleFlag.ETCHED)) return;
chunk.flag(MantleFlag.ETCHED, true);
Semaphore semaphore = new Semaphore(3);
chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> J.s(() -> {
mantle.iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> {
int betterY = y + getWorld().minHeight(); int betterY = y + getWorld().minHeight();
if (!TileData.setTileState(c.getBlock(x, betterY, z), tile.getData())) if (!TileData.setTileState(c.getBlock(x, betterY, z), v.getData()))
Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), tile.getData().getTileId()); Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), v.getData().getMaterial().name());
}); });
})); })));
getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.CUSTOM, () -> J.s(() -> { chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> J.s(() -> {
getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> { mantle.iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> {
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v); Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
}); });
})); })));
getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.UPDATE, () -> J.s(() -> { chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> J.s(() -> {
PrecisionStopwatch p = PrecisionStopwatch.start(); PrecisionStopwatch p = PrecisionStopwatch.start();
KMap<Long, Integer> updates = new KMap<>(); KMap<Long, Integer> updates = new KMap<>();
RNG r = new RNG(Cache.key(c.getX(), c.getZ())); RNG r = new RNG(Cache.key(c.getX(), c.getZ()));
getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), MatterCavern.class, (x, yf, z, v) -> { mantle.iterateChunk(c.getX(), c.getZ(), MatterCavern.class, (x, yf, z, v) -> {
int y = yf + getWorld().minHeight(); int y = yf + getWorld().minHeight();
if (!B.isFluid(c.getBlock(x & 15, y, z & 15).getBlockData())) { if (!B.isFluid(c.getBlock(x & 15, y, z & 15).getBlockData())) {
return; return;
@ -329,7 +340,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
}); });
updates.forEach((k, v) -> update(Cache.keyX(k), v, Cache.keyZ(k), c, r)); updates.forEach((k, v) -> update(Cache.keyX(k), v, Cache.keyZ(k), c, r));
getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), MatterUpdate.class, (x, yf, z, v) -> { mantle.iterateChunk(c.getX(), c.getZ(), MatterUpdate.class, (x, yf, z, v) -> {
int y = yf + getWorld().minHeight(); int y = yf + getWorld().minHeight();
if (v != null && v.isUpdate()) { if (v != null && v.isUpdate()) {
int vx = x & 15; int vx = x & 15;
@ -340,9 +351,25 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
} }
} }
}); });
getMantle().getMantle().deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class); mantle.deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class);
getMetrics().getUpdates().put(p.getMilliseconds()); getMetrics().getUpdates().put(p.getMilliseconds());
}, RNG.r.i(0, 20))); }, RNG.r.i(0, 20))));
try {
semaphore.acquire(3);
} catch (InterruptedException ignored) {}
}
private static Runnable run(Semaphore semaphore, Runnable runnable) {
return () -> {
if (!semaphore.tryAcquire())
return;
try {
runnable.run();
} finally {
semaphore.release();
}
};
} }
@BlockCoordinates @BlockCoordinates
@ -388,7 +415,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
if (tables.isEmpty()) if (tables.isEmpty())
return; return;
InventoryHolder m = (InventoryHolder) block.getState(); InventoryHolder m = (InventoryHolder) block.getState();
addItems(false, m.getInventory(), rx, tables, slot, x, y, z, 15); addItems(false, m.getInventory(), rx, tables, slot, c.getWorld(), x, y, z, 15);
} catch (Throwable e) { } catch (Throwable e) {
Iris.reportError(e); Iris.reportError(e);
@ -441,7 +468,10 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
} }
@Override @Override
default void injectTables(KList<IrisLootTable> list, IrisLootReference r) { default void injectTables(KList<IrisLootTable> list, IrisLootReference r, boolean fallback) {
if (r.getMode().equals(IrisLootMode.FALLBACK) && !fallback)
return;
if (r.getMode().equals(IrisLootMode.CLEAR) || r.getMode().equals(IrisLootMode.REPLACE)) { if (r.getMode().equals(IrisLootMode.CLEAR) || r.getMode().equals(IrisLootMode.REPLACE)) {
list.clear(); list.clear();
} }
@ -476,10 +506,11 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
IrisBiome biomeUnder = ry < he ? getComplex().getCaveBiomeStream().get(rx, rz) : biomeSurface; IrisBiome biomeUnder = ry < he ? getComplex().getCaveBiomeStream().get(rx, rz) : biomeSurface;
double multiplier = 1D * getDimension().getLoot().getMultiplier() * region.getLoot().getMultiplier() * biomeSurface.getLoot().getMultiplier() * biomeUnder.getLoot().getMultiplier(); double multiplier = 1D * getDimension().getLoot().getMultiplier() * region.getLoot().getMultiplier() * biomeSurface.getLoot().getMultiplier() * biomeUnder.getLoot().getMultiplier();
injectTables(tables, getDimension().getLoot()); boolean fallback = tables.isEmpty();
injectTables(tables, region.getLoot()); injectTables(tables, getDimension().getLoot(), fallback);
injectTables(tables, biomeSurface.getLoot()); injectTables(tables, region.getLoot(), fallback);
injectTables(tables, biomeUnder.getLoot()); injectTables(tables, biomeSurface.getLoot(), fallback);
injectTables(tables, biomeUnder.getLoot(), fallback);
if (tables.isNotEmpty()) { if (tables.isNotEmpty()) {
int target = (int) Math.round(tables.size() * multiplier); int target = (int) Math.round(tables.size() * multiplier);
@ -497,16 +528,16 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
} }
@Override @Override
default void addItems(boolean debug, Inventory inv, RNG rng, KList<IrisLootTable> tables, InventorySlotType slot, int x, int y, int z, int mgf) { default void addItems(boolean debug, Inventory inv, RNG rng, KList<IrisLootTable> tables, InventorySlotType slot, World world, int x, int y, int z, int mgf) {
KList<ItemStack> items = new KList<>(); KList<ItemStack> items = new KList<>();
int b = 4;
for (IrisLootTable i : tables) { for (IrisLootTable i : tables) {
if (i == null) if (i == null)
continue; continue;
b++; items.addAll(i.getLoot(debug, rng, slot, world, x, y, z));
items.addAll(i.getLoot(debug, rng, slot, x, y, z));
} }
if (IrisLootEvent.callLootEvent(items, inv, world, x, y, z))
return;
if (PaperLib.isPaper() && getWorld().hasRealWorld()) { if (PaperLib.isPaper() && getWorld().hasRealWorld()) {
PaperLib.getChunkAtAsync(getWorld().realWorld(), x >> 4, z >> 4).thenAccept((c) -> { PaperLib.getChunkAtAsync(getWorld().realWorld(), x >> 4, z >> 4).thenAccept((c) -> {
@ -840,7 +871,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
default void gotoJigsaw(IrisJigsawStructure s, Player player, boolean teleport) { default void gotoJigsaw(IrisJigsawStructure s, Player player, boolean teleport) {
if (s.getLoadKey().equals(getDimension().getStronghold())) { if (s.getLoadKey().equals(getDimension().getStronghold())) {
KList<Position2> p = getDimension().getStrongholds(getSeedManager().getSpawn()); KList<Position2> p = getDimension().getStrongholds(getSeedManager().getMantle());
if (p.isEmpty()) { if (p.isEmpty()) {
player.sendMessage(C.GOLD + "No strongholds in world."); player.sendMessage(C.GOLD + "No strongholds in world.");

View File

@ -110,7 +110,7 @@ public abstract class EngineAssignedWorldManager extends EngineAssignedComponent
return; return;
} }
KList<Position2> positions = getEngine().getDimension().getStrongholds(getEngine().getSeedManager().getSpawn()); KList<Position2> positions = getEngine().getDimension().getStrongholds(getEngine().getSeedManager().getMantle());
if (positions.isEmpty()) { if (positions.isEmpty()) {
return; return;
} }

View File

@ -1,32 +0,0 @@
package com.volmit.iris.engine.framework;
import com.volmit.iris.engine.object.InventorySlotType;
import com.volmit.iris.engine.object.IrisLootTable;
import com.volmit.iris.util.collection.KList;
import lombok.Getter;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
@Getter
public class IrisLootEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private final Engine engine;
private final Block block;
private final InventorySlotType slot;
private final KList<IrisLootTable> tables;
public IrisLootEvent(Engine engine, Block block, InventorySlotType slot, KList<IrisLootTable> tables) {
this.engine = engine;
this.block = block;
this.slot = slot;
this.tables = tables;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@ -0,0 +1,10 @@
package com.volmit.iris.engine.framework;
import com.volmit.iris.core.loader.IrisData;
import java.util.function.Function;
public interface ListFunction<R> extends Function<IrisData, R> {
String key();
String fancyName();
}

View File

@ -23,15 +23,16 @@ import com.volmit.iris.engine.object.IrisLootReference;
import com.volmit.iris.engine.object.IrisLootTable; import com.volmit.iris.engine.object.IrisLootTable;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
public interface LootProvider { public interface LootProvider {
void scramble(Inventory inventory, RNG rng); void scramble(Inventory inventory, RNG rng);
void injectTables(KList<IrisLootTable> list, IrisLootReference r); void injectTables(KList<IrisLootTable> list, IrisLootReference r, boolean fallback);
KList<IrisLootTable> getLootTables(RNG rng, Block b); KList<IrisLootTable> getLootTables(RNG rng, Block b);
void addItems(boolean debug, Inventory inv, RNG rng, KList<IrisLootTable> tables, InventorySlotType slot, int x, int y, int z, int mgf); void addItems(boolean debug, Inventory inv, RNG rng, KList<IrisLootTable> tables, InventorySlotType slot, World world, int x, int y, int z, int mgf);
} }

View File

@ -0,0 +1,121 @@
package com.volmit.iris.engine.framework;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.engine.object.IrisJigsawStructure;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import org.apache.commons.lang3.function.TriFunction;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
@FunctionalInterface
public interface ResultLocator<T> {
static void cancelSearch() {
if (LocatorCanceller.cancel != null) {
LocatorCanceller.cancel.run();
LocatorCanceller.cancel = null;
}
}
static ResultLocator<IrisJigsawStructure> locateStructure(Collection<String> keys) {
return (e, pos) -> {
var structure = e.getStructureAt(pos.getX(), pos.getZ());
return structure != null && keys.contains(structure.getLoadKey()) ? structure : null;
};
}
static ResultLocator<IrisObject> locateObject(Collection<String> keys) {
return (e, pos) -> {
Set<String> objects = e.getObjectsAt(pos.getX(), pos.getZ());
for (String object : objects) {
if (!keys.contains(object)) continue;
return e.getData().getObjectLoader().load(object);
}
return null;
};
}
T find(Engine e, Position2 chunkPos);
default <R> ResultLocator<R> then(TriFunction<Engine, Position2, T, R> filter) {
return (e, pos) -> {
var t = find(e, pos);
return t != null ? filter.apply(e, pos, t) : null;
};
}
default Future<Result<T>> find(Engine engine, Position2 pos, long timeout, Consumer<Integer> checks, boolean cancelable) throws WrongEngineBroException {
if (engine.isClosed()) {
throw new WrongEngineBroException();
}
cancelSearch();
return MultiBurst.burst.completeValue(() -> {
int tc = IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism()) * 17;
MultiBurst burst = MultiBurst.burst;
AtomicBoolean found = new AtomicBoolean(false);
AtomicReference<Result<T>> foundObj = new AtomicReference<>();
Position2 cursor = pos;
AtomicInteger searched = new AtomicInteger();
AtomicBoolean stop = new AtomicBoolean(false);
PrecisionStopwatch px = PrecisionStopwatch.start();
if (cancelable) LocatorCanceller.cancel = () -> stop.set(true);
AtomicReference<Position2> next = new AtomicReference<>(cursor);
Spiraler s = new Spiraler(100000, 100000, (x, z) -> next.set(new Position2(x, z)));
s.setOffset(cursor.getX(), cursor.getZ());
s.next();
while (!found.get() && !stop.get() && px.getMilliseconds() < timeout) {
BurstExecutor e = burst.burst(tc);
for (int i = 0; i < tc; i++) {
Position2 p = next.get();
s.next();
e.queue(() -> {
var o = find(engine, p);
if (o != null) {
if (foundObj.get() == null) {
foundObj.set(new Result<>(o, p));
}
found.set(true);
}
searched.incrementAndGet();
});
}
e.complete();
checks.accept(searched.get());
}
LocatorCanceller.cancel = null;
if (found.get() && foundObj.get() != null) {
return foundObj.get();
}
return null;
});
}
record Result<T>(T obj, Position2 pos) {
public int getBlockX() {
return (pos.getX() << 4) + 8;
}
public int getBlockZ() {
return (pos.getZ() << 4) + 8;
}
}
}

View File

@ -79,7 +79,7 @@ public class HeightmapObjectPlacer implements IObjectPlacer {
return oplacer.isDebugSmartBore(); return oplacer.isDebugSmartBore();
} }
public void setTile(int param1Int1, int param1Int2, int param1Int3, TileData<? extends TileState> param1TileData) { public void setTile(int param1Int1, int param1Int2, int param1Int3, TileData param1TileData) {
oplacer.setTile(param1Int1, param1Int2, param1Int3, param1TileData); oplacer.setTile(param1Int1, param1Int2, param1Int3, param1TileData);
} }

View File

@ -5,7 +5,7 @@ import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
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.engine.framework.IrisLootEvent; import com.volmit.iris.core.events.IrisLootEvent;
import com.volmit.iris.engine.mantle.EngineMantle; import com.volmit.iris.engine.mantle.EngineMantle;
import com.volmit.iris.engine.object.IObjectPlacer; import com.volmit.iris.engine.object.IObjectPlacer;
import com.volmit.iris.engine.object.InventorySlotType; import com.volmit.iris.engine.object.InventorySlotType;
@ -20,8 +20,6 @@ import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
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.InventoryHolder; import org.bukkit.inventory.InventoryHolder;
@ -74,7 +72,7 @@ public class WorldObjectPlacer implements IObjectPlacer {
if (tables.isEmpty()) if (tables.isEmpty())
return; return;
InventoryHolder m = (InventoryHolder) block.getState(); InventoryHolder m = (InventoryHolder) block.getState();
engine.addItems(false, m.getInventory(), rx, tables, slot, x, y, z, 15); engine.addItems(false, m.getInventory(), rx, tables, slot, world, x, y, z, 15);
} catch (Throwable e) { } catch (Throwable e) {
Iris.reportError(e); Iris.reportError(e);
} }
@ -119,9 +117,7 @@ public class WorldObjectPlacer implements IObjectPlacer {
} }
@Override @Override
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) { public void setTile(int xx, int yy, int zz, TileData tile) {
BlockState state = world.getBlockAt(xx, yy + world.getMinHeight(), zz).getState(); tile.toBukkitTry(world.getBlockAt(xx, yy + world.getMinHeight(), zz));
tile.toBukkitTry(state);
state.update();
} }
} }

View File

@ -50,16 +50,18 @@ public class PlannedStructure {
private IrisPosition position; private IrisPosition position;
private IrisData data; private IrisData data;
private RNG rng; private RNG rng;
private boolean forcePlace;
private boolean verbose; private boolean verbose;
private boolean terminating; private boolean terminating;
public PlannedStructure(IrisJigsawStructure structure, IrisPosition position, RNG rng) { public PlannedStructure(IrisJigsawStructure structure, IrisPosition position, RNG rng, boolean forcePlace) {
terminating = false; terminating = false;
verbose = true; verbose = true;
this.pieces = new KList<>(); this.pieces = new KList<>();
this.structure = structure; this.structure = structure;
this.position = position; this.position = position;
this.rng = rng; this.rng = rng;
this.forcePlace = forcePlace || structure.isForcePlace();
this.data = structure.getLoader(); this.data = structure.getLoader();
generateStartPiece(); generateStartPiece();
@ -108,6 +110,9 @@ public class PlannedStructure {
} else { } else {
options.setMode(i.getPiece().getPlaceMode()); options.setMode(i.getPiece().getPlaceMode());
} }
if (forcePlace) {
options.setForcePlace(true);
}
IrisObject v = i.getObject(); IrisObject v = i.getObject();
int sx = (v.getW() / 2); int sx = (v.getW() / 2);

View File

@ -107,7 +107,7 @@ public interface EngineMantle extends IObjectPlacer {
} }
@Override @Override
default void setTile(int x, int y, int z, TileData<? extends TileState> d) { default void setTile(int x, int y, int z, TileData d) {
getMantle().set(x, y, z, new TileWrapper(d)); getMantle().set(x, y, z, new TileWrapper(d));
} }

View File

@ -206,7 +206,7 @@ public class MantleWriter implements IObjectPlacer {
} }
@Override @Override
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) { public void setTile(int xx, int yy, int zz, TileData tile) {
getEngineMantle().setTile(xx, yy, zz, tile); getEngineMantle().setTile(xx, yy, zz, tile);
} }

View File

@ -57,7 +57,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
@ChunkCoordinates @ChunkCoordinates
private void generateJigsaw(MantleWriter writer, int x, int z, IrisBiome biome, IrisRegion region) { private void generateJigsaw(MantleWriter writer, int x, int z, IrisBiome biome, IrisRegion region) {
long seed = cng.fit(Integer.MIN_VALUE, Integer.MIN_VALUE, x, z); long seed = cng.fit(Integer.MIN_VALUE, Integer.MAX_VALUE, x, z);
if (getDimension().getStronghold() != null) { if (getDimension().getStronghold() != null) {
List<Position2> poss = getDimension().getStrongholds(seed()); List<Position2> poss = getDimension().getStrongholds(seed());
@ -66,7 +66,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
for (Position2 pos : poss) { for (Position2 pos : poss) {
if (x == pos.getX() >> 4 && z == pos.getZ() >> 4) { if (x == pos.getX() >> 4 && z == pos.getZ() >> 4) {
IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(getDimension().getStronghold()); IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(getDimension().getStronghold());
place(writer, pos.toIris(), structure, new RNG(seed)); place(writer, pos.toIris(), structure, new RNG(seed), true);
return; return;
} }
} }
@ -92,7 +92,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
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());
return place(writer, position, structure, rng); return place(writer, position, structure, rng, false);
} }
@ChunkCoordinates @ChunkCoordinates
@ -130,7 +130,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
public IrisJigsawStructure guess(int x, int z) { public IrisJigsawStructure guess(int x, int z) {
// todo The guess doesnt bring into account that the placer may return -1 // todo The guess doesnt bring into account that the placer may return -1
// todo doesnt bring skipped placements into account // todo doesnt bring skipped placements into account
long seed = cng.fit(Integer.MIN_VALUE, Integer.MIN_VALUE, x, z); long seed = cng.fit(Integer.MIN_VALUE, Integer.MAX_VALUE, x, z);
IrisBiome biome = getEngineMantle().getEngine().getSurfaceBiome((x << 4) + 8, (z << 4) + 8); IrisBiome biome = getEngineMantle().getEngine().getSurfaceBiome((x << 4) + 8, (z << 4) + 8);
IrisRegion region = getEngineMantle().getEngine().getRegion((x << 4) + 8, (z << 4) + 8); IrisRegion region = getEngineMantle().getEngine().getRegion((x << 4) + 8, (z << 4) + 8);
@ -161,8 +161,8 @@ public class MantleJigsawComponent extends IrisMantleComponent {
} }
@BlockCoordinates @BlockCoordinates
private boolean place(MantleWriter writer, IrisPosition position, IrisJigsawStructure structure, RNG rng) { private boolean place(MantleWriter writer, IrisPosition position, IrisJigsawStructure structure, RNG rng, boolean forcePlace) {
return new PlannedStructure(structure, position, rng).place(writer, getMantle(), writer.getEngine()); return new PlannedStructure(structure, position, rng, forcePlace).place(writer, getMantle(), writer.getEngine());
} }
private long jigsaw() { private long jigsaw() {

View File

@ -0,0 +1,13 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.util.collection.KList;
import org.bukkit.block.data.BlockData;
public interface IObjectLoot {
KList<IrisBlockData> getFilter();
KList<BlockData> getFilter(IrisData manager);
boolean isExact();
String getName();
int getWeight();
}

View File

@ -44,7 +44,7 @@ public interface IObjectPlacer {
boolean isDebugSmartBore(); boolean isDebugSmartBore();
void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile); void setTile(int xx, int yy, int zz, TileData tile);
Engine getEngine(); Engine getEngine();
} }

View File

@ -104,7 +104,7 @@ public class IrisBiomeCustom {
JSONObject po = new JSONObject(); JSONObject po = new JSONObject();
po.put("type", ambientParticle.getParticle().name().toLowerCase()); po.put("type", ambientParticle.getParticle().name().toLowerCase());
particle.put("options", po); particle.put("options", po);
particle.put("probability", ambientParticle.getRarity()); particle.put("probability", 1f/ambientParticle.getRarity());
effects.put("particle", particle); effects.put("particle", particle);
} }

View File

@ -37,12 +37,10 @@ public class IrisBiomeCustomSpawn {
private EntityType type = EntityType.COW; private EntityType type = EntityType.COW;
@MinNumber(1) @MinNumber(1)
@MaxNumber(20)
@Desc("The min to spawn") @Desc("The min to spawn")
private int minCount = 2; private int minCount = 2;
@MinNumber(1) @MinNumber(1)
@MaxNumber(20)
@Desc("The max to spawn") @Desc("The max to spawn")
private int maxCount = 5; private int maxCount = 5;

View File

@ -21,6 +21,7 @@ package com.volmit.iris.engine.object;
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.loader.IrisRegistrant; import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.nms.INMS;
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;
@ -61,6 +62,8 @@ public class IrisBlockData extends IrisRegistrant {
private IrisBlockData backup = null; private IrisBlockData backup = null;
@Desc("Optional properties for this block data such as 'waterlogged': true") @Desc("Optional properties for this block data such as 'waterlogged': true")
private KMap<String, Object> data = new KMap<>(); private KMap<String, Object> data = new KMap<>();
@Desc("Optional tile data for this block data")
private KMap<String, Object> tileData = new KMap<>();
public IrisBlockData(String b) { public IrisBlockData(String b) {
this.block = b; this.block = b;
@ -196,17 +199,12 @@ public class IrisBlockData extends IrisRegistrant {
}); });
} }
public TileData<?> tryGetTile() { public TileData tryGetTile(IrisData data) {
//TODO Do like a registry thing with the tile data registry. Also update the parsing of data to include **block** entities. //TODO Do like a registry thing with the tile data registry. Also update the parsing of data to include **block** entities.
if (data.containsKey("entitySpawn")) { var type = getBlockData(data).getMaterial();
TileSpawner spawner = new TileSpawner(); if (!INMS.get().hasTile(type) || tileData == null || tileData.isEmpty())
String name = (String) data.get("entitySpawn"); return null;
if (name.contains(":")) return new TileData(type, this.tileData);
name = name.split(":")[1];
spawner.setEntityType(EntityType.fromName(name));
return spawner;
}
return null;
} }
private String keyify(String dat) { private String keyify(String dat) {

View File

@ -21,6 +21,7 @@ package com.volmit.iris.engine.object;
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.loader.IrisRegistrant; import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.datapack.IDataFixer; 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.*;
@ -300,10 +301,8 @@ public class IrisDimension extends IrisRegistrant {
private IrisMaterialPalette rockPalette = new IrisMaterialPalette().qclear().qadd("stone"); private IrisMaterialPalette rockPalette = new IrisMaterialPalette().qclear().qadd("stone");
@Desc("The palette of blocks for 'water'") @Desc("The palette of blocks for 'water'")
private IrisMaterialPalette fluidPalette = new IrisMaterialPalette().qclear().qadd("water"); private IrisMaterialPalette fluidPalette = new IrisMaterialPalette().qclear().qadd("water");
@Desc("Remove cartographers so they do not crash the server (Iris worlds only)") @Desc("Prevent cartographers to generate explorer maps (Iris worlds only)\nONLY TOUCH IF YOUR SERVER CRASHES WHILE GENERATING EXPLORER MAPS")
private boolean removeCartographersDueToCrash = true; private boolean disableExplorerMaps = false;
@Desc("Notify players of cancelled cartographer villager in this radius in blocks (set to -1 to disable, -2 for everyone)")
private int notifyPlayersOfCartographerCancelledRadius = 30;
@Desc("Collection of ores to be generated") @Desc("Collection of ores to be generated")
@ArrayType(type = IrisOreGenerator.class, min = 1) @ArrayType(type = IrisOreGenerator.class, min = 1)
private KList<IrisOreGenerator> ores = new KList<>(); private KList<IrisOreGenerator> ores = new KList<>();
@ -489,10 +488,10 @@ public class IrisDimension extends IrisRegistrant {
{ {
"pack": { "pack": {
"description": "Iris Data Pack. This pack contains all installed Iris Packs' resources.", "description": "Iris Data Pack. This pack contains all installed Iris Packs' resources.",
"pack_format": 10 "pack_format": {}
} }
} }
"""); """.replace("{}", INMS.get().getDataVersion().getPackFormat() + ""));
} catch (IOException e) { } catch (IOException e) {
Iris.reportError(e); Iris.reportError(e);
e.printStackTrace(); e.printStackTrace();

View File

@ -271,7 +271,7 @@ public class IrisEntity extends IrisRegistrant {
for (String fi : getLoot().getTables()) { for (String fi : getLoot().getTables()) {
IrisLootTable i = gen.getData().getLootLoader().load(fi); IrisLootTable i = gen.getData().getLootLoader().load(fi);
items.addAll(i.getLoot(gen.isStudio(), rng.nextParallelRNG(345911), InventorySlotType.STORAGE, finalAt.getBlockX(), finalAt.getBlockY(), finalAt.getBlockZ())); items.addAll(i.getLoot(gen.isStudio(), rng.nextParallelRNG(345911), InventorySlotType.STORAGE, finalAt.getWorld(), finalAt.getBlockX(), finalAt.getBlockY(), finalAt.getBlockZ()));
} }
return items; return items;

View File

@ -22,6 +22,7 @@ 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.annotations.*; import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.engine.object.annotations.functions.StructureKeyFunction;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
@ -69,6 +70,13 @@ public class IrisJigsawStructure extends IrisRegistrant {
@Desc("Set to true to prevent rotating the initial structure piece") @Desc("Set to true to prevent rotating the initial structure piece")
private boolean disableInitialRotation = false; private boolean disableInitialRotation = false;
@RegistryListFunction(StructureKeyFunction.class)
@Desc("The minecraft key to use when creating treasure maps")
private String structureKey = null;
@Desc("Force Place the whole structure")
private boolean forcePlace = false;
private transient AtomicCache<Integer> maxDimension = new AtomicCache<>(); private transient AtomicCache<Integer> maxDimension = new AtomicCache<>();
private void loadPool(String p, KList<String> pools, KList<String> pieces) { private void loadPool(String p, KList<String> pools, KList<String> pieces) {
@ -137,7 +145,7 @@ public class IrisJigsawStructure extends IrisRegistrant {
avg += getLoader().getJigsawPieceLoader().load(i).getMax2dDimension(); avg += getLoader().getJigsawPieceLoader().load(i).getMax2dDimension();
} }
return (avg / (pieces.size() > 0 ? pieces.size() : 1)) * (((getMaxDepth() + 1) * 2) + 1); return (avg / (!pieces.isEmpty() ? pieces.size() : 1)) * (((getMaxDepth() + 1) * 2) + 1);
} }
}); });
} }

View File

@ -27,5 +27,7 @@ public enum IrisLootMode {
@Desc("Clear all loot tables then add this table") @Desc("Clear all loot tables then add this table")
CLEAR, CLEAR,
@Desc("Replace all loot tables with this table (same as clear)") @Desc("Replace all loot tables with this table (same as clear)")
REPLACE REPLACE,
@Desc("Only use when there was no loot table defined by an object")
FALLBACK
} }

View File

@ -33,6 +33,7 @@ import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@Accessors(chain = true) @Accessors(chain = true)
@ -67,7 +68,7 @@ public class IrisLootTable extends IrisRegistrant {
@ArrayType(min = 1, type = IrisLoot.class) @ArrayType(min = 1, type = IrisLoot.class)
private KList<IrisLoot> loot = new KList<>(); private KList<IrisLoot> loot = new KList<>();
public KList<ItemStack> getLoot(boolean debug, RNG rng, InventorySlotType slot, int x, int y, int z) { public KList<ItemStack> getLoot(boolean debug, RNG rng, InventorySlotType slot, World world, int x, int y, int z) {
KList<ItemStack> lootf = new KList<>(); KList<ItemStack> lootf = new KList<>();
int m = 0; int m = 0;

View File

@ -64,11 +64,11 @@ public class IrisMaterialPalette {
return getLayerGenerator(rng, rdata).fit(getBlockData(rdata), x / zoom, y / zoom, z / zoom); return getLayerGenerator(rng, rdata).fit(getBlockData(rdata), x / zoom, y / zoom, z / zoom);
} }
public Optional<TileData<?>> getTile(RNG rng, double x, double y, double z, IrisData rdata) { public Optional<TileData> getTile(RNG rng, double x, double y, double z, IrisData rdata) {
if (getBlockData(rdata).isEmpty()) if (getBlockData(rdata).isEmpty())
return Optional.empty(); return Optional.empty();
TileData<?> tile = getBlockData(rdata).size() == 1 ? palette.get(0).tryGetTile() : palette.getRandom(rng).tryGetTile(); TileData tile = getBlockData(rdata).size() == 1 ? palette.get(0).tryGetTile(rdata) : palette.getRandom(rng).tryGetTile(rdata);
return tile != null ? Optional.of(tile) : Optional.empty(); return tile != null ? Optional.of(tile) : Optional.empty();
} }

View File

@ -43,6 +43,7 @@ import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.IrisLock; import com.volmit.iris.util.scheduling.IrisLock;
import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.scheduling.jobs.Job;
import com.volmit.iris.util.stream.ProceduralStream; import com.volmit.iris.util.stream.ProceduralStream;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@ -63,7 +64,9 @@ import org.bukkit.util.Vector;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
@Accessors(chain = true) @Accessors(chain = true)
@ -84,7 +87,7 @@ public class IrisObject extends IrisRegistrant {
@Setter @Setter
protected transient AtomicCache<AxisAlignedBB> aabb = new AtomicCache<>(); protected transient AtomicCache<AxisAlignedBB> aabb = new AtomicCache<>();
private KMap<BlockVector, BlockData> blocks; private KMap<BlockVector, BlockData> blocks;
private KMap<BlockVector, TileData<? extends TileState>> states; private KMap<BlockVector, TileData> states;
@Getter @Getter
@Setter @Setter
private int w; private int w;
@ -384,15 +387,97 @@ public class IrisObject extends IrisRegistrant {
} }
} }
public void write(OutputStream o, VolmitSender sender) throws IOException {
AtomicReference<IOException> ref = new AtomicReference<>();
CountDownLatch latch = new CountDownLatch(1);
new Job() {
private int total = getBlocks().size() * 3 + getStates().size();
private int c = 0;
@Override
public String getName() {
return "Saving Object";
}
@Override
public void execute() {
try {
DataOutputStream dos = new DataOutputStream(o);
dos.writeInt(w);
dos.writeInt(h);
dos.writeInt(d);
dos.writeUTF("Iris V2 IOB;");
KList<String> palette = new KList<>();
for (BlockData i : getBlocks().values()) {
palette.addIfMissing(i.getAsString());
++c;
}
total -= getBlocks().size() - palette.size();
dos.writeShort(palette.size());
for (String i : palette) {
dos.writeUTF(i);
++c;
}
dos.writeInt(getBlocks().size());
for (BlockVector i : getBlocks().keySet()) {
dos.writeShort(i.getBlockX());
dos.writeShort(i.getBlockY());
dos.writeShort(i.getBlockZ());
dos.writeShort(palette.indexOf(getBlocks().get(i).getAsString()));
++c;
}
dos.writeInt(getStates().size());
for (BlockVector i : getStates().keySet()) {
dos.writeShort(i.getBlockX());
dos.writeShort(i.getBlockY());
dos.writeShort(i.getBlockZ());
getStates().get(i).toBinary(dos);
++c;
}
} catch (IOException e) {
ref.set(e);
} finally {
latch.countDown();
}
}
@Override
public void completeWork() {}
@Override
public int getTotalWork() {
return total;
}
@Override
public int getWorkCompleted() {
return c;
}
}.execute(sender, true, () -> {});
try {
latch.await();
} catch (InterruptedException ignored) {}
if (ref.get() != null)
throw ref.get();
}
public void read(File file) throws IOException { public void read(File file) throws IOException {
FileInputStream fin = new FileInputStream(file); var fin = new BufferedInputStream(new FileInputStream(file));
try { try {
read(fin); read(fin);
fin.close(); fin.close();
} catch (Throwable e) { } catch (Throwable e) {
Iris.reportError(e); Iris.reportError(e);
fin.close(); fin.close();
fin = new FileInputStream(file); fin = new BufferedInputStream(new FileInputStream(file));
readLegacy(fin); readLegacy(fin);
fin.close(); fin.close();
} }
@ -408,6 +493,16 @@ public class IrisObject extends IrisRegistrant {
out.close(); out.close();
} }
public void write(File file, VolmitSender sender) throws IOException {
if (file == null) {
return;
}
FileOutputStream out = new FileOutputStream(file);
write(out, sender);
out.close();
}
public void shrinkwrap() { public void shrinkwrap() {
BlockVector min = new BlockVector(); BlockVector min = new BlockVector();
BlockVector max = new BlockVector(); BlockVector max = new BlockVector();
@ -434,7 +529,7 @@ public class IrisObject extends IrisRegistrant {
d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i))); d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i)));
} }
KMap<BlockVector, TileData<? extends TileState>> dx = new KMap<>(); KMap<BlockVector, TileData> dx = new KMap<>();
for (BlockVector i : getBlocks().keySet()) { for (BlockVector i : getBlocks().keySet()) {
d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i))); d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i)));
@ -467,7 +562,7 @@ public class IrisObject extends IrisRegistrant {
} }
} }
public void setUnsigned(int x, int y, int z, Block block) { public void setUnsigned(int x, int y, int z, Block block, boolean legacy) {
BlockVector v = getSigned(x, y, z); BlockVector v = getSigned(x, y, z);
if (block == null) { if (block == null) {
@ -476,9 +571,9 @@ public class IrisObject extends IrisRegistrant {
} else { } else {
BlockData data = block.getBlockData(); BlockData data = block.getBlockData();
getBlocks().put(v, data); getBlocks().put(v, data);
TileData<? extends TileState> state = TileData.getTileState(block); TileData state = TileData.getTileState(block, legacy);
if (state != null) { if (state != null) {
Iris.info("Saved State " + v); Iris.debug("Saved State " + v);
getStates().put(v, state); getStates().put(v, state);
} }
} }
@ -568,7 +663,18 @@ public class IrisObject extends IrisRegistrant {
yrand = yrand > 0 ? rng.i(0, yrand) : yrand < 0 ? rng.i(yrand, 0) : yrand; yrand = yrand > 0 ? rng.i(0, yrand) : yrand < 0 ? rng.i(yrand, 0) : yrand;
boolean bail = false; boolean bail = false;
if (yv < 0) { if (config.isFromBottom()) {
// todo Convert this to a mode and make it compatible with jigsaw
y = (getH() + 1) + rty;
if (!config.isForcePlace()) {
if (placer.isCarved(x, y, z) ||
placer.isCarved(x, y - 1, z) ||
placer.isCarved(x, y - 2, z) ||
placer.isCarved(x, y - 3, z)) {
bail = true;
}
}
} else if (yv < 0) {
if (config.getMode().equals(ObjectPlaceMode.CENTER_HEIGHT) || config.getMode() == ObjectPlaceMode.CENTER_STILT) { if (config.getMode().equals(ObjectPlaceMode.CENTER_HEIGHT) || config.getMode() == ObjectPlaceMode.CENTER_STILT) {
y = (c != null ? c.getSurface() : placer.getHighest(x, z, getLoader(), config.isUnderwater())) + rty; y = (c != null ? c.getSurface() : placer.getHighest(x, z, getLoader(), config.isUnderwater())) + rty;
if (!config.isForcePlace()) { if (!config.isForcePlace()) {
@ -802,7 +908,7 @@ public class IrisObject extends IrisRegistrant {
for (BlockVector g : getBlocks().keySet()) { for (BlockVector g : getBlocks().keySet()) {
BlockData d; BlockData d;
TileData<? extends TileState> tile = null; TileData tile = null;
try { try {
d = getBlocks().get(g); d = getBlocks().get(g);
@ -842,11 +948,9 @@ public class IrisObject extends IrisRegistrant {
else else
data = newData; data = newData;
if (newData.getMaterial() == Material.SPAWNER) { Optional<TileData> t = j.getReplace().getTile(rng, x, y, z, rdata);
Optional<TileData<?>> t = j.getReplace().getTile(rng, x, y, z, rdata); if (t.isPresent()) {
if (t.isPresent()) { tile = t.get();
tile = t.get();
}
} }
} }
} }
@ -1044,7 +1148,7 @@ public class IrisObject extends IrisRegistrant {
spinx, spiny, spinz)); spinx, spiny, spinz));
} }
KMap<BlockVector, TileData<? extends TileState>> dx = new KMap<>(); KMap<BlockVector, TileData> dx = new KMap<>();
for (BlockVector i : getStates().keySet()) { for (BlockVector i : getStates().keySet()) {
dx.put(r.rotate(i.clone(), spinx, spiny, spinz), getStates().get(i)); dx.put(r.rotate(i.clone(), spinx, spiny, spinz), getStates().get(i));
@ -1062,9 +1166,7 @@ public class IrisObject extends IrisRegistrant {
if (getStates().containsKey(i)) { if (getStates().containsKey(i)) {
Iris.info(Objects.requireNonNull(states.get(i)).toString()); Iris.info(Objects.requireNonNull(states.get(i)).toString());
BlockState st = b.getState(); Objects.requireNonNull(getStates().get(i)).toBukkitTry(b);
Objects.requireNonNull(getStates().get(i)).toBukkitTry(st);
st.update();
} }
} }
} }
@ -1075,7 +1177,7 @@ public class IrisObject extends IrisRegistrant {
b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false); b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false);
if (getStates().containsKey(i)) { if (getStates().containsKey(i)) {
Objects.requireNonNull(getStates().get(i)).toBukkitTry(b.getState()); Objects.requireNonNull(getStates().get(i)).toBukkitTry(b);
} }
} }
} }
@ -1084,7 +1186,7 @@ public class IrisObject extends IrisRegistrant {
return blocks; return blocks;
} }
public synchronized KMap<BlockVector, TileData<? extends TileState>> getStates() { public synchronized KMap<BlockVector, TileData> getStates() {
return states; return states;
} }

View File

@ -34,7 +34,7 @@ import org.bukkit.block.data.BlockData;
@AllArgsConstructor @AllArgsConstructor
@Desc("Represents loot within this object or jigsaw piece") @Desc("Represents loot within this object or jigsaw piece")
@Data @Data
public class IrisObjectLoot { public class IrisObjectLoot implements IObjectLoot {
private final transient AtomicCache<KList<BlockData>> filterCache = new AtomicCache<>(); private final transient AtomicCache<KList<BlockData>> filterCache = new AtomicCache<>();
@ArrayType(min = 1, type = IrisBlockData.class) @ArrayType(min = 1, type = IrisBlockData.class)
@Desc("The list of blocks this loot table should apply to") @Desc("The list of blocks this loot table should apply to")

View File

@ -34,9 +34,15 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.TreeType; import org.bukkit.TreeType;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.function.Function;
@Snippet("object-placer") @Snippet("object-placer")
@EqualsAndHashCode() @EqualsAndHashCode()
@ -103,6 +109,8 @@ public class IrisObjectPlacement {
private boolean onwater = false; private boolean onwater = false;
@Desc("If set to true, this object will only place parts of itself where blocks already exist. Warning: Melding is very performance intensive!") @Desc("If set to true, this object will only place parts of itself where blocks already exist. Warning: Melding is very performance intensive!")
private boolean meld = false; private boolean meld = false;
@Desc("If set to true, this object will get placed from the bottom of the world up")
private boolean fromBottom;
@Desc("If set to true, this object will place from the ground up instead of height checks when not y locked to the surface. This is not compatable with X and Z axis rotations (it may look off)") @Desc("If set to true, this object will place from the ground up instead of height checks when not y locked to the surface. This is not compatable with X and Z axis rotations (it may look off)")
private boolean bottom = false; private boolean bottom = false;
@Desc("If set to true, air will be placed before the schematic places.") @Desc("If set to true, air will be placed before the schematic places.")
@ -123,6 +131,9 @@ public class IrisObjectPlacement {
@ArrayType(min = 1, type = IrisObjectLoot.class) @ArrayType(min = 1, type = IrisObjectLoot.class)
@Desc("The loot tables to apply to these objects") @Desc("The loot tables to apply to these objects")
private KList<IrisObjectLoot> loot = new KList<>(); private KList<IrisObjectLoot> loot = new KList<>();
@ArrayType(min = 1, type = IrisObjectVanillaLoot.class)
@Desc("The vanilla loot tables to apply to these objects")
private KList<IrisObjectVanillaLoot> vanillaLoot = new KList<>();
@Desc("Whether the given loot tables override any and all other loot tables available in the dimension, region or biome.") @Desc("Whether the given loot tables override any and all other loot tables available in the dimension, region or biome.")
private boolean overrideGlobalLoot = false; private boolean overrideGlobalLoot = false;
@Desc("This object / these objects override the following trees when they grow...") @Desc("This object / these objects override the following trees when they grow...")
@ -211,46 +222,63 @@ public class IrisObjectPlacement {
private TableCache getCache(IrisData manager) { private TableCache getCache(IrisData manager) {
return cache.aquire(() -> { return cache.aquire(() -> {
TableCache tc = new TableCache(); TableCache cache = new TableCache();
for (IrisObjectLoot loot : getLoot()) { cache.merge(getCache(manager, getVanillaLoot(), IrisObjectPlacement::getVanillaTable));
if (loot == null) cache.merge(getCache(manager, getLoot(), manager.getLootLoader()::load));
continue;
IrisLootTable table = manager.getLootLoader().load(loot.getName()); return cache;
if (table == null) { });
Iris.warn("Couldn't find loot table " + loot.getName()); }
continue;
private TableCache getCache(IrisData manager, KList<? extends IObjectLoot> list, Function<String, IrisLootTable> loader) {
TableCache tc = new TableCache();
for (IObjectLoot loot : list) {
if (loot == null)
continue;
IrisLootTable table = loader.apply(loot.getName());
if (table == null) {
Iris.warn("Couldn't find loot table " + loot.getName());
continue;
}
if (loot.getFilter().isEmpty()) //Table applies to all containers
{
tc.global.put(table, loot.getWeight());
} else if (!loot.isExact()) //Table is meant to be by type
{
for (BlockData filterData : loot.getFilter(manager)) {
if (!tc.basic.containsKey(filterData.getMaterial())) {
tc.basic.put(filterData.getMaterial(), new WeightedRandom<>());
}
tc.basic.get(filterData.getMaterial()).put(table, loot.getWeight());
} }
} else //Filter is exact
if (loot.getFilter().isEmpty()) //Table applies to all containers {
{ for (BlockData filterData : loot.getFilter(manager)) {
tc.global.put(table, loot.getWeight()); if (!tc.exact.containsKey(filterData.getMaterial())) {
} else if (!loot.isExact()) //Table is meant to be by type tc.exact.put(filterData.getMaterial(), new KMap<>());
{
for (BlockData filterData : loot.getFilter(manager)) {
if (!tc.basic.containsKey(filterData.getMaterial())) {
tc.basic.put(filterData.getMaterial(), new WeightedRandom<>());
}
tc.basic.get(filterData.getMaterial()).put(table, loot.getWeight());
} }
} else //Filter is exact
{
for (BlockData filterData : loot.getFilter(manager)) {
if (!tc.exact.containsKey(filterData.getMaterial())) {
tc.exact.put(filterData.getMaterial(), new KMap<>());
}
if (!tc.exact.get(filterData.getMaterial()).containsKey(filterData)) { if (!tc.exact.get(filterData.getMaterial()).containsKey(filterData)) {
tc.exact.get(filterData.getMaterial()).put(filterData, new WeightedRandom<>()); tc.exact.get(filterData.getMaterial()).put(filterData, new WeightedRandom<>());
}
tc.exact.get(filterData.getMaterial()).get(filterData).put(table, loot.getWeight());
} }
tc.exact.get(filterData.getMaterial()).get(filterData).put(table, loot.getWeight());
} }
} }
return tc; }
}); return tc;
}
@Nullable
private static IrisVanillaLootTable getVanillaTable(String name) {
return Optional.ofNullable(NamespacedKey.fromString(name))
.map(Bukkit::getLootTable)
.map(IrisVanillaLootTable::new)
.orElse(null);
} }
/** /**
@ -262,7 +290,6 @@ public class IrisObjectPlacement {
*/ */
public IrisLootTable getTable(BlockData data, IrisData dataManager) { public IrisLootTable getTable(BlockData data, IrisData dataManager) {
TableCache cache = getCache(dataManager); TableCache cache = getCache(dataManager);
if (B.isStorageChest(data)) { if (B.isStorageChest(data)) {
IrisLootTable picked = null; IrisLootTable picked = null;
if (cache.exact.containsKey(data.getMaterial()) && cache.exact.get(data.getMaterial()).containsKey(data)) { if (cache.exact.containsKey(data.getMaterial()) && cache.exact.get(data.getMaterial()).containsKey(data)) {
@ -283,5 +310,11 @@ public class IrisObjectPlacement {
final transient WeightedRandom<IrisLootTable> global = new WeightedRandom<>(); final transient WeightedRandom<IrisLootTable> global = new WeightedRandom<>();
final transient KMap<Material, WeightedRandom<IrisLootTable>> basic = new KMap<>(); final transient KMap<Material, WeightedRandom<IrisLootTable>> basic = new KMap<>();
final transient KMap<Material, KMap<BlockData, WeightedRandom<IrisLootTable>>> exact = new KMap<>(); final transient KMap<Material, KMap<BlockData, WeightedRandom<IrisLootTable>>> exact = new KMap<>();
private void merge(TableCache other) {
global.merge(other.global);
basic.merge(other.basic, WeightedRandom::merge);
exact.merge(other.exact, (a, b) -> a.merge(b, WeightedRandom::merge));
}
} }
} }

View File

@ -22,6 +22,7 @@ import com.volmit.iris.Iris;
import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.Snippet; 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 lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@ -30,9 +31,12 @@ import org.bukkit.Axis;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.data.*; import org.bukkit.block.data.*;
import org.bukkit.block.data.type.Wall;
import org.bukkit.block.structure.StructureRotation;
import org.bukkit.util.BlockVector; import org.bukkit.util.BlockVector;
import java.util.List; import java.util.List;
import java.util.Map;
@Snippet("object-rotator") @Snippet("object-rotator")
@Accessors(chain = true) @Accessors(chain = true)
@ -41,6 +45,8 @@ import java.util.List;
@Desc("Configures rotation for iris") @Desc("Configures rotation for iris")
@Data @Data
public class IrisObjectRotation { public class IrisObjectRotation {
private static final List<BlockFace> WALL_FACES = List.of(BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST);
@Desc("If this rotator is enabled or not") @Desc("If this rotator is enabled or not")
private boolean enabled = true; private boolean enabled = true;
@ -282,6 +288,22 @@ public class IrisObjectRotation {
for (BlockFace i : faces) { for (BlockFace i : faces) {
g.setFace(i, true); g.setFace(i, true);
} }
} else if (d instanceof Wall wall) {
KMap<BlockFace, Wall.Height> faces = new KMap<>();
for (BlockFace i : WALL_FACES) {
Wall.Height h = wall.getHeight(i);
BlockVector bv = new BlockVector(i.getModX(), i.getModY(), i.getModZ());
bv = rotate(bv.clone(), spinx, spiny, spinz);
BlockFace r = getFace(bv);
if (WALL_FACES.contains(r)) {
faces.put(r, h);
}
}
for (BlockFace i : WALL_FACES) {
wall.setHeight(i, faces.getOrDefault(i, Wall.Height.NONE));
}
} else if (d.getMaterial().equals(Material.NETHER_PORTAL) && d instanceof Orientable g) { } else if (d.getMaterial().equals(Material.NETHER_PORTAL) && d instanceof Orientable g) {
//TODO: Fucks up logs //TODO: Fucks up logs
BlockFace f = faceForAxis(g.getAxis()); BlockFace f = faceForAxis(g.getAxis());

View File

@ -0,0 +1,50 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.engine.object.annotations.functions.LootTableKeyFunction;
import com.volmit.iris.util.collection.KList;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.bukkit.block.data.BlockData;
@Snippet("object-vanilla-loot")
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Desc("Represents vanilla loot within this object or jigsaw piece")
@Data
public class IrisObjectVanillaLoot implements IObjectLoot {
private final transient AtomicCache<KList<BlockData>> filterCache = new AtomicCache<>();
@ArrayType(min = 1, type = IrisBlockData.class)
@Desc("The list of blocks this loot table should apply to")
private KList<IrisBlockData> filter = new KList<>();
@Desc("Exactly match the block data or not")
private boolean exact = false;
@Desc("The vanilla loot table key")
@Required
@RegistryListFunction(LootTableKeyFunction.class)
private String name;
@Desc("The weight of this loot table being chosen")
private int weight = 1;
public KList<BlockData> getFilter(IrisData rdata) {
return filterCache.aquire(() ->
{
KList<BlockData> b = new KList<>();
for (IrisBlockData i : filter) {
BlockData bx = i.getBlockData(rdata);
if (bx != null) {
b.add(bx);
}
}
return b;
});
}
}

View File

@ -0,0 +1,80 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.RNG;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.inventory.ItemStack;
import org.bukkit.loot.LootContext;
import org.bukkit.loot.LootTable;
import java.io.File;
@Data
@EqualsAndHashCode(callSuper = false)
public class IrisVanillaLootTable extends IrisLootTable {
private final LootTable lootTable;
@Override
public String getName() {
return "Vanilla " + lootTable.getKey();
}
@Override
public int getRarity() {
return 0;
}
@Override
public int getMaxPicked() {
return 0;
}
@Override
public int getMinPicked() {
return 0;
}
@Override
public int getMaxTries() {
return 0;
}
@Override
public KList<IrisLoot> getLoot() {
return new KList<>();
}
@Override
public KList<ItemStack> getLoot(boolean debug, RNG rng, InventorySlotType slot, World world, int x, int y, int z) {
return new KList<>(lootTable.populateLoot(rng, new LootContext.Builder(new Location(world, x, y, z)).build()));
}
@Override
public String getFolderName() {
throw new UnsupportedOperationException("VanillaLootTables do not have a folder name");
}
@Override
public String getTypeName() {
throw new UnsupportedOperationException("VanillaLootTables do not have a type name");
}
@Override
public File getLoadFile() {
throw new UnsupportedOperationException("VanillaLootTables do not have a load file");
}
@Override
public IrisData getLoader() {
throw new UnsupportedOperationException("VanillaLootTables do not have a loader");
}
@Override
public KList<String> getPreprocessors() {
return new KList<>();
}
}

View File

@ -0,0 +1,282 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.scheduling.J;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
import lombok.ToString;
import org.apache.commons.io.function.IOFunction;
import org.bukkit.*;
import org.bukkit.block.*;
import org.bukkit.block.banner.Pattern;
import org.bukkit.block.banner.PatternType;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
@ToString
@EqualsAndHashCode(callSuper = false)
public class LegacyTileData extends TileData {
private static final Map<Integer, Pair<Builder, IOFunction<DataInputStream, Handler>>> legacy = Map.of(
0, new Pair<>(SignHandler::fromBukkit, SignHandler::new),
1, new Pair<>(SpawnerHandler::fromBukkit, SpawnerHandler::new),
2, new Pair<>(BannerHandler::fromBukkit, BannerHandler::new));
private static final AtomicCache<Tag<Material>> SIGNS = new AtomicCache<>();
private final int id;
private final Handler handler;
public LegacyTileData(DataInputStream in) throws IOException {
id = in.readShort();
var factory = legacy.get(id);
if (factory == null)
throw new IOException("Unknown tile type: " + id);
handler = factory.getB().apply(in);
}
private LegacyTileData(int id, Handler handler) {
this.id = id;
this.handler = handler;
}
@Nullable
public static LegacyTileData fromBukkit(@NonNull BlockState tileState) {
var type = tileState.getType();
for (var id : legacy.keySet()) {
var factory = legacy.get(id);
var handler = factory.getA().apply(tileState, type);
if (handler != null)
return new LegacyTileData(id, handler);
}
return null;
}
@Override
public @NonNull KMap<String, Object> getProperties() {
return new KMap<>();
}
@Override
public @NonNull Material getMaterial() {
return handler.getMaterial();
}
@Override
public boolean isApplicable(BlockData data) {
return handler.isApplicable(data);
}
@Override
public void toBukkit(Block block) {
J.s(() -> handler.toBukkit(block));
}
@Override
public void toBinary(DataOutputStream out) throws IOException {
out.writeShort(id);
handler.toBinary(out);
}
@Override
public TileData clone() {
return this;
}
private interface Handler {
Material getMaterial();
boolean isApplicable(BlockData data);
void toBinary(DataOutputStream out) throws IOException;
void toBukkit(Block block);
}
@FunctionalInterface
private interface Builder {
@Nullable Handler apply(@NonNull BlockState blockState, @NonNull Material type);
}
@ToString
@EqualsAndHashCode
@AllArgsConstructor
private static class SignHandler implements Handler {
private final String line1;
private final String line2;
private final String line3;
private final String line4;
private final DyeColor dyeColor;
private SignHandler(DataInputStream in) throws IOException {
line1 = in.readUTF();
line2 = in.readUTF();
line3 = in.readUTF();
line4 = in.readUTF();
dyeColor = DyeColor.values()[in.readByte()];
}
@SuppressWarnings("deprecation")
private static SignHandler fromBukkit(BlockState blockState, Material type) {
if (!signsTag().isTagged(type) || !(blockState instanceof Sign sign))
return null;
return new SignHandler(sign.getLine(0), sign.getLine(1), sign.getLine(2), sign.getLine(3), sign.getColor());
}
@Override
public Material getMaterial() {
return Material.OAK_SIGN;
}
@Override
public boolean isApplicable(BlockData data) {
return signsTag().isTagged(data.getMaterial());
}
@Override
public void toBinary(DataOutputStream out) throws IOException {
out.writeUTF(line1);
out.writeUTF(line2);
out.writeUTF(line3);
out.writeUTF(line4);
out.writeByte(dyeColor.ordinal());
}
@Override
public void toBukkit(Block block) {
Sign sign = (Sign) block.getState();
sign.setLine(0, line1);
sign.setLine(1, line2);
sign.setLine(2, line3);
sign.setLine(3, line4);
sign.setColor(dyeColor);
sign.update();
}
}
@ToString
@EqualsAndHashCode
@AllArgsConstructor
private static class SpawnerHandler implements Handler {
private final EntityType type;
private SpawnerHandler(DataInputStream in) throws IOException {
type = EntityType.values()[in.readShort()];
}
private static SpawnerHandler fromBukkit(BlockState blockState, Material material) {
if (material != Material.SPAWNER || !(blockState instanceof CreatureSpawner spawner))
return null;
return new SpawnerHandler(spawner.getSpawnedType());
}
@Override
public Material getMaterial() {
return Material.SPAWNER;
}
@Override
public boolean isApplicable(BlockData data) {
return data.getMaterial() == Material.SPAWNER;
}
@Override
public void toBinary(DataOutputStream out) throws IOException {
out.writeShort(type.ordinal());
}
@Override
public void toBukkit(Block block) {
CreatureSpawner spawner = (CreatureSpawner) block.getState();
spawner.setSpawnedType(type);
spawner.update();
}
}
@ToString
@EqualsAndHashCode
@AllArgsConstructor
private static class BannerHandler implements Handler {
private final KList<Pattern> patterns;
private final DyeColor baseColor;
private BannerHandler(DataInputStream in) throws IOException {
baseColor = DyeColor.values()[in.readByte()];
patterns = new KList<>();
int listSize = in.readByte();
for (int i = 0; i < listSize; i++) {
DyeColor color = DyeColor.values()[in.readByte()];
PatternType pattern = PatternType.values()[in.readByte()];
patterns.add(new Pattern(color, pattern));
}
}
private static BannerHandler fromBukkit(BlockState blockState, Material type) {
if (!Tag.BANNERS.isTagged(type) || !(blockState instanceof Banner banner))
return null;
return new BannerHandler(new KList<>(banner.getPatterns()), banner.getBaseColor());
}
@Override
public Material getMaterial() {
return Material.WHITE_BANNER;
}
@Override
public boolean isApplicable(BlockData data) {
return Tag.BANNERS.isTagged(data.getMaterial());
}
@Override
public void toBinary(DataOutputStream out) throws IOException {
out.writeByte(baseColor.ordinal());
out.writeByte(patterns.size());
for (Pattern i : patterns) {
out.writeByte(i.getColor().ordinal());
out.writeByte(i.getPattern().ordinal());
}
}
@Override
public void toBukkit(Block block) {
Banner banner = (Banner) block.getState();
banner.setBaseColor(baseColor);
banner.setPatterns(patterns);
banner.update();
}
}
private static Tag<Material> signsTag() {
return SIGNS.aquire(() -> {
var signs = Bukkit.getTag("blocks", NamespacedKey.minecraft("all_signs"), Material.class);
if (signs != null)
return signs;
return new Tag<>() {
@Override
public boolean isTagged(@NotNull Material item) {
return item.getKey().getKey().endsWith("_sign");
}
@NotNull
@Override
public Set<Material> getValues() {
return StreamSupport.stream(Registry.MATERIAL.spliterator(), false)
.filter(this::isTagged)
.collect(Collectors.toUnmodifiableSet());
}
@NotNull
@Override
public NamespacedKey getKey() {
return NamespacedKey.minecraft("all_signs");
}
};
});
}
}

View File

@ -1,120 +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.util.nbt.tag.CompoundTag;
import com.volmit.iris.util.nbt.tag.ListTag;
import lombok.Data;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.bukkit.block.Banner;
import org.bukkit.block.banner.Pattern;
import org.bukkit.block.banner.PatternType;
import org.bukkit.block.data.BlockData;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Data
public class TileBanner implements TileData<Banner> {
public static final int id = 2;
private List<Pattern> patterns = new ArrayList<>();
private DyeColor baseColor;
@Override
public String getTileId() {
return "minecraft:banner";
}
@Override
public boolean isApplicable(BlockData data) {
return isBanner(data.getMaterial());
}
@Override
public void toBukkit(Banner banner) {
banner.setPatterns(patterns);
banner.setBaseColor(baseColor);
}
@Override
public void fromBukkit(Banner banner) {
this.patterns = banner.getPatterns();
this.baseColor = banner.getBaseColor();
}
@SuppressWarnings("MethodDoesntCallSuperMethod")
@Override
public TileBanner clone() {
TileBanner ts = new TileBanner();
ts.setBaseColor(getBaseColor());
ts.setPatterns(getPatterns());
return ts;
}
@Override
public void toBinary(DataOutputStream out) throws IOException {
out.writeShort(id);
out.writeByte(baseColor.ordinal());
out.writeByte(patterns.size());
for (Pattern p : patterns) {
out.writeByte(p.getColor().ordinal());
out.writeByte(p.getPattern().ordinal());
}
}
@Override
public void fromBinary(DataInputStream in) throws IOException {
baseColor = DyeColor.values()[in.readByte()];
int listSize = in.readByte();
patterns = new ArrayList<>();
for (int i = 0; i < listSize; i++) {
DyeColor color = DyeColor.values()[in.readByte()];
PatternType type = PatternType.values()[in.readByte()];
patterns.add(new Pattern(color, type));
}
}
@SuppressWarnings("deprecation")
@Override
public CompoundTag toNBT(CompoundTag tag) {
@SuppressWarnings("unchecked") ListTag<CompoundTag> listTag = (ListTag<CompoundTag>) ListTag.createUnchecked(CompoundTag.class);
for (Pattern p : patterns) {
CompoundTag pattern = new CompoundTag();
pattern.putString("Pattern", p.getPattern().getIdentifier());
pattern.putByte("Color", p.getColor().getDyeData());
listTag.add(pattern);
}
tag.put("Patterns", listTag);
return tag;
}
public boolean isBanner(Material material) {
return switch (material) {
case RED_BANNER, RED_WALL_BANNER, ORANGE_BANNER, ORANGE_WALL_BANNER, YELLOW_BANNER, YELLOW_WALL_BANNER, LIME_BANNER, LIME_WALL_BANNER, GREEN_BANNER, GREEN_WALL_BANNER, CYAN_BANNER, CYAN_WALL_BANNER, LIGHT_BLUE_BANNER, LIGHT_BLUE_WALL_BANNER, BLUE_BANNER, BLUE_WALL_BANNER, PURPLE_BANNER, PURPLE_WALL_BANNER, MAGENTA_BANNER, MAGENTA_WALL_BANNER, PINK_BANNER, PINK_WALL_BANNER, WHITE_BANNER, WHITE_WALL_BANNER, LIGHT_GRAY_BANNER, LIGHT_GRAY_WALL_BANNER, GRAY_BANNER, GRAY_WALL_BANNER, BLACK_BANNER, BLACK_WALL_BANNER, BROWN_BANNER, BROWN_WALL_BANNER ->
true;
default -> false;
};
}
}

View File

@ -18,84 +18,104 @@
package com.volmit.iris.engine.object; package com.volmit.iris.engine.object;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.collection.KMap;
import lombok.*;
import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.TileState; import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public interface TileData<T extends TileState> extends Cloneable { @Getter
@ToString
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class TileData implements Cloneable {
private static final Gson gson = new GsonBuilder().disableHtmlEscaping().setLenient().create();
static final KList<TileData<? extends TileState>> registry = setup(); @NonNull
private Material material;
@NonNull
private KMap<String, Object> properties;
static KList<TileData<? extends TileState>> setup() { public static boolean setTileState(Block block, TileData data) {
KList<TileData<? extends TileState>> registry = new KList<>();
registry.add(new TileSign());
registry.add(new TileSpawner());
registry.add(new TileBanner());
return registry;
}
static TileData<? extends TileState> read(DataInputStream s) throws IOException {
try {
int id = s.readShort();
@SuppressWarnings("unchecked") TileData<? extends TileState> d = registry.get(id).getClass().getConstructor().newInstance();
d.fromBinary(s);
return d;
} catch (InvocationTargetException | InstantiationException | IllegalAccessException |
NoSuchMethodException e) {
throw new IOException("Failed to create TileData instance due to missing type registrar!");
}
}
static boolean setTileState(Block block, TileData<? extends TileState> data) {
if (block.getState() instanceof TileState && data.isApplicable(block.getBlockData())) if (block.getState() instanceof TileState && data.isApplicable(block.getBlockData()))
return data.toBukkitTry(block.getState()); return data.toBukkitTry(block);
return false; return false;
} }
static TileData<? extends TileState> getTileState(Block block) { public static TileData getTileState(Block block, boolean useLegacy) {
for (TileData<? extends TileState> i : registry) { if (!INMS.get().hasTile(block.getType()))
BlockData data = block.getBlockData(); return null;
if (useLegacy) {
if (i.isApplicable(data)) { var legacy = LegacyTileData.fromBukkit(block.getState());
try { if (legacy != null)
@SuppressWarnings("unchecked") TileData<? extends TileState> s = i.getClass().getConstructor().newInstance(); return legacy;
s.fromBukkitTry(block.getState());
return s;
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
}
} }
return null; return new TileData().fromBukkit(block);
} }
String getTileId(); public static TileData read(DataInputStream in) throws IOException {
if (!in.markSupported())
throw new IOException("Mark not supported");
in.mark(Integer.MAX_VALUE);
try {
return new TileData(
Material.matchMaterial(in.readUTF()),
gson.fromJson(in.readUTF(), KMap.class));
} catch (Throwable e) {
in.reset();
return new LegacyTileData(in);
} finally {
in.mark(0);
}
}
boolean isApplicable(BlockData data); public boolean isApplicable(BlockData data) {
return material != null && data.getMaterial() == material;
}
void toBukkit(T t); public void toBukkit(Block block) {
if (material == null) throw new IllegalStateException("Material not set");
if (block.getType() != material)
throw new IllegalStateException("Material mismatch: " + block.getType() + " vs " + material);
INMS.get().deserializeTile(properties, block.getLocation());
}
void fromBukkit(T t); public TileData fromBukkit(Block block) {
if (material != null && block.getType() != material)
throw new IllegalStateException("Material mismatch: " + block.getType() + " vs " + material);
if (material == null) material = block.getType();
properties = INMS.get().serializeTile(block.getLocation());
return this;
}
default boolean toBukkitTry(BlockState t) { public boolean toBukkitTry(Block block) {
try { try {
//noinspection unchecked //noinspection unchecked
toBukkit((T) t); toBukkit(block);
t.update(); return true;
} catch (Throwable e) {
Iris.reportError(e);
}
return false;
}
public boolean fromBukkitTry(Block block) {
try {
//noinspection unchecked
fromBukkit(block);
return true; return true;
} catch (Throwable e) { } catch (Throwable e) {
Iris.reportError(e); Iris.reportError(e);
@ -105,24 +125,16 @@ public interface TileData<T extends TileState> extends Cloneable {
return false; return false;
} }
default boolean fromBukkitTry(BlockState t) { public void toBinary(DataOutputStream out) throws IOException {
try { out.writeUTF(material == null ? "" : material.getKey().toString());
//noinspection unchecked out.writeUTF(gson.toJson(properties));
fromBukkit((T) t);
return true;
} catch (Throwable e) {
Iris.reportError(e);
}
return false;
} }
CompoundTag toNBT(CompoundTag parent); @Override
public TileData clone() {
void toBinary(DataOutputStream out) throws IOException; var clone = new TileData();
clone.material = material;
void fromBinary(DataInputStream in) throws IOException; clone.properties = properties.copy(); //TODO make a deep copy
return clone;
TileData<T> clone(); }
} }

View File

@ -1,109 +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.util.nbt.tag.CompoundTag;
import lombok.Data;
import org.bukkit.DyeColor;
import org.bukkit.block.Sign;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.WallSign;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@Data
public class TileSign implements TileData<Sign> {
public static final int id = 0;
private String line1;
private String line2;
private String line3;
private String line4;
private DyeColor dyeColor;
@Override
public String getTileId() {
return "minecraft:sign";
}
@Override
public boolean isApplicable(BlockData data) {
return data instanceof org.bukkit.block.data.type.Sign || data instanceof WallSign;
}
@Override
public void toBukkit(Sign t) {
t.setLine(0, line1);
t.setLine(1, line2);
t.setLine(2, line3);
t.setLine(3, line4);
t.setColor(dyeColor);
}
@Override
public void fromBukkit(Sign sign) {
line1 = sign.getLine(0);
line2 = sign.getLine(1);
line3 = sign.getLine(2);
line4 = sign.getLine(3);
dyeColor = sign.getColor();
}
@SuppressWarnings("MethodDoesntCallSuperMethod")
@Override
public TileSign clone() {
TileSign ts = new TileSign();
ts.setDyeColor(getDyeColor());
ts.setLine1(getLine1());
ts.setLine2(getLine2());
ts.setLine3(getLine3());
ts.setLine4(getLine4());
return ts;
}
@Override
public void toBinary(DataOutputStream out) throws IOException {
out.writeShort(id);
out.writeUTF(line1);
out.writeUTF(line2);
out.writeUTF(line3);
out.writeUTF(line4);
out.writeByte(dyeColor.ordinal());
}
@Override
public void fromBinary(DataInputStream in) throws IOException {
line1 = in.readUTF();
line2 = in.readUTF();
line3 = in.readUTF();
line4 = in.readUTF();
dyeColor = DyeColor.values()[in.readByte()];
}
@Override
public CompoundTag toNBT(CompoundTag tag) {
tag.putString("Text1", line1);
tag.putString("Text2", line2);
tag.putString("Text3", line3);
tag.putString("Text4", line4);
tag.putString("Color", dyeColor.name().toLowerCase());
return tag;
}
}

View File

@ -1,91 +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.util.nbt.tag.CompoundTag;
import com.volmit.iris.util.nbt.tag.ListTag;
import lombok.Data;
import org.bukkit.Material;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.EntityType;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@Data
public class TileSpawner implements TileData<CreatureSpawner> {
public static final int id = 1;
private EntityType entityType;
@Override
public String getTileId() {
return "minecraft:mob_spawner";
}
@Override
public boolean isApplicable(BlockData data) {
return data.getMaterial() == Material.SPAWNER;
}
@Override
public void toBukkit(CreatureSpawner t) {
t.setSpawnedType(entityType);
}
@Override
public void fromBukkit(CreatureSpawner sign) {
entityType = sign.getSpawnedType();
}
@SuppressWarnings("MethodDoesntCallSuperMethod")
@Override
public TileSpawner clone() {
TileSpawner ts = new TileSpawner();
ts.setEntityType(getEntityType());
return ts;
}
@Override
public void toBinary(DataOutputStream out) throws IOException {
out.writeShort(id);
out.writeShort(entityType.ordinal());
}
@Override
public void fromBinary(DataInputStream in) throws IOException {
entityType = EntityType.values()[in.readShort()];
}
@Override
public CompoundTag toNBT(CompoundTag parent) {
@SuppressWarnings("unchecked") ListTag<CompoundTag> potentials = (ListTag<CompoundTag>) ListTag.createUnchecked(CompoundTag.class);
CompoundTag t = new CompoundTag();
CompoundTag ent = new CompoundTag();
ent.putString("id", entityType.getKey().toString());
t.put("Entity", ent);
t.putInt("Weight", 1);
potentials.add(t);
parent.put("SpawnPotentials", potentials);
return parent;
}
}

View File

@ -0,0 +1,16 @@
package com.volmit.iris.engine.object.annotations;
import com.volmit.iris.engine.framework.ListFunction;
import com.volmit.iris.util.collection.KList;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
@Target({PARAMETER, TYPE, FIELD})
public @interface RegistryListFunction {
Class<? extends ListFunction<KList<String>>> value();
}

View File

@ -0,0 +1,33 @@
package com.volmit.iris.engine.object.annotations.functions;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.framework.ListFunction;
import com.volmit.iris.util.collection.KList;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.loot.LootTable;
import org.bukkit.loot.LootTables;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
public class LootTableKeyFunction implements ListFunction<KList<String>> {
@Override
public String key() {
return "loot-table-key";
}
@Override
public String fancyName() {
return "LootTable Key";
}
@Override
public KList<String> apply(IrisData data) {
return StreamSupport.stream(Registry.LOOT_TABLES.spliterator(), false)
.map(LootTables::getLootTable)
.map(LootTable::getKey)
.map(NamespacedKey::toString)
.collect(Collectors.toCollection(KList::new));
}
}

View File

@ -0,0 +1,23 @@
package com.volmit.iris.engine.object.annotations.functions;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.engine.framework.ListFunction;
import com.volmit.iris.util.collection.KList;
public class StructureKeyFunction implements ListFunction<KList<String>> {
@Override
public String key() {
return "structure-key";
}
@Override
public String fancyName() {
return "Structure Key";
}
@Override
public KList<String> apply(IrisData irisData) {
return INMS.get().getStructureKeys();
}
}

View File

@ -129,31 +129,29 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
@EventHandler @EventHandler
public void onWorldInit(WorldInitEvent event) { public void onWorldInit(WorldInitEvent event) {
try { try {
if (!initialized) { if (initialized || !world.name().equals(event.getWorld().getName()))
world.setRawWorldSeed(event.getWorld().getSeed()); return;
if (world.name().equals(event.getWorld().getName())) { world.setRawWorldSeed(event.getWorld().getSeed());
Engine engine = getEngine(event.getWorld()); Engine engine = getEngine(event.getWorld());
if (engine == null) { if (engine == null) {
Iris.warn("Failed to get Engine!"); Iris.warn("Failed to get Engine!");
J.s(() -> { J.s(() -> {
Engine engine1 = getEngine(event.getWorld()); Engine engine1 = getEngine(event.getWorld());
if (engine1 != null) { if (engine1 != null) {
try { try {
INMS.get().inject(event.getWorld().getSeed(), engine1, event.getWorld()); INMS.get().inject(event.getWorld().getSeed(), engine1, event.getWorld());
Iris.info("Injected Iris Biome Source into " + event.getWorld().getName()); Iris.info("Injected Iris Biome Source into " + event.getWorld().getName());
initialized = true; initialized = true;
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
} }
}
}, 10);
} else {
INMS.get().inject(event.getWorld().getSeed(), engine, event.getWorld());
Iris.info("Injected Iris Biome Source into " + event.getWorld().getName());
spawnChunks.complete(INMS.get().getSpawnChunkCount(event.getWorld()));
initialized = true;
} }
} }, 10);
} else {
INMS.get().inject(event.getWorld().getSeed(), engine, event.getWorld());
Iris.info("Injected Iris Biome Source into " + event.getWorld().getName());
spawnChunks.complete(INMS.get().getSpawnChunkCount(event.getWorld()));
initialized = true;
} }
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -80,15 +80,6 @@ public class KList<T> extends ArrayList<T> implements List<T> {
return indexOf(v); return indexOf(v);
} }
/**
* Remove the last element
*/
public KList<T> removeLast() {
remove(last());
return this;
}
public void addMultiple(T t, int c) { public void addMultiple(T t, int c) {
for (int i = 0; i < c; i++) { for (int i = 0; i < c; i++) {
add(t); add(t);

View File

@ -28,6 +28,7 @@ import java.util.Comparator;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class KMap<K, V> extends ConcurrentHashMap<K, V> { public class KMap<K, V> extends ConcurrentHashMap<K, V> {
@ -151,6 +152,17 @@ public class KMap<K, V> extends ConcurrentHashMap<K, V> {
return this; return this;
} }
/**
* Merge with another map
*
* @param m the map to merge
* @return this map (builder)
*/
public KMap<K, V> merge(KMap<K, V> m, BiFunction<V, V, V> merger) {
m.forEach((k, v) -> merge(k, v, merger));
return this;
}
/** /**
* Return a copy of this map * Return a copy of this map
* *

View File

@ -20,6 +20,7 @@ package com.volmit.iris.util.data;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.Direction; import com.volmit.iris.util.math.Direction;
import com.volmit.iris.util.math.Position2;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.configuration.serialization.ConfigurationSerializable; import org.bukkit.configuration.serialization.ConfigurationSerializable;
@ -651,6 +652,10 @@ public class Cuboid implements Iterable<Block>, Cloneable, ConfigurationSerializ
return new CuboidIterator(getWorld(), x1, y1, z1, x2, y2, z2); return new CuboidIterator(getWorld(), x1, y1, z1, x2, y2, z2);
} }
public Iterator<Block> chunkedIterator() {
return new ChunkedCuboidIterator(getWorld(), x1, y1, z1, x2, y2, z2);
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
@ -746,4 +751,82 @@ public class Cuboid implements Iterable<Block>, Cloneable, ConfigurationSerializ
} }
} }
public static class ChunkedCuboidIterator implements Iterator<Block> {
private final World w;
private final int minRX, minY, minRZ, maxRX, maxY, maxRZ;
private final int minCX, minCZ, maxCX, maxCZ;
private int mX, mZ, bX, rX, rZ, y;
private Position2 chunk;
private int cX, cZ;
public ChunkedCuboidIterator(World w, int x1, int y1, int z1, int x2, int y2, int z2) {
this.w = w;
minY = Math.min(y1, y2);
maxY = Math.max(y1, y2);
int minX = Math.min(x1, x2);
int minZ = Math.min(z1, z2);
int maxX = Math.max(x1, x2);
int maxZ = Math.max(z1, z2);
minRX = minX & 15;
minRZ = minZ & 15;
maxRX = maxX & 15;
maxRZ = maxZ & 15;
minCX = minX >> 4;
minCZ = minZ >> 4;
maxCX = maxX >> 4;
maxCZ = maxZ >> 4;
cX = minCX;
cZ = minCZ;
rX = minX & 15;
rZ = minZ & 15;
y = minY;
}
@Override
public boolean hasNext() {
return chunk != null || hasNextChunk();
}
public boolean hasNextChunk() {
return cX <= maxCX && cZ <= maxCZ;
}
@Override
public Block next() {
if (chunk == null) {
chunk = new Position2(cX, cZ);
if (++cX > maxCX) {
cX = minCX;
cZ++;
}
mX = chunk.getX() == maxCX ? maxRX : 15;
mZ = chunk.getZ() == maxCZ ? maxRZ : 15;
rX = bX = chunk.getX() == minCX ? minRX : 0;
rZ = chunk.getZ() == minCZ ? minRZ : 0;
}
var b = w.getBlockAt((chunk.getX() << 4) + rX, y, (chunk.getZ() << 4) + rZ);
if (++y > maxY) {
y = minY;
if (++rX > mX) {
if (++rZ > mZ) {
chunk = null;
return b;
}
rX = bX;
}
}
return b;
}
@Override
public void remove() {
// nop
}
}
} }

View File

@ -42,11 +42,18 @@ public class WeightedRandom<T> {
totalWeight += weight; totalWeight += weight;
} }
public WeightedRandom<T> merge(WeightedRandom<T> other) {
weightedObjects.addAll(other.weightedObjects);
totalWeight += other.totalWeight;
return this;
}
public T pullRandom() { public T pullRandom() {
int pull = random.nextInt(totalWeight); int pull = random.nextInt(totalWeight);
int index = 0; int index = 0;
while (pull > 0) { while (pull > 0) {
pull -= weightedObjects.get(index).getV(); pull -= weightedObjects.get(index).getV();
if (pull <= 0) break;
index++; index++;
} }
return weightedObjects.get(index).getK(); return weightedObjects.get(index).getK();

View File

@ -997,7 +997,10 @@ public class IrisInterpolation {
return getNoise3D(method, x, y, z, rad, rad, rad, n); return getNoise3D(method, x, y, z, rad, rad, rad, n);
} }
public static double getNoise(InterpolationMethod method, int x, int z, double h, NoiseProvider n) { public static double getNoise(InterpolationMethod method, int x, int z, double h, NoiseProvider noise) {
HashMap<NoiseKey, Double> cache = new HashMap<>(64);
NoiseProvider n = (x1, z1) -> cache.computeIfAbsent(new NoiseKey(x1, z1), k -> noise.noise(k.x, k.z));
if (method.equals(InterpolationMethod.BILINEAR)) { if (method.equals(InterpolationMethod.BILINEAR)) {
return getBilinearNoise(x, z, h, n); return getBilinearNoise(x, z, h, n);
} else if (method.equals(InterpolationMethod.STARCAST_3)) { } else if (method.equals(InterpolationMethod.STARCAST_3)) {
@ -1058,4 +1061,7 @@ public class IrisInterpolation {
public static double rangeScale(double amin, double amax, double bmin, double bmax, double b) { public static double rangeScale(double amin, double amax, double bmin, double bmax, double b) {
return amin + ((amax - amin) * ((b - bmin) / (bmax - bmin))); return amin + ((amax - amin) * ((b - bmin) / (bmax - bmin)));
} }
public record NoiseKey(double x, double z) {
}
} }

View File

@ -0,0 +1,87 @@
package com.volmit.iris.util.io;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
public class CountingDataInputStream extends DataInputStream {
private final Counter counter;
private CountingDataInputStream(@NotNull InputStream in) {
super(in);
if (!(in instanceof Counter c))
throw new IllegalArgumentException("Underlying stream must be a Counter");
this.counter = c;
}
public static CountingDataInputStream wrap(@NotNull InputStream in) {
return new CountingDataInputStream(new Counter(in));
}
public long count() {
return counter.count;
}
public void skipTo(long target) throws IOException {
skipNBytes(Math.max(target - counter.count, 0));
}
@RequiredArgsConstructor
private static class Counter extends InputStream {
private final InputStream in;
private long count;
private long mark = -1;
private int markLimit = 0;
@Override
public int read() throws IOException {
int i = in.read();
if (i != -1) count(1);
return i;
}
@Override
public int read(@NotNull byte[] b, int off, int len) throws IOException {
int i = in.read(b, off, len);
count(i);
return i;
}
private void count(int i) {
count += i;
if (mark == -1)
return;
markLimit -= i;
if (markLimit <= 0)
mark = -1;
}
@Override
public boolean markSupported() {
return in.markSupported();
}
@Override
public synchronized void mark(int readlimit) {
if (!in.markSupported()) return;
in.mark(readlimit);
mark = count;
markLimit = readlimit;
}
@Override
public synchronized void reset() throws IOException {
in.reset();
count = mark;
}
@Override
public void close() throws IOException {
in.close();
}
}
}

View File

@ -28,9 +28,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.*; import java.util.*;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.zip.GZIPInputStream; import java.util.zip.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class IO { public class IO {
@ -113,6 +111,45 @@ public class IO {
return "¯\\_(ツ)_/¯"; return "¯\\_(ツ)_/¯";
} }
public static String hashRecursive(File base) {
LinkedList<File> files = new LinkedList<>();
Set<File> processed = new HashSet<>();
files.add(base);
try {
CRC32 crc = new CRC32();
while (!files.isEmpty()) {
File file = files.removeFirst();
if (!processed.add(file))
continue;
if (file.isDirectory()) {
File[] arr = file.listFiles();
if (arr == null)
continue;
Arrays.parallelSort(arr, Comparator.comparing(File::getName));
files.addAll(Arrays.asList(arr));
continue;
}
try (var fin = new FileInputStream(file)) {
var din = new CheckedInputStream(fin, crc);
fullTransfer(din, new VoidOutputStream(), 8192);
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
}
return Long.toHexString(crc.getValue());
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
return "";
}
public static String hash(File b) { public static String hash(File b) {
try { try {
MessageDigest d = MessageDigest.getInstance("SHA-256"); MessageDigest d = MessageDigest.getInstance("SHA-256");

View File

@ -567,9 +567,6 @@ public class Mantle {
} }
File file = fileForRegion(dataFolder, x, z); File file = fileForRegion(dataFolder, x, z);
if (!file.exists())
file = new File(dataFolder, file.getName().substring(".lz4b".length()));
if (file.exists()) { if (file.exists()) {
try { try {
Iris.addPanic("reading.tectonic-plate", file.getAbsolutePath()); Iris.addPanic("reading.tectonic-plate", file.getAbsolutePath());

View File

@ -21,12 +21,13 @@ package com.volmit.iris.util.mantle;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.function.Consumer4; import com.volmit.iris.util.function.Consumer4;
import com.volmit.iris.util.io.CountingDataInputStream;
import com.volmit.iris.util.matter.IrisMatter; import com.volmit.iris.util.matter.IrisMatter;
import com.volmit.iris.util.matter.Matter; import com.volmit.iris.util.matter.Matter;
import com.volmit.iris.util.matter.MatterSlice; import com.volmit.iris.util.matter.MatterSlice;
import lombok.Getter; import lombok.Getter;
import java.io.DataInputStream; import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.atomic.AtomicIntegerArray; import java.util.concurrent.atomic.AtomicIntegerArray;
@ -69,7 +70,7 @@ public class MantleChunk {
* @throws IOException shit happens * @throws IOException shit happens
* @throws ClassNotFoundException shit happens * @throws ClassNotFoundException shit happens
*/ */
public MantleChunk(int sectionHeight, DataInputStream din) throws IOException, ClassNotFoundException { public MantleChunk(int sectionHeight, CountingDataInputStream din) throws IOException {
this(sectionHeight, din.readByte(), din.readByte()); this(sectionHeight, din.readByte(), din.readByte());
int s = din.readByte(); int s = din.readByte();
@ -79,8 +80,23 @@ public class MantleChunk {
for (int i = 0; i < s; i++) { for (int i = 0; i < s; i++) {
Iris.addPanic("read.section", "Section[" + i + "]"); Iris.addPanic("read.section", "Section[" + i + "]");
if (din.readBoolean()) { long size = din.readInt();
if (size == 0) continue;
long start = din.count();
try {
sections.set(i, Matter.readDin(din)); sections.set(i, Matter.readDin(din));
} catch (IOException e) {
long end = start + size;
Iris.error("Failed to read chunk section, skipping it.");
Iris.addPanic("read.byte.range", start + " " + end);
Iris.addPanic("read.byte.current", din.count() + "");
Iris.reportError(e);
e.printStackTrace();
Iris.panic();
din.skipTo(end);
TectonicPlate.addError();
} }
} }
} }
@ -174,15 +190,22 @@ public class MantleChunk {
dos.writeBoolean(flags.get(i) == 1); dos.writeBoolean(flags.get(i) == 1);
} }
var bytes = new ByteArrayOutputStream(8192);
var sub = new DataOutputStream(bytes);
for (int i = 0; i < sections.length(); i++) { for (int i = 0; i < sections.length(); i++) {
trimSlice(i); trimSlice(i);
if (exists(i)) { if (exists(i)) {
dos.writeBoolean(true); try {
Matter matter = get(i); Matter matter = get(i);
matter.writeDos(dos); matter.writeDos(sub);
dos.writeInt(bytes.size());
bytes.writeTo(dos);
} finally {
bytes.reset();
}
} else { } else {
dos.writeBoolean(false); dos.writeInt(0);
} }
} }
} }

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