Merge branch 'refs/heads/dev' into feat/kts

# Conflicts:
#	core/build.gradle.kts
#	core/src/main/java/com/volmit/iris/Iris.java
#	core/src/main/java/com/volmit/iris/core/link/data/MythicMobsDataProvider.java
#	core/src/main/java/com/volmit/iris/util/misc/SlimJar.java
#	gradle/libs.versions.toml
This commit is contained in:
Julian Krings 2025-07-29 13:34:25 +02:00
commit 12c2c71739
No known key found for this signature in database
GPG Key ID: 208C6E08C3B718D2
57 changed files with 1756 additions and 1455 deletions

View File

@ -37,7 +37,7 @@ plugins {
} }
group = "com.volmit" group = "com.volmit"
version = "3.6.11-1.20.1-1.21.5" version = "3.7.0-1.20.1-1.21.7"
apply<ApiGenerator>() apply<ApiGenerator>()

View File

@ -1,5 +1,6 @@
import io.github.slimjar.func.slimjar import io.github.slimjar.func.slimjar
import io.github.slimjar.resolver.data.Mirror import io.github.slimjar.resolver.data.Mirror
import org.ajoberstar.grgit.Grgit
import java.net.URI import java.net.URI
/* /*
@ -26,6 +27,7 @@ plugins {
alias(libs.plugins.shadow) alias(libs.plugins.shadow)
alias(libs.plugins.sentry) alias(libs.plugins.sentry)
alias(libs.plugins.slimjar) alias(libs.plugins.slimjar)
alias(libs.plugins.grgit)
alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.lombok) alias(libs.plugins.kotlin.lombok)
} }
@ -154,6 +156,15 @@ tasks {
"version" to rootProject.version, "version" to rootProject.version,
"apiVersion" to apiVersion, "apiVersion" to apiVersion,
"main" to main, "main" to main,
"environment" to if (project.hasProperty("release")) "production" else "development",
"commit" to provider {
val res = runCatching { project.extensions.getByType<Grgit>().head().id }
res.getOrDefault("")
.takeIf { it.length == 40 } ?: {
logger.error("Git commit hash not found", res.exceptionOrNull())
"unknown"
}()
},
) )
filesMatching("**/plugin.yml") { filesMatching("**/plugin.yml") {
expand(inputs.properties) expand(inputs.properties)
@ -164,6 +175,7 @@ tasks {
mergeServiceFiles() mergeServiceFiles()
//minimize() //minimize()
relocate("io.github.slimjar", "$lib.slimjar") relocate("io.github.slimjar", "$lib.slimjar")
exclude("modules/loader-agent.isolated-jar")
} }
} }

View File

@ -22,10 +22,10 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.IrisWorlds;
import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.link.IrisPapiExpansion; import com.volmit.iris.core.link.IrisPapiExpansion;
import com.volmit.iris.core.link.MultiverseCoreLink; import com.volmit.iris.core.link.MultiverseCoreLink;
import com.volmit.iris.core.link.MythicMobsLink;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.v1X.NMSBinding1X; import com.volmit.iris.core.nms.v1X.NMSBinding1X;
@ -62,15 +62,11 @@ 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.Queue; import com.volmit.iris.util.scheduling.Queue;
import com.volmit.iris.util.scheduling.ShurikenQueue; import com.volmit.iris.util.scheduling.ShurikenQueue;
import io.github.slimjar.app.builder.ApplicationBuilder;
import lombok.NonNull; import lombok.NonNull;
import org.bukkit.*; 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;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.*; import org.bukkit.event.*;
import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.BiomeProvider;
@ -84,6 +80,7 @@ import java.io.*;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.net.URL; import java.net.URL;
import java.util.*; import java.util.*;
import java.util.function.Predicate;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -97,7 +94,6 @@ public class Iris extends VolmitPlugin implements Listener {
public static Iris instance; public static Iris instance;
public static Bindings.Adventure audiences; public static Bindings.Adventure audiences;
public static MultiverseCoreLink linkMultiverseCore; public static MultiverseCoreLink linkMultiverseCore;
public static MythicMobsLink linkMythicMobs;
public static IrisCompat compat; public static IrisCompat compat;
public static FileWatcher configWatcher; public static FileWatcher configWatcher;
private static VolmitSender sender; private static VolmitSender sender;
@ -439,11 +435,11 @@ public class Iris extends VolmitPlugin implements Listener {
} }
public Iris() { public Iris() {
instance = this;
SlimJar.load(getDataFolder("cache", "libraries")); SlimJar.load(getDataFolder("cache", "libraries"));
} }
private void enable() { private void enable() {
instance = this;
services = new KMap<>(); services = new KMap<>();
setupAudience(); setupAudience();
Bindings.setupSentry(); Bindings.setupSentry();
@ -456,7 +452,6 @@ public class Iris extends VolmitPlugin implements Listener {
getSender().setTag(getTag()); getSender().setTag(getTag());
IrisSafeguard.splash(true); IrisSafeguard.splash(true);
linkMultiverseCore = new MultiverseCoreLink(); linkMultiverseCore = new MultiverseCoreLink();
linkMythicMobs = new MythicMobsLink();
configWatcher = new FileWatcher(getDataFile("settings.json")); configWatcher = new FileWatcher(getDataFile("settings.json"));
services.values().forEach(IrisService::onEnable); services.values().forEach(IrisService::onEnable);
services.values().forEach(this::registerListener); services.values().forEach(this::registerListener);
@ -472,48 +467,34 @@ public class Iris extends VolmitPlugin implements Listener {
IrisSafeguard.splash(false); IrisSafeguard.splash(false);
autoStartStudio(); autoStartStudio();
checkForBukkitWorlds(); checkForBukkitWorlds(s -> true);
IrisToolbelt.retainMantleDataForSlice(String.class.getCanonicalName()); IrisToolbelt.retainMantleDataForSlice(String.class.getCanonicalName());
IrisToolbelt.retainMantleDataForSlice(BlockData.class.getCanonicalName()); IrisToolbelt.retainMantleDataForSlice(BlockData.class.getCanonicalName());
}); });
} }
private void checkForBukkitWorlds() { public void checkForBukkitWorlds(Predicate<String> filter) {
FileConfiguration fc = new YamlConfiguration();
try { try {
fc.load(new File("bukkit.yml")); IrisWorlds.readBukkitWorlds().forEach((s, generator) -> {
ConfigurationSection section = fc.getConfigurationSection("worlds"); try {
if (section == null) { if (Bukkit.getWorld(s) != null || !filter.test(s)) return;
return;
}
for (String s : section.getKeys(false)) { Iris.info("Loading World: %s | Generator: %s", s, generator);
ConfigurationSection entry = section.getConfigurationSection(s); var gen = getDefaultWorldGenerator(s, generator);
if (!entry.contains("generator", true)) { var dim = loadDimension(s, generator);
continue; assert dim != null && gen != null;
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "...");
WorldCreator c = new WorldCreator(s)
.generator(gen)
.environment(dim.getEnvironment());
INMS.get().createWorld(c);
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
} catch (Throwable e) {
Iris.error("Failed to load world " + s + "!");
e.printStackTrace();
} }
});
String generator = entry.getString("generator");
if (generator.startsWith("Iris:")) {
generator = generator.split("\\Q:\\E")[1];
} else if (generator.equalsIgnoreCase("Iris")) {
generator = IrisSettings.get().getGenerator().getDefaultWorldType();
} else {
continue;
}
if (Bukkit.getWorld(s) != null)
continue;
Iris.info("Loading World: %s | Generator: %s", s, generator);
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "...");
WorldCreator c = new WorldCreator(s)
.generator(getDefaultWorldGenerator(s, generator))
.environment(IrisData.loadAnyDimension(generator).getEnvironment());
INMS.get().createWorld(c);
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
}
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
reportError(e); reportError(e);

View File

@ -4,10 +4,14 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.io.IO; import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.misc.ServerProperties;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -25,6 +29,7 @@ public class IrisWorlds {
private IrisWorlds(KMap<String, String> worlds) { private IrisWorlds(KMap<String, String> worlds) {
this.worlds = worlds; this.worlds = worlds;
readBukkitWorlds().forEach(this::put0);
save(); save();
} }
@ -50,14 +55,33 @@ public class IrisWorlds {
} }
public void put(String name, String type) { public void put(String name, String type) {
String old = worlds.put(name, type); put0(name, type);
if (!type.equals(old))
dirty = true;
save(); save();
} }
public Stream<File> getFolders() { private void put0(String name, String type) {
return worlds.keySet().stream().map(k -> new File(Bukkit.getWorldContainer(), k)); String old = worlds.put(name, type);
if (!type.equals(old))
dirty = true;
}
public KMap<String, String> getWorlds() {
return readBukkitWorlds().put(worlds);
}
public Stream<IrisData> getPacks() {
return getDimensions()
.map(IrisDimension::getLoader)
.filter(Objects::nonNull);
}
public Stream<IrisDimension> getDimensions() {
return readBukkitWorlds()
.put(worlds)
.entrySet()
.stream()
.map(entry -> Iris.loadDimension(entry.getKey(), entry.getValue()))
.filter(Objects::nonNull);
} }
public void clean() { public void clean() {
@ -76,4 +100,27 @@ public class IrisWorlds {
Iris.reportError(e); Iris.reportError(e);
} }
} }
public static KMap<String, String> readBukkitWorlds() {
var bukkit = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML);
var worlds = bukkit.getConfigurationSection("worlds");
if (worlds == null) return new KMap<>();
var result = new KMap<String, String>();
for (String world : worlds.getKeys(false)) {
var gen = worlds.getString(world + ".generator");
if (gen == null) continue;
String loadKey;
if (gen.equalsIgnoreCase("iris")) {
loadKey = IrisSettings.get().getGenerator().getDefaultWorldType();
} else if (gen.startsWith("Iris:")) {
loadKey = gen.substring(5);
} else continue;
result.put(world, loadKey);
}
return result;
}
} }

View File

@ -44,6 +44,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicIntegerArray; import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -140,6 +141,7 @@ public class ServerConfigurator {
var loader = data.getDimensionLoader(); var loader = data.getDimensionLoader();
return loader.loadAll(loader.getPossibleKeys()) return loader.loadAll(loader.getPossibleKeys())
.stream() .stream()
.filter(Objects::nonNull)
.map(ServerConfigurator::verifyDataPackInstalled) .map(ServerConfigurator::verifyDataPackInstalled)
.toList() .toList()
.contains(false); .contains(false);
@ -235,14 +237,13 @@ public class ServerConfigurator {
} }
public static Stream<IrisData> allPacks() { public static Stream<IrisData> allPacks() {
return Stream.concat(listFiles(Iris.instance.getDataFolder("packs")), return Stream.concat(listFiles(Iris.instance.getDataFolder("packs"))
IrisWorlds.get().getFolders().map(w -> new File(w, "iris/pack")))
.filter(File::isDirectory) .filter(File::isDirectory)
.filter( base -> { .filter( base -> {
var content = new File(base, "dimensions").listFiles(); var content = new File(base, "dimensions").listFiles();
return content != null && content.length > 0; return content != null && content.length > 0;
}) })
.map(IrisData::get); .map(IrisData::get), IrisWorlds.get().getPacks());
} }
@Nullable @Nullable
@ -280,6 +281,7 @@ public class ServerConfigurator {
var loader = data.getDimensionLoader(); var loader = data.getDimensionLoader();
return loader.loadAll(loader.getPossibleKeys()) return loader.loadAll(loader.getPossibleKeys())
.stream() .stream()
.filter(Objects::nonNull)
.peek(this::merge); .peek(this::merge);
} }

View File

