mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-23 16:44:06 +00:00
[VERY VERY VERY BAD IDEA]
This commit is contained in:
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);
|
||||
}
|
||||
|
||||
+11
-9
@@ -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;
|
||||
|
||||
+4
-13
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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'
|
||||
}
|
||||
+11
@@ -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'
|
||||
+252
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
+28
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -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
-1
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user