[VERY VERY VERY BAD IDEA]

This commit is contained in:
Brian Neumann-Fopiano committed 2026-09-20 04:24:42 -04:00
1 parent f0e7fea13b
commit 2fa0853e42
892 files changed
+13482 -53554

No files matched your search

@@ -56,7 +56,7 @@ import art.arcane.volmlib.util.director.help.DirectorMiniMenu;
import art.arcane.volmlib.util.localization.BukkitLanguageSwitcher;
import art.arcane.iris.integration.MultiverseCoreLink;
import art.arcane.iris.platform.bukkit.nms.INMS;
import art.arcane.iris.platform.bukkit.nms.ServerShutdownBoundary;
import art.arcane.volmlib.nativelib.terrain.ServerShutdownBoundary;
import art.arcane.iris.studio.view.BukkitGuiHost;
import art.arcane.iris.studio.view.PregeneratorJob;
import art.arcane.iris.platform.bukkit.BoardSVC;
@@ -782,7 +782,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
reconcileStartupWorlds();
}
IrisToolbelt.retainMantleDataForSlice(String.class.getCanonicalName());
// The mantle stores block values as PlatformBlockState, so a BlockData retention can never
// The mantle stores block values as NativeBlockState, so a BlockData retention can never
// match a slice type; the block-state slice is deliberately never retainable (regenerable, huge).
IrisToolbelt.retainMantleDataForSlice(TreeBlockMaterial.class.getCanonicalName());
});
@@ -1270,6 +1270,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
} else {
try {
INMS.get().releasePluginClassLoaderClose();
SlimJar.closeNativeProviders();
} catch (Throwable failure) {
SHUTDOWN_ERRORS.println("[Iris] Failed to release the plugin class loader after runtime cleanup.");
failure.printStackTrace(SHUTDOWN_ERRORS);
@@ -9,7 +9,7 @@ import art.arcane.iris.world.lifecycle.WorldReplacementBootstrap;
import art.arcane.iris.world.lifecycle.WorldReplacementBootstrapMarker;
import art.arcane.iris.pack.DefaultPackBootstrapProvisioner;
import art.arcane.iris.pack.DefaultPackBootstrapProvisioner.BootstrapRequest;
import art.arcane.iris.platform.bukkit.nms.datapack.DataVersion;
import art.arcane.iris.pack.datapack.DataVersion;
import io.papermc.paper.ServerBuildInfo;
import art.arcane.iris.pack.DefaultPackBootstrapProvisioner.ProvisionResult;
import art.arcane.iris.platform.bootstrap.SlimJar;
@@ -46,6 +46,7 @@ public final class IrisBootstrap implements PluginBootstrap {
private static void loadRuntimeLibraries(BootstrapContext context) {
SlimJar.loadBootstrap(
context.getDataDirectory().resolve("cache").resolve("libraries"),
ServerBuildInfo.buildInfo().minecraftVersionId(),
new SlimJar.BootstrapLogger() {
@Override
public void info(String message) {
@@ -1,6 +1,7 @@
package art.arcane.iris;
import art.arcane.iris.platform.bootstrap.SlimJar;
import io.papermc.paper.ServerBuildInfo;
import io.papermc.paper.plugin.bootstrap.PluginProviderContext;
import io.papermc.paper.plugin.loader.PluginClasspathBuilder;
import io.papermc.paper.plugin.loader.PluginLoader;
@@ -18,7 +19,7 @@ public final class IrisPluginLoader implements PluginLoader {
public void classloader(PluginClasspathBuilder classpathBuilder) {
PluginProviderContext context = classpathBuilder.getContext();
Path libraryRoot = context.getDataDirectory().resolve("cache").resolve("libraries");
SlimJar.loadBootstrap(libraryRoot, new SlimJar.BootstrapLogger() {
SlimJar.loadBootstrap(libraryRoot, ServerBuildInfo.buildInfo().minecraftVersionId(), new SlimJar.BootstrapLogger() {
@Override
public void info(String message) {
context.getLogger().info(message);
@@ -35,7 +36,9 @@ public final class IrisPluginLoader implements PluginLoader {
}
});
for (Path library : relocatedLibraries(libraryRoot)) {
classpathBuilder.addLibrary(new JarLibrary(library));
if (!library.startsWith(libraryRoot.resolve("com/github/VolmitSoftware/VolmLib"))) {
classpathBuilder.addLibrary(new JarLibrary(library));
}
}
}
@@ -21,7 +21,7 @@ package art.arcane.iris.command;
import com.google.gson.JsonObject;
import art.arcane.iris.Iris;
import art.arcane.iris.pack.datapack.ServerConfigurator;
import art.arcane.iris.platform.bukkit.nms.datapack.DataVersion;
import art.arcane.iris.pack.datapack.DataVersion;
import art.arcane.iris.world.runtime.ChunkClearer;
import art.arcane.iris.generation.validation.GoldenHashScanner;
import art.arcane.iris.world.runtime.InPlaceChunkRegenerator;
@@ -44,7 +44,7 @@ import art.arcane.iris.generation.block.TileData;
import art.arcane.iris.platform.bukkit.BukkitBlockState;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.spi.PlatformBlockState;
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
import art.arcane.volmlib.util.data.Cuboid;
import art.arcane.iris.generation.block.IrisCustomData;
import art.arcane.iris.command.specialhandlers.NullableDimensionHandler;
@@ -218,7 +218,7 @@ public class CommandObject implements DirectorExecutor {
}
@Override
public void set(int x, int y, int z, PlatformBlockState s) {
public void set(int x, int y, int z, NativeBlockState s) {
BlockData d = (BlockData) s.nativeHandle();
Block block = world.getBlockAt(x, y, z);
@@ -242,7 +242,7 @@ public class CommandObject implements DirectorExecutor {
}
@Override
public PlatformBlockState get(int x, int y, int z) {
public NativeBlockState get(int x, int y, int z) {
return BukkitBlockState.of(world.getBlockAt(x, y, z).getBlockData());
}
@@ -20,7 +20,7 @@ package art.arcane.iris.command;
import art.arcane.iris.Iris;
import art.arcane.iris.configuration.IrisSettings;
import art.arcane.iris.generation.cache.AtomicCache;
import art.arcane.volmlib.util.cache.AtomicCache;
import art.arcane.iris.localization.C;
import art.arcane.iris.platform.bukkit.plugin.IrisService;
import art.arcane.iris.platform.bukkit.plugin.VolmitSender;
@@ -111,7 +111,7 @@ public class CommandWhat implements DirectorExecutor {
if (key == null || key.getKey().equals("custom")) {
try {
commandSender.sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_WHAT_DATA_PACK_BIOME_ID, MessageArgument.untrusted("value", INMS.get().getTrueBiomeBaseKey(location)), MessageArgument.untrusted("value2", INMS.get().getTrueBiomeBaseId(INMS.get().getTrueBiomeBase(location)))));
commandSender.sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_WHAT_DATA_PACK_BIOME_ID, MessageArgument.untrusted("value", INMS.get().getTrueBiomeBaseKey(location)), MessageArgument.untrusted("value2", INMS.get().getBiomeId(location))));
} catch (Throwable ee) {
Iris.reportError(ee);
}
@@ -18,6 +18,8 @@
package art.arcane.iris.studio.view;
import art.arcane.volmlib.nativelib.view.WorldMarker;
import art.arcane.iris.generation.runtime.IrisComplex;
import art.arcane.iris.generation.runtime.Engine;
import art.arcane.iris.studio.render.RenderType;
@@ -45,7 +47,7 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import static art.arcane.iris.platform.bukkit.registry.Attributes.MAX_HEALTH;
import static art.arcane.iris.platform.registry.Attributes.MAX_HEALTH;
public final class BukkitVisionOverlay implements GuiOverlay {
private final Engine engine;
@@ -54,7 +56,7 @@ public final class BukkitVisionOverlay implements GuiOverlay {
private final AtomicBoolean playerRefreshQueued = new AtomicBoolean();
private final AtomicLong teleportSequence = new AtomicLong();
private final AtomicReference<VisionTeleportRequest> latestTeleport = new AtomicReference<>();
private volatile List<GuiMarker> playerMarkers = List.of();
private volatile List<WorldMarker> playerMarkers = List.of();
public BukkitVisionOverlay(Engine engine, UUID openerId) {
this.engine = engine;
@@ -66,7 +68,7 @@ public final class BukkitVisionOverlay implements GuiOverlay {
* built by a server thread.
*/
@Override
public List<GuiMarker> players() {
public List<WorldMarker> players() {
queuePlayerRefresh();
return playerMarkers;
}
@@ -78,10 +80,10 @@ public final class BukkitVisionOverlay implements GuiOverlay {
boolean scheduled = J.runGlobal(() -> {
try {
List<GuiMarker> markers = new ArrayList<>();
List<WorldMarker> markers = new ArrayList<>();
for (Player player : BukkitWorldBinding.players(engine.getWorld())) {
Location at = player.getLocation();
markers.add(GuiMarker.player(player.getName(), at.getX(), at.getZ()));
markers.add(WorldMarker.player(player.getName(), at.getX(), at.getZ()));
}
playerMarkers = List.copyOf(markers);
} finally {
@@ -95,7 +97,7 @@ public final class BukkitVisionOverlay implements GuiOverlay {
}
@Override
public void requestEntities(Consumer<List<GuiMarker>> sink) {
public void requestEntities(Consumer<List<WorldMarker>> sink) {
J.runGlobal(() -> {
IrisWorld target = engine.getWorld();
World world = BukkitWorldBinding.world(target);
@@ -116,7 +118,7 @@ public final class BukkitVisionOverlay implements GuiOverlay {
return;
}
List<GuiMarker> collected = Collections.synchronizedList(new ArrayList<>(living.size()));
List<WorldMarker> collected = Collections.synchronizedList(new ArrayList<>(living.size()));
AtomicInteger pending = new AtomicInteger(living.size());
Runnable complete = () -> {
if (pending.decrementAndGet() == 0) {
@@ -142,14 +144,14 @@ public final class BukkitVisionOverlay implements GuiOverlay {
});
}
private GuiMarker marker(LivingEntity entity, Location at) {
private WorldMarker marker(LivingEntity entity, Location at) {
String label = Form.capitalizeWords(entity.getType().name().toLowerCase(Locale.ROOT).replaceAll("\\Q_\\E", " "));
double maxHealth = 0;
try {
maxHealth = entity.getAttribute(MAX_HEALTH).getValue();
} catch (Throwable ignored) {
}
return GuiMarker.entity(label, at.getX(), at.getY(), at.getZ(), entity.getHealth(), maxHealth);
return WorldMarker.entity(label, at.getX(), at.getY(), at.getZ(), entity.getHealth(), maxHealth);
}
@Override
@@ -67,8 +67,8 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import static art.arcane.iris.platform.bukkit.registry.Particles.CRIT_MAGIC;
import static art.arcane.iris.platform.bukkit.registry.Particles.REDSTONE;
import static art.arcane.iris.platform.registry.Particles.CRIT_MAGIC;
import static art.arcane.iris.platform.registry.Particles.REDSTONE;
public class WandSVC implements IrisService {
private static final int MS_PER_TICK = Integer.parseInt(System.getProperty("iris.ms_per_tick", "30"));
@@ -26,7 +26,7 @@ import org.bukkit.entity.Player;
import java.awt.Color;
import static art.arcane.iris.platform.bukkit.registry.Particles.REDSTONE;
import static art.arcane.iris.platform.registry.Particles.REDSTONE;
public class WandSelection {
private static final double STEP = 0.10;
@@ -18,6 +18,8 @@
package art.arcane.iris.world;
import art.arcane.volmlib.nativelib.NativeAdapters;
import art.arcane.volmlib.nativelib.server.NativeServerDiagnostics;
import art.arcane.iris.pack.datapack.ServerConfigurator;
import art.arcane.iris.Iris;
@@ -413,19 +415,8 @@ public final class BukkitWorldReconciler {
}
private static boolean containsCreateWorldUnsupportedOperation(Throwable throwable) {
Throwable cursor = throwable;
while (cursor != null) {
if (cursor instanceof UnsupportedOperationException || cursor instanceof IllegalStateException) {
for (StackTraceElement element : cursor.getStackTrace()) {
if ("org.bukkit.craftbukkit.CraftServer".equals(element.getClassName())
&& "createWorld".equals(element.getMethodName())) {
return true;
}
}
}
cursor = cursor.getCause();
}
return false;
return NativeAdapters.find(NativeServerDiagnostics.class)
.map(diagnostics -> diagnostics.isRejectedWorldCreation(throwable)).orElse(false);
}
interface Backend {
@@ -36,7 +36,7 @@ import art.arcane.iris.world.history.SavedTerrainChunk;
import java.util.concurrent.CompletableFuture;
import art.arcane.iris.generation.runtime.EngineMode;
import art.arcane.iris.generation.runtime.EnginePlatformHooks;
import art.arcane.iris.structure.nativegen.NativeStructureVolume;
import art.arcane.volmlib.nativelib.terrain.structure.NativeStructureVolume;
import art.arcane.iris.generation.terrain.IrisDimension;
import art.arcane.iris.generation.terrain.IrisDimensionRuntimeContract;
import art.arcane.iris.world.IrisWorld;
@@ -0,0 +1,34 @@
plugins {
id 'java'
}
version = '1.0.0'
repositories {
mavenCentral()
maven { url = 'https://repo.papermc.io/repository/maven-public/' }
}
dependencies {
compileOnly files(providers.gradleProperty('irisJar').get())
compileOnly 'io.papermc.paper:paper-api:26.1.2.build.74-stable'
}
java {
toolchain.languageVersion = JavaLanguageVersion.of(25)
}
sourceSets {
main {
java.srcDirs = ['src']
resources.srcDirs = ['resources']
}
}
tasks.withType(JavaCompile).configureEach {
options.compilerArgs += '-parameters'
}
tasks.named('jar') {
archiveBaseName = 'IrisNativeLifecycleFixture'
}
@@ -0,0 +1,11 @@
name: IrisNativeLifecycleFixture
version: 1.0.0
main: art.arcane.iris.fixture.NativeLifecycleFixture
api-version: '26.1.2'
depend: [Iris]
commands:
irislifecycle:
permission: irislifecycle.run
permissions:
irislifecycle.run:
default: op
@@ -0,0 +1 @@
rootProject.name = 'iris-native-lifecycle-fixture'
@@ -0,0 +1,252 @@
package art.arcane.iris.fixture;
import art.arcane.volmlib.nativelib.NativeAdapters;
import art.arcane.iris.world.runtime.RuntimeInjection;
import art.arcane.iris.world.IrisCreator;
import art.arcane.iris.world.IrisToolbelt;
import org.bukkit.Material;
import org.bukkit.block.Biome;
import art.arcane.volmlib.nativelib.terrain.NativeTerrainAccess;
import art.arcane.volmlib.nativelib.terrain.NativeStructureReader;
import art.arcane.volmlib.nativelib.terrain.NativeWorldRuntime;
import art.arcane.volmlib.nativelib.terrain.WorldRuntimeExecution;
import art.arcane.volmlib.nativelib.terrain.WorldRuntimeOptions;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.concurrent.CompletableFuture;
import java.util.List;
import java.util.logging.Level;
public final class NativeLifecycleFixture extends JavaPlugin implements WorldRuntimeExecution {
private static final NamespacedKey WORLD_KEY = NamespacedKey.minecraft("native_lifecycle_probe");
private static final NamespacedKey TERRAIN_KEY = new NamespacedKey("iris", "native_terrain_probe");
private static final long WORLD_SEED = 78264193L;
private NativeWorldRuntime runtime;
@Override
public void onEnable() {
runtime = NativeAdapters.require(NativeWorldRuntime.class);
NativeTerrainAccess terrain = NativeAdapters.require(NativeTerrainAccess.class);
getLogger().info("Native lifecycle ready: " + runtime.description()
+ "; terrain provider=" + terrain.getClass().getName());
}
@Override
public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {
return new ChunkGenerator() {};
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] arguments) {
if (arguments.length != 1) {
sender.sendMessage("Use /irislifecycle create|unload|status|structures|terrain-create|terrain-check|terrain-unload");
return true;
}
try {
switch (arguments[0]) {
case "create" -> create(sender);
case "unload" -> unload(sender);
case "structures" -> structures(sender);
case "terrain-create" -> createTerrain(sender);
case "terrain-check" -> checkTerrain(sender);
case "terrain-unload" -> unloadTerrain(sender);
case "status" -> sender.sendMessage("NATIVE_STATUS available=" + runtime.available()
+ " loaded=" + (Bukkit.getWorld(WORLD_KEY) != null));
default -> throw new IllegalArgumentException("Unknown lifecycle operation");
}
} catch (Throwable failure) {
fail(sender, failure);
}
return true;
}
private void create(CommandSender sender) throws ReflectiveOperationException {
if (!runtime.available() || Bukkit.getWorld(WORLD_KEY) != null) {
throw new IllegalStateException("Native runtime unavailable or probe world already loaded");
}
RuntimeInjection.installIfDeferred();
WorldRuntimeOptions options = new WorldRuntimeOptions(WORLD_KEY.getKey(), WORLD_KEY,
World.Environment.NORMAL, null, getName() + ":runtime", false, WORLD_SEED, false,
Bukkit.getWorlds().getFirst().getWorldFolder());
World world = runtime.create(options, this);
if (!WORLD_KEY.equals(world.getKey()) || world.getSeed() != WORLD_SEED) {
throw new IllegalStateException("World identity or seed differs from requested options");
}
world.getChunkAtAsync(0, 0, true).whenComplete((chunk, failure) -> runGlobal(() -> {
if (failure != null) {
fail(sender, failure);
return;
}
if (chunk == null || chunk.getWorld() != world || !chunk.isLoaded()) {
fail(sender, new IllegalStateException("Native runtime world failed chunk generation"));
return;
}
sender.sendMessage("NATIVE_CREATED seed=" + world.getSeed() + " chunk=true");
}));
}
private void createTerrain(CommandSender sender) {
if (Bukkit.getWorld(TERRAIN_KEY) != null) {
throw new IllegalStateException("Terrain world is already loaded");
}
runAsync(() -> {
try {
new IrisCreator().name(TERRAIN_KEY.toString()).dimension("native-terrain")
.seed(WORLD_SEED).create();
runGlobal(() -> checkTerrain(sender));
} catch (Throwable failure) {
runGlobal(() -> fail(sender, failure));
}
});
}
private void checkTerrain(CommandSender sender) {
World world = Bukkit.getWorld(TERRAIN_KEY);
if (world == null || world.getSeed() != WORLD_SEED || !IrisToolbelt.isIrisWorld(world)
|| IrisToolbelt.access(world).getEngine() == null) {
throw new IllegalStateException("Iris terrain engine or world identity is absent");
}
world.getChunkAtAsync(2, -3, true).whenComplete((chunk, failure) -> runGlobal(() -> {
if (failure != null) {
fail(sender, failure);
return;
}
try {
int columns = 0;
for (int x = 32; x < 48; x += 5) {
for (int z = -48; z < -32; z += 5) {
int y = world.getHighestBlockYAt(x, z);
if (y < 90 || y > 100 || world.getBlockAt(x, y, z).getType() != Material.LIME_WOOL
|| world.getBlockAt(x, y - 3, z).getType() != Material.GREEN_CONCRETE
|| world.getBiome(x, y, z) != Biome.PLAINS) {
throw new IllegalStateException("Terrain column differs at " + x + "," + y + "," + z
+ ": " + world.getBlockAt(x, y, z).getType());
}
columns++;
}
}
sender.sendMessage("NATIVE_TERRAIN seed=" + world.getSeed() + " columns=" + columns + " biome=plains");
} catch (Throwable assertion) {
fail(sender, assertion);
}
}));
}
private void unloadTerrain(CommandSender sender) {
World world = Bukkit.getWorld(TERRAIN_KEY);
if (world == null) {
throw new IllegalStateException("Terrain world is absent");
}
runtime.unload(world, true, this).whenComplete((unloaded, failure) -> runGlobal(() -> {
if (failure != null) {
fail(sender, failure);
} else if (!Boolean.TRUE.equals(unloaded) || Bukkit.getWorld(TERRAIN_KEY) != null) {
fail(sender, new IllegalStateException("Terrain world did not unload"));
} else {
sender.sendMessage("NATIVE_TERRAIN_UNLOADED true");
}
}));
}
private void structures(CommandSender sender) throws Exception {
NativeStructureReader reader = NativeAdapters.require(NativeStructureReader.class);
List<String> templates = reader.templates();
if (!templates.contains("minecraft:village/plains/town_centers/plains_fountain_01")) {
throw new IllegalStateException("Vanilla village template was not enumerated");
}
NativeStructureReader.Session session = reader.open();
NativeStructureReader.Structure village = session.structure("minecraft:village_plains");
if (village == null || !village.jigsaw() || village.maxDepth() <= 0
|| village.maxDistanceFromCenter() <= 0) {
throw new IllegalStateException("Vanilla village metadata is missing");
}
NativeStructureReader.Pool pool = session.pool(village.startPoolKey());
if (pool == null || !"minecraft:empty".equals(pool.fallbackKey()) || pool.entries().isEmpty()) {
throw new IllegalStateException("Vanilla village start pool is missing");
}
int connectorCount = 0;
for (NativeStructureReader.Entry entry : pool.entries()) {
NativeStructureReader.Element element = entry.element();
if (entry.weight() <= 0 || element == null || element.templateLocation() == null) {
throw new IllegalStateException("Vanilla village pool element is invalid");
}
NativeStructureReader.ConnectorSet connectors = element.connectors(() -> 91L);
if (connectors.status() != NativeStructureReader.ConnectorStatus.AVAILABLE) {
throw new IllegalStateException("Vanilla village connectors unavailable");
}
for (NativeStructureReader.Connector connector : connectors.connectors()) {
NativeStructureReader.ConnectorData data = connector.read();
if (data.front() == null || data.top() == null || data.pool() == null
|| data.metadata().finalState() == null) {
throw new IllegalStateException("Vanilla village connector metadata is incomplete");
}
connectorCount++;
}
}
if (connectorCount == 0) {
throw new IllegalStateException("Vanilla village pool has no connectors");
}
sender.sendMessage("NATIVE_STRUCTURES templates=" + templates.size() + " village=true connectors=" + connectorCount);
}
private void unload(CommandSender sender) {
World world = Bukkit.getWorld(WORLD_KEY);
if (world == null) {
throw new IllegalStateException("Probe world is absent");
}
runtime.unload(world, true, this).whenComplete((unloaded, failure) -> runGlobal(() -> {
if (failure != null) {
fail(sender, failure);
} else if (!Boolean.TRUE.equals(unloaded) || Bukkit.getWorld(WORLD_KEY) != null) {
fail(sender, new IllegalStateException("Native unload did not remove the world"));
} else {
sender.sendMessage("NATIVE_UNLOADED true");
}
}));
}
public boolean regionized() {
return false;
}
public boolean primaryThread() {
return Bukkit.isPrimaryThread();
}
public CompletableFuture<Void> runGlobal(Runnable task) {
CompletableFuture<Void> result = new CompletableFuture<>();
Runnable wrapped = () -> {
try {
task.run();
result.complete(null);
} catch (Throwable failure) {
result.completeExceptionally(failure);
}
};
if (Bukkit.isPrimaryThread()) {
wrapped.run();
} else {
Bukkit.getScheduler().runTask(this, wrapped);
}
return result;
}
public CompletableFuture<Void> runAsync(Runnable task) {
return CompletableFuture.runAsync(task);
}
public void reportFailure(String message, Throwable failure) {
getLogger().log(Level.SEVERE, message, failure);
}
private void fail(CommandSender sender, Throwable failure) {
reportFailure("Native lifecycle assertion failed", failure);
sender.sendMessage("NATIVE_FAILED " + failure.getMessage());
}
}
@@ -0,0 +1,22 @@
export default {
name: 'iris-native-lifecycle',
description: 'Verify native structure metadata, runtime world creation, seeded chunk generation, and asynchronous unload.',
async run(context) {
await context.step('native world capability is available', async () => {
await context.command('/irislifecycle status', /NATIVE_STATUS available=true loaded=false/, 10000)
})
await context.step('read vanilla templates, village pools, and connector metadata', async () => {
const response = await context.command('/irislifecycle structures', /NATIVE_STRUCTURES|NATIVE_FAILED/, 30000)
context.expect(/NATIVE_STRUCTURES templates=\d+ village=true connectors=[1-9]\d*/.test(response), response)
})
await context.step('create a world with the requested seed and generate a chunk', async () => {
const response = await context.command('/irislifecycle create', /NATIVE_CREATED|NATIVE_FAILED/, 90000)
context.expect(response.includes('NATIVE_CREATED seed=78264193 chunk=true'), response)
})
await context.step('unload and detach the created world', async () => {
const response = await context.command('/irislifecycle unload', /NATIVE_UNLOADED|NATIVE_FAILED/, 90000)
context.expect(response.includes('NATIVE_UNLOADED true'), response)
await context.command('/irislifecycle status', /NATIVE_STATUS available=true loaded=false/, 10000)
})
}
}
@@ -0,0 +1,23 @@
{
"name": "Flat",
"derivative": "minecraft:plains",
"vanillaDerivative": "minecraft:plains",
"layers": [
{
"minHeight": 1,
"maxHeight": 1,
"palette": [
{
"block": "minecraft:lime_wool"
}
]
}
],
"generators": [
{
"generator": "flat",
"min": 96,
"max": 96
}
]
}
@@ -0,0 +1,28 @@
{
"name": "Native Terrain",
"version": 1,
"mode": {
"type": "OVERWORLD"
},
"regions": [
"flat"
],
"focusRegion": "flat",
"focus": "flat",
"landChance": 1,
"environment": "NORMAL",
"dimensionHeight": {
"min": -64,
"max": 320
},
"logicalHeight": 384,
"fluidHeight": 0,
"bedrock": false,
"rockPalette": {
"palette": [
{
"block": "minecraft:green_concrete"
}
]
}
}
@@ -0,0 +1,15 @@
{
"interpolator": {
"function": "NONE",
"horizontalScale": 1
},
"seed": 310,
"composite": [
{
"seed": 310,
"style": {
"style": "FLAT"
}
}
]
}
@@ -0,0 +1,12 @@
{
"name": "Flat",
"landBiomes": [
"flat"
],
"seaBiomes": [
"flat"
],
"shoreBiomes": [
"flat"
]
}
@@ -0,0 +1,18 @@
export default {
name: 'iris-native-terrain',
description: 'Generate an Iris pack through the shared native adapter and verify terrain, biome, seed, and unload.',
async run(context) {
await context.step('create a real Iris terrain world', async () => {
const response = await context.command('/irislifecycle terrain-create', /NATIVE_TERRAIN seed=|NATIVE_FAILED/, 180000)
context.expect(response.includes('NATIVE_TERRAIN seed=78264193 columns=16 biome=plains'), response)
})
await context.step('read generated terrain again', async () => {
const response = await context.command('/irislifecycle terrain-check', /NATIVE_TERRAIN seed=|NATIVE_FAILED/, 60000)
context.expect(response.includes('NATIVE_TERRAIN seed=78264193 columns=16 biome=plains'), response)
})
await context.step('save and unload the terrain world', async () => {
const response = await context.command('/irislifecycle terrain-unload', /NATIVE_TERRAIN_UNLOADED|NATIVE_FAILED/, 90000)
context.expect(response.includes('NATIVE_TERRAIN_UNLOADED true'), response)
})
}
}
@@ -4,7 +4,7 @@ import art.arcane.iris.integration.Identifier;
import art.arcane.iris.integration.ExternalDataSVC;
import art.arcane.iris.structure.object.IObjectPlacer;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.spi.PlatformBlockState;
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
import art.arcane.iris.generation.block.IrisCustomData;
import org.bukkit.Material;
import org.bukkit.World;
@@ -37,7 +37,7 @@ public class CommandObjectCustomBlockPlacementTest {
BlockData previousCustom = IrisCustomData.of(previous, new Identifier("craftengine", "test/lamp[lit=false]"));
Identifier id = new Identifier("craftengine", "test/lamp[lit=true]");
BlockData base = mock(BlockData.class);
PlatformBlockState state = mock(PlatformBlockState.class);
NativeBlockState state = mock(NativeBlockState.class);
when(state.nativeHandle()).thenReturn(IrisCustomData.of(base, id));
ExternalDataSVC external = mock(ExternalDataSVC.class);
when(external.captureBlockData(previous)).thenReturn(previousCustom);
@@ -65,7 +65,7 @@ public class CommandObjectCustomBlockPlacementTest {
when(target.getType()).thenReturn(Material.STONE);
BlockData base = mock(BlockData.class);
Identifier id = new Identifier("craftengine", "test/chair[variant=alpha]");
PlatformBlockState state = mock(PlatformBlockState.class);
NativeBlockState state = mock(NativeBlockState.class);
when(state.nativeHandle()).thenReturn(IrisCustomData.of(base, id));
ExternalDataSVC external = mock(ExternalDataSVC.class);
try (MockedStatic<IrisServices> services = mockStatic(IrisServices.class)) {
@@ -1,6 +1,6 @@
package art.arcane.iris.studio.wand;
import art.arcane.iris.platform.bukkit.registry.RegistryUtil;
import art.arcane.iris.platform.registry.RegistryUtil;
import art.arcane.volmlib.util.data.Cuboid;
import art.arcane.volmlib.util.math.M;
import org.bukkit.Location;