@ -46,18 +46,20 @@ import com.volmit.iris.util.interpolation.InterpolationMethod;
import com.volmit.iris.util.io.IO; import com.volmit.iris.util.io.IO;
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.mantle.MantleChunk;
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.Position2;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.math.Spiraler; import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.noise.CNG; import com.volmit.iris.util.noise.CNG;
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.parallel.SyncExecutor;
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.O; import com.volmit.iris.util.scheduling.O;
import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.scheduling.jobs.QueueJob; import com.volmit.iris.util.scheduling.jobs.ParallelQueueJob;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.inventory.InventoryType;
@ -76,8 +78,7 @@ import java.time.temporal.ChronoUnit;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ExecutionException; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -91,18 +92,19 @@ public class CommandStudio implements DecreeExecutor {
return duration.toString().substring(2).replaceAll("(\\d[HMS])(?!$)", "$1 ").toLowerCase(); return duration.toString().substring(2).replaceAll("(\\d[HMS])(?!$)", "$1 ").toLowerCase();
} }
//TODO fix pack trimming
@Decree(description = "Download a project.", aliases = "dl") @Decree(description = "Download a project.", aliases = "dl")
public void download( public void download(
@Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project") @Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project")
String pack, String pack,
@Param(name = "branch", description = "The branch to download from", defaultValue = "master") @Param(name = "branch", description = "The branch to download from", defaultValue = "master")
String branch, String branch,
@Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false") //@Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false")
boolean trim, //boolean trim,
@Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false") @Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false")
boolean overwrite boolean overwrite
) { ) {
new CommandIris().download(pack, branch, trim, overwrite); new CommandIris().download(pack, branch, overwrite);
} }
@Decree(description = "Open a new studio world", aliases = "o", sync = true) @Decree(description = "Open a new studio world", aliases = "o", sync = true)
@ -161,70 +163,77 @@ public class CommandStudio implements DecreeExecutor {
@Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5") @Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5")
int radius int radius
) { ) {
if (IrisToolbelt.isIrisWorld(player().getWorld())) { World world = player().getWorld();
VolmitSender sender = sender(); if (!IrisToolbelt.isIrisWorld(world)) {
J.a(() -> {
DecreeContext.touch(sender);
PlatformChunkGenerator plat = IrisToolbelt.access(player().getWorld());
Engine engine = plat.getEngine();
try {
Chunk cx = player().getLocation().getChunk();
KList<Runnable> js = new KList<>();
BurstExecutor b = MultiBurst.burst.burst();
b.setMulticore(false);
int rad = engine.getMantle().getRadius();
for (int i = -(radius + rad); i <= radius + rad; i++) {
for (int j = -(radius + rad); j <= radius + rad; j++) {
engine.getMantle().getMantle().deleteChunk(i + cx.getX(), j + cx.getZ());
}
}
for (int i = -radius; i <= radius; i++) {
for (int j = -radius; j <= radius; j++) {
int finalJ = j;
int finalI = i;
b.queue(() -> plat.injectChunkReplacement(player().getWorld(), finalI + cx.getX(), finalJ + cx.getZ(), (f) -> {
synchronized (js) {
js.add(f);
}
}));
}
}
b.complete();
sender().sendMessage(C.GREEN + "Regenerating " + Form.f(js.size()) + " Sections");
QueueJob<Runnable> r = new QueueJob<>() {
final KList<Future<?>> futures = new KList<>();
@Override
public void execute(Runnable runnable) {
futures.add(J.sfut(runnable));
if (futures.size() > 64) {
while (futures.isNotEmpty()) {
try {
futures.remove(0).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
@Override
public String getName() {
return "Regenerating";
}
};
r.queue(js);
r.execute(sender());
} catch (Throwable e) {
sender().sendMessage("Unable to parse view-distance");
}
});
} else {
sender().sendMessage(C.RED + "You must be in an Iris World to use regen!"); sender().sendMessage(C.RED + "You must be in an Iris World to use regen!");
} }
VolmitSender sender = sender();
var loc = player().getLocation().clone();
J.a(() -> {
DecreeContext.touch(sender);
PlatformChunkGenerator plat = IrisToolbelt.access(world);
Engine engine = plat.getEngine();
try (SyncExecutor executor = new SyncExecutor(20)) {
int x = loc.getBlockX() >> 4;
int z = loc.getBlockZ() >> 4;
int rad = engine.getMantle().getRadius();
var mantle = engine.getMantle().getMantle();
var chunkMap = new KMap<Position2, MantleChunk>();
for (int i = -(radius + rad); i <= radius + rad; i++) {
for (int j = -(radius + rad); j <= radius + rad; j++) {
int xx = i + x, zz = j + z;
if (Math.abs(i) <= radius && Math.abs(j) <= radius) {
mantle.deleteChunk(xx, zz);
continue;
}
chunkMap.put(new Position2(xx, zz), mantle.getChunk(xx, zz));
mantle.deleteChunk(xx, zz);
}
}
ParallelQueueJob<Position2> job = new ParallelQueueJob<>() {
@Override
public void execute(Position2 p) {
plat.injectChunkReplacement(world, p.getX(), p.getZ(), executor);
}
@Override
public String getName() {
return "Regenerating";
}
};
for (int i = -radius; i <= radius; i++) {
for (int j = -radius; j <= radius; j++) {
job.queue(new Position2(i + x, j + z));
}
}
CountDownLatch latch = new CountDownLatch(1);
job.execute(sender(), latch::countDown);
latch.await();
int sections = mantle.getWorldHeight() >> 4;
chunkMap.forEach((pos, chunk) -> {
var c = mantle.getChunk(pos.getX(), pos.getZ());
for (MantleFlag flag : MantleFlag.values()) {
c.flag(flag, chunk.isFlagged(flag));
}
c.clear();
for (int y = 0; y < sections; y++) {
var slice = chunk.get(y);
if (slice == null) continue;
var s = c.getOrCreate(y);
slice.getSliceMap().forEach(s::putSlice);
}
});
} catch (Throwable e) {
sender().sendMessage("Error while regenerating chunks");
e.printStackTrace();
}
});
} }
@Decree(description = "Convert objects in the \"convert\" folder") @Decree(description = "Convert objects in the \"convert\" folder")

View File

@ -1,24 +1,33 @@
package com.volmit.iris.core.link; package com.volmit.iris.core.link;
import com.volmit.iris.core.link.data.DataType;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.IrisCustomData; import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.math.RNG;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Entity;
import org.bukkit.event.Listener;
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.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.MissingResourceException; import java.util.MissingResourceException;
@Getter @Getter
@RequiredArgsConstructor @RequiredArgsConstructor
public abstract class ExternalDataProvider { public abstract class ExternalDataProvider implements Listener {
@NonNull @NonNull
private final String pluginId; private final String pluginId;
@ -53,7 +62,9 @@ public abstract class ExternalDataProvider {
* @throws MissingResourceException when the blockId is invalid * @throws MissingResourceException when the blockId is invalid
*/ */
@NotNull @NotNull
public abstract BlockData getBlockData(@NotNull Identifier blockId, @NotNull 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());
}
/** /**
* @see ExternalDataProvider#getItemStack(Identifier) * @see ExternalDataProvider#getItemStack(Identifier)
@ -73,7 +84,9 @@ public abstract class ExternalDataProvider {
* @throws MissingResourceException when the itemId is invalid * @throws MissingResourceException when the itemId is invalid
*/ */
@NotNull @NotNull
public abstract ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException; public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
}
/** /**
* This method is used for placing blocks that need to use the plugins api * This method is used for placing blocks that need to use the plugins api
@ -85,9 +98,43 @@ public abstract class ExternalDataProvider {
*/ */
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {} public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {}
public abstract @NotNull Identifier[] getBlockTypes(); /**
* Spawns a mob in the specified location using the given engine and entity identifier.
*
* @param location The location in the world where the mob should spawn. Must not be null.
* @param entityId The identifier of the mob entity to spawn. Must not be null.
* @return The spawned {@link Entity} if successful, or null if the mob could not be spawned.
*/
@Nullable
public Entity spawnMob(@NotNull Location location, @NotNull Identifier entityId) throws MissingResourceException {
throw new MissingResourceException("Failed to find Entity!", entityId.namespace(), entityId.key());
}
public abstract @NotNull Identifier[] getItemTypes(); public abstract @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType);
public abstract boolean isValidProvider(@NotNull Identifier id, boolean isItem); public abstract boolean isValidProvider(@NotNull Identifier id, DataType dataType);
protected static Pair<Float, BlockFace> parseYawAndFace(@NotNull Engine engine, @NotNull Block block, @NotNull KMap<@NotNull String, @NotNull String> state) {
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;
}
return new Pair<>(yaw, face);
}
} }

View File

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

View File

@ -0,0 +1,33 @@
package com.volmit.iris.core.link.data;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import java.util.MissingResourceException;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
public enum DataType implements BiPredicate<ExternalDataProvider, Identifier> {
ITEM,
BLOCK,
ENTITY;
@Override
public boolean test(ExternalDataProvider dataProvider, Identifier identifier) {
if (!dataProvider.isValidProvider(identifier, this)) return false;
try {
switch (this) {
case ITEM -> dataProvider.getItemStack(identifier);
case BLOCK -> dataProvider.getBlockData(identifier);
case ENTITY -> {}
}
return true;
} catch (MissingResourceException e) {
return false;
}
}
public Predicate<Identifier> asPredicate(ExternalDataProvider dataProvider) {
return i -> test(dataProvider, i);
}
}

View File

@ -1,16 +1,18 @@
package com.volmit.iris.core.link; package com.volmit.iris.core.link.data;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.reflect.WrappedField; import com.volmit.iris.util.reflect.WrappedField;
import com.willfp.ecoitems.items.EcoItem; import com.willfp.ecoitems.items.EcoItem;
import com.willfp.ecoitems.items.EcoItems; import com.willfp.ecoitems.items.EcoItems;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException; import java.util.MissingResourceException;
public class EcoItemsDataProvider extends ExternalDataProvider { public class EcoItemsDataProvider extends ExternalDataProvider {
@ -34,12 +36,6 @@ public class EcoItemsDataProvider extends ExternalDataProvider {
} }
} }
@NotNull
@Override
public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@NotNull @NotNull
@Override @Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException { public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
@ -48,30 +44,18 @@ public class EcoItemsDataProvider extends ExternalDataProvider {
return itemStack.get(item).clone(); return itemStack.get(item).clone();
} }
@NotNull
@Override @Override
public Identifier[] getBlockTypes() { public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
return new Identifier[0]; if (dataType != DataType.ITEM) return List.of();
} return EcoItems.INSTANCE.values()
.stream()
@NotNull .map(x -> Identifier.fromNamespacedKey(id.get(x)))
@Override .filter(dataType.asPredicate(this))
public Identifier[] getItemTypes() { .toList();
KList<Identifier> names = new KList<>();
for (EcoItem item : EcoItems.INSTANCE.values()) {
try {
Identifier key = Identifier.fromNamespacedKey(id.get(item));
if (getItemStack(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
return names.toArray(new Identifier[0]);
} }
@Override @Override
public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
return id.namespace().equalsIgnoreCase("ecoitems") && isItem; return id.namespace().equalsIgnoreCase("ecoitems") && dataType == DataType.ITEM;
} }
} }

View File

@ -1,13 +1,15 @@
package com.volmit.iris.core.link; package com.volmit.iris.core.link.data;
import com.ssomar.score.api.executableitems.ExecutableItemsAPI; import com.ssomar.score.api.executableitems.ExecutableItemsAPI;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.Optional; import java.util.Optional;
@ -21,12 +23,6 @@ public class ExecutableItemsDataProvider extends ExternalDataProvider {
Iris.info("Setting up ExecutableItems Link..."); Iris.info("Setting up ExecutableItems Link...");
} }
@NotNull
@Override
public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@NotNull @NotNull
@Override @Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException { public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
@ -35,30 +31,19 @@ public class ExecutableItemsDataProvider extends ExternalDataProvider {
.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 @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
return new Identifier[0]; if (dataType != DataType.ITEM) return List.of();
} return ExecutableItemsAPI.getExecutableItemsManager()
.getExecutableItemIdsList()
@NotNull .stream()
@Override .map(name -> new Identifier("executable_items", name))
public Identifier[] getItemTypes() { .filter(dataType.asPredicate(this))
KList<Identifier> names = new KList<>(); .toList();
for (String name : ExecutableItemsAPI.getExecutableItemsManager().getExecutableItemIdsList()) {
try {
Identifier key = new Identifier("executable_items", name);
if (getItemStack(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
return names.toArray(new Identifier[0]);
} }
@Override @Override
public boolean isValidProvider(@NotNull Identifier key, boolean isItem) { public boolean isValidProvider(@NotNull Identifier key, DataType dataType) {
return key.namespace().equalsIgnoreCase("executable_items") && isItem; return key.namespace().equalsIgnoreCase("executable_items") && dataType == DataType.ITEM;
} }
} }

View File

@ -1,10 +1,11 @@
package com.volmit.iris.core.link; package com.volmit.iris.core.link.data;
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.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.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.data.IrisCustomData; import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.reflect.WrappedField; import com.volmit.iris.util.reflect.WrappedField;
@ -18,6 +19,8 @@ import org.bukkit.block.data.type.Leaves;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -89,41 +92,20 @@ public class HMCLeavesDataProvider extends ExternalDataProvider {
} }
} }
@NotNull
@Override @Override
public Identifier[] getBlockTypes() { public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
KList<Identifier> names = new KList<>(); if (dataType == DataType.ENTITY) return List.of();
for (String name : blockDataMap.keySet()) { return (dataType == DataType.BLOCK ? blockDataMap.keySet() : itemDataField.keySet())
try { .stream()
Identifier key = new Identifier("hmcleaves", name); .map(x -> new Identifier("hmcleaves", x))
if (getBlockData(key) != null) .filter(dataType.asPredicate(this))
names.add(key); .toList();
} catch (MissingResourceException ignored) {
}
}
return names.toArray(new Identifier[0]);
}
@NotNull
@Override
public Identifier[] getItemTypes() {
KList<Identifier> names = new KList<>();
for (String name : itemDataField.keySet()) {
try {
Identifier key = new Identifier("hmcleaves", name);
if (getItemStack(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
return names.toArray(new Identifier[0]);
} }
@Override @Override
public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
return (isItem ? itemDataField.keySet() : blockDataMap.keySet()).contains(id.key()); if (dataType == DataType.ENTITY) return false;
return (dataType == DataType.ITEM ? itemDataField.keySet() : blockDataMap.keySet()).contains(id.key());
} }
private <C, T> Map<String, T> getMap(C config, String name) { private <C, T> Map<String, T> getMap(C config, String name) {

View File

@ -0,0 +1,89 @@
package com.volmit.iris.core.link.data;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
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.IrisCustomData;
import dev.lone.itemsadder.api.CustomBlock;
import dev.lone.itemsadder.api.CustomStack;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
public class ItemAdderDataProvider extends ExternalDataProvider {
private KList<String> itemNamespaces, blockNamespaces;
public ItemAdderDataProvider() {
super("ItemsAdder");
}
@Override
public void init() {
this.itemNamespaces = new KList<>();
this.blockNamespaces = new KList<>();
for (Identifier i : getTypes(DataType.ITEM)) {
itemNamespaces.addIfMissing(i.namespace());
}
for (Identifier i : getTypes(DataType.BLOCK)) {
blockNamespaces.addIfMissing(i.namespace());
Iris.info("Found ItemAdder Block: " + i);
}
}
@NotNull
@Override
public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
CustomBlock block = CustomBlock.getInstance(blockId.toString());
if (block == null) {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
return new IrisCustomData(B.getAir(), blockId);
}
@NotNull
@Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
CustomStack stack = CustomStack.getInstance(itemId.toString());
if (stack == null) {
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
}
return stack.getItemStack();
}
@Override
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
CustomBlock.place(blockId.toString(), block.getLocation());
}
@Override
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
return switch (dataType) {
case ENTITY -> List.of();
case ITEM -> CustomStack.getNamespacedIdsInRegistry()
.stream()
.map(Identifier::fromString)
.toList();
case BLOCK -> CustomBlock.getNamespacedIdsInRegistry()
.stream()
.map(Identifier::fromString)
.toList();
};
}
@Override
public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
if (dataType == DataType.ENTITY) return false;
return dataType == DataType.ITEM ? this.itemNamespaces.contains(id.namespace()) : this.blockNamespaces.contains(id.namespace());
}
}

View File

@ -1,5 +1,7 @@
package com.volmit.iris.core.link; package com.volmit.iris.core.link.data;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
@ -14,6 +16,8 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException; import java.util.MissingResourceException;
public class KGeneratorsDataProvider extends ExternalDataProvider { public class KGeneratorsDataProvider extends ExternalDataProvider {
@ -54,35 +58,17 @@ public class KGeneratorsDataProvider extends ExternalDataProvider {
} }
@Override @Override
public @NotNull Identifier[] getBlockTypes() { public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
if (dataType == DataType.ENTITY) return List.of();
return Main.getGenerators().getAll().stream() return Main.getGenerators().getAll().stream()
.map(gen -> new Identifier("kgenerators", gen.getId())) .map(gen -> new Identifier("kgenerators", gen.getId()))
.filter(i -> { .filter(dataType.asPredicate(this))
try { .toList();
return getBlockData(i) != null;
} catch (MissingResourceException e) {
return false;
}
})
.toArray(Identifier[]::new);
} }
@Override @Override
public @NotNull Identifier[] getItemTypes() { public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
return Main.getGenerators().getAll().stream() if (dataType == DataType.ENTITY) return false;
.map(gen -> new Identifier("kgenerators", gen.getId()))
.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 "kgenerators".equalsIgnoreCase(id.namespace()); return "kgenerators".equalsIgnoreCase(id.namespace());
} }
} }

View File

