mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-07-13 02:15:46 +00:00
Bukkit SPI
This commit is contained in:
@@ -61,6 +61,8 @@ boolean hasSentryAuthToken = sentryAuthToken != null && !sentryAuthToken.isBlank
|
||||
* these dependencies if they are available on mvn central.
|
||||
*/
|
||||
dependencies {
|
||||
api(project(':spi'))
|
||||
|
||||
// Provided or Classpath
|
||||
compileOnly(libs.spigot)
|
||||
compileOnly(libs.log4j.api)
|
||||
|
||||
@@ -49,6 +49,8 @@ import art.arcane.iris.engine.object.IrisWorld;
|
||||
import art.arcane.iris.engine.platform.BukkitChunkGenerator;
|
||||
import art.arcane.iris.core.safeguard.IrisSafeguard;
|
||||
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import art.arcane.volmlib.integration.ReloadAware;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
@@ -911,6 +913,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
}
|
||||
|
||||
public void onEnable() {
|
||||
IrisPlatforms.bind(new BukkitPlatform());
|
||||
enable();
|
||||
super.onEnable();
|
||||
Bukkit.getPluginManager().registerEvents(this, this);
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.platform.bukkit;
|
||||
|
||||
import art.arcane.iris.spi.PlatformBiome;
|
||||
import org.bukkit.block.Biome;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Interned Bukkit adapter for a neutral biome handle.
|
||||
*/
|
||||
public final class BukkitBiome implements PlatformBiome {
|
||||
private static final ConcurrentHashMap<String, BukkitBiome> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private final Biome biome;
|
||||
private final String key;
|
||||
private final String namespace;
|
||||
|
||||
private BukkitBiome(Biome biome, String key) {
|
||||
this.biome = biome;
|
||||
this.key = key;
|
||||
int colon = key.indexOf(':');
|
||||
this.namespace = colon >= 0 ? key.substring(0, colon) : "minecraft";
|
||||
}
|
||||
|
||||
public static BukkitBiome of(Biome biome) {
|
||||
String key = biomeKey(biome);
|
||||
return CACHE.computeIfAbsent(key, (String k) -> new BukkitBiome(biome, k));
|
||||
}
|
||||
|
||||
private static String biomeKey(Biome biome) {
|
||||
for (String method : new String[]{"getKeyOrNull", "getKeyOrThrow", "getKey"}) {
|
||||
try {
|
||||
Object key = Biome.class.getMethod(method).invoke(biome);
|
||||
if (key != null) {
|
||||
return key.toString();
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
return biome.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String key() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String namespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object nativeHandle() {
|
||||
return biome;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.platform.bukkit;
|
||||
|
||||
import art.arcane.iris.core.nms.INMS;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.util.common.data.B;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Interned Bukkit adapter for a neutral block state backed by BlockData.
|
||||
*/
|
||||
public final class BukkitBlockState implements PlatformBlockState {
|
||||
private static final ConcurrentHashMap<String, BukkitBlockState> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private final BlockData data;
|
||||
private final String key;
|
||||
private final String namespace;
|
||||
|
||||
private BukkitBlockState(BlockData data, String key) {
|
||||
this.data = data;
|
||||
this.key = key;
|
||||
this.namespace = parseNamespace(key);
|
||||
}
|
||||
|
||||
public static BukkitBlockState of(BlockData data) {
|
||||
String key = data.getAsString();
|
||||
return CACHE.computeIfAbsent(key, (String k) -> new BukkitBlockState(data, k));
|
||||
}
|
||||
|
||||
private static String parseNamespace(String key) {
|
||||
String base = key;
|
||||
int bracket = base.indexOf('[');
|
||||
if (bracket >= 0) {
|
||||
base = base.substring(0, bracket);
|
||||
}
|
||||
int colon = base.indexOf(':');
|
||||
return colon >= 0 ? base.substring(0, colon) : "minecraft";
|
||||
}
|
||||
|
||||
private static String mergeProperty(String key, String name, String value) {
|
||||
int bracket = key.indexOf('[');
|
||||
if (bracket < 0) {
|
||||
return key + "[" + name + "=" + value + "]";
|
||||
}
|
||||
String base = key.substring(0, bracket);
|
||||
String body = key.substring(bracket + 1, key.lastIndexOf(']'));
|
||||
LinkedHashMap<String, String> properties = new LinkedHashMap<>();
|
||||
for (String entry : body.split(",")) {
|
||||
int equals = entry.indexOf('=');
|
||||
if (equals < 0) {
|
||||
continue;
|
||||
}
|
||||
properties.put(entry.substring(0, equals).trim(), entry.substring(equals + 1).trim());
|
||||
}
|
||||
properties.put(name, value);
|
||||
StringBuilder merged = new StringBuilder(base).append('[');
|
||||
boolean first = true;
|
||||
for (Map.Entry<String, String> property : properties.entrySet()) {
|
||||
if (!first) {
|
||||
merged.append(',');
|
||||
}
|
||||
merged.append(property.getKey()).append('=').append(property.getValue());
|
||||
first = false;
|
||||
}
|
||||
return merged.append(']').toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String key() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String namespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir() {
|
||||
return B.isAir(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return B.isSolid(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTileEntity() {
|
||||
return INMS.get().hasTile(data.getMaterial());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformBlockState withProperty(String name, String value) {
|
||||
String merged = mergeProperty(key, name, value);
|
||||
BlockData resolved = Bukkit.createBlockData(merged);
|
||||
return of(resolved);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object nativeHandle() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.platform.bukkit;
|
||||
|
||||
import art.arcane.iris.engine.data.chunk.TerrainChunk;
|
||||
import art.arcane.iris.spi.ChunkWriteTarget;
|
||||
import art.arcane.iris.spi.PlatformBiome;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
/**
|
||||
* Bukkit adapter for the hot-path chunk write surface backed by TerrainChunk.
|
||||
*/
|
||||
public final class BukkitChunkWriteTarget implements ChunkWriteTarget {
|
||||
private final TerrainChunk terrain;
|
||||
|
||||
public BukkitChunkWriteTarget(TerrainChunk terrain) {
|
||||
this.terrain = terrain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, PlatformBlockState state) {
|
||||
terrain.setBlock(x, y, z, (BlockData) state.nativeHandle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(int x, int y, int z, PlatformBiome biome) {
|
||||
terrain.setBiome(x, y, z, (Biome) biome.nativeHandle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int minHeight() {
|
||||
return terrain.getMinHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int maxHeight() {
|
||||
return terrain.getMaxHeight();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.platform.bukkit;
|
||||
|
||||
import art.arcane.iris.spi.PlatformEntityType;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Interned Bukkit adapter for a neutral entity type handle.
|
||||
*/
|
||||
public final class BukkitEntityType implements PlatformEntityType {
|
||||
private static final ConcurrentHashMap<String, BukkitEntityType> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private final EntityType type;
|
||||
private final String key;
|
||||
private final String namespace;
|
||||
|
||||
private BukkitEntityType(EntityType type, String key) {
|
||||
this.type = type;
|
||||
this.key = key;
|
||||
int colon = key.indexOf(':');
|
||||
this.namespace = colon >= 0 ? key.substring(0, colon) : "minecraft";
|
||||
}
|
||||
|
||||
public static BukkitEntityType of(EntityType type) {
|
||||
String key = type.getKey().toString();
|
||||
return CACHE.computeIfAbsent(key, (String k) -> new BukkitEntityType(type, k));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String key() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String namespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object nativeHandle() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.platform.bukkit;
|
||||
|
||||
import art.arcane.iris.spi.PlatformItem;
|
||||
import org.bukkit.Material;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Interned Bukkit adapter for a neutral item handle backed by Material.
|
||||
*/
|
||||
public final class BukkitItem implements PlatformItem {
|
||||
private static final ConcurrentHashMap<String, BukkitItem> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private final Material material;
|
||||
private final String key;
|
||||
private final String namespace;
|
||||
|
||||
private BukkitItem(Material material, String key) {
|
||||
this.material = material;
|
||||
this.key = key;
|
||||
int colon = key.indexOf(':');
|
||||
this.namespace = colon >= 0 ? key.substring(0, colon) : "minecraft";
|
||||
}
|
||||
|
||||
public static BukkitItem of(Material material) {
|
||||
String key = material.getKey().toString();
|
||||
return CACHE.computeIfAbsent(key, (String k) -> new BukkitItem(material, k));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String key() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String namespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object nativeHandle() {
|
||||
return material;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.platform.bukkit;
|
||||
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.nms.INMS;
|
||||
import art.arcane.iris.spi.IrisPlatform;
|
||||
import art.arcane.iris.spi.LogLevel;
|
||||
import art.arcane.iris.spi.PlatformCapabilities;
|
||||
import art.arcane.iris.spi.PlatformRegistries;
|
||||
import art.arcane.iris.spi.PlatformScheduler;
|
||||
import art.arcane.iris.util.common.scheduling.J;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Bukkit implementation of the root Iris platform service.
|
||||
*/
|
||||
public final class BukkitPlatform implements IrisPlatform {
|
||||
private final BukkitRegistries registries = new BukkitRegistries();
|
||||
private final BukkitScheduler scheduler = new BukkitScheduler();
|
||||
private final PlatformCapabilities capabilities = new BukkitCapabilities();
|
||||
|
||||
@Override
|
||||
public String platformName() {
|
||||
return "bukkit";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String minecraftVersion() {
|
||||
return Bukkit.getBukkitVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformRegistries registries() {
|
||||
return registries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformScheduler scheduler() {
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformCapabilities capabilities() {
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File dataFolder() {
|
||||
return Iris.instance.getDataFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(LogLevel level, String message) {
|
||||
switch (level) {
|
||||
case DEBUG -> Iris.debug(message);
|
||||
case INFO -> Iris.info(message);
|
||||
case WARN -> Iris.warn(message);
|
||||
case ERROR -> Iris.error(message);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class BukkitCapabilities implements PlatformCapabilities {
|
||||
@Override
|
||||
public boolean customBiomes() {
|
||||
return INMS.get().supportsCustomBiomes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dataPacks() {
|
||||
return INMS.get().supportsDataPacks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean structurePlacement() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regionizedThreading() {
|
||||
return J.isFolia();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.platform.bukkit;
|
||||
|
||||
import art.arcane.iris.core.nms.INMS;
|
||||
import art.arcane.iris.spi.PlatformBiome;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.spi.PlatformEntityType;
|
||||
import art.arcane.iris.spi.PlatformItem;
|
||||
import art.arcane.iris.spi.PlatformRegistries;
|
||||
import art.arcane.iris.util.common.data.B;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Bukkit adapter resolving namespaced keys against the live Bukkit registries.
|
||||
*/
|
||||
public final class BukkitRegistries implements PlatformRegistries {
|
||||
@Override
|
||||
public PlatformBlockState block(String key) {
|
||||
BlockData data = B.get(key);
|
||||
return data == null ? null : BukkitBlockState.of(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformBiome biome(String key) {
|
||||
NamespacedKey namespacedKey = NamespacedKey.fromString(key);
|
||||
if (namespacedKey == null) {
|
||||
return null;
|
||||
}
|
||||
Biome biome = Registry.BIOME.get(namespacedKey);
|
||||
return biome == null ? null : BukkitBiome.of(biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformItem item(String key) {
|
||||
Material material = Material.matchMaterial(key);
|
||||
return material == null ? null : BukkitItem.of(material);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformEntityType entity(String key) {
|
||||
NamespacedKey namespacedKey = NamespacedKey.fromString(key);
|
||||
if (namespacedKey == null) {
|
||||
return null;
|
||||
}
|
||||
EntityType type = Registry.ENTITY_TYPE.get(namespacedKey);
|
||||
return type == null ? null : BukkitEntityType.of(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> blockKeys() {
|
||||
List<String> keys = new ArrayList<>();
|
||||
for (Material material : Registry.MATERIAL) {
|
||||
if (material.isBlock()) {
|
||||
keys.add(material.getKey().toString());
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> biomeKeys() {
|
||||
List<String> keys = new ArrayList<>();
|
||||
for (Biome biome : Registry.BIOME) {
|
||||
keys.add(BukkitBiome.of(biome).key());
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> structureKeys() {
|
||||
return new ArrayList<>(INMS.get().getStructureKeys());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.platform.bukkit;
|
||||
|
||||
import art.arcane.iris.spi.PlatformScheduler;
|
||||
import art.arcane.iris.spi.PlatformWorld;
|
||||
import art.arcane.iris.util.common.scheduling.J;
|
||||
import org.bukkit.World;
|
||||
|
||||
/**
|
||||
* Bukkit adapter dispatching platform tasks through the Folia-aware J scheduler.
|
||||
*/
|
||||
public final class BukkitScheduler implements PlatformScheduler {
|
||||
@Override
|
||||
public void global(Runnable task) {
|
||||
J.s(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void region(PlatformWorld world, int chunkX, int chunkZ, Runnable task) {
|
||||
World bukkitWorld = (World) world.nativeHandle();
|
||||
if (!J.runRegion(bukkitWorld, chunkX, chunkZ, task)) {
|
||||
J.s(task);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void async(Runnable task) {
|
||||
J.a(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void laterGlobal(Runnable task, int ticks) {
|
||||
J.s(task, ticks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void laterRegion(PlatformWorld world, int chunkX, int chunkZ, Runnable task, int ticks) {
|
||||
World bukkitWorld = (World) world.nativeHandle();
|
||||
if (!J.runRegion(bukkitWorld, chunkX, chunkZ, task, ticks)) {
|
||||
J.s(task, ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.platform.bukkit;
|
||||
|
||||
import art.arcane.iris.spi.PlatformBiome;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import art.arcane.iris.spi.PlatformWorld;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
/**
|
||||
* Bukkit adapter for a neutral world view backed by org.bukkit.World.
|
||||
*/
|
||||
public final class BukkitWorld implements PlatformWorld {
|
||||
private final World world;
|
||||
|
||||
public BukkitWorld(World world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return world.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long seed() {
|
||||
return world.getSeed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int minHeight() {
|
||||
return world.getMinHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int maxHeight() {
|
||||
return world.getMaxHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformBlockState getBlock(int x, int y, int z) {
|
||||
return BukkitBlockState.of(world.getBlockAt(x, y, z).getBlockData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, PlatformBlockState block, int flags) {
|
||||
world.getBlockAt(x, y, z).setBlockData((BlockData) block.nativeHandle(), (flags & 1) != 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformBiome getBiome(int x, int y, int z) {
|
||||
return BukkitBiome.of(world.getBiome(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkLoaded(int chunkX, int chunkZ) {
|
||||
return world.isChunkLoaded(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object nativeHandle() {
|
||||
return world;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.platform.bukkit;
|
||||
|
||||
import art.arcane.iris.spi.IrisPlatform;
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import art.arcane.iris.spi.PlatformBlockState;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class BukkitSpiConformanceTest {
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
Server server = Bukkit.getServer();
|
||||
if (server == null) {
|
||||
server = mock(Server.class);
|
||||
doReturn(Logger.getLogger("IrisTest")).when(server).getLogger();
|
||||
doReturn("IrisTestServer").when(server).getName();
|
||||
doReturn("1.0").when(server).getVersion();
|
||||
doReturn("1.0").when(server).getBukkitVersion();
|
||||
doReturn(mock(BlockData.class)).when(server).createBlockData(any(Material.class));
|
||||
Bukkit.setServer(server);
|
||||
}
|
||||
doAnswer((InvocationOnMock invocation) -> blockData(invocation.getArgument(0))).when(server).createBlockData(anyString());
|
||||
}
|
||||
|
||||
private static BlockData blockData(String asString) {
|
||||
BlockData data = mock(BlockData.class);
|
||||
doReturn(asString).when(data).getAsString();
|
||||
return data;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void blockStateInterningReturnsSameInstanceForSameKey() {
|
||||
BlockData first = blockData("iristest:intern_block[axis=y]");
|
||||
BlockData second = blockData("iristest:intern_block[axis=y]");
|
||||
assertSame(BukkitBlockState.of(first), BukkitBlockState.of(second));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void blockStateKeyMatchesCanonicalString() {
|
||||
BlockData data = blockData("iristest:key_block[facing=north,lit=true]");
|
||||
assertEquals("iristest:key_block[facing=north,lit=true]", BukkitBlockState.of(data).key());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void blockStateNamespaceParsesWithAndWithoutProperties() {
|
||||
BlockData withProps = blockData("iristest:ns_block[axis=y]");
|
||||
BlockData withoutProps = blockData("iristest:ns_plain");
|
||||
assertEquals("iristest", BukkitBlockState.of(withProps).namespace());
|
||||
assertEquals("iristest", BukkitBlockState.of(withoutProps).namespace());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withPropertyReplacesExistingProperty() {
|
||||
BlockData data = blockData("iristest:merge_block[axis=y,waterlogged=false]");
|
||||
PlatformBlockState merged = BukkitBlockState.of(data).withProperty("axis", "x");
|
||||
assertEquals("iristest:merge_block[axis=x,waterlogged=false]", merged.key());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withPropertyAppendsToExistingProperties() {
|
||||
BlockData data = blockData("iristest:append_block[axis=y]");
|
||||
PlatformBlockState merged = BukkitBlockState.of(data).withProperty("lit", "true");
|
||||
assertEquals("iristest:append_block[axis=y,lit=true]", merged.key());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withPropertyAddsBracketSectionWhenAbsent() {
|
||||
BlockData data = blockData("iristest:bare_block");
|
||||
PlatformBlockState merged = BukkitBlockState.of(data).withProperty("lit", "true");
|
||||
assertEquals("iristest:bare_block[lit=true]", merged.key());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void platformBindingLifecycle() {
|
||||
assertFalse(IrisPlatforms.isBound());
|
||||
try {
|
||||
IrisPlatforms.get();
|
||||
fail("get() must throw while unbound");
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
IrisPlatform first = mock(IrisPlatform.class);
|
||||
IrisPlatforms.bind(first);
|
||||
assertTrue(IrisPlatforms.isBound());
|
||||
assertSame(first, IrisPlatforms.get());
|
||||
IrisPlatforms.bind(first);
|
||||
assertSame(first, IrisPlatforms.get());
|
||||
IrisPlatform second = mock(IrisPlatform.class);
|
||||
try {
|
||||
IrisPlatforms.bind(second);
|
||||
fail("bind() must reject a different instance");
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
assertSame(first, IrisPlatforms.get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.spi;
|
||||
|
||||
/**
|
||||
* Static holder binding the active platform adapter for the lifetime of the runtime.
|
||||
*/
|
||||
public final class IrisPlatforms {
|
||||
private static volatile IrisPlatform platform;
|
||||
|
||||
private IrisPlatforms() {
|
||||
}
|
||||
|
||||
public static synchronized void bind(IrisPlatform p) {
|
||||
if (platform != null && platform != p) {
|
||||
throw new IllegalStateException("Iris platform is already bound to a different instance");
|
||||
}
|
||||
platform = p;
|
||||
}
|
||||
|
||||
public static IrisPlatform get() {
|
||||
IrisPlatform bound = platform;
|
||||
if (bound == null) {
|
||||
throw new IllegalStateException("No Iris platform is bound");
|
||||
}
|
||||
return bound;
|
||||
}
|
||||
|
||||
public static boolean isBound() {
|
||||
return platform != null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user