mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-08-30 14:00:53 +00:00
Honor bound platform
- Route shared runtime hooks through the active Iris platform instead of classpath presence. - Keep Bukkit-specific mantle and Matter behavior behind explicit platform capabilities. - Cover hybrid classpaths and bound hook precedence with regression tests.
This commit is contained in:
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
package art.arcane.iris.engine;
|
package art.arcane.iris.engine;
|
||||||
|
|
||||||
import art.arcane.iris.spi.IrisPlatforms;
|
|
||||||
import art.arcane.iris.core.IrisSettings;
|
import art.arcane.iris.core.IrisSettings;
|
||||||
import art.arcane.iris.core.loader.IrisData;
|
import art.arcane.iris.core.loader.IrisData;
|
||||||
import art.arcane.iris.core.tools.WorldMaintenance;
|
import art.arcane.iris.core.tools.WorldMaintenance;
|
||||||
@@ -32,6 +31,7 @@ import art.arcane.iris.engine.mantle.components.MantleFloatingObjectComponent;
|
|||||||
import art.arcane.iris.engine.mantle.components.MantleObjectComponent;
|
import art.arcane.iris.engine.mantle.components.MantleObjectComponent;
|
||||||
import art.arcane.iris.engine.mantle.components.IrisStructureComponent;
|
import art.arcane.iris.engine.mantle.components.IrisStructureComponent;
|
||||||
import art.arcane.iris.spi.IrisLogging;
|
import art.arcane.iris.spi.IrisLogging;
|
||||||
|
import art.arcane.iris.spi.IrisPlatforms;
|
||||||
import art.arcane.iris.spi.PlatformBlockState;
|
import art.arcane.iris.spi.PlatformBlockState;
|
||||||
import art.arcane.iris.util.project.matter.IrisMatterContext;
|
import art.arcane.iris.util.project.matter.IrisMatterContext;
|
||||||
import art.arcane.iris.util.project.matter.IrisMatterSupport;
|
import art.arcane.iris.util.project.matter.IrisMatterSupport;
|
||||||
@@ -51,7 +51,6 @@ import art.arcane.iris.util.common.format.C;
|
|||||||
import art.arcane.volmlib.util.matter.IrisMatter;
|
import art.arcane.volmlib.util.matter.IrisMatter;
|
||||||
import art.arcane.volmlib.util.matter.Matter;
|
import art.arcane.volmlib.util.matter.Matter;
|
||||||
import art.arcane.volmlib.util.matter.MatterSlice;
|
import art.arcane.volmlib.util.matter.MatterSlice;
|
||||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
|
||||||
import art.arcane.iris.util.common.parallel.HyperLock;
|
import art.arcane.iris.util.common.parallel.HyperLock;
|
||||||
import art.arcane.iris.util.common.parallel.MultiBurst;
|
import art.arcane.iris.util.common.parallel.MultiBurst;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
@@ -73,7 +72,6 @@ import java.util.function.Supplier;
|
|||||||
@EqualsAndHashCode(exclude = "engine")
|
@EqualsAndHashCode(exclude = "engine")
|
||||||
@ToString(exclude = "engine")
|
@ToString(exclude = "engine")
|
||||||
public class IrisEngineMantle implements EngineMantle {
|
public class IrisEngineMantle implements EngineMantle {
|
||||||
private static final boolean BUKKIT_PRESENT = IrisMatterSupport.isBukkitPresent();
|
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final Mantle<Matter> mantle;
|
private final Mantle<Matter> mantle;
|
||||||
@Getter(AccessLevel.NONE)
|
@Getter(AccessLevel.NONE)
|
||||||
@@ -248,10 +246,7 @@ public class IrisEngineMantle implements EngineMantle {
|
|||||||
if (value instanceof PlatformBlockState) {
|
if (value instanceof PlatformBlockState) {
|
||||||
return PlatformBlockState.class;
|
return PlatformBlockState.class;
|
||||||
}
|
}
|
||||||
if (BUKKIT_PRESENT) {
|
return IrisPlatforms.get().classifyMantleValue(value);
|
||||||
return BukkitPlatform.classifyMantleValue(value);
|
|
||||||
}
|
|
||||||
return value.getClass();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -43,21 +43,11 @@ final class DecoratorCore {
|
|||||||
private static final String WEEPING_VINES_PLANT = "minecraft:weeping_vines_plant";
|
private static final String WEEPING_VINES_PLANT = "minecraft:weeping_vines_plant";
|
||||||
private static final String TWISTING_VINES = "minecraft:twisting_vines";
|
private static final String TWISTING_VINES = "minecraft:twisting_vines";
|
||||||
private static final String TWISTING_VINES_PLANT = "minecraft:twisting_vines_plant";
|
private static final String TWISTING_VINES_PLANT = "minecraft:twisting_vines_plant";
|
||||||
private static final boolean BUKKIT_PRESENT = detectBukkit();
|
|
||||||
private static volatile PlatformBlockState weepingVines;
|
private static volatile PlatformBlockState weepingVines;
|
||||||
private static volatile PlatformBlockState weepingVinesPlant;
|
private static volatile PlatformBlockState weepingVinesPlant;
|
||||||
private static volatile PlatformBlockState twistingVines;
|
private static volatile PlatformBlockState twistingVines;
|
||||||
private static volatile PlatformBlockState twistingVinesPlant;
|
private static volatile PlatformBlockState twistingVinesPlant;
|
||||||
|
|
||||||
private static boolean detectBukkit() {
|
|
||||||
try {
|
|
||||||
Class.forName("org.bukkit.Bukkit", false, DecoratorCore.class.getClassLoader());
|
|
||||||
return true;
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static final ThreadLocal<PlaceOpts> SCRATCH_OPTS = ThreadLocal.withInitial(PlaceOpts::new);
|
static final ThreadLocal<PlaceOpts> SCRATCH_OPTS = ThreadLocal.withInitial(PlaceOpts::new);
|
||||||
|
|
||||||
static final class PlaceOpts {
|
static final class PlaceOpts {
|
||||||
@@ -391,9 +381,9 @@ final class DecoratorCore {
|
|||||||
if (!B.isVineBlock(b)) {
|
if (!B.isVineBlock(b)) {
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
if (!BUKKIT_PRESENT) {
|
|
||||||
DecoratorPlatformHooks.FaceFixer fixer = DecoratorPlatformHooks.faceFixer();
|
DecoratorPlatformHooks.FaceFixer fixer = DecoratorPlatformHooks.faceFixer();
|
||||||
return fixer == null ? b : fixer.fixFaces(b, hunk, rX, rZ, x, y, z, mantle);
|
if (fixer != null) {
|
||||||
|
return fixer.fixFaces(b, hunk, rX, rZ, x, y, z, mantle);
|
||||||
}
|
}
|
||||||
BlockData rawB = (BlockData) b.nativeHandle();
|
BlockData rawB = (BlockData) b.nativeHandle();
|
||||||
BlockData cloned = rawB.clone();
|
BlockData cloned = rawB.clone();
|
||||||
@@ -447,9 +437,9 @@ final class DecoratorCore {
|
|||||||
if (!B.canPlaceOnto(decorator, surface)) {
|
if (!B.canPlaceOnto(decorator, surface)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!BUKKIT_PRESENT) {
|
|
||||||
DecoratorPlatformHooks.SurfaceSturdiness sturdiness = DecoratorPlatformHooks.surfaceSturdiness();
|
DecoratorPlatformHooks.SurfaceSturdiness sturdiness = DecoratorPlatformHooks.surfaceSturdiness();
|
||||||
return sturdiness == null ? B.isSolid(surface) : sturdiness.canGoOn(surface);
|
if (sturdiness != null) {
|
||||||
|
return sturdiness.canGoOn(surface);
|
||||||
}
|
}
|
||||||
return ((BlockData) surface.nativeHandle()).isFaceSturdy(BlockFace.UP, BlockSupport.FULL);
|
return ((BlockData) surface.nativeHandle()).isFaceSturdy(BlockFace.UP, BlockSupport.FULL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import java.util.Objects;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public final class BlockDataMergeSupport {
|
public final class BlockDataMergeSupport {
|
||||||
private static final boolean BUKKIT_PRESENT = detectBukkit();
|
|
||||||
private static volatile StateMerger PLATFORM_MERGER = null;
|
private static volatile StateMerger PLATFORM_MERGER = null;
|
||||||
|
|
||||||
private BlockDataMergeSupport() {
|
private BlockDataMergeSupport() {
|
||||||
@@ -29,31 +28,15 @@ public final class BlockDataMergeSupport {
|
|||||||
PLATFORM_MERGER = merger;
|
PLATFORM_MERGER = merger;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean detectBukkit() {
|
|
||||||
try {
|
|
||||||
Class.forName("org.bukkit.Bukkit", false, BlockDataMergeSupport.class.getClassLoader());
|
|
||||||
return true;
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PlatformBlockState merge(PlatformBlockState base, PlatformBlockState update) {
|
static PlatformBlockState merge(PlatformBlockState base, PlatformBlockState update) {
|
||||||
if (!BUKKIT_PRESENT) {
|
StateMerger merger = PLATFORM_MERGER;
|
||||||
StateMerger merger = requirePlatformMerger(PLATFORM_MERGER);
|
if (merger != null) {
|
||||||
return merger.merge(base, update);
|
return merger.merge(base, update);
|
||||||
}
|
}
|
||||||
BlockData merged = merge((BlockData) base.nativeHandle(), (BlockData) update.nativeHandle(), BukkitBlockResolution::get);
|
BlockData merged = merge((BlockData) base.nativeHandle(), (BlockData) update.nativeHandle(), BukkitBlockResolution::get);
|
||||||
return merged == null ? null : BukkitBlockState.of(merged);
|
return merged == null ? null : BukkitBlockState.of(merged);
|
||||||
}
|
}
|
||||||
|
|
||||||
static StateMerger requirePlatformMerger(StateMerger merger) {
|
|
||||||
if (merger == null) {
|
|
||||||
throw new IllegalStateException("No platform block-state merger is bound");
|
|
||||||
}
|
|
||||||
return merger;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BlockData merge(BlockData base, BlockData update, Function<String, BlockData> resolver) {
|
static BlockData merge(BlockData base, BlockData update, Function<String, BlockData> resolver) {
|
||||||
try {
|
try {
|
||||||
return base.merge(update);
|
return base.merge(update);
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ import java.util.Set;
|
|||||||
@Desc("Configures rotation for iris")
|
@Desc("Configures rotation for iris")
|
||||||
@Data
|
@Data
|
||||||
public class IrisObjectRotation {
|
public class IrisObjectRotation {
|
||||||
private static final boolean BUKKIT_PRESENT = detectBukkit();
|
|
||||||
private static volatile StateRotator PLATFORM_ROTATOR = null;
|
private static volatile StateRotator PLATFORM_ROTATOR = null;
|
||||||
|
|
||||||
public interface StateRotator {
|
public interface StateRotator {
|
||||||
@@ -70,15 +69,6 @@ public class IrisObjectRotation {
|
|||||||
PLATFORM_ROTATOR = rotator;
|
PLATFORM_ROTATOR = rotator;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean detectBukkit() {
|
|
||||||
try {
|
|
||||||
Class.forName("org.bukkit.Bukkit", false, IrisObjectRotation.class.getClassLoader());
|
|
||||||
return true;
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class Faces {
|
private static final class Faces {
|
||||||
private static final List<BlockFace> WALL_FACES = List.of(BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST);
|
private static final List<BlockFace> WALL_FACES = List.of(BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST);
|
||||||
}
|
}
|
||||||
@@ -298,8 +288,8 @@ public class IrisObjectRotation {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!BUKKIT_PRESENT) {
|
StateRotator rotator = PLATFORM_ROTATOR;
|
||||||
StateRotator rotator = requirePlatformRotator(PLATFORM_ROTATOR);
|
if (rotator != null) {
|
||||||
return rotator.rotate(this, state, spinx, spiny, spinz);
|
return rotator.rotate(this, state, spinx, spiny, spinz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,13 +303,6 @@ public class IrisObjectRotation {
|
|||||||
return rotated == null ? null : BukkitBlockState.of(rotated);
|
return rotated == null ? null : BukkitBlockState.of(rotated);
|
||||||
}
|
}
|
||||||
|
|
||||||
static StateRotator requirePlatformRotator(StateRotator rotator) {
|
|
||||||
if (rotator == null) {
|
|
||||||
throw new IllegalStateException("No platform block-state rotator is bound");
|
|
||||||
}
|
|
||||||
return rotator;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean canRotateBlockData(BlockData data) {
|
private static boolean canRotateBlockData(BlockData data) {
|
||||||
return data instanceof Directional
|
return data instanceof Directional
|
||||||
|| data instanceof Rotatable
|
|| data instanceof Rotatable
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ import java.util.stream.StreamSupport;
|
|||||||
/**
|
/**
|
||||||
* Bukkit-only pre-key tile format. Unreachable from the modded loaders: every entry point is
|
* Bukkit-only pre-key tile format. Unreachable from the modded loaders: every entry point is
|
||||||
* either Bukkit-typed ({@link #fromBukkit(BlockState)}, reached only from
|
* either Bukkit-typed ({@link #fromBukkit(BlockState)}, reached only from
|
||||||
* {@link TileData#getTileState(Block, boolean)} and the Bukkit structure importer) or sits behind
|
* {@link TileData#getTileState(Block, boolean)} and the Bukkit structure importer) or follows the
|
||||||
* the {@code BUKKIT_PRESENT} short-circuit in {@link TileData#read(DataInputStream)}, which hands
|
* bound platform-reader path in {@link TileData#read(DataInputStream)}, which returns before this
|
||||||
* off to the bound platform reader before this class is ever referenced. The nested handler types
|
* class is ever referenced. The nested handler types
|
||||||
* therefore keep their raw Bukkit fields.
|
* therefore keep their raw Bukkit fields.
|
||||||
*/
|
*/
|
||||||
@ToString
|
@ToString
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ public class TileData implements Cloneable {
|
|||||||
* never part of that walk. Bounded by the number of distinct material keys a pack can name.
|
* never part of that walk. Bounded by the number of distinct material keys a pack can name.
|
||||||
*/
|
*/
|
||||||
private static final Map<String, Material> RESOLVED_MATERIALS = new ConcurrentHashMap<>();
|
private static final Map<String, Material> RESOLVED_MATERIALS = new ConcurrentHashMap<>();
|
||||||
private static final boolean BUKKIT_PRESENT = detectBukkit();
|
|
||||||
private static volatile TileReader PLATFORM_READER = null;
|
private static volatile TileReader PLATFORM_READER = null;
|
||||||
private static volatile TileFactory PLATFORM_FACTORY = null;
|
private static volatile TileFactory PLATFORM_FACTORY = null;
|
||||||
|
|
||||||
@@ -96,15 +95,6 @@ public class TileData implements Cloneable {
|
|||||||
PLATFORM_FACTORY = factory;
|
PLATFORM_FACTORY = factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean detectBukkit() {
|
|
||||||
try {
|
|
||||||
Class.forName("org.bukkit.Bukkit", false, TileData.class.getClassLoader());
|
|
||||||
return true;
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The block key this tile belongs to, stored as text so the field type never drags
|
* The block key this tile belongs to, stored as text so the field type never drags
|
||||||
* org.bukkit.Material onto a Gson field walk or into generated equals/hashCode/toString.
|
* org.bukkit.Material onto a Gson field walk or into generated equals/hashCode/toString.
|
||||||
@@ -147,8 +137,9 @@ public class TileData implements Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static TileData of(PlatformBlockState state, KMap<String, Object> properties) {
|
public static TileData of(PlatformBlockState state, KMap<String, Object> properties) {
|
||||||
if (!BUKKIT_PRESENT) {
|
TileFactory factory = PLATFORM_FACTORY;
|
||||||
return requirePlatformFactory(PLATFORM_FACTORY).create(state, properties);
|
if (factory != null) {
|
||||||
|
return factory.create(state, properties);
|
||||||
}
|
}
|
||||||
Object handle = state.nativeHandle();
|
Object handle = state.nativeHandle();
|
||||||
if (!(handle instanceof BlockData blockData)) {
|
if (!(handle instanceof BlockData blockData)) {
|
||||||
@@ -158,8 +149,9 @@ public class TileData implements Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static TileData read(DataInputStream in) throws IOException {
|
public static TileData read(DataInputStream in) throws IOException {
|
||||||
if (!BUKKIT_PRESENT) {
|
TileReader reader = PLATFORM_READER;
|
||||||
return requirePlatformReader(PLATFORM_READER).read(in);
|
if (reader != null) {
|
||||||
|
return reader.read(in);
|
||||||
}
|
}
|
||||||
if (!in.markSupported())
|
if (!in.markSupported())
|
||||||
throw new IOException("Mark not supported");
|
throw new IOException("Mark not supported");
|
||||||
@@ -215,20 +207,6 @@ public class TileData implements Cloneable {
|
|||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TileFactory requirePlatformFactory(TileFactory factory) {
|
|
||||||
if (factory == null) {
|
|
||||||
throw new IllegalStateException("No platform tile-data factory is bound");
|
|
||||||
}
|
|
||||||
return factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TileReader requirePlatformReader(TileReader reader) throws IOException {
|
|
||||||
if (reader == null) {
|
|
||||||
throw new IOException("No platform tile-data reader is bound");
|
|
||||||
}
|
|
||||||
return reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isApplicable(BlockData data) {
|
public boolean isApplicable(BlockData data) {
|
||||||
Material resolved = resolveMaterial();
|
Material resolved = resolveMaterial();
|
||||||
return resolved != null && data.getMaterial() == resolved;
|
return resolved != null && data.getMaterial() == resolved;
|
||||||
|
|||||||
@@ -175,7 +175,8 @@ public final class BukkitPlatform implements IrisPlatform {
|
|||||||
return BukkitBiome.of((Biome) biome);
|
return BukkitBiome.of((Biome) biome);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Class<?> classifyMantleValue(Object value) {
|
@Override
|
||||||
|
public Class<?> classifyMantleValue(Object value) {
|
||||||
if (value instanceof World) {
|
if (value instanceof World) {
|
||||||
return World.class;
|
return World.class;
|
||||||
}
|
}
|
||||||
@@ -191,6 +192,11 @@ public final class BukkitPlatform implements IrisPlatform {
|
|||||||
return value.getClass();
|
return value.getClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsMatterWorldIo() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static void unregisterListener(Object candidate) {
|
public static void unregisterListener(Object candidate) {
|
||||||
if (candidate instanceof Listener listener) {
|
if (candidate instanceof Listener listener) {
|
||||||
volmitPlugin().unregisterListener(listener);
|
volmitPlugin().unregisterListener(listener);
|
||||||
|
|||||||
@@ -36,25 +36,11 @@ import art.arcane.iris.util.common.math.IrisBlockVector;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
public final class IrisMatterSupport {
|
public final class IrisMatterSupport {
|
||||||
private static final boolean BUKKIT_PRESENT = detectBukkit();
|
|
||||||
private static boolean registered;
|
private static boolean registered;
|
||||||
|
|
||||||
private IrisMatterSupport() {
|
private IrisMatterSupport() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isBukkitPresent() {
|
|
||||||
return BUKKIT_PRESENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean detectBukkit() {
|
|
||||||
try {
|
|
||||||
Class.forName("org.bukkit.World", false, IrisMatterSupport.class.getClassLoader());
|
|
||||||
return true;
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized void ensureRegistered() {
|
public static synchronized void ensureRegistered() {
|
||||||
if (registered) {
|
if (registered) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ package art.arcane.iris.util.project.matter.slices;
|
|||||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||||
import art.arcane.iris.core.nms.INMS;
|
import art.arcane.iris.core.nms.INMS;
|
||||||
import art.arcane.iris.engine.object.IrisPosition;
|
import art.arcane.iris.engine.object.IrisPosition;
|
||||||
import art.arcane.iris.util.project.matter.IrisMatterSupport;
|
import art.arcane.iris.spi.IrisPlatforms;
|
||||||
import art.arcane.volmlib.util.collection.KList;
|
import art.arcane.volmlib.util.collection.KList;
|
||||||
import art.arcane.volmlib.util.collection.KMap;
|
import art.arcane.volmlib.util.collection.KMap;
|
||||||
import art.arcane.volmlib.util.data.Varint;
|
import art.arcane.volmlib.util.data.Varint;
|
||||||
@@ -53,7 +53,7 @@ public class EntityMatter extends RawMatter<MatterEntityGroup> {
|
|||||||
|
|
||||||
public EntityMatter(int width, int height, int depth) {
|
public EntityMatter(int width, int height, int depth) {
|
||||||
super(width, height, depth, MatterEntityGroup.class);
|
super(width, height, depth, MatterEntityGroup.class);
|
||||||
if (IrisMatterSupport.isBukkitPresent()) {
|
if (IrisPlatforms.isBound() && IrisPlatforms.get().supportsMatterWorldIo()) {
|
||||||
registerBukkitIO();
|
registerBukkitIO();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ package art.arcane.iris.util.project.matter.slices;
|
|||||||
|
|
||||||
import art.arcane.iris.engine.object.TileData;
|
import art.arcane.iris.engine.object.TileData;
|
||||||
|
|
||||||
import art.arcane.iris.util.project.matter.IrisMatterSupport;
|
import art.arcane.iris.spi.IrisPlatforms;
|
||||||
import art.arcane.iris.util.project.matter.TileWrapper;
|
import art.arcane.iris.util.project.matter.TileWrapper;
|
||||||
import art.arcane.volmlib.util.data.palette.Palette;
|
import art.arcane.volmlib.util.data.palette.Palette;
|
||||||
import art.arcane.volmlib.util.matter.Sliced;
|
import art.arcane.volmlib.util.matter.Sliced;
|
||||||
@@ -42,7 +42,7 @@ public class TileMatter extends RawMatter<TileWrapper> {
|
|||||||
|
|
||||||
public TileMatter(int width, int height, int depth) {
|
public TileMatter(int width, int height, int depth) {
|
||||||
super(width, height, depth, TileWrapper.class);
|
super(width, height, depth, TileWrapper.class);
|
||||||
if (IrisMatterSupport.isBukkitPresent()) {
|
if (IrisPlatforms.isBound() && IrisPlatforms.get().supportsMatterWorldIo()) {
|
||||||
registerBukkitIO();
|
registerBukkitIO();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public class IrisEnginePlatformHookIsolationTest {
|
|||||||
);
|
);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sharedGeneratorHotPathsDoNotLinkBukkitImplementations() throws IOException {
|
public void sharedGeneratorHotPathsDoNotLinkBukkitImplementations() throws IOException, ClassNotFoundException {
|
||||||
assertNoClassLinks(IrisEngine.class, BUKKIT_ENGINE_CLASSES);
|
assertNoClassLinks(IrisEngine.class, BUKKIT_ENGINE_CLASSES);
|
||||||
assertNoClassLinks(EngineBackgroundTasks.class, BUKKIT_ENGINE_CLASSES);
|
assertNoClassLinks(EngineBackgroundTasks.class, BUKKIT_ENGINE_CLASSES);
|
||||||
assertNoClassLinks(EngineDataStore.class, BUKKIT_ENGINE_CLASSES);
|
assertNoClassLinks(EngineDataStore.class, BUKKIT_ENGINE_CLASSES);
|
||||||
@@ -56,6 +56,8 @@ public class IrisEnginePlatformHookIsolationTest {
|
|||||||
assertNoClassLinks(EngineRuntimeBuilder.class, BUKKIT_ENGINE_CLASSES);
|
assertNoClassLinks(EngineRuntimeBuilder.class, BUKKIT_ENGINE_CLASSES);
|
||||||
assertNoClassLinks(EngineShutdownSequence.class, BUKKIT_ENGINE_CLASSES);
|
assertNoClassLinks(EngineShutdownSequence.class, BUKKIT_ENGINE_CLASSES);
|
||||||
assertNoClassLinks(EngineTickRegistry.class, BUKKIT_ENGINE_CLASSES);
|
assertNoClassLinks(EngineTickRegistry.class, BUKKIT_ENGINE_CLASSES);
|
||||||
|
assertNoClassLinks(IrisEngineMantle.class, BUKKIT_ENGINE_CLASSES);
|
||||||
|
assertNoClassLinks(Class.forName(IrisEngineMantle.class.getName() + "$1"), BUKKIT_ENGINE_CLASSES);
|
||||||
assertNoClassLinks(Engine.class, ENGINE_POLICY_CLASSES);
|
assertNoClassLinks(Engine.class, ENGINE_POLICY_CLASSES);
|
||||||
assertNoClassLinks(EngineMode.class, PLATFORM_POLICY_CLASSES);
|
assertNoClassLinks(EngineMode.class, PLATFORM_POLICY_CLASSES);
|
||||||
assertNoClassLinks(EngineMantle.class, PLATFORM_POLICY_CLASSES);
|
assertNoClassLinks(EngineMantle.class, PLATFORM_POLICY_CLASSES);
|
||||||
@@ -63,7 +65,8 @@ public class IrisEnginePlatformHookIsolationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void assertNoClassLinks(Class<?> type, List<String> forbiddenClasses) throws IOException {
|
private static void assertNoClassLinks(Class<?> type, List<String> forbiddenClasses) throws IOException {
|
||||||
InputStream stream = type.getResourceAsStream(type.getSimpleName() + ".class");
|
String resourceName = type.getName().substring(type.getName().lastIndexOf('.') + 1) + ".class";
|
||||||
|
InputStream stream = type.getResourceAsStream(resourceName);
|
||||||
assertNotNull(stream);
|
assertNotNull(stream);
|
||||||
String bytecode;
|
String bytecode;
|
||||||
try (InputStream input = stream) {
|
try (InputStream input = stream) {
|
||||||
|
|||||||
@@ -429,6 +429,28 @@ public class DecoratorCoreTest {
|
|||||||
assertEquals("minecraft:twisting_vines", DecoratorCore.stackedVineKey(vine, 3, 2));
|
assertEquals("minecraft:twisting_vines", DecoratorCore.stackedVineKey(vine, 3, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void boundDecoratorHooksWinWhenBukkitClassesArePresent() {
|
||||||
|
PlatformBlockState vine = mock(PlatformBlockState.class);
|
||||||
|
PlatformBlockState fixed = mock(PlatformBlockState.class);
|
||||||
|
PlatformBlockState decorator = mock(PlatformBlockState.class);
|
||||||
|
PlatformBlockState surface = mock(PlatformBlockState.class);
|
||||||
|
Hunk<PlatformBlockState> output = Hunk.newArrayHunk(1, 1, 1);
|
||||||
|
DecoratorPlatformHooks.FaceFixer faceFixer = mock(DecoratorPlatformHooks.FaceFixer.class);
|
||||||
|
DecoratorPlatformHooks.SurfaceSturdiness sturdiness = mock(DecoratorPlatformHooks.SurfaceSturdiness.class);
|
||||||
|
when(vine.isVineBlock()).thenReturn(true);
|
||||||
|
when(faceFixer.fixFaces(vine, output, 0, 0, 0, 0, 0, null)).thenReturn(fixed);
|
||||||
|
when(decorator.canPlaceOnto(surface)).thenReturn(true);
|
||||||
|
when(sturdiness.canGoOn(surface)).thenReturn(true);
|
||||||
|
DecoratorPlatformHooks.Bindings previous = DecoratorPlatformHooks.bind(faceFixer, sturdiness);
|
||||||
|
try {
|
||||||
|
assertSame(fixed, DecoratorCore.fixFacesForHunk(vine, output, 0, 0, 0, 0, 0, null));
|
||||||
|
assertTrue(DecoratorCore.canGoOn(decorator, surface));
|
||||||
|
} finally {
|
||||||
|
DecoratorPlatformHooks.restore(previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private PlatformBlockState airState() {
|
private PlatformBlockState airState() {
|
||||||
PlatformBlockState air = mock(PlatformBlockState.class);
|
PlatformBlockState air = mock(PlatformBlockState.class);
|
||||||
when(air.isAir()).thenReturn(true);
|
when(air.isAir()).thenReturn(true);
|
||||||
|
|||||||
+54
-22
@@ -1,42 +1,74 @@
|
|||||||
package art.arcane.iris.engine.object;
|
package art.arcane.iris.engine.object;
|
||||||
|
|
||||||
|
import art.arcane.iris.spi.PlatformBlockState;
|
||||||
|
import art.arcane.volmlib.util.collection.KMap;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertSame;
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
public class PlatformStateHookContractTest {
|
public class PlatformStateHookContractTest {
|
||||||
@Test
|
@Test
|
||||||
public void missingPlatformRotatorFailsLoudly() {
|
public void boundRotatorWinsWhenBukkitClassesArePresent() {
|
||||||
IllegalStateException error = assertThrows(IllegalStateException.class,
|
PlatformBlockState source = mock(PlatformBlockState.class);
|
||||||
() -> IrisObjectRotation.requirePlatformRotator(null));
|
PlatformBlockState rotated = mock(PlatformBlockState.class);
|
||||||
|
IrisObjectRotation.StateRotator hook = mock(IrisObjectRotation.StateRotator.class);
|
||||||
assertEquals("No platform block-state rotator is bound", error.getMessage());
|
IrisObjectRotation rotation = new IrisObjectRotation();
|
||||||
|
when(hook.rotate(rotation, source, 1, 2, 3)).thenReturn(rotated);
|
||||||
|
IrisObjectRotation.StateRotator previous = IrisObjectRotation.bindPlatformRotator(hook);
|
||||||
|
try {
|
||||||
|
assertSame(rotated, rotation.rotate(source, 1, 2, 3));
|
||||||
|
} finally {
|
||||||
|
IrisObjectRotation.restorePlatformRotator(previous);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void missingPlatformMergerFailsLoudly() {
|
public void boundMergerWinsWhenBukkitClassesArePresent() {
|
||||||
IllegalStateException error = assertThrows(IllegalStateException.class,
|
PlatformBlockState base = mock(PlatformBlockState.class);
|
||||||
() -> BlockDataMergeSupport.requirePlatformMerger(null));
|
PlatformBlockState update = mock(PlatformBlockState.class);
|
||||||
|
PlatformBlockState merged = mock(PlatformBlockState.class);
|
||||||
assertEquals("No platform block-state merger is bound", error.getMessage());
|
BlockDataMergeSupport.StateMerger hook = mock(BlockDataMergeSupport.StateMerger.class);
|
||||||
|
when(hook.merge(base, update)).thenReturn(merged);
|
||||||
|
BlockDataMergeSupport.StateMerger previous = BlockDataMergeSupport.bindPlatformMerger(hook);
|
||||||
|
try {
|
||||||
|
assertSame(merged, BlockDataMergeSupport.merge(base, update));
|
||||||
|
} finally {
|
||||||
|
BlockDataMergeSupport.restorePlatformMerger(previous);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void missingPlatformTileFactoryFailsLoudly() {
|
public void boundTileFactoryWinsWhenBukkitClassesArePresent() {
|
||||||
IllegalStateException error = assertThrows(IllegalStateException.class,
|
PlatformBlockState state = mock(PlatformBlockState.class);
|
||||||
() -> TileData.requirePlatformFactory(null));
|
KMap<String, Object> properties = new KMap<>();
|
||||||
|
TileData expected = mock(TileData.class);
|
||||||
assertEquals("No platform tile-data factory is bound", error.getMessage());
|
TileData.TileFactory hook = mock(TileData.TileFactory.class);
|
||||||
|
when(hook.create(state, properties)).thenReturn(expected);
|
||||||
|
TileData.TileFactory previous = TileData.bindPlatformFactory(hook);
|
||||||
|
try {
|
||||||
|
assertSame(expected, TileData.of(state, properties));
|
||||||
|
} finally {
|
||||||
|
TileData.restorePlatformFactory(previous);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void missingPlatformTileReaderFailsLoudly() {
|
public void boundTileReaderWinsWhenBukkitClassesArePresent() throws IOException {
|
||||||
IOException error = assertThrows(IOException.class,
|
TileData expected = mock(TileData.class);
|
||||||
() -> TileData.requirePlatformReader(null));
|
TileData.TileReader hook = mock(TileData.TileReader.class);
|
||||||
|
DataInputStream input = new DataInputStream(new ByteArrayInputStream(new byte[0]));
|
||||||
assertEquals("No platform tile-data reader is bound", error.getMessage());
|
when(hook.read(input)).thenReturn(expected);
|
||||||
|
TileData.TileReader previous = TileData.bindPlatformReader(hook);
|
||||||
|
try {
|
||||||
|
assertSame(expected, TileData.read(input));
|
||||||
|
} finally {
|
||||||
|
TileData.restorePlatformReader(previous);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ import art.arcane.iris.spi.PlatformRegistries;
|
|||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.junit.Assume;
|
import org.junit.Assume;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -102,6 +104,16 @@ public class BukkitSpiConformanceTest {
|
|||||||
assertSame(BukkitBlockState.of(first), BukkitBlockState.of(second));
|
assertSame(BukkitBlockState.of(first), BukkitBlockState.of(second));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mantleValuesUseStableBukkitInterfaceSlices() {
|
||||||
|
BukkitPlatform platform = new BukkitPlatform();
|
||||||
|
assertTrue(platform.supportsMatterWorldIo());
|
||||||
|
assertSame(World.class, platform.classifyMantleValue(mock(World.class)));
|
||||||
|
assertSame(BlockData.class, platform.classifyMantleValue(blockData("minecraft:stone")));
|
||||||
|
assertSame(Entity.class, platform.classifyMantleValue(mock(Entity.class)));
|
||||||
|
assertSame(String.class, platform.classifyMantleValue("value"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void blockStateKeyMatchesCanonicalString() {
|
public void blockStateKeyMatchesCanonicalString() {
|
||||||
BlockData data = blockData("iristest:key_block[facing=north,lit=true]");
|
BlockData data = blockData("iristest:key_block[facing=north,lit=true]");
|
||||||
|
|||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
package art.arcane.iris.util.project.matter.slices;
|
||||||
|
|
||||||
|
import art.arcane.iris.spi.IrisPlatform;
|
||||||
|
import art.arcane.iris.spi.IrisPlatforms;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
public class IrisMatterPlatformSelectionTest {
|
||||||
|
@Test
|
||||||
|
public void hybridClasspathDoesNotEnableBukkitMatterIoForModdedPlatform() {
|
||||||
|
IrisPlatform platform = mock(IrisPlatform.class);
|
||||||
|
withPlatform(platform, () -> {
|
||||||
|
assertNull(new EntityMatter().readFrom(World.class));
|
||||||
|
assertNull(new TileMatter().readFrom(World.class));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void bukkitPlatformCapabilityEnablesBukkitMatterIo() {
|
||||||
|
IrisPlatform platform = mock(IrisPlatform.class);
|
||||||
|
when(platform.supportsMatterWorldIo()).thenReturn(true);
|
||||||
|
withPlatform(platform, () -> {
|
||||||
|
assertNotNull(new EntityMatter().readFrom(World.class));
|
||||||
|
assertNotNull(new TileMatter().readFrom(World.class));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void withPlatform(IrisPlatform platform, Runnable test) {
|
||||||
|
IrisPlatform previous = IrisPlatforms.isBound() ? IrisPlatforms.get() : null;
|
||||||
|
IrisPlatforms.unbind();
|
||||||
|
IrisPlatforms.bind(platform);
|
||||||
|
try {
|
||||||
|
test.run();
|
||||||
|
} finally {
|
||||||
|
IrisPlatforms.unbind();
|
||||||
|
if (previous != null) {
|
||||||
|
IrisPlatforms.bind(previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -66,6 +66,14 @@ public interface IrisPlatform {
|
|||||||
*/
|
*/
|
||||||
PlatformBiomeWriter biomeWriter();
|
PlatformBiomeWriter biomeWriter();
|
||||||
|
|
||||||
|
default Class<?> classifyMantleValue(Object value) {
|
||||||
|
return value.getClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
default boolean supportsMatterWorldIo() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Root folder Iris owns for packs, settings and generated data. Created if missing. Never null.
|
* Root folder Iris owns for packs, settings and generated data. Created if missing. Never null.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user