@ -1,21 +1,24 @@
package com.volmit.iris.core.link; package com.volmit.iris.core.link.data;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
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.ItemTier;
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 org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
public class MMOItemsDataProvider extends ExternalDataProvider { public class MMOItemsDataProvider extends ExternalDataProvider {
@ -85,52 +88,35 @@ public class MMOItemsDataProvider extends ExternalDataProvider {
return item; return item;
} }
@NotNull
@Override @Override
public Identifier[] getBlockTypes() { public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
KList<Identifier> names = new KList<>(); return switch (dataType) {
for (Integer id : api().getCustomBlocks().getBlockIds()) { case ENTITY -> List.of();
try { case BLOCK -> api().getCustomBlocks().getBlockIds().stream().map(id -> new Identifier("mmoitems", String.valueOf(id)))
Identifier key = new Identifier("mmoitems", String.valueOf(id)); .filter(dataType.asPredicate(this))
if (getBlockData(key) != null) .toList();
names.add(key); case ITEM -> {
} catch (MissingResourceException ignored) { Supplier<Collection<Identifier>> supplier = () -> api().getTypes()
} .getAll()
} .stream()
return names.toArray(new Identifier[0]); .flatMap(type -> api()
} .getTemplates()
.getTemplateNames(type)
.stream()
.map(name -> new Identifier("mmoitems_" + type.getId(), name)))
.filter(dataType.asPredicate(this))
.toList();
@NotNull if (Bukkit.isPrimaryThread()) yield supplier.get();
@Override else yield J.sfut(supplier).join();
public Identifier[] getItemTypes() {
KList<Identifier> names = new KList<>();
Runnable run = () -> {
for (Type type : api().getTypes().getAll()) {
for (String name : api().getTemplates().getTemplateNames(type)) {
try {
Identifier key = new Identifier("mmoitems_" + type.getId(), name);
if (getItemStack(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
} }
}; };
if (Bukkit.isPrimaryThread()) run.run();
else {
try {
J.sfut(run).get();
} catch (InterruptedException | ExecutionException e) {
Iris.error("Failed getting MMOItems item types!");
Iris.reportError(e);
}
}
return names.toArray(new Identifier[0]);
} }
@Override @Override
public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
return isItem ? id.namespace().split("_", 2).length == 2 : id.namespace().equals("mmoitems"); if (dataType == DataType.ENTITY) return false;
return dataType == DataType.ITEM ? id.namespace().split("_", 2).length == 2 : id.namespace().equals("mmoitems");
} }
private MMOItems api() { private MMOItems api() {

View File

@ -16,19 +16,18 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.volmit.iris.core.link; package com.volmit.iris.core.link.data;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.service.ExternalDataSVC; 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.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.data.B; import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisCustomData; import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.math.RNG;
import io.lumine.mythic.bukkit.BukkitAdapter; import io.lumine.mythic.bukkit.BukkitAdapter;
import io.lumine.mythic.bukkit.utils.serialize.Chroma; import io.lumine.mythic.bukkit.utils.serialize.Chroma;
import io.lumine.mythiccrucible.MythicCrucible; import io.lumine.mythiccrucible.MythicCrucible;
@ -37,11 +36,11 @@ import io.lumine.mythiccrucible.items.ItemManager;
import io.lumine.mythiccrucible.items.blocks.CustomBlockItemContext; import io.lumine.mythiccrucible.items.blocks.CustomBlockItemContext;
import io.lumine.mythiccrucible.items.furniture.FurnitureItemContext; import io.lumine.mythiccrucible.items.furniture.FurnitureItemContext;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
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 org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.Optional; import java.util.Optional;
@ -88,69 +87,27 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider {
.generateItemStack(1)); .generateItemStack(1));
} }
@NotNull
@Override @Override
public Identifier[] getBlockTypes() { public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
KList<Identifier> names = new KList<>(); return itemManager.getItems()
for (CrucibleItem item : this.itemManager.getItems()) { .stream()
if (item.getBlockData() == null) continue; .map(i -> new Identifier("crucible", i.getInternalName()))
try { .filter(dataType.asPredicate(this))
Identifier key = new Identifier("crucible", item.getInternalName()); .toList();
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 @Override
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) { public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
var pair = ExternalDataSVC.parseState(blockId); var parsedState = ExternalDataSVC.parseState(blockId);
var state = pair.getB(); var state = parsedState.getB();
blockId = pair.getA(); blockId = parsedState.getA();
Optional<CrucibleItem> item = itemManager.getItem(blockId.key()); Optional<CrucibleItem> item = itemManager.getItem(blockId.key());
if (item.isEmpty()) return; if (item.isEmpty()) return;
FurnitureItemContext furniture = item.get().getFurnitureData(); FurnitureItemContext furniture = item.get().getFurnitureData();
if (furniture == null) return; if (furniture == null) return;
float yaw = 0; var pair = parseYawAndFace(engine, block, state);
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; BiomeColor type = null;
Chroma color = null; Chroma color = null;
try { try {
@ -161,11 +118,12 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider {
if (biomeColor == null) return; if (biomeColor == null) return;
color = Chroma.of(biomeColor.getRGB()); color = Chroma.of(biomeColor.getRGB());
} }
furniture.place(block, face, yaw, color); furniture.place(block, pair.getB(), pair.getA(), color);
} }
@Override @Override
public boolean isValidProvider(@NotNull Identifier key, boolean isItem) { public boolean isValidProvider(@NotNull Identifier key, DataType dataType) {
if (dataType == DataType.ENTITY) return false;
return key.namespace().equalsIgnoreCase("crucible"); return key.namespace().equalsIgnoreCase("crucible");
} }
} }

View File

@ -1,25 +1,7 @@
/* package com.volmit.iris.core.link.data;
* 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.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.google.common.collect.Sets;
import com.volmit.iris.Iris;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
import io.lumine.mythic.api.adapters.AbstractLocation; import io.lumine.mythic.api.adapters.AbstractLocation;
import io.lumine.mythic.api.config.MythicLineConfig; import io.lumine.mythic.api.config.MythicLineConfig;
@ -30,60 +12,60 @@ import io.lumine.mythic.bukkit.events.MythicConditionLoadEvent;
import io.lumine.mythic.core.skills.SkillCondition; import io.lumine.mythic.core.skills.SkillCondition;
import io.lumine.mythic.core.utils.annotations.MythicCondition; import io.lumine.mythic.core.utils.annotations.MythicCondition;
import io.lumine.mythic.core.utils.annotations.MythicField; import io.lumine.mythic.core.utils.annotations.MythicField;
import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.jetbrains.annotations.NotNull;
import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class MythicMobsLink { public class MythicMobsDataProvider extends ExternalDataProvider {
public MythicMobsDataProvider() {
public MythicMobsLink() { super("MythicMobs");
if (getPlugin() == null) return;
Iris.instance.registerListener(new ConditionListener());
} }
public boolean isEnabled() { @Override
return getPlugin() != null; public void init() {
} }
public Plugin getPlugin() { @Override
return Bukkit.getPluginManager().getPlugin("MythicMobs"); public @Nullable Entity spawnMob(@NotNull Location location, @NotNull Identifier entityId) throws MissingResourceException {
var mm = MythicBukkit.inst().getMobManager().spawnMob(entityId.key(), location);
if (mm == null) throw new MissingResourceException("Failed to find mob!", entityId.namespace(), entityId.key());
return mm.getEntity().getBukkitEntity();
} }
/** @Override
* Spawn a mythic mob at this location public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
* if (dataType != DataType.ENTITY) return List.of();
* @param mob The mob return MythicBukkit.inst()
* @param location The location .getMobManager()
* @return The mob, or null if it can't be spawned .getMobNames()
*/ .stream()
public @Nullable Entity spawnMob(String mob, Location location) { .map(name -> new Identifier("mythicmobs", name))
return isEnabled() ? MythicBukkit.inst().getMobManager().spawnMob(mob, location).getEntity().getBukkitEntity() : null; .toList();
} }
public Collection<String> getMythicMobTypes() { @Override
return isEnabled() ? MythicBukkit.inst().getMobManager().getMobNames() : List.of(); public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
return id.namespace().equalsIgnoreCase("mythicmobs") && dataType == DataType.ENTITY;
} }
private static class ConditionListener implements Listener { @EventHandler
@EventHandler public void on(MythicConditionLoadEvent event) {
public void on(MythicConditionLoadEvent event) { switch (event.getConditionName()) {
switch (event.getConditionName()) { case "irisbiome" -> event.register(new IrisBiomeCondition(event.getConditionName(), event.getConfig()));
case "irisbiome" -> event.register(new IrisBiomeCondition(event.getConditionName(), event.getConfig())); case "irisregion" -> event.register(new IrisRegionCondition(event.getConditionName(), event.getConfig()));
case "irisregion" -> event.register(new IrisRegionCondition(event.getConditionName(), event.getConfig()));
}
} }
} }
@MythicCondition(author = "CrazyDev22", name = "irisbiome", description = "Tests if the target is within the given list of biomes") @MythicCondition(author = "CrazyDev22", name = "irisbiome", description = "Tests if the target is within the given list of biomes")
public static class IrisBiomeCondition extends SkillCondition implements ILocationCondition { public static class IrisBiomeCondition extends SkillCondition implements ILocationCondition {
@MythicField(name = "biome", aliases = {"b"}, description = "A list of biomes to check") @MythicField(name = "biome", aliases = {"b"}, description = "A list of biomes to check")
private Set<String> biomes = Sets.newConcurrentHashSet(); private Set<String> biomes = ConcurrentHashMap.newKeySet();
@MythicField(name = "surface", aliases = {"s"}, description = "If the biome check should only be performed on the surface") @MythicField(name = "surface", aliases = {"s"}, description = "If the biome check should only be performed on the surface")
private boolean surface; private boolean surface;
@ -107,10 +89,10 @@ public class MythicMobsLink {
} }
} }
@MythicCondition(author = "CrazyDev22", name = "irisbiome", description = "Tests if the target is within the given list of biomes") @MythicCondition(author = "CrazyDev22", name = "irisregion", description = "Tests if the target is within the given list of biomes")
public static class IrisRegionCondition extends SkillCondition implements ILocationCondition { public static class IrisRegionCondition extends SkillCondition implements ILocationCondition {
@MythicField(name = "region", aliases = {"r"}, description = "A list of regions to check") @MythicField(name = "region", aliases = {"r"}, description = "A list of regions to check")
private Set<String> regions = Sets.newConcurrentHashSet(); private Set<String> regions = ConcurrentHashMap.newKeySet();
public IrisRegionCondition(String line, MythicLineConfig mlc) { public IrisRegionCondition(String line, MythicLineConfig mlc) {
super(line); super(line);

View File

@ -1,28 +1,30 @@
package com.volmit.iris.core.link; package com.volmit.iris.core.link.data;
import com.nexomc.nexo.api.NexoBlocks; import com.nexomc.nexo.api.NexoBlocks;
import com.nexomc.nexo.api.NexoFurniture; import com.nexomc.nexo.api.NexoFurniture;
import com.nexomc.nexo.api.NexoItems; import com.nexomc.nexo.api.NexoItems;
import com.nexomc.nexo.items.ItemBuilder; import com.nexomc.nexo.items.ItemBuilder;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.service.ExternalDataSVC; 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.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisCustomData; import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.math.RNG;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.entity.ItemDisplay; import org.bukkit.entity.ItemDisplay;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.bukkit.inventory.meta.MapMeta;
import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.inventory.meta.PotionMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Arrays; import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -69,9 +71,9 @@ public class NexoDataProvider extends ExternalDataProvider {
@Override @Override
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) { public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
var pair = ExternalDataSVC.parseState(blockId); var statePair = ExternalDataSVC.parseState(blockId);
var state = pair.getB(); var state = statePair.getB();
blockId = pair.getA(); blockId = statePair.getA();
if (NexoBlocks.isCustomBlock(blockId.key())) { if (NexoBlocks.isCustomBlock(blockId.key())) {
NexoBlocks.place(blockId.key(), block.getLocation()); NexoBlocks.place(blockId.key(), block.getLocation());
@ -81,26 +83,8 @@ public class NexoDataProvider extends ExternalDataProvider {
if (!NexoFurniture.isFurniture(blockId.key())) if (!NexoFurniture.isFurniture(blockId.key()))
return; return;
float yaw = 0; var pair = parseYawAndFace(engine, block, state);
BlockFace face = BlockFace.NORTH; ItemDisplay display = NexoFurniture.place(blockId.key(), block.getLocation(), pair.getA(), pair.getB());
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; if (display == null) return;
ItemStack itemStack = display.getItemStack(); ItemStack itemStack = display.getItemStack();
if (itemStack == null) return; if (itemStack == null) return;
@ -114,46 +98,31 @@ public class NexoDataProvider extends ExternalDataProvider {
var biomeColor = INMS.get().getBiomeColor(block.getLocation(), type); var biomeColor = INMS.get().getBiomeColor(block.getLocation(), type);
if (biomeColor == null) return; if (biomeColor == null) return;
var potionColor = Color.fromARGB(biomeColor.getAlpha(), biomeColor.getRed(), biomeColor.getGreen(), biomeColor.getBlue()); var potionColor = Color.fromARGB(biomeColor.getAlpha(), biomeColor.getRed(), biomeColor.getGreen(), biomeColor.getBlue());
if (itemStack.getItemMeta() instanceof PotionMeta meta) { var meta = itemStack.getItemMeta();
meta.setColor(potionColor); switch (meta) {
itemStack.setItemMeta(meta); case LeatherArmorMeta armor -> armor.setColor(potionColor);
case PotionMeta potion -> potion.setColor(potionColor);
case MapMeta map -> map.setColor(potionColor);
case null, default -> {}
} }
itemStack.setItemMeta(meta);
} }
display.setItemStack(itemStack); display.setItemStack(itemStack);
} }
@NotNull
@Override @Override
public Identifier[] getBlockTypes() { public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
return NexoItems.itemNames().stream() if (dataType == DataType.ENTITY) return List.of();
return NexoItems.itemNames()
.stream()
.map(i -> new Identifier("nexo", i)) .map(i -> new Identifier("nexo", i))
.filter(i -> { .filter(dataType.asPredicate(this))
try { .toList();
return getBlockData(i) != null;
} catch (MissingResourceException e) {
return false;
}
})
.toArray(Identifier[]::new);
}
@NotNull
@Override
public Identifier[] getItemTypes() {
return NexoItems.itemNames().stream()
.map(i -> new Identifier("nexo", i))
.filter(i -> {
try {
return getItemStack(i) != null;
} catch (MissingResourceException e) {
return false;
}
})
.toArray(Identifier[]::new);
} }
@Override @Override
public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
if (dataType == DataType.ENTITY) return false;
return "nexo".equalsIgnoreCase(id.namespace()); return "nexo".equalsIgnoreCase(id.namespace());
} }

View File

@ -24,22 +24,23 @@ import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import java.util.List; import java.util.List;
import java.util.Map;
public class INMS { public class INMS {
private static final Map<String, String> REVISION = Map.of( private static final Version CURRENT = Boolean.getBoolean("iris.no-version-limit") ?
"1.20.5", "v1_20_R4", new Version(Integer.MAX_VALUE, Integer.MAX_VALUE, null) :
"1.20.6", "v1_20_R4", new Version(21, 8, null);
"1.21", "v1_21_R1",
"1.21.1", "v1_21_R1", private static final List<Version> REVISION = List.of(
"1.21.2", "v1_21_R2", new Version(21, 6, "v1_21_R5"),
"1.21.3", "v1_21_R2", new Version(21, 5, "v1_21_R4"),
"1.21.4", "v1_21_R3", new Version(21, 4, "v1_21_R3"),
"1.21.5", "v1_21_R4", new Version(21, 2, "v1_21_R2"),
"1.21.6", "v1_21_R5", new Version(21, 0, "v1_21_R1"),
"1.21.7", "v1_21_R5" new Version(20, 5, "v1_20_R4")
); );
private static final List<Version> PACKS = List.of( private static final List<Version> PACKS = List.of(
new Version(21, 5, "31100"),
new Version(21, 4, "31020"), new Version(21, 4, "31020"),
new Version(21, 2, "31000"), new Version(21, 2, "31000"),
new Version(20, 1, "3910") new Version(20, 1, "3910")
@ -47,7 +48,7 @@ public class INMS {
//@done //@done
private static final INMSBinding binding = bind(); private static final INMSBinding binding = bind();
public static final String OVERWORLD_TAG = getOverworldTag(); public static final String OVERWORLD_TAG = getTag(PACKS, "3910");
public static INMSBinding get() { public static INMSBinding get() {
return binding; return binding;
@ -61,7 +62,7 @@ public class INMS {
try { try {
String name = Bukkit.getServer().getClass().getCanonicalName(); String name = Bukkit.getServer().getClass().getCanonicalName();
if (name.equals("org.bukkit.craftbukkit.CraftServer")) { if (name.equals("org.bukkit.craftbukkit.CraftServer")) {
return REVISION.getOrDefault(Bukkit.getServer().getBukkitVersion().split("-")[0], "BUKKIT"); return getTag(REVISION, "BUKKIT");
} else { } else {
return name.split("\\Q.\\E")[3]; return name.split("\\Q.\\E")[3];
} }
@ -99,7 +100,7 @@ public class INMS {
return new NMSBinding1X(); return new NMSBinding1X();
} }
private static String getOverworldTag() { private static String getTag(List<Version> versions, String def) {
var version = Bukkit.getServer().getBukkitVersion().split("-")[0].split("\\.", 3); var version = Bukkit.getServer().getBukkitVersion().split("-")[0].split("\\.", 3);
int major = 0; int major = 0;
int minor = 0; int minor = 0;
@ -110,13 +111,16 @@ public class INMS {
} else if (version.length == 2) { } else if (version.length == 2) {
major = Integer.parseInt(version[1]); major = Integer.parseInt(version[1]);
} }
if (CURRENT.major < major || CURRENT.minor < minor) {
return versions.getFirst().tag;
}
for (var p : PACKS) { for (var p : versions) {
if (p.major > major || p.minor > minor) if (p.major > major || p.minor > minor)
continue; continue;
return p.tag; return p.tag;
} }
return "3910"; return def;
} }
private record Version(int major, int minor, String tag) {} private record Version(int major, int minor, String tag) {}

View File

@ -153,12 +153,11 @@ public class IrisPregenerator {
} }
private long computeETA() { private long computeETA() {
double d = (long) (totalChunks.get() > 1024 ? // Generated chunks exceed 1/8th of total? double d = (long) (generated.get() > 1024 ? // Generated chunks exceed 1/8th of total?
// If yes, use smooth function (which gets more accurate over time since its less sensitive to outliers) // If yes, use smooth function (which gets more accurate over time since its less sensitive to outliers)
((totalChunks.get() - generated.get() - cached.get()) * ((double) (M.ms() - startTime.get()) / ((double) generated.get() - cached.get()))) : ((totalChunks.get() - generated.get()) * ((double) (M.ms() - startTime.get()) / (double) generated.get())) :
// If no, use quick function (which is less accurate over time but responds better to the initial delay) // If no, use quick function (which is less accurate over time but responds better to the initial delay)
((totalChunks.get() - generated.get() - cached.get()) / chunksPerSecond.getAverage()) * 1000 ((totalChunks.get() - generated.get()) / chunksPerSecond.getAverage()) * 1000);
);
return Double.isFinite(d) && d != INVALID ? (long) d : 0; return Double.isFinite(d) && d != INVALID ? (long) d : 0;
} }

View File

@ -19,9 +19,12 @@
package com.volmit.iris.core.project; package com.volmit.iris.core.project;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.link.data.DataType;
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.loader.ResourceLoader; import com.volmit.iris.core.loader.ResourceLoader;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
@ -39,7 +42,6 @@ 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.function.Function;
import java.util.stream.Collectors;
public class SchemaBuilder { public class SchemaBuilder {
private static final String SYMBOL_LIMIT__N = "*"; private static final String SYMBOL_LIMIT__N = "*";
@ -268,16 +270,18 @@ public class SchemaBuilder {
if (!definitions.containsKey(key)) { if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject(); JSONObject j = new JSONObject();
KList<String> list = new KList<>(); KList<String> list = Iris.service(ExternalDataSVC.class)
list.addAll(Iris.linkMythicMobs.getMythicMobTypes().stream().map(s -> "MythicMobs:" + s).collect(Collectors.toList())); .getAllIdentifiers(DataType.ENTITY)
//TODO add Citizens stuff here too .stream()
.map(Identifier::toString)
.collect(KList.collector());
j.put("enum", list.toJSONStringArray()); j.put("enum", list.toJSONStringArray());
definitions.put(key, j); definitions.put(key, j);
} }
fancyType = "Mythic Mob Type"; fancyType = "Custom Mob Type";
prop.put("$ref", "#/definitions/" + key); prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Mythic Mob Type (use ctrl+space for auto complete!) Define mythic mobs with the mythic mobs plugin configuration files."); description.add(SYMBOL_TYPE__N + " Must be a valid Custom Mob Type (use ctrl+space for auto complete!)");
} else if (k.isAnnotationPresent(RegistryListFont.class)) { } else if (k.isAnnotationPresent(RegistryListFont.class)) {
String key = "enum-font"; String key = "enum-font";

View File

@ -1,15 +1,13 @@
package com.volmit.iris.core.safeguard; package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisWorlds;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.v1X.NMSBinding1X; import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.agent.Agent; import com.volmit.iris.util.agent.Agent;
import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.misc.ServerProperties;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import javax.tools.JavaCompiler; import javax.tools.JavaCompiler;
@ -21,6 +19,7 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import static com.volmit.iris.Iris.getJavaVersion; import static com.volmit.iris.Iris.getJavaVersion;
import static com.volmit.iris.core.safeguard.IrisSafeguard.*; import static com.volmit.iris.core.safeguard.IrisSafeguard.*;
@ -187,27 +186,9 @@ public class ServerBootSFG {
} }
private static KSet<String> getDimensionTypes() { private static KSet<String> getDimensionTypes() {
var bukkit = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML); return IrisWorlds.get()
var worlds = bukkit.getConfigurationSection("worlds"); .getDimensions()
if (worlds == null) return new KSet<>(); .map(IrisDimension::getDimensionTypeKey)
.collect(Collectors.toCollection(KSet::new));
var types = new KSet<String>();
for (String world : worlds.getKeys(false)) {
var gen = worlds.getString(world + ".generator");
if (gen == null) continue;
String loadKey;
if (gen.equalsIgnoreCase("iris")) {
loadKey = IrisSettings.get().getGenerator().getDefaultWorldType();
} else if (gen.startsWith("Iris:")) {
loadKey = gen.substring(5);
} else continue;
IrisDimension dimension = Iris.loadDimension(world, loadKey);
if (dimension == null) continue;
types.add(dimension.getDimensionTypeKey());
}
return types;
} }
} }

View File

@ -20,16 +20,21 @@ package com.volmit.iris.core.service;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.link.*; import com.volmit.iris.core.link.*;
import com.volmit.iris.core.link.data.DataType;
import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.io.JarScanner;
import com.volmit.iris.util.plugin.IrisService; import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.scheduling.J;
import lombok.Data; import lombok.Data;
import lombok.NonNull; import lombok.NonNull;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location;
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.entity.Entity;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.server.PluginEnableEvent; import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -47,43 +52,12 @@ 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 NexoDataProvider()); providers.addAll(createProviders());
if (Bukkit.getPluginManager().getPlugin("Nexo") != null) {
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());
if (Bukkit.getPluginManager().getPlugin("ItemAdder") != null) {
Iris.info("ItemAdder found, loading ItemAdderDataProvider...");
}
providers.add(new ExecutableItemsDataProvider());
if (Bukkit.getPluginManager().getPlugin("ExecutableItems") != null) {
Iris.info("ExecutableItems found, loading ExecutableItemsDataProvider...");
}
providers.add(new HMCLeavesDataProvider());
if (Bukkit.getPluginManager().getPlugin("HMCLeaves") != null) {
Iris.info("BlockAdder found, loading HMCLeavesDataProvider...");
}
providers.add(new MMOItemsDataProvider());
if (Bukkit.getPluginManager().getPlugin("MMOItems") != null) {
Iris.info("MMOItems found, loading MMOItemsDataProvider...");
}
providers.add(new EcoItemsDataProvider());
if (Bukkit.getPluginManager().getPlugin("EcoItems") != null) {
Iris.info("EcoItems found, loading EcoItemsDataProvider...");
}
providers.add(new KGeneratorsDataProvider());
if (Bukkit.getPluginManager().getPlugin("KGenerators") != null) {
Iris.info("KGenerators found, loading KGeneratorsDataProvider...");
}
for (ExternalDataProvider p : providers) { for (ExternalDataProvider p : providers) {
if (p.isReady()) { if (p.isReady()) {
activeProviders.add(p); activeProviders.add(p);
p.init(); p.init();
Iris.instance.registerListener(p);
Iris.info("Enabled ExternalDataProvider for %s.", p.getPluginId()); Iris.info("Enabled ExternalDataProvider for %s.", p.getPluginId());
} }
} }
@ -99,6 +73,7 @@ public class ExternalDataSVC implements IrisService {
providers.stream().filter(p -> p.isReady() && p.getPlugin().equals(e.getPlugin())).findFirst().ifPresent(edp -> { providers.stream().filter(p -> p.isReady() && p.getPlugin().equals(e.getPlugin())).findFirst().ifPresent(edp -> {
activeProviders.add(edp); activeProviders.add(edp);
edp.init(); edp.init();
Iris.instance.registerListener(edp);
Iris.info("Enabled ExternalDataProvider for %s.", edp.getPluginId()); Iris.info("Enabled ExternalDataProvider for %s.", edp.getPluginId());
}); });
} }
@ -113,6 +88,7 @@ public class ExternalDataSVC implements IrisService {
if (provider.isReady()) { if (provider.isReady()) {
activeProviders.add(provider); activeProviders.add(provider);
provider.init(); provider.init();
Iris.instance.registerListener(provider);
} }
} }
@ -120,7 +96,7 @@ public class ExternalDataSVC implements IrisService {
var pair = parseState(key); var pair = parseState(key);
Identifier mod = pair.getA(); Identifier mod = pair.getA();
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(mod, false)).findFirst(); Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(mod, DataType.BLOCK)).findFirst();
if (provider.isEmpty()) if (provider.isEmpty())
return Optional.empty(); return Optional.empty();
try { try {
@ -132,7 +108,7 @@ public class ExternalDataSVC implements IrisService {
} }
public Optional<ItemStack> getItemStack(Identifier key, KMap<String, Object> customNbt) { public Optional<ItemStack> getItemStack(Identifier key, KMap<String, Object> customNbt) {
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(key, true)).findFirst(); Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(key, DataType.ITEM)).findFirst();
if (provider.isEmpty()) { if (provider.isEmpty()) {
Iris.warn("No matching Provider found for modded material \"%s\"!", key); Iris.warn("No matching Provider found for modded material \"%s\"!", key);
return Optional.empty(); return Optional.empty();
@ -146,7 +122,7 @@ public class ExternalDataSVC implements IrisService {
} }
public void processUpdate(Engine engine, Block block, Identifier blockId) { public void processUpdate(Engine engine, Block block, Identifier blockId) {
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(blockId, false)).findFirst(); Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(blockId, DataType.BLOCK)).findFirst();
if (provider.isEmpty()) { if (provider.isEmpty()) {
Iris.warn("No matching Provider found for modded material \"%s\"!", blockId); Iris.warn("No matching Provider found for modded material \"%s\"!", blockId);
return; return;
@ -154,16 +130,24 @@ public class ExternalDataSVC implements IrisService {
provider.get().processUpdate(engine, block, blockId); provider.get().processUpdate(engine, block, blockId);
} }
public Identifier[] getAllBlockIdentifiers() { public Entity spawnMob(Location location, Identifier mobId) {
KList<Identifier> names = new KList<>(); Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(mobId, DataType.ENTITY)).findFirst();
activeProviders.forEach(p -> names.add(p.getBlockTypes())); if (provider.isEmpty()) {
return names.toArray(new Identifier[0]); Iris.warn("No matching Provider found for modded mob \"%s\"!", mobId);
return null;
}
try {
return provider.get().spawnMob(location, mobId);
} catch (MissingResourceException e) {
Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]");
return null;
}
} }
public Identifier[] getAllItemIdentifiers() { public Collection<Identifier> getAllIdentifiers(DataType dataType) {
KList<Identifier> names = new KList<>(); return activeProviders.stream()
activeProviders.forEach(p -> names.add(p.getItemTypes())); .flatMap(p -> p.getTypes(dataType).stream())
return names.toArray(new Identifier[0]); .toList();
} }
public static Pair<Identifier, KMap<String, String>> parseState(Identifier key) { public static Pair<Identifier, KMap<String, String>> parseState(Identifier key) {
@ -188,4 +172,21 @@ public class ExternalDataSVC implements IrisService {
.collect(Collectors.joining(",", key.key() + "[", "]")); .collect(Collectors.joining(",", key.key() + "[", "]"));
return new Identifier(key.namespace(), path); return new Identifier(key.namespace(), path);
} }
private static KList<ExternalDataProvider> createProviders() {
JarScanner jar = new JarScanner(Iris.instance.getJarFile(), "com.volmit.iris.core.link.data", false);
J.attempt(jar::scan);
KList<ExternalDataProvider> providers = new KList<>();
for (Class<?> c : jar.getClasses()) {
if (ExternalDataProvider.class.isAssignableFrom(c)) {
try {
ExternalDataProvider p = (ExternalDataProvider) c.getDeclaredConstructor().newInstance();
if (p.getPlugin() != null) Iris.info(p.getPluginId() + " found, loading " + c.getSimpleName() + "...");
providers.add(p);
} catch (Throwable ignored) {}
}
}
return providers;
}
} }

View File

@ -18,7 +18,6 @@
package com.volmit.iris.core.service; package com.volmit.iris.core.service;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisSettings;
@ -250,30 +249,25 @@ public class StudioSVC implements IrisService {
return; return;
} }
File dimensions = new File(dir, "dimensions"); IrisData data = IrisData.get(dir);
String[] dimensions = data.getDimensionLoader().getPossibleKeys();
if (!(dimensions.exists() && dimensions.isDirectory())) { if (dimensions == null || dimensions.length == 0) {
sender.sendMessage("Invalid Format. Missing dimensions folder");
return;
}
if (dimensions.listFiles() == null) {
sender.sendMessage("No dimension file found in the extracted zip file."); sender.sendMessage("No dimension file found in the extracted zip file.");
sender.sendMessage("Check it is there on GitHub and report this to staff!"); sender.sendMessage("Check it is there on GitHub and report this to staff!");
} else if (dimensions.listFiles().length != 1) { } else if (dimensions.length != 1) {
sender.sendMessage("Dimensions folder must have 1 file in it"); sender.sendMessage("Dimensions folder must have 1 file in it");
return; return;
} }
File dim = dimensions.listFiles()[0]; IrisDimension d = data.getDimensionLoader().load(dimensions[0]);
if (!dim.isFile()) { if (d == null) {
sender.sendMessage("Invalid dimension (folder) in dimensions folder"); sender.sendMessage("Invalid dimension (folder) in dimensions folder");
return; return;
} }
String key = dim.getName().split("\\Q.\\E")[0]; String key = d.getLoadKey();
IrisDimension d = new Gson().fromJson(IO.readAll(dim), IrisDimension.class);
sender.sendMessage("Importing " + d.getName() + " (" + key + ")"); sender.sendMessage("Importing " + d.getName() + " (" + key + ")");
File packEntry = new File(packs, key); File packEntry = new File(packs, key);

View File

@ -46,13 +46,14 @@ 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.util.misc.ServerProperties.BUKKIT_YML;
/** /**
* 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
*/ */
@Data @Data
@Accessors(fluent = true, chain = true) @Accessors(fluent = true, chain = true)
public class IrisCreator { public class IrisCreator {
private static final File BUKKIT_YML = new File("bukkit.yml");
/** /**
* Specify an area to pregenerate during creation * Specify an area to pregenerate during creation
*/ */

View File

@ -21,13 +21,10 @@ package com.volmit.iris.core.tools;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.platform.BukkitChunkGenerator; import com.volmit.iris.engine.platform.BukkitChunkGenerator;
import com.volmit.iris.util.reflect.WrappedField;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.WorldCreator; import org.bukkit.WorldCreator;
import org.bukkit.WorldType;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import sun.misc.Unsafe;
import java.io.File; import java.io.File;

View File

@ -47,6 +47,7 @@ import com.volmit.iris.util.mantle.flag.MantleFlag;
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.matter.MatterStructurePOI; import com.volmit.iris.util.matter.MatterStructurePOI;
import com.volmit.iris.util.matter.slices.container.JigsawStructureContainer;
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;
@ -224,6 +225,12 @@ public class IrisEngine implements Engine {
return getMantle().getJigsawComponent().guess(x, z); return getMantle().getJigsawComponent().guess(x, z);
} }
@Override
public IrisJigsawStructure getStructureAt(int x, int y, int z) {
var container = getMantle().getMantle().get(x, y, z, JigsawStructureContainer.class);
return container == null ? null : container.load(getData());
}
private void warmupChunk(int x, int z) { private void warmupChunk(int x, int z) {
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) { for (int j = 0; j < 16; j++) {

View File

@ -231,6 +231,9 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
@ChunkCoordinates @ChunkCoordinates
IrisJigsawStructure getStructureAt(int x, int z); IrisJigsawStructure getStructureAt(int x, int z);
@BlockCoordinates
IrisJigsawStructure getStructureAt(int x, int y, int z);
@BlockCoordinates @BlockCoordinates
default IrisBiome getCaveBiome(int x, int z) { default IrisBiome getCaveBiome(int x, int z) {
return getComplex().getCaveBiomeStream().get(x, z); return getComplex().getCaveBiomeStream().get(x, z);
@ -262,7 +265,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
getMantle().updateBlock(x, y, z); getMantle().updateBlock(x, y, z);
} }
if (data instanceof IrisCustomData) { if (data instanceof IrisCustomData) {
getMantle().getMantle().flag(x >> 4, z >> 4, MantleFlag.CUSTOM, true); getMantle().getMantle().flag(x >> 4, z >> 4, MantleFlag.CUSTOM_ACTIVE, true);
} }
} }

View File

@ -29,6 +29,7 @@ import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.slices.container.JigsawPieceContainer; import com.volmit.iris.util.matter.slices.container.JigsawPieceContainer;
import com.volmit.iris.util.matter.slices.container.JigsawStructureContainer;
import com.volmit.iris.util.matter.slices.container.JigsawStructuresContainer; import com.volmit.iris.util.matter.slices.container.JigsawStructuresContainer;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
import lombok.Data; import lombok.Data;
@ -149,11 +150,13 @@ public class PlannedStructure {
} }
int id = rng.i(0, Integer.MAX_VALUE); int id = rng.i(0, Integer.MAX_VALUE);
JigsawPieceContainer container = JigsawPieceContainer.toContainer(i.getPiece()); JigsawPieceContainer piece = JigsawPieceContainer.toContainer(i.getPiece());
JigsawStructureContainer structure = JigsawStructureContainer.toContainer(getStructure());
i.setRealPositions(xx, height, zz, placer); i.setRealPositions(xx, height, zz, placer);
return v.place(xx, height, zz, placer, options, rng, (b, data) -> { return v.place(xx, height, zz, placer, options, rng, (b, data) -> {
e.set(b.getX(), b.getY(), b.getZ(), v.getLoadKey() + "@" + id); e.set(b.getX(), b.getY(), b.getZ(), v.getLoadKey() + "@" + id);
e.set(b.getX(), b.getY(), b.getZ(), container); e.set(b.getX(), b.getY(), b.getZ(), structure);
e.set(b.getX(), b.getY(), b.getZ(), piece);
}, null, getData().getEngine() != null ? getData() : eng.getData()) != -1; }, null, getData().getEngine() != null ? getData() : eng.getData()) != -1;
} }

View File

@ -35,6 +35,7 @@ import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.mantle.MantleChunk; import com.volmit.iris.util.mantle.MantleChunk;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.Matter; import com.volmit.iris.util.matter.Matter;
import com.volmit.iris.util.noise.CNG;
import lombok.Data; import lombok.Data;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
@ -71,6 +72,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
private static Set<IrisPosition> getBallooned(Set<IrisPosition> vset, double radius) { private static Set<IrisPosition> getBallooned(Set<IrisPosition> vset, double radius) {
Set<IrisPosition> returnset = new HashSet<>(); Set<IrisPosition> returnset = new HashSet<>();
int ceilrad = (int) Math.ceil(radius); int ceilrad = (int) Math.ceil(radius);
double r2 = Math.pow(radius, 2);
for (IrisPosition v : vset) { for (IrisPosition v : vset) {
int tipx = v.getX(); int tipx = v.getX();
@ -80,7 +82,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
for (int loopx = tipx - ceilrad; loopx <= tipx + ceilrad; loopx++) { for (int loopx = tipx - ceilrad; loopx <= tipx + ceilrad; loopx++) {
for (int loopy = tipy - ceilrad; loopy <= tipy + ceilrad; loopy++) { for (int loopy = tipy - ceilrad; loopy <= tipy + ceilrad; loopy++) {
for (int loopz = tipz - ceilrad; loopz <= tipz + ceilrad; loopz++) { for (int loopz = tipz - ceilrad; loopz <= tipz + ceilrad; loopz++) {
if (hypot(loopx - tipx, loopy - tipy, loopz - tipz) <= radius) { if (hypot(loopx - tipx, loopy - tipy, loopz - tipz) <= r2) {
returnset.add(new IrisPosition(loopx, loopy, loopz)); returnset.add(new IrisPosition(loopx, loopy, loopz));
} }
} }
@ -113,7 +115,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
for (double d : pars) { for (double d : pars) {
sum += Math.pow(d, 2); sum += Math.pow(d, 2);
} }
return Math.sqrt(sum); return sum;
} }
private static double lengthSq(double x, double y, double z) { private static double lengthSq(double x, double y, double z) {
@ -453,6 +455,62 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
* @param <T> the type of data to apply to the mantle * @param <T> the type of data to apply to the mantle
*/ */
public <T> void setLineConsumer(List<IrisPosition> vectors, double radius, boolean filled, Function3<Integer, Integer, Integer, T> data) { public <T> void setLineConsumer(List<IrisPosition> vectors, double radius, boolean filled, Function3<Integer, Integer, Integer, T> data) {
Set<IrisPosition> vset = cleanup(vectors);
vset = getBallooned(vset, radius);
if (!filled) {
vset = getHollowed(vset);
}
setConsumer(vset, data);
}
/**
* Set lines for points
*
* @param vectors the points
* @param radius the radius
* @param filled hollow or filled?
* @param data the data to set
* @param <T> the type of data to apply to the mantle
*/
public <T> void setNoiseMasked(List<IrisPosition> vectors, double radius, double threshold, CNG shape, Set<IrisPosition> masks, boolean filled, Function3<Integer, Integer, Integer, T> data) {
Set<IrisPosition> vset = cleanup(vectors);
vset = masks == null ? getBallooned(vset, radius) : getMasked(vset, masks, radius);
vset.removeIf(p -> shape.noise(p.getX(), p.getY(), p.getZ()) < threshold);
if (!filled) {
vset = getHollowed(vset);
}
setConsumer(vset, data);
}
private static Set<IrisPosition> getMasked(Set<IrisPosition> vectors, Set<IrisPosition> masks, double radius) {
Set<IrisPosition> vset = new KSet<>();
int ceil = (int) Math.ceil(radius);
double r2 = Math.pow(radius, 2);
for (IrisPosition v : vectors) {
int tipX = v.getX();
int tipY = v.getY();
int tipZ = v.getZ();
for (int x = -ceil; x <= ceil; x++) {
for (int y = -ceil; y <= ceil; y++) {
for (int z = -ceil; z <= ceil; z++) {
if (hypot(x, y, z) > r2 || !masks.contains(new IrisPosition(x, y, z)))
continue;
vset.add(new IrisPosition(tipX + x, tipY + y, tipZ + z));
}
}
}
}
return vset;
}
private static Set<IrisPosition> cleanup(List<IrisPosition> vectors) {
Set<IrisPosition> vset = new KSet<>(); Set<IrisPosition> vset = new KSet<>();
for (int i = 0; vectors.size() != 0 && i < vectors.size() - 1; i++) { for (int i = 0; vectors.size() != 0 && i < vectors.size() - 1; i++) {
@ -504,13 +562,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
} }
} }
vset = getBallooned(vset, radius); return vset;
if (!filled) {
vset = getHollowed(vset);
}
setConsumer(vset, data);
} }
/** /**

View File

@ -62,31 +62,31 @@ public class IrisCarving {
@BlockCoordinates @BlockCoordinates
public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int depth) { public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int depth) {
doCarving(writer, rng, engine, x, y, z, depth, -1); doCarving(writer, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, depth, -1);
} }
@BlockCoordinates @BlockCoordinates
public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { public void doCarving(MantleWriter writer, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) {
int nextRecursion = recursion + 1; int nextRecursion = recursion + 1;
if (caves.isNotEmpty()) { if (caves.isNotEmpty()) {
for (IrisCavePlacer i : caves) { for (IrisCavePlacer i : caves) {
if (recursion > i.getMaxRecursion()) continue; if (recursion > i.getMaxRecursion()) continue;
i.generateCave(writer, rng, engine, x, y, z, nextRecursion, waterHint); i.generateCave(writer, rng, base, engine, x, y, z, nextRecursion, waterHint);
} }
} }
if (ravines.isNotEmpty()) { if (ravines.isNotEmpty()) {
for (IrisRavinePlacer i : ravines) { for (IrisRavinePlacer i : ravines) {
if (recursion > i.getMaxRecursion()) continue; if (recursion > i.getMaxRecursion()) continue;
i.generateRavine(writer, rng, engine, x, y, z, nextRecursion, waterHint); i.generateRavine(writer, rng, base, engine, x, y, z, nextRecursion, waterHint);
} }
} }
if (spheres.isNotEmpty()) { if (spheres.isNotEmpty()) {
for (IrisSphere i : spheres) { for (IrisSphere i : spheres) {
if (rng.nextInt(i.getRarity()) == 0) { if (rng.nextInt(i.getRarity()) == 0) {
i.generate(rng, engine, writer, x, y, z); i.generate(base, engine, writer, x, y, z);
} }
} }
} }
@ -94,7 +94,7 @@ public class IrisCarving {
if (elipsoids.isNotEmpty()) { if (elipsoids.isNotEmpty()) {
for (IrisElipsoid i : elipsoids) { for (IrisElipsoid i : elipsoids) {
if (rng.nextInt(i.getRarity()) == 0) { if (rng.nextInt(i.getRarity()) == 0) {
i.generate(rng, engine, writer, x, y, z); i.generate(base, engine, writer, x, y, z);
} }
} }
} }
@ -102,7 +102,7 @@ public class IrisCarving {
if (pyramids.isNotEmpty()) { if (pyramids.isNotEmpty()) {
for (IrisPyramid i : pyramids) { for (IrisPyramid i : pyramids) {
if (rng.nextInt(i.getRarity()) == 0) { if (rng.nextInt(i.getRarity()) == 0) {
i.generate(rng, engine, writer, x, y, z); i.generate(base, engine, writer, x, y, z);
} }
} }
} }

View File

@ -25,9 +25,11 @@ import com.volmit.iris.engine.mantle.MantleWriter;
import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.RegistryListResource; import com.volmit.iris.engine.object.annotations.RegistryListResource;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.MatterCavern; import com.volmit.iris.util.matter.MatterCavern;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
@ -55,6 +57,9 @@ public class IrisCave extends IrisRegistrant {
@Desc("Limit the worm from ever getting higher or lower than this range") @Desc("Limit the worm from ever getting higher or lower than this range")
private IrisRange verticalRange = new IrisRange(3, 255); private IrisRange verticalRange = new IrisRange(3, 255);
@Desc("Shape of the caves")
private IrisCaveShape shape = new IrisCaveShape();
@Override @Override
public String getFolderName() { public String getFolderName() {
return "caves"; return "caves";
@ -66,12 +71,12 @@ public class IrisCave extends IrisRegistrant {
} }
public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) { public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) {
generate(writer, rng, engine, x, y, z, 0, -1, true); generate(writer, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1, true);
} }
public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint, boolean breakSurface) { public void generate(MantleWriter writer, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint, boolean breakSurface) {
double girth = getWorm().getGirth().get(rng, x, z, engine.getData()); double girth = getWorm().getGirth().get(base.nextParallelRNG(465156), x, z, engine.getData());
KList<IrisPosition> points = getWorm().generate(rng, engine.getData(), writer, verticalRange, x, y, z, breakSurface, girth + 9); KList<IrisPosition> points = getWorm().generate(base.nextParallelRNG(784684), engine.getData(), writer, verticalRange, x, y, z, breakSurface, girth + 9);
int highestWater = Math.max(waterHint, -1); int highestWater = Math.max(waterHint, -1);
if (highestWater == -1) { if (highestWater == -1) {
@ -87,17 +92,19 @@ public class IrisCave extends IrisRegistrant {
} }
int h = Math.min(Math.max(highestWater, waterHint), engine.getDimension().getFluidHeight()); int h = Math.min(highestWater, engine.getDimension().getFluidHeight());
for (IrisPosition i : points) { for (IrisPosition i : points) {
fork.doCarving(writer, rng, engine, i.getX(), i.getY(), i.getZ(), recursion, h); fork.doCarving(writer, rng, base, engine, i.getX(), i.getY(), i.getZ(), recursion, h);
} }
MatterCavern c = new MatterCavern(true, customBiome, (byte) 0); MatterCavern c = new MatterCavern(true, customBiome, (byte) 0);
MatterCavern w = new MatterCavern(true, customBiome, (byte) 1); MatterCavern w = new MatterCavern(true, customBiome, (byte) 1);
writer.setLineConsumer(points, CNG cng = shape.getNoise(base.nextParallelRNG(8131545), engine);
girth, true, KSet<IrisPosition> mask = shape.getMasked(rng, engine);
writer.setNoiseMasked(points,
girth, cng.noise(x, y, z), cng, mask, true,
(xf, yf, zf) -> yf <= h ? w : c); (xf, yf, zf) -> yf <= h ? w : c);
} }
@ -107,6 +114,6 @@ public class IrisCave extends IrisRegistrant {
} }
public int getMaxSize(IrisData data, int depth) { public int getMaxSize(IrisData data, int depth) {
return getWorm().getMaxDistance() + fork.getMaxRange(data, depth); return (int) (Math.ceil(getWorm().getGirth().getMax() * 2) + getWorm().getMaxDistance() + fork.getMaxRange(data, depth));
} }
} }

View File

@ -64,10 +64,10 @@ public class IrisCavePlacer implements IRare {
} }
public void generateCave(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z) { public void generateCave(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z) {
generateCave(mantle, rng, engine, x, y, z, 0, -1); generateCave(mantle, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1);
} }
public void generateCave(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { public void generateCave(MantleWriter mantle, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) {
if (fail.get()) { if (fail.get()) {
return; return;
} }
@ -86,13 +86,13 @@ public class IrisCavePlacer implements IRare {
} }
if (y == -1) { if (y == -1) {
int h = (int) caveStartHeight.get(rng, x, z, data); int h = (int) caveStartHeight.get(base, x, z, data);
int ma = breakSurface ? h : (int) (engine.getComplex().getHeightStream().get(x, z) - 9); int ma = breakSurface ? h : (int) (engine.getComplex().getHeightStream().get(x, z) - 9);
y = Math.min(h, ma); y = Math.min(h, ma);
} }
try { try {
cave.generate(mantle, rng, engine, x + rng.nextInt(15), y, z + rng.nextInt(15), recursion, waterHint, breakSurface); cave.generate(mantle, rng, base, engine, x + rng.nextInt(15), y, z + rng.nextInt(15), recursion, waterHint, breakSurface);
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
fail.set(true); fail.set(true);

View File

@ -0,0 +1,76 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.RegistryListResource;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Snippet("cave-shape")
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Desc("Cave Shape")
@Data
public class IrisCaveShape {
private transient final KMap<IrisPosition, KSet<IrisPosition>> cache = new KMap<>();
@Desc("Noise used for the shape of the cave")
private IrisGeneratorStyle noise = new IrisGeneratorStyle();
@RegistryListResource(IrisObject.class)
@Desc("Object used as mask for the shape of the cave")
private String object = null;
@Desc("Rotation to apply to objects before using them as mask")
private IrisObjectRotation objectRotation = new IrisObjectRotation();
public CNG getNoise(RNG rng, Engine engine) {
return noise.create(rng, engine.getData());
}
public KSet<IrisPosition> getMasked(RNG rng, Engine engine) {
if (object == null) return null;
return cache.computeIfAbsent(randomRotation(rng), pos -> {
var rotated = new KSet<IrisPosition>();
engine.getData().getObjectLoader().load(object).getBlocks().forEach((vector, data) -> {
if (data.getMaterial().isAir()) return;
rotated.add(new IrisPosition(objectRotation.rotate(vector, pos.getX(), pos.getY(), pos.getZ())));
});
return rotated;
});
}
private IrisPosition randomRotation(RNG rng) {
if (objectRotation == null || !objectRotation.canRotate())
return new IrisPosition(0,0,0);
return new IrisPosition(
randomDegree(rng, objectRotation.getXAxis()),
randomDegree(rng, objectRotation.getYAxis()),
randomDegree(rng, objectRotation.getZAxis())
);
}
private int randomDegree(RNG rng, IrisAxisRotationClamp clamp) {
if (!clamp.isEnabled()) return 0;
if (clamp.isLocked()) return (int) clamp.getMax();
double interval = clamp.getInterval();
if (interval < 1) interval = 1;
double min = clamp.getMin(), max = clamp.getMax();
double value = (interval * (Math.ceil(Math.abs(rng.d(0, 360) / interval)))) % 360D;
if (clamp.isUnlimited()) return (int) value;
if (min > max) {
max = clamp.getMin();
min = clamp.getMax();
}
return (int) (double) M.clip(value, min, max);
}
}

View File

@ -20,8 +20,10 @@ package com.volmit.iris.engine.object;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
@ -451,24 +453,13 @@ public class IrisEntity extends IrisRegistrant {
} }
if (isSpecialType()) { if (isSpecialType()) {
if (specialType.toLowerCase().startsWith("mythicmobs:")) { return Iris.service(ExternalDataSVC.class).spawnMob(at, Identifier.fromString(specialType));
return Iris.linkMythicMobs.spawnMob(specialType.substring(11), at);
} else {
Iris.warn("Invalid mob type to spawn: '" + specialType + "'!");
return null;
}
} }
return INMS.get().spawnEntity(at, getType(), getReason()); return INMS.get().spawnEntity(at, getType(), getReason());
} }
public boolean isCitizens() {
return false;
// TODO: return Iris.linkCitizens.supported() && someType is not empty;
}
public boolean isSpecialType() { public boolean isSpecialType() {
return specialType != null && !specialType.equals(""); return specialType != null && !specialType.equals("");
} }

View File

@ -93,13 +93,13 @@ public class IrisRavine extends IrisRegistrant {
} }
public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) { public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) {
generate(writer, rng, engine, x, y, z, 0, -1); generate(writer, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1);
} }
public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { public void generate(MantleWriter writer, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) {
KList<IrisPosition> pos = getWorm().generate(rng, engine.getData(), writer, null, x, y, z, true, 0); KList<IrisPosition> pos = getWorm().generate(base.nextParallelRNG(879615), engine.getData(), writer, null, x, y, z, true, 0);
CNG dg = depthStyle.getGenerator().createNoCache(rng, engine.getData()); CNG dg = depthStyle.getGenerator().create(base.nextParallelRNG(7894156), engine.getData());
CNG bw = baseWidthStyle.getGenerator().createNoCache(rng, engine.getData()); CNG bw = baseWidthStyle.getGenerator().create(base.nextParallelRNG(15315456), engine.getData());
int highestWater = Math.max(waterHint, -1); int highestWater = Math.max(waterHint, -1);
boolean water = false; boolean water = false;
@ -134,7 +134,7 @@ public class IrisRavine extends IrisRegistrant {
int width = (int) Math.round(bw.fitDouble(baseWidthStyle.getMin(), baseWidthStyle.getMax(), p.getX(), p.getZ())); int width = (int) Math.round(bw.fitDouble(baseWidthStyle.getMin(), baseWidthStyle.getMax(), p.getX(), p.getZ()));
int surface = (int) Math.round(rsurface - depth * 0.45); int surface = (int) Math.round(rsurface - depth * 0.45);
fork.doCarving(writer, rng, engine, p.getX(), rng.i(surface - depth, surface), p.getZ(), recursion, Math.max(highestWater, waterHint)); fork.doCarving(writer, rng, base, engine, p.getX(), rng.i(surface - depth, surface), p.getZ(), recursion, highestWater);
for (int i = surface + depth; i >= surface; i--) { for (int i = surface + depth; i >= surface; i--) {
if (i % ribThickness == 0) { if (i % ribThickness == 0) {

View File

@ -60,10 +60,10 @@ public class IrisRavinePlacer implements IRare {
} }
public void generateRavine(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z) { public void generateRavine(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z) {
generateRavine(mantle, rng, engine, x, y, z, 0, -1); generateRavine(mantle, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1);
} }
public void generateRavine(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { public void generateRavine(MantleWriter mantle, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) {
if (fail.get()) { if (fail.get()) {
return; return;
} }
@ -84,7 +84,7 @@ public class IrisRavinePlacer implements IRare {
try { try {
int xx = x + rng.nextInt(15); int xx = x + rng.nextInt(15);
int zz = z + rng.nextInt(15); int zz = z + rng.nextInt(15);
ravine.generate(mantle, rng, engine, xx, y, zz, recursion, waterHint); ravine.generate(mantle, rng, base, engine, xx, y, zz, recursion, waterHint);
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
fail.set(true); fail.set(true);

View File

@ -71,9 +71,9 @@ public class IrisWorm {
IrisPosition start = new IrisPosition(x, y, z); IrisPosition start = new IrisPosition(x, y, z);
KList<IrisPosition> pos = new KList<>(); KList<IrisPosition> pos = new KList<>();
KSet<IrisPosition> check = allowLoops ? null : new KSet<>(); KSet<IrisPosition> check = allowLoops ? null : new KSet<>();
CNG gx = xStyle.getGenerator().createNoCache(new RNG(rng.lmax()), data); CNG gx = xStyle.getGenerator().create(rng.nextParallelRNG(14567), data);
CNG gy = yStyle.getGenerator().createNoCache(new RNG(rng.lmax()), data); CNG gy = yStyle.getGenerator().create(rng.nextParallelRNG(64789), data);
CNG gz = zStyle.getGenerator().createNoCache(new RNG(rng.lmax()), data); CNG gz = zStyle.getGenerator().create(rng.nextParallelRNG(34790), data);
while (itr-- > 0) { while (itr-- > 0) {
IrisPosition current = new IrisPosition(Math.round(cx), Math.round(cy), Math.round(cz)); IrisPosition current = new IrisPosition(Math.round(cx), Math.round(cy), Math.round(cz));

View File

@ -64,12 +64,10 @@ import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.*;
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.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Data @Data
@ -95,8 +93,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
@Setter @Setter
private volatile StudioGenerator studioGenerator; private volatile StudioGenerator studioGenerator;
private boolean initialized = false;
public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) { public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) {
setup = new AtomicBoolean(false); setup = new AtomicBoolean(false);
studioGenerator = null; studioGenerator = null;
@ -114,8 +110,8 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void onWorldInit(WorldInitEvent event) { public void onWorldInit(WorldInitEvent event) {
if (initialized || !world.name().equals(event.getWorld().getName())) if (!world.name().equals(event.getWorld().getName())) return;
return; Iris.instance.unregisterListener(this);
world.setRawWorldSeed(event.getWorld().getSeed()); world.setRawWorldSeed(event.getWorld().getSeed());
if (initialize(event.getWorld())) return; if (initialize(event.getWorld())) return;
@ -140,7 +136,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
} }
spawnChunks.complete(INMS.get().getSpawnChunkCount(world)); spawnChunks.complete(INMS.get().getSpawnChunkCount(world));
Iris.instance.unregisterListener(this); Iris.instance.unregisterListener(this);
initialized = true;
IrisWorlds.get().put(world.getName(), dimensionKey); IrisWorlds.get().put(world.getName(), dimensionKey);
return true; return true;
} }
@ -205,50 +200,57 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
} }
@Override @Override
public void injectChunkReplacement(World world, int x, int z, Consumer<Runnable> jobs) { public void injectChunkReplacement(World world, int x, int z, Executor syncExecutor) {
try { try {
loadLock.acquire(); loadLock.acquire();
IrisBiomeStorage st = new IrisBiomeStorage(); IrisBiomeStorage st = new IrisBiomeStorage();
TerrainChunk tc = TerrainChunk.createUnsafe(world, st); TerrainChunk tc = TerrainChunk.createUnsafe(world, st);
Hunk<BlockData> blocks = Hunk.view(tc);
Hunk<Biome> biomes = Hunk.view(tc, tc.getMinHeight(), tc.getMaxHeight());
this.world.bind(world); this.world.bind(world);
getEngine().generate(x << 4, z << 4, blocks, biomes, true); getEngine().generate(x << 4, z << 4, tc, false);
Iris.debug("Regenerated " + x + " " + z);
int t = 0; Chunk c = PaperLib.getChunkAtAsync(world, x, z)
.thenApply(d -> {
d.addPluginChunkTicket(Iris.instance);
for (Entity ee : d.getEntities()) {
if (ee instanceof Player) {
continue;
}
ee.remove();
}
engine.getWorldManager().onChunkLoad(d, false);
return d;
}).get();
KList<CompletableFuture<?>> futures = new KList<>(1 + getEngine().getHeight() >> 4);
for (int i = getEngine().getHeight() >> 4; i >= 0; i--) { for (int i = getEngine().getHeight() >> 4; i >= 0; i--) {
if (!world.isChunkLoaded(x, z)) { int finalI = i << 4;
continue; futures.add(CompletableFuture.runAsync(() -> {
}
Chunk c = world.getChunkAt(x, z);
for (Entity ee : c.getEntities()) {
if (ee instanceof Player) {
continue;
}
J.s(ee::remove);
}
J.s(() -> engine.getWorldManager().onChunkLoad(c, false));
int finalI = i;
jobs.accept(() -> {
for (int xx = 0; xx < 16; xx++) { for (int xx = 0; xx < 16; xx++) {
for (int yy = 0; yy < 16; yy++) { for (int yy = 0; yy < 16; yy++) {
for (int zz = 0; zz < 16; zz++) { for (int zz = 0; zz < 16; zz++) {
if (yy + (finalI << 4) >= engine.getHeight() || yy + (finalI << 4) < 0) { if (yy + finalI >= engine.getHeight() || yy + finalI < 0) {
continue; continue;
} }
c.getBlock(xx, yy + (finalI << 4) + world.getMinHeight(), zz) int y = yy + finalI + world.getMinHeight();
.setBlockData(tc.getBlockData(xx, yy + (finalI << 4) + world.getMinHeight(), zz), false); c.getBlock(xx, y, zz).setBlockData(tc.getBlockData(xx, y, zz), false);
} }
} }
} }
}); }, syncExecutor));
} }
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenRunAsync(() -> {
c.removePluginChunkTicket(Iris.instance);
c.unload();
}, syncExecutor)
.get();
Iris.debug("Regenerated " + x + " " + z);
loadLock.release(); loadLock.release();
} catch (Throwable e) { } catch (Throwable e) {
loadLock.release(); loadLock.release();

View File

@ -28,7 +28,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer; import java.util.concurrent.Executor;
public interface PlatformChunkGenerator extends Hotloadable, DataProvider { public interface PlatformChunkGenerator extends Hotloadable, DataProvider {
@Nullable @Nullable
@ -42,7 +42,7 @@ public interface PlatformChunkGenerator extends Hotloadable, DataProvider {
@NotNull @NotNull
EngineTarget getTarget(); EngineTarget getTarget();
void injectChunkReplacement(World world, int x, int z, Consumer<Runnable> jobs); void injectChunkReplacement(World world, int x, int z, Executor syncExecutor);
void close(); void close();

View File

@ -19,6 +19,7 @@
package com.volmit.iris.util.collection; package com.volmit.iris.util.collection;
import com.google.common.util.concurrent.AtomicDoubleArray; import com.google.common.util.concurrent.AtomicDoubleArray;
import com.volmit.iris.util.function.NastyFunction;
import com.volmit.iris.util.json.JSONArray; import com.volmit.iris.util.json.JSONArray;
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;
@ -306,6 +307,18 @@ public class KList<T> extends ArrayList<T> implements List<T> {
return v; return v;
} }
/**
* Convert this list into another list type. Such as GList<Integer> to
* GList<String>. list.convertNasty((i) -> "" + i);
*/
public <V> KList<V> convertNasty(NastyFunction<T, V> converter) throws Throwable {
KList<V> v = new KList<V>(size());
for (final var t : this) {
v.addNonNull(converter.run(t));
}
return v;
}
public KList<T> removeWhere(Predicate<T> t) { public KList<T> removeWhere(Predicate<T> t) {
for (T i : copy()) { for (T i : copy()) {
if (t.test(i)) { if (t.test(i)) {

View File

@ -21,6 +21,7 @@ package com.volmit.iris.util.data;
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.link.Identifier; import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.link.data.DataType;
import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.core.service.ExternalDataSVC;
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;
@ -673,7 +674,7 @@ public class B {
} }
} }
for (Identifier id : Iris.service(ExternalDataSVC.class).getAllBlockIdentifiers()) for (Identifier id : Iris.service(ExternalDataSVC.class).getAllIdentifiers(DataType.BLOCK))
bt.add(id.toString()); bt.add(id.toString());
bt.addAll(custom.k()); bt.addAll(custom.k());
@ -688,7 +689,7 @@ public class B {
bt.add(v); bt.add(v);
} }
for (Identifier id : Iris.service(ExternalDataSVC.class).getAllItemIdentifiers()) for (Identifier id : Iris.service(ExternalDataSVC.class).getAllIdentifiers(DataType.ITEM))
bt.add(id.toString()); bt.add(id.toString());
return bt.toArray(new String[0]); return bt.toArray(new String[0]);

View File

@ -18,6 +18,7 @@
package com.volmit.iris.util.function; package com.volmit.iris.util.function;
@FunctionalInterface
public interface NastyFunction<T, R> { public interface NastyFunction<T, R> {
R run(T t); R run(T t) throws Throwable;
} }

View File

@ -36,6 +36,7 @@ import org.dom4j.io.XMLWriter;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.security.DigestInputStream; import java.security.DigestInputStream;
import java.security.MessageDigest; import java.security.MessageDigest;
@ -598,6 +599,25 @@ public class IO {
} }
} }
public static void copyDirectory(Path source, Path target) throws IOException {
Files.walk(source).forEach(sourcePath -> {
Path targetPath = target.resolve(source.relativize(sourcePath));
try {
if (Files.isDirectory(sourcePath)) {
if (!Files.exists(targetPath)) {
Files.createDirectories(targetPath);
}
} else {
Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
}
} catch (IOException e) {
Iris.error("Failed to copy " + targetPath);
e.printStackTrace();
}
});
}
/** /**
* Unconditionally close an <code>Reader</code>. * Unconditionally close an <code>Reader</code>.
* <p> * <p>

View File

@ -48,7 +48,6 @@ import org.bukkit.Chunk;
import java.io.EOFException; import java.io.EOFException;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -59,16 +58,18 @@ import java.util.concurrent.atomic.AtomicInteger;
*/ */
public class Mantle { public class Mantle {
private static final int LOCK_SIZE = Short.MAX_VALUE;
private final File dataFolder; private final File dataFolder;
@Getter @Getter
private final int worldHeight; private final int worldHeight;
private final Map<Long, Long> lastUse; private final KMap<Long, Long> lastUse;
private final Map<Long, TectonicPlate> loadedRegions; private final KMap<Long, TectonicPlate> loadedRegions;
private final HyperLock hyperLock; private final HyperLock hyperLock;
private final AtomicBoolean closed; private final AtomicBoolean closed;
private final MultiBurst ioBurst; private final MultiBurst ioBurst;
private final AtomicBoolean ioTrim; private final Semaphore ioTrim;
private final AtomicBoolean ioTectonicUnload; private final Semaphore ioTectonicUnload;
private final AtomicDouble adjustedIdleDuration; private final AtomicDouble adjustedIdleDuration;
private final KSet<Long> toUnload; private final KSet<Long> toUnload;
@ -84,8 +85,8 @@ public class Mantle {
this.closed = new AtomicBoolean(false); this.closed = new AtomicBoolean(false);
this.dataFolder = dataFolder; this.dataFolder = dataFolder;
this.worldHeight = worldHeight; this.worldHeight = worldHeight;
this.ioTrim = new AtomicBoolean(false); this.ioTrim = new Semaphore(LOCK_SIZE, true);
this.ioTectonicUnload = new AtomicBoolean(false); this.ioTectonicUnload = new Semaphore(LOCK_SIZE, true);
loadedRegions = new KMap<>(); loadedRegions = new KMap<>();
lastUse = new KMap<>(); lastUse = new KMap<>();
ioBurst = MultiBurst.burst; ioBurst = MultiBurst.burst;
@ -422,19 +423,19 @@ public class Mantle {
throw new RuntimeException("The Mantle is closed"); throw new RuntimeException("The Mantle is closed");
} }
adjustedIdleDuration.set(baseIdleDuration); double idleDuration = baseIdleDuration;
if (loadedRegions.size() > tectonicLimit) { if (loadedRegions.size() > tectonicLimit) {
// todo update this correctly and maybe do something when its above a 100% // todo update this correctly and maybe do something when its above a 100%
adjustedIdleDuration.set(Math.max(adjustedIdleDuration.get() - (1000 * (((loadedRegions.size() - tectonicLimit) / (double) tectonicLimit) * 100) * 0.4), 4000)); idleDuration = Math.max(idleDuration - (1000 * (((loadedRegions.size() - tectonicLimit) / (double) tectonicLimit) * 100) * 0.4), 4000);
} }
adjustedIdleDuration.set(idleDuration);
ioTrim.set(true); ioTrim.acquireUninterruptibly(LOCK_SIZE);
try { try {
double adjustedIdleDuration = this.adjustedIdleDuration.get(); Iris.debug("Trimming Tectonic Plates older than " + Form.duration(idleDuration, 0));
Iris.debug("Trimming Tectonic Plates older than " + Form.duration(adjustedIdleDuration, 0));
if (lastUse.isEmpty()) return; if (lastUse.isEmpty()) return;
double unloadTime = M.ms() - adjustedIdleDuration; double unloadTime = M.ms() - idleDuration;
for (long id : lastUse.keySet()) { for (long id : lastUse.keySet()) {
hyperLock.withLong(id, () -> { hyperLock.withLong(id, () -> {
Long lastUseTime = lastUse.get(id); Long lastUseTime = lastUse.get(id);
@ -447,7 +448,7 @@ public class Mantle {
} catch (Throwable e) { } catch (Throwable e) {
Iris.reportError(e); Iris.reportError(e);
} finally { } finally {
ioTrim.set(false); ioTrim.release(LOCK_SIZE);
} }
} }
@ -460,9 +461,10 @@ public class Mantle {
BurstExecutor burst = ioBurst.burst(toUnload.size()); BurstExecutor burst = ioBurst.burst(toUnload.size());
burst.setMulticore(toUnload.size() > tectonicLimit); burst.setMulticore(toUnload.size() > tectonicLimit);
ioTectonicUnload.set(true); ioTectonicUnload.acquireUninterruptibly(LOCK_SIZE);
try { try {
for (long id : toUnload) { for (long id : toUnload) {
double unloadTime = M.ms() - adjustedIdleDuration.get();
burst.queue(() -> hyperLock.withLong(id, () -> { burst.queue(() -> hyperLock.withLong(id, () -> {
TectonicPlate m = loadedRegions.get(id); TectonicPlate m = loadedRegions.get(id);
if (m == null) { if (m == null) {
@ -471,17 +473,21 @@ public class Mantle {
return; return;
} }
var used = lastUse.getOrDefault(id, 0L);
if (!toUnload.contains(id) || used >= unloadTime) {
return;
}
if (m.inUse()) { if (m.inUse()) {
Iris.debug("Tectonic Plate was added to unload while in use " + C.DARK_GREEN + m.getX() + " " + m.getZ()); Iris.debug("Tectonic Plate was added to unload while in use " + C.DARK_GREEN + m.getX() + " " + m.getZ());
lastUse.put(id, M.ms()); use(id);
toUnload.remove(id);
return; return;
} }
try { try {
m.write(fileForRegion(dataFolder, id, false)); m.write(fileForRegion(dataFolder, id, false));
oldFileForRegion(dataFolder, id).delete(); oldFileForRegion(dataFolder, id).delete();
loadedRegions.remove(id); loadedRegions.remove(id, m);
lastUse.remove(id); lastUse.remove(id);
toUnload.remove(id); toUnload.remove(id);
i.incrementAndGet(); i.incrementAndGet();
@ -497,7 +503,7 @@ public class Mantle {
e.printStackTrace(); e.printStackTrace();
burst.complete(); burst.complete();
} finally { } finally {
ioTectonicUnload.set(false); ioTectonicUnload.release(LOCK_SIZE);
} }
return i.get(); return i.get();
} }
@ -513,30 +519,39 @@ public class Mantle {
*/ */
@RegionCoordinates @RegionCoordinates
private TectonicPlate get(int x, int z) { private TectonicPlate get(int x, int z) {
if (ioTrim.get() || ioTectonicUnload.get()) { boolean trim = ioTrim.tryAcquire();
boolean unload = ioTectonicUnload.tryAcquire();
try {
if (!trim || !unload) {
try {
return getSafe(x, z).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
Long key = key(x, z);
TectonicPlate p = loadedRegions.get(key);
if (p != null && !p.isClosed()) {
use(key);
return p;
}
try { try {
return getSafe(x, z).get(); return getSafe(x, z).get();
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread intterruption (hotload?)");
Iris.reportError(e);
} catch (ExecutionException e) { } catch (ExecutionException e) {
e.printStackTrace(); Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread execution exception (engine close?)");
Iris.reportError(e);
} }
} } finally {
if (trim) ioTrim.release();
TectonicPlate p = loadedRegions.get(key(x, z)); if (unload) ioTectonicUnload.release();
if (p != null) {
return p;
}
try {
return getSafe(x, z).get();
} catch (InterruptedException e) {
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread intterruption (hotload?)");
Iris.reportError(e);
} catch (ExecutionException e) {
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread execution exception (engine close?)");
Iris.reportError(e);
} }
Iris.warn("Retrying to get " + x + " " + z + " Mantle Region"); Iris.warn("Retrying to get " + x + " " + z + " Mantle Region");
@ -553,19 +568,12 @@ public class Mantle {
*/ */
@RegionCoordinates @RegionCoordinates
private Future<TectonicPlate> getSafe(int x, int z) { private Future<TectonicPlate> getSafe(int x, int z) {
Long k = key(x, z);
TectonicPlate p = loadedRegions.get(k);
if (p != null) {
lastUse.put(k, M.ms());
return CompletableFuture.completedFuture(p);
}
return ioBurst.completeValue(() -> hyperLock.withResult(x, z, () -> { return ioBurst.completeValue(() -> hyperLock.withResult(x, z, () -> {
lastUse.put(k, M.ms()); Long k = key(x, z);
use(k);
TectonicPlate region = loadedRegions.get(k); TectonicPlate region = loadedRegions.get(k);
if (region != null) { if (region != null && !region.isClosed()) {
return region; return region;
} }
@ -593,16 +601,23 @@ public class Mantle {
Iris.debug("Created new Tectonic Plate (Due to Load Failure) " + C.DARK_GREEN + x + " " + z); Iris.debug("Created new Tectonic Plate (Due to Load Failure) " + C.DARK_GREEN + x + " " + z);
} }
use(k);
return region; return region;
} }
region = new TectonicPlate(worldHeight, x, z); region = new TectonicPlate(worldHeight, x, z);
loadedRegions.put(k, region); loadedRegions.put(k, region);
Iris.debug("Created new Tectonic Plate " + C.DARK_GREEN + x + " " + z); Iris.debug("Created new Tectonic Plate " + C.DARK_GREEN + x + " " + z);
use(k);
return region; return region;
})); }));
} }
private void use(Long key) {
lastUse.put(key, M.ms());
toUnload.remove(key);
}
public void saveAll() { public void saveAll() {
} }

View File

@ -29,6 +29,7 @@ import com.volmit.iris.util.matter.Matter;
import com.volmit.iris.util.matter.MatterSlice; import com.volmit.iris.util.matter.MatterSlice;
import com.volmit.iris.util.parallel.AtomicBooleanArray; import com.volmit.iris.util.parallel.AtomicBooleanArray;
import lombok.Getter; import lombok.Getter;
import lombok.SneakyThrows;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
@ -118,9 +119,11 @@ public class MantleChunk {
} }
} }
public void close() throws InterruptedException { @SneakyThrows
public void close() {
closed.set(true); closed.set(true);
ref.acquire(Integer.MAX_VALUE); ref.acquire(Integer.MAX_VALUE);
ref.release(Integer.MAX_VALUE);
} }
public boolean inUse() { public boolean inUse() {
@ -130,6 +133,10 @@ public class MantleChunk {
public MantleChunk use() { public MantleChunk use() {
if (closed.get()) throw new IllegalStateException("Chunk is closed!"); if (closed.get()) throw new IllegalStateException("Chunk is closed!");
ref.acquireUninterruptibly(); ref.acquireUninterruptibly();
if (closed.get()) {
ref.release();
throw new IllegalStateException("Chunk is closed!");
}
return this; return this;
} }
@ -220,6 +227,7 @@ public class MantleChunk {
* @throws IOException shit happens * @throws IOException shit happens
*/ */
public void write(DataOutputStream dos) throws IOException { public void write(DataOutputStream dos) throws IOException {
close();
dos.writeByte(x); dos.writeByte(x);
dos.writeByte(z); dos.writeByte(z);
dos.writeByte(sections.length()); dos.writeByte(sections.length());

View File

@ -39,6 +39,7 @@ import java.nio.channels.FileChannel;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReferenceArray; import java.util.concurrent.atomic.AtomicReferenceArray;
/** /**
@ -52,6 +53,7 @@ public class TectonicPlate {
private final int sectionHeight; private final int sectionHeight;
private final AtomicReferenceArray<MantleChunk> chunks; private final AtomicReferenceArray<MantleChunk> chunks;
private final AtomicBoolean closed;
@Getter @Getter
private final int x; private final int x;
@ -67,6 +69,7 @@ public class TectonicPlate {
public TectonicPlate(int worldHeight, int x, int z) { public TectonicPlate(int worldHeight, int x, int z) {
this.sectionHeight = worldHeight >> 4; this.sectionHeight = worldHeight >> 4;
this.chunks = new AtomicReferenceArray<>(1024); this.chunks = new AtomicReferenceArray<>(1024);
this.closed = new AtomicBoolean(false);
this.x = x; this.x = x;
this.z = z; this.z = z;
} }
@ -143,6 +146,7 @@ public class TectonicPlate {
} }
public void close() throws InterruptedException { public void close() throws InterruptedException {
closed.set(true);
for (int i = 0; i < chunks.length(); i++) { for (int i = 0; i < chunks.length(); i++) {
MantleChunk chunk = chunks.get(i); MantleChunk chunk = chunks.get(i);
if (chunk != null) { if (chunk != null) {
@ -151,6 +155,10 @@ public class TectonicPlate {
} }
} }
public boolean isClosed() {
return closed.get();
}
/** /**
* Check if a chunk exists in this plate or not (same as get(x, z) != null) * Check if a chunk exists in this plate or not (same as get(x, z) != null)
* *

View File

@ -0,0 +1,35 @@
package com.volmit.iris.util.matter.slices;
import com.volmit.iris.util.data.palette.Palette;
import com.volmit.iris.util.matter.Sliced;
import com.volmit.iris.util.matter.slices.container.JigsawPieceContainer;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@Sliced
public class JigsawStructureMatter extends RawMatter<JigsawPieceContainer> {
public JigsawStructureMatter() {
this(1,1,1);
}
public JigsawStructureMatter(int width, int height, int depth) {
super(width, height, depth, JigsawPieceContainer.class);
}
@Override
public Palette<JigsawPieceContainer> getGlobalPalette() {
return null;
}
@Override
public void writeNode(JigsawPieceContainer b, DataOutputStream dos) throws IOException {
dos.writeUTF(b.getLoadKey());
}
@Override
public JigsawPieceContainer readNode(DataInputStream din) throws IOException {
return new JigsawPieceContainer(din.readUTF());
}
}

View File

@ -0,0 +1,13 @@
package com.volmit.iris.util.matter.slices.container;
import com.volmit.iris.engine.object.IrisJigsawStructure;
public class JigsawStructureContainer extends RegistrantContainer<IrisJigsawStructure> {
public JigsawStructureContainer(String loadKey) {
super(IrisJigsawStructure.class, loadKey);
}
public static JigsawStructureContainer toContainer(IrisJigsawStructure structure) {
return new JigsawStructureContainer(structure.getLoadKey());
}
}

View File

@ -23,9 +23,11 @@ import org.bstats.charts.SimplePie;
import org.bstats.charts.SingleLineChart; import org.bstats.charts.SingleLineChart;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import oshi.SystemInfo; import oshi.SystemInfo;
import java.io.InputStreamReader;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.HashMap; import java.util.HashMap;
@ -45,6 +47,9 @@ public class Bindings {
if (settings.disableAutoReporting || Sentry.isEnabled() || Boolean.getBoolean("iris.suppressReporting")) return; if (settings.disableAutoReporting || Sentry.isEnabled() || Boolean.getBoolean("iris.suppressReporting")) return;
Iris.info("Enabling Sentry for anonymous error reporting. You can disable this in the settings."); Iris.info("Enabling Sentry for anonymous error reporting. You can disable this in the settings.");
Iris.info("Your server ID is: " + ServerID.ID); Iris.info("Your server ID is: " + ServerID.ID);
var resource = Iris.instance.getResource("plugin.yml");
YamlConfiguration desc = resource != null ? YamlConfiguration.loadConfiguration(new InputStreamReader(resource)) : new YamlConfiguration();
Sentry.init(options -> { Sentry.init(options -> {
options.setDsn("https://b16ecc222e9c1e0c48faecacb906fd89@o4509451052646400.ingest.de.sentry.io/4509452722765904"); options.setDsn("https://b16ecc222e9c1e0c48faecacb906fd89@o4509451052646400.ingest.de.sentry.io/4509452722765904");
if (settings.debug) { if (settings.debug) {
@ -55,6 +60,7 @@ public class Bindings {
options.setAttachServerName(false); options.setAttachServerName(false);
options.setEnableUncaughtExceptionHandler(false); options.setEnableUncaughtExceptionHandler(false);
options.setRelease(Iris.instance.getDescription().getVersion()); options.setRelease(Iris.instance.getDescription().getVersion());
options.setEnvironment(desc.getString("environment", "production"));
options.setBeforeSend((event, hint) -> { options.setBeforeSend((event, hint) -> {
if (suppress(event.getThrowable())) return null; if (suppress(event.getThrowable())) return null;
event.setTag("iris.safeguard", IrisSafeguard.mode()); event.setTag("iris.safeguard", IrisSafeguard.mode());
@ -71,6 +77,7 @@ public class Bindings {
scope.setTag("server", Bukkit.getVersion()); scope.setTag("server", Bukkit.getVersion());
scope.setTag("server.type", Bukkit.getName()); scope.setTag("server.type", Bukkit.getName());
scope.setTag("server.api", Bukkit.getBukkitVersion()); scope.setTag("server.api", Bukkit.getBukkitVersion());
scope.setTag("iris.commit", desc.getString("commit", "unknown"));
}); });
Runtime.getRuntime().addShutdownHook(new Thread(Sentry::close)); Runtime.getRuntime().addShutdownHook(new Thread(Sentry::close));
} }

View File

@ -1,5 +1,8 @@
package com.volmit.iris.util.misc; package com.volmit.iris.util.misc;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
@ -22,12 +25,13 @@ public class ServerProperties {
String bukkitYml = "bukkit.yml"; String bukkitYml = "bukkit.yml";
String levelName = null; String levelName = null;
for (int i = 0; i < args.length - 1; i++) { for (int i = 0; i < args.length; i++) {
switch (args[i]) { String arg = args[i];
case "-c", "--config" -> propertiesPath = args[i + 1]; String next = i < args.length - 1 ? args[i + 1] : null;
case "-b", "--bukkit-settings" -> bukkitYml = args[i + 1];
case "-w", "--level-name", "--world" -> levelName = args[i + 1]; propertiesPath = parse(arg, next, propertiesPath, "-c", "--config");
} bukkitYml = parse(arg, next, bukkitYml, "-b", "--bukkit-settings");
levelName = parse(arg, next, levelName, "-w", "--level-name", "--world");
} }
SERVER_PROPERTIES = new File(propertiesPath); SERVER_PROPERTIES = new File(propertiesPath);
@ -41,4 +45,19 @@ public class ServerProperties {
if (levelName != null) LEVEL_NAME = levelName; if (levelName != null) LEVEL_NAME = levelName;
else LEVEL_NAME = DATA.getProperty("level-name", "world"); else LEVEL_NAME = DATA.getProperty("level-name", "world");
} }
private static String parse(
@NotNull String current,
@Nullable String next,
String fallback,
@NotNull String @NotNull ... keys
) {
for (String k : keys) {
if (current.equals(k) && next != null)
return next;
if (current.startsWith(k + "=") && current.length() > k.length() + 1)
return current.substring(k.length() + 1);
}
return fallback;
}
} }

View File

@ -1,15 +1,32 @@
package com.volmit.iris.util.misc; package com.volmit.iris.util.misc;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.util.collection.KList;
import io.github.slimjar.app.builder.ApplicationBuilder; import io.github.slimjar.app.builder.ApplicationBuilder;
import io.github.slimjar.injector.loader.IsolatedInjectableClassLoader;
import io.github.slimjar.injector.loader.factory.InjectableFactory;
import io.github.slimjar.logging.ProcessLogger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.logging.Logger; import java.util.logging.Logger;
public class SlimJar { public class SlimJar {
private static final Logger LOGGER = Logger.getLogger("Iris"); private static final String NAME = "Iris";
private static final Logger LOGGER = Logger.getLogger(NAME);
private static final boolean DEBUG = Boolean.getBoolean("iris.debug-slimjar");
private static final boolean DISABLE_REMAPPER = Boolean.getBoolean("iris.disable-remapper");
private static final ReentrantLock lock = new ReentrantLock(); private static final ReentrantLock lock = new ReentrantLock();
private static final AtomicBoolean loaded = new AtomicBoolean(); private static final AtomicBoolean loaded = new AtomicBoolean();
@ -23,15 +40,85 @@ public class SlimJar {
localRepository = new File(".iris/libraries"); localRepository = new File(".iris/libraries");
} }
ApplicationBuilder.appending("Iris") LOGGER.info("Loading libraries...");
.downloadDirectoryPath(localRepository.toPath()) load(localRepository.toPath(), new ProcessLogger() {
.logger((message, args) -> { @Override
if (!message.startsWith("Loaded library ")) return; public void info(@NotNull String message, @Nullable Object... args) {
LOGGER.info(message.formatted(args)); if (!DEBUG) return;
}) LOGGER.info(message.formatted(args));
.build(); }
@Override
public void error(@NotNull String message, @Nullable Object... args) {
LOGGER.severe(message.formatted(args));
}
@Override
public void debug(@NotNull String message, @Nullable Object... args) {
if (!DEBUG) return;
LOGGER.info(message.formatted(args));
}
});
LOGGER.info("Libraries loaded successfully!");
} finally { } finally {
lock.unlock(); lock.unlock();
} }
} }
private static void load(Path downloadPath, ProcessLogger logger) {
try {
loadSpigot(downloadPath, logger);
} catch (Throwable e) {
Iris.warn("Failed to inject the library loader, falling back to application builder");
ApplicationBuilder.appending(NAME)
.injectableFactory(InjectableFactory.selecting(InjectableFactory.ERROR, InjectableFactory.INJECTABLE, InjectableFactory.WRAPPED, InjectableFactory.UNSAFE))
.downloadDirectoryPath(downloadPath)
.logger(logger)
.build();
}
}
private static void loadSpigot(Path downloadPath, ProcessLogger logger) throws Throwable {
var current = SlimJar.class.getClassLoader();
var libraryLoaderField = current.getClass().getDeclaredField("libraryLoader");
libraryLoaderField.setAccessible(true);
if (!ClassLoader.class.isAssignableFrom(libraryLoaderField.getType())) throw new IllegalStateException("Failed to find library loader");
final var libraryLoader = (ClassLoader) libraryLoaderField.get(current);
final var pair = findRemapper();
final var remapper = pair.getA();
final var factory = pair.getB();
final var classpath = new KList<URL>();
ApplicationBuilder.injecting(NAME, classpath::add)
.downloadDirectoryPath(downloadPath)
.logger(logger)
.build();
final var urls = remapper.andThen(KList::new)
.apply(classpath.convertNasty(url -> Path.of(url.toURI())))
.convertNasty(path -> path.toUri().toURL())
.toArray(URL[]::new);
libraryLoaderField.set(current, factory.apply(urls, libraryLoader == null ? current.getParent() : libraryLoader));
}
private static Pair<Function<List<Path>, List<Path>>, BiFunction<URL[], ClassLoader, URLClassLoader>> findRemapper() {
Function<List<Path>, List<Path>> mapper = null;
BiFunction<URL[], ClassLoader, URLClassLoader> factory = null;
if (!DISABLE_REMAPPER) {
try {
var libraryLoader = Class.forName("org.bukkit.plugin.java.LibraryLoader");
var mapperField = libraryLoader.getDeclaredField("REMAPPER");
var factoryField = libraryLoader.getDeclaredField("LIBRARY_LOADER_FACTORY");
mapperField.setAccessible(true);
factoryField.setAccessible(true);
mapper = (Function<List<Path>, List<Path>>) mapperField.get(null);
factory = (BiFunction<URL[], ClassLoader, URLClassLoader>) factoryField.get(null);
} catch (Throwable ignored) {}
}
if (mapper == null) mapper = Function.identity();
if (factory == null) factory = (urls, parent) -> new IsolatedInjectableClassLoader(urls, List.of(), parent);
return new Pair<>(mapper, factory);
}
} }

View File

@ -0,0 +1,46 @@
package com.volmit.iris.util.parallel;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.scheduling.SR;
import org.jetbrains.annotations.NotNull;
import java.util.Queue;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
public class SyncExecutor implements Executor, AutoCloseable {
private final CountDownLatch latch = new CountDownLatch(1);
private final Queue<Runnable> queue = new ConcurrentLinkedQueue<>();
private final AtomicBoolean closed = new AtomicBoolean(false);
public SyncExecutor(int msPerTick) {
new SR() {
@Override
public void run() {
var time = M.ms() + msPerTick;
while (time > M.ms()) {
Runnable r = queue.poll();
if (r == null) break;
r.run();
}
if (closed.get() && queue.isEmpty()) {
cancel();
latch.countDown();
}
}
};
}
@Override
public void execute(@NotNull Runnable command) {
if (closed.get()) throw new IllegalStateException("Executor is closed!");
queue.add(command);
}
@Override
public void close() throws Exception {
closed.set(true);
latch.await();
}
}

View File

@ -240,6 +240,21 @@ public class J {
return f; return f;
} }
public static <T> CompletableFuture<T> sfut(Supplier<T> r) {
CompletableFuture<T> f = new CompletableFuture<>();
if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) {
return null;
}
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> {
try {
f.complete(r.get());
} catch (Throwable e) {
f.completeExceptionally(e);
}
});
return f;
}
public static CompletableFuture sfut(Runnable r, int delay) { public static CompletableFuture sfut(Runnable r, int delay) {
CompletableFuture f = new CompletableFuture(); CompletableFuture f = new CompletableFuture();

View File

@ -5,6 +5,8 @@ load: STARTUP
authors: [ cyberpwn, NextdoorPsycho, Vatuu ] authors: [ cyberpwn, NextdoorPsycho, Vatuu ]
website: volmit.com website: volmit.com
description: More than a Dimension! description: More than a Dimension!
environment: '${environment}'
commit: '${commit}'
commands: commands:
iris: iris:
aliases: [ ir, irs ] aliases: [ ir, irs ]

View File

@ -5,10 +5,11 @@
[versions] [versions]
# Plugins # Plugins
shadow = "9.0.0-rc1" # https://plugins.gradle.org/plugin/com.gradleup.shadow shadow = "9.0.0-rc1" # https://plugins.gradle.org/plugin/com.gradleup.shadow
slimjar = "2.0.6" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar slimjar = "2.1.2" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar
download = "5.6.0" # https://plugins.gradle.org/plugin/de.undercouch.download download = "5.6.0" # https://plugins.gradle.org/plugin/de.undercouch.download
runPaper = "2.3.1" # https://plugins.gradle.org/plugin/xyz.jpenilla.run-paper runPaper = "2.3.1" # https://plugins.gradle.org/plugin/xyz.jpenilla.run-paper
sentryPlugin = "5.8.0" # https://github.com/getsentry/sentry-android-gradle-plugin sentryPlugin = "5.8.0" # https://github.com/getsentry/sentry-android-gradle-plugin
grgit = "5.3.2" # https://github.com/ajoberstar/grgit
# Core Libraries # Core Libraries
lombok = "1.18.38" lombok = "1.18.38"
@ -116,3 +117,4 @@ runPaper = { id = "xyz.jpenilla.run-paper", version.ref = "runPaper" }
sentry = { id = "io.sentry.jvm.gradle", version.ref = "sentryPlugin" } sentry = { id = "io.sentry.jvm.gradle", version.ref = "sentryPlugin" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-lombok = { id = "org.jetbrains.kotlin.plugin.lombok", version.ref = "kotlin" } kotlin-lombok = { id = "org.jetbrains.kotlin.plugin.lombok", version.ref = "kotlin" }
grgit = { id = "org.ajoberstar.grgit", version.ref = "grgit" }