Service Facade

This commit is contained in:
Brian Neumann-Fopiano
2026-06-11 17:17:51 -04:00
parent b584cb4193
commit b5d08b6203
22 changed files with 163 additions and 63 deletions
+6 -1
View File
@@ -51,6 +51,7 @@ 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.iris.spi.IrisServices;
import art.arcane.volmlib.integration.ReloadAware;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.collection.KMap;
@@ -554,7 +555,10 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
services = new KMap<>();
setupAudience();
Bindings.setupSentry();
initialize("art.arcane.iris.core.service").forEach((i) -> services.put((Class<? extends IrisService>) i.getClass(), (IrisService) i));
initialize("art.arcane.iris.core.service").forEach((i) -> {
services.put((Class<? extends IrisService>) i.getClass(), (IrisService) i);
IrisServices.register(i.getClass(), i);
});
IO.delete(new File("iris"));
compat = IrisCompat.configured(getDataFile("compat.json"));
ServerConfigurator.configure();
@@ -927,6 +931,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
if (services != null) {
services.values().forEach(IrisService::onDisable);
}
IrisServices.clear();
if (configHotloadEngine != null) {
configHotloadEngine.clear();
configHotloadEngine = null;
@@ -21,7 +21,8 @@ package art.arcane.iris.engine;
import art.arcane.iris.spi.IrisLogging;
import com.google.common.util.concurrent.AtomicDouble;
import com.google.gson.Gson;
import art.arcane.iris.Iris;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.ServerConfigurator;
import art.arcane.iris.core.events.IrisEngineHotloadEvent;
@@ -391,7 +392,7 @@ public class IrisEngine implements Engine {
@Override
public void hotload() {
hotloadSilently();
Iris.callEvent(new IrisEngineHotloadEvent(this));
IrisPlatforms.get().callEvent(new IrisEngineHotloadEvent(this));
}
public void hotloadComplex() {
@@ -433,9 +434,9 @@ public class IrisEngine implements Engine {
if (data == null) {
data = new IrisEngineData();
data.getStatistics().setVersion(Iris.instance.getIrisVersion());
data.getStatistics().setMCVersion(Iris.instance.getMCVersion());
data.getStatistics().setUpgradedVersion(Iris.instance.getIrisVersion());
data.getStatistics().setVersion(IrisPlatforms.get().irisVersionNumber());
data.getStatistics().setMCVersion(IrisPlatforms.get().minecraftVersionNumber());
data.getStatistics().setUpgradedVersion(IrisPlatforms.get().irisVersionNumber());
if (data.getStatistics().getVersion() == -1 || data.getStatistics().getMCVersion() == -1 ) {
IrisLogging.error("Failed to setup Engine Data!");
}
@@ -601,7 +602,7 @@ public class IrisEngine implements Engine {
worldManager = null;
getData().dump();
getData().clearLists();
Iris.service(PreservationSVC.class).dereference();
IrisServices.get(PreservationSVC.class).dereference();
IrisLogging.debug("Engine Fully Shutdown!");
}
@@ -756,8 +757,8 @@ public class IrisEngine implements Engine {
// Todo: this has potential if done right
int EngineMCVersion = getEngineData().getStatistics().getMCVersion();
int EngineIrisVersion = getEngineData().getStatistics().getVersion();
int MinecraftVersion = Iris.instance.getMCVersion();
int IrisVersion = Iris.instance.getIrisVersion();
int MinecraftVersion = IrisPlatforms.get().minecraftVersionNumber();
int IrisVersion = IrisPlatforms.get().irisVersionNumber();
if (EngineIrisVersion != IrisVersion) {
return false;
}
@@ -18,7 +18,7 @@
package art.arcane.iris.engine;
import art.arcane.iris.Iris;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.tools.IrisToolbelt;
import art.arcane.iris.engine.EnginePanic;
@@ -275,7 +275,7 @@ public class IrisEngineMantle implements EngineMantle {
return new MantleHooks() {
@Override
public void onBeforeReadSection(int index) {
Iris.addPanic("read.section", "Section[" + index + "]");
EnginePanic.add("read.section", "Section[" + index + "]");
}
@Override
@@ -285,17 +285,17 @@ public class IrisEngineMantle implements EngineMantle {
art.arcane.volmlib.util.io.CountingDataInputStream din,
IOException error) {
IrisLogging.error("Failed to read chunk section, skipping it.");
Iris.addPanic("read.byte.range", start + " " + end);
Iris.addPanic("read.byte.current", din.count() + "");
EnginePanic.add("read.byte.range", start + " " + end);
EnginePanic.add("read.byte.current", din.count() + "");
IrisLogging.reportError(error);
error.printStackTrace();
Iris.panic();
EnginePanic.panic();
TectonicPlate.addError();
}
@Override
public void onBeforeReadChunk(int index) {
Iris.addPanic("read-chunk", "Chunk[" + index + "]");
EnginePanic.add("read-chunk", "Chunk[" + index + "]");
}
@Override
@@ -310,11 +310,11 @@ public class IrisEngineMantle implements EngineMantle {
art.arcane.volmlib.util.io.CountingDataInputStream din,
Throwable error) {
IrisLogging.error("Failed to read chunk, creating a new chunk instead.");
Iris.addPanic("read.byte.range", start + " " + end);
Iris.addPanic("read.byte.current", din.count() + "");
EnginePanic.add("read.byte.range", start + " " + end);
EnginePanic.add("read.byte.current", din.count() + "");
IrisLogging.reportError(error);
error.printStackTrace();
Iris.panic();
EnginePanic.panic();
}
@Override
@@ -373,7 +373,7 @@ public class IrisEngineMantle implements EngineMantle {
TectonicPlate.read(worldHeight, in, regionName.startsWith("pv."), adapter, hooks));
} finally {
if (TectonicPlate.hasError() && IrisSettings.get().getGeneral().isDumpMantleOnError()) {
File dump = Iris.instance.getDataFolder("dump", name + ".bin");
File dump = IrisPlatforms.get().dataFile("dump", name + ".bin");
worker.dumpDecoded(name, dump.toPath());
} else {
IrisLogging.debug("Read Tectonic Plate " + C.DARK_GREEN + name + C.RED + " in " + Form.duration(stopwatch.getMilliseconds(), 2));
@@ -18,7 +18,6 @@
package art.arcane.iris.engine;
import art.arcane.iris.Iris;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.gui.PregeneratorJob;
import art.arcane.iris.core.loader.IrisData;
@@ -771,7 +770,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
chunkFuture.get();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
Iris.verbose("Chunk warmup interrupted while loading async teleport chunk.");
IrisLogging.debug("Chunk warmup interrupted while loading async teleport chunk.");
} catch (ExecutionException ex) {
IrisLogging.reportError(ex);
}
@@ -18,7 +18,7 @@
package art.arcane.iris.engine.framework;
import art.arcane.iris.Iris;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.events.IrisLootEvent;
import art.arcane.iris.core.gui.components.RenderType;
@@ -386,7 +386,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
Runnable customTask = () -> {
chunk.iterate(Identifier.class, (x, y, z, v) -> {
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
IrisServices.get(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
});
};
@@ -18,7 +18,7 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.Iris;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.Required;
@@ -60,7 +60,7 @@ public class IrisCompatabilityItemFilter {
return null;
}
Iris.verbose("Compat: Using " + supplement + " in place of " + when + " since this server doesnt support '" + supplement + "'");
IrisLogging.debug("Compat: Using " + supplement + " in place of " + when + " since this server doesnt support '" + supplement + "'");
return b;
});
@@ -18,7 +18,6 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.Iris;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.ServerConfigurator.DimensionHeight;
import art.arcane.iris.core.loader.IrisData;
@@ -488,7 +487,7 @@ public class IrisDimension extends IrisRegistrant {
synchronized (biomes) {
if (!biomes.add(customBiomeId)) {
Iris.verbose("Duplicate Data Pack Biome: " + getLoadKey() + "/" + customBiomeId);
IrisLogging.debug("Duplicate Data Pack Biome: " + getLoadKey() + "/" + customBiomeId);
continue;
}
}
@@ -496,7 +495,7 @@ public class IrisDimension extends IrisRegistrant {
for (File datapacks : folders) {
File output = new File(datapacks, "iris/data/" + namespace + "/worldgen/biome/" + customBiomeId + ".json");
Iris.verbose(" Installing Data Pack Biome: " + output.getPath());
IrisLogging.debug(" Installing Data Pack Biome: " + output.getPath());
output.getParentFile().mkdirs();
try {
IO.writeAll(output, json);
@@ -556,7 +555,7 @@ public class IrisDimension extends IrisRegistrant {
String json = type.toJson(fixer);
String dimensionTypeKey = getDimensionTypeKey();
Iris.verbose(" Installing Data Pack Dimension Type: \"iris:" + dimensionTypeKey + '"');
IrisLogging.debug(" Installing Data Pack Dimension Type: \"iris:" + dimensionTypeKey + '"');
for (File datapacks : folders) {
File output = new File(datapacks, "iris/data/iris/dimension_type/" + dimensionTypeKey + ".json");
output.getParentFile().mkdirs();
@@ -585,7 +584,7 @@ public class IrisDimension extends IrisRegistrant {
}
public static void writeShared(KList<File> folders, DimensionHeight height) {
Iris.verbose(" Installing Data Pack Vanilla Dimension Types");
IrisLogging.debug(" Installing Data Pack Vanilla Dimension Types");
String[] jsonStrings = height.jsonStrings();
for (File datapacks : folders) {
write(datapacks, "overworld", jsonStrings[0]);
@@ -612,7 +611,7 @@ public class IrisDimension extends IrisRegistrant {
IrisLogging.reportError(e);
e.printStackTrace();
}
Iris.verbose(" Installing Data Pack MCMeta: " + mcm.getPath());
IrisLogging.debug(" Installing Data Pack MCMeta: " + mcm.getPath());
}
}
@@ -18,7 +18,7 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.Iris;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.link.Identifier;
import art.arcane.iris.core.loader.IrisRegistrant;
@@ -251,7 +251,7 @@ public class IrisEntity extends IrisRegistrant {
l.setLootTable(new LootTable() {
@Override
public NamespacedKey getKey() {
return new NamespacedKey(Iris.instance, "loot-" + IrisEntity.this.hashCode());
return new NamespacedKey("iris", "loot-" + IrisEntity.this.hashCode());
}
@Override
@@ -447,7 +447,7 @@ public class IrisEntity extends IrisRegistrant {
}
if (isSpecialType()) {
return Iris.service(ExternalDataSVC.class).spawnMob(at, Identifier.fromString(specialType));
return IrisServices.get(ExternalDataSVC.class).spawnMob(at, Identifier.fromString(specialType));
}
@@ -18,7 +18,7 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.Iris;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.core.link.Identifier;
import art.arcane.iris.core.service.ExternalDataSVC;
import art.arcane.iris.engine.data.cache.AtomicCache;
@@ -148,7 +148,7 @@ public class IrisLoot {
// TODO Better Third Party Item Acquisition
private ItemStack getItemStack(RNG rng) {
if (!type.startsWith("minecraft:") && type.contains(":")) {
Optional<ItemStack> opt = Iris.service(ExternalDataSVC.class).getItemStack(Identifier.fromString(type), customNbt);
Optional<ItemStack> opt = IrisServices.get(ExternalDataSVC.class).getItemStack(Identifier.fromString(type), customNbt);
if (opt.isEmpty()) {
IrisLogging.warn("Unknown Material: " + type);
return new ItemStack(Material.AIR);
@@ -1,11 +1,13 @@
package art.arcane.iris.engine.object.annotations.functions;
import art.arcane.iris.Iris;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.framework.ListFunction;
import art.arcane.iris.engine.mantle.ComponentFlag;
import art.arcane.iris.engine.mantle.MantleComponent;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.util.common.scheduling.J;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.io.JarScanner;
import art.arcane.volmlib.util.mantle.flag.MantleFlag;
import java.util.Objects;
@@ -25,8 +27,11 @@ public class ComponentFlagFunction implements ListFunction<KList<String>> {
public KList<String> apply(IrisData data) {
var engine = data.getEngine();
if (engine != null) return engine.getMantle().getComponentFlags().toStringList();
return Iris.getClasses("art.arcane.iris.engine.mantle.components", ComponentFlag.class)
JarScanner scanner = new JarScanner(IrisPlatforms.get().pluginJar(), "art.arcane.iris.engine.mantle.components");
J.attempt(scanner::scan);
return scanner.getClasses()
.stream()
.filter(c -> c.isAnnotationPresent(ComponentFlag.class))
.filter(MantleComponent.class::isAssignableFrom)
.map(c -> c.getDeclaredAnnotation(ComponentFlag.class))
.filter(Objects::nonNull)
@@ -41,6 +41,7 @@ import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.event.Event;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.inventory.ItemStack;
@@ -168,6 +169,31 @@ public final class BukkitPlatform implements IrisPlatform {
return Iris.instance.getDataFolder();
}
@Override
public File dataFile(String... path) {
return Iris.instance.getDataFile(path);
}
@Override
public File pluginJar() {
return Iris.instance.getJarFile();
}
@Override
public int irisVersionNumber() {
return Iris.instance.getIrisVersion();
}
@Override
public int minecraftVersionNumber() {
return Iris.instance.getMCVersion();
}
@Override
public void callEvent(Object event) {
Iris.callEvent((Event) event);
}
@Override
public void dispatchConsoleCommand(String command) {
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), command);
@@ -183,6 +209,11 @@ public final class BukkitPlatform implements IrisPlatform {
}
}
@Override
public void msg(String message) {
Iris.msg(message);
}
@Override
public void reportError(Throwable error) {
Iris.reportError(error);
@@ -1,6 +1,6 @@
package art.arcane.iris.util.project.agent;
import art.arcane.iris.Iris;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.spi.IrisLogging;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
@@ -13,7 +13,7 @@ import java.nio.file.StandardCopyOption;
public class Agent {
private static final String NAME = "art.arcane.iris.util.project.agent.Installer";
public static final File AGENT_JAR = new File(Iris.instance.getDataFolder(), "agent.jar");
public static final File AGENT_JAR = new File(IrisPlatforms.get().dataFolder(), "agent.jar");
public static ClassReloadingStrategy installed() {
return ClassReloadingStrategy.of(getInstrumentation());
@@ -75,11 +75,6 @@ public class Agent {
}
private static InputStream openBundledAgentJar() {
InputStream stream = Iris.instance.getResource("agent.jar");
if (stream != null) {
return stream;
}
return Agent.class.getClassLoader().getResourceAsStream("agent.jar");
}
@@ -1,6 +1,6 @@
package art.arcane.iris.util.project.context;
import art.arcane.iris.Iris;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.engine.IrisComplex;
import art.arcane.iris.engine.framework.EngineMetrics;
import art.arcane.iris.engine.object.IrisBiome;
@@ -98,7 +98,7 @@ public class ChunkContext {
}
static boolean shouldPrefillAsync(int fillTaskCount) {
if (fillTaskCount <= 1 || Iris.instance == null) {
if (fillTaskCount <= 1 || !IrisPlatforms.isBound()) {
return false;
}
@@ -18,7 +18,7 @@
package art.arcane.iris.util.project.hunk.view;
import art.arcane.iris.Iris;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.core.service.EditSVC;
import art.arcane.iris.platform.bukkit.BukkitBiome;
import art.arcane.iris.spi.PlatformBiome;
@@ -31,7 +31,7 @@ public class ChunkBiomeHunkView extends art.arcane.volmlib.util.hunk.view.ChunkW
public ChunkBiomeHunkView(Chunk chunk) {
super(chunk,
chunk.getWorld().getMaxHeight(),
(wx, y, wz, t) -> Iris.service(EditSVC.class).setBiome(chunk.getWorld(), wx, y, wz, (Biome) t.nativeHandle()),
(wx, y, wz) -> BukkitBiome.of(Iris.service(EditSVC.class).getBiome(chunk.getWorld(), wx, y, wz)));
(wx, y, wz, t) -> IrisServices.get(EditSVC.class).setBiome(chunk.getWorld(), wx, y, wz, (Biome) t.nativeHandle()),
(wx, y, wz) -> BukkitBiome.of(IrisServices.get(EditSVC.class).getBiome(chunk.getWorld(), wx, y, wz)));
}
}
@@ -18,7 +18,7 @@
package art.arcane.iris.util.project.hunk.view;
import art.arcane.iris.Iris;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.core.service.EditSVC;
import art.arcane.iris.platform.bukkit.BukkitBlockState;
import art.arcane.iris.spi.PlatformBlockState;
@@ -31,7 +31,7 @@ public class ChunkHunkView extends art.arcane.volmlib.util.hunk.view.ChunkWorldH
public ChunkHunkView(Chunk chunk) {
super(chunk,
chunk.getWorld().getMaxHeight(),
(wx, y, wz, t) -> Iris.service(EditSVC.class).set(chunk.getWorld(), wx, y, wz, (BlockData) t.nativeHandle()),
(wx, y, wz) -> BukkitBlockState.of(Iris.service(EditSVC.class).get(chunk.getWorld(), wx, y, wz)));
(wx, y, wz, t) -> IrisServices.get(EditSVC.class).set(chunk.getWorld(), wx, y, wz, (BlockData) t.nativeHandle()),
(wx, y, wz) -> BukkitBlockState.of(IrisServices.get(EditSVC.class).get(chunk.getWorld(), wx, y, wz)));
}
}
@@ -1,6 +1,6 @@
package art.arcane.iris.util.project.sentry;
import art.arcane.iris.Iris;
import art.arcane.iris.spi.IrisLogging;
import io.sentry.ILogger;
import io.sentry.SentryLevel;
import org.jetbrains.annotations.NotNull;
@@ -12,7 +12,7 @@ import java.io.StringWriter;
public class IrisLogger implements ILogger {
@Override
public void log(@NotNull SentryLevel level, @NotNull String message, @Nullable Object... args) {
Iris.msg(String.format("%s: %s", level, String.format(message, args)));
IrisLogging.msg(String.format("%s: %s", level, String.format(message, args)));
}
@Override
@@ -20,7 +20,7 @@ public class IrisLogger implements ILogger {
if (throwable == null) {
log(level, message);
} else {
Iris.msg(String.format("%s: %s\n%s", level, String.format(message, throwable), captureStackTrace(throwable)));
IrisLogging.msg(String.format("%s: %s\n%s", level, String.format(message, throwable), captureStackTrace(throwable)));
}
}
@@ -29,7 +29,7 @@ public class IrisLogger implements ILogger {
if (throwable == null) {
log(level, message, args);
} else {
Iris.msg(String.format("%s: %s\n%s", level, String.format(message, throwable), captureStackTrace(throwable)));
IrisLogging.msg(String.format("%s: %s\n%s", level, String.format(message, throwable), captureStackTrace(throwable)));
}
}
@@ -1,6 +1,6 @@
package art.arcane.iris.util.project.stream.utility;
import art.arcane.iris.Iris;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.core.service.PreservationSVC;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.framework.MeteredCache;
@@ -19,7 +19,7 @@ public class CachedDoubleStream2D extends BasicStream<Double> implements Procedu
this.stream = stream;
this.engine = engine;
this.cache = new WorldCache2DDouble((x, z) -> stream.getDouble(x, z), size);
Iris.service(PreservationSVC.class).registerCache(this);
IrisServices.get(PreservationSVC.class).registerCache(this);
}
@Override
@@ -18,7 +18,7 @@
package art.arcane.iris.util.project.stream.utility;
import art.arcane.iris.Iris;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.core.service.PreservationSVC;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.framework.MeteredCache;
@@ -38,7 +38,7 @@ public class CachedStream2D<T> extends BasicStream<T> implements ProceduralStrea
this.stream = stream;
this.engine = engine;
cache = new WorldCache2D<>(stream::get, size, () -> new ChunkCache2D<>("iris"));
Iris.service(PreservationSVC.class).registerCache(this);
IrisServices.get(PreservationSVC.class).registerCache(this);
}
@Override
@@ -18,7 +18,7 @@
package art.arcane.iris.util.project.stream.utility;
import art.arcane.iris.Iris;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.core.service.PreservationSVC;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.framework.MeteredCache;
@@ -36,7 +36,7 @@ public class CachedStream3D<T> extends BasicStream<T> implements ProceduralStrea
this.stream = stream;
this.engine = engine;
cache = new KCache<>((k) -> stream.get(k.getX(), k.getY(), k.getZ()), size);
Iris.service(PreservationSVC.class).registerCache(this);
IrisServices.get(PreservationSVC.class).registerCache(this);
}
@Override
@@ -40,6 +40,15 @@ public final class IrisLogging {
emit(LogLevel.ERROR, safeFormat(format, args));
}
public static void msg(String message) {
if (IrisPlatforms.isBound()) {
IrisPlatforms.get().msg(message);
return;
}
System.out.println("[Iris] " + message);
}
public static void reportError(Throwable error) {
if (IrisPlatforms.isBound()) {
IrisPlatforms.get().reportError(error);
@@ -40,9 +40,21 @@ public interface IrisPlatform {
File dataFolder();
File dataFile(String... path);
File pluginJar();
int irisVersionNumber();
int minecraftVersionNumber();
void callEvent(Object event);
void dispatchConsoleCommand(String command);
void log(LogLevel level, String message);
void msg(String message);
void reportError(Throwable error);
}
@@ -0,0 +1,44 @@
/*
* 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;
import java.util.concurrent.ConcurrentHashMap;
public final class IrisServices {
private static final ConcurrentHashMap<Class<?>, Object> SERVICES = new ConcurrentHashMap<>();
private IrisServices() {
}
public static void register(Class<?> type, Object implementation) {
SERVICES.put(type, type.cast(implementation));
}
public static <T> T get(Class<T> type) {
Object implementation = SERVICES.get(type);
if (implementation == null) {
throw new IllegalStateException("No Iris service registered for " + type.getName());
}
return type.cast(implementation);
}
public static void clear() {
SERVICES.clear();
}
}