This commit is contained in:
Brian Neumann-Fopiano
2026-07-09 13:54:59 -04:00
parent d1fec88769
commit 0a7a531646
259 changed files with 11055 additions and 884 deletions
+1
View File
@@ -201,6 +201,7 @@ def generateTemplates = tasks.register('generateTemplates', Copy) {
logger.error('Git commit hash not found', failure)
return 'unknown'
},
minecraftVersion: providers.gradleProperty('minecraftVersion'),
])
from(templateSource)
-9
View File
@@ -7,7 +7,6 @@ art/arcane/iris/core/edit/DustRevealer.java
art/arcane/iris/core/events/IrisEngineEvent.java
art/arcane/iris/core/events/IrisEngineHotloadEvent.java
art/arcane/iris/core/events/IrisLootEvent.java
art/arcane/iris/core/gui/PregeneratorJob.java
art/arcane/iris/core/lifecycle/BukkitPublicBackend.java
art/arcane/iris/core/lifecycle/CapabilitySnapshot.java
art/arcane/iris/core/lifecycle/PaperLibBootstrap.java
@@ -36,16 +35,13 @@ art/arcane/iris/core/link/data/NexoDataProvider.java
art/arcane/iris/core/nms/INMS.java
art/arcane/iris/core/nms/INMSBinding.java
art/arcane/iris/core/nms/MinecraftVersion.java
art/arcane/iris/core/nms/datapack/v1206/DataFixerV1206.java
art/arcane/iris/core/nms/v1X/NMSBinding1X.java
art/arcane/iris/core/pack/IrisPack.java
art/arcane/iris/core/pregenerator/DeepSearchPregenerator.java
art/arcane/iris/core/pregenerator/methods/AsyncOrMedievalPregenMethod.java
art/arcane/iris/core/pregenerator/methods/AsyncPregenMethod.java
art/arcane/iris/core/pregenerator/methods/HybridPregenMethod.java
art/arcane/iris/core/pregenerator/methods/MedievalPregenMethod.java
art/arcane/iris/core/project/IrisProject.java
art/arcane/iris/core/project/SchemaBuilder.java
art/arcane/iris/core/runtime/BukkitPublicRuntimeControlBackend.java
art/arcane/iris/core/runtime/ChunkClearer.java
art/arcane/iris/core/runtime/ChunkJobReporter.java
@@ -78,25 +74,20 @@ art/arcane/iris/core/tools/IrisWorldCreator.java
art/arcane/iris/core/tools/TreePlausibilizer.java
art/arcane/iris/engine/IrisEngineEffects.java
art/arcane/iris/engine/IrisWorldManager.java
art/arcane/iris/engine/actuator/IrisBiomeActuator.java
art/arcane/iris/engine/data/chunk/LinkedTerrainChunk.java
art/arcane/iris/engine/data/chunk/TerrainChunk.java
art/arcane/iris/engine/decorator/DecoratorCore.java
art/arcane/iris/engine/framework/Engine.java
art/arcane/iris/engine/framework/EngineAssignedWorldManager.java
art/arcane/iris/engine/framework/EnginePlayer.java
art/arcane/iris/engine/framework/EngineWorldManager.java
art/arcane/iris/engine/framework/placer/WorldObjectPlacer.java
art/arcane/iris/engine/mantle/MantleWriter.java
art/arcane/iris/engine/modifier/IrisFloatingChildBiomeModifier.java
art/arcane/iris/engine/object/BlockDataMergeSupport.java
art/arcane/iris/engine/object/IPostBlockAccess.java
art/arcane/iris/engine/object/IrisAttributeModifier.java
art/arcane/iris/engine/object/IrisBiome.java
art/arcane/iris/engine/object/IrisBiomeCustom.java
art/arcane/iris/engine/object/IrisBiomeCustomParticle.java
art/arcane/iris/engine/object/IrisBiomeCustomSpawn.java
art/arcane/iris/engine/object/IrisBlockData.java
art/arcane/iris/engine/object/IrisBlockDrops.java
art/arcane/iris/engine/object/IrisCommandRegistry.java
art/arcane/iris/engine/object/IrisCompat.java
@@ -73,6 +73,7 @@ public class IrisSettings {
try {
String ss = IO.readAll(s);
settings = new Gson().fromJson(ss, IrisSettings.class);
migrateLegacyKeys(ss);
try {
IO.writeAll(s, new JSONObject(new Gson().toJson(settings)).toString(4));
} catch (IOException e) {
@@ -87,6 +88,17 @@ public class IrisSettings {
return settings;
}
private static void migrateLegacyKeys(String rawJson) {
JSONObject root = new JSONObject(rawJson);
JSONObject worldObject = root.optJSONObject("world");
if (worldObject == null || !worldObject.has("anbientEntitySpawningSystem")) {
return;
}
settings.getWorld().setAmbientEntitySpawningSystem(worldObject.optBoolean("anbientEntitySpawningSystem", settings.getWorld().isAmbientEntitySpawningSystem()));
IrisLogging.info("Migrated legacy settings key world.anbientEntitySpawningSystem -> world.ambientEntitySpawningSystem");
}
public static void invalidate() {
synchronized (settings) {
settings = null;
@@ -115,7 +127,7 @@ public class IrisSettings {
public static class IrisSettingsWorld {
public boolean postLoadBlockUpdates = true;
public boolean forcePersistEntities = true;
public boolean anbientEntitySpawningSystem = true;
public boolean ambientEntitySpawningSystem = true;
public long asyncTickIntervalMS = 700;
public double targetSpawnEntitiesPerChunk = 0.95;
public boolean markerEntitySpawningSystem = true;
@@ -8,7 +8,10 @@ import art.arcane.iris.spi.IrisLogging;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.iris.util.common.scheduling.J;
import lombok.Getter;
import org.bukkit.*;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
@@ -19,7 +19,10 @@
package art.arcane.iris.core.gui;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.spi.protocol.IrisMessage;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.protocol.IrisProtocolServer;
import art.arcane.iris.core.pregenerator.IrisPregenerator;
import art.arcane.iris.core.pregenerator.PregenListener;
import art.arcane.iris.core.pregenerator.PregenTask;
@@ -345,6 +348,7 @@ public class PregeneratorJob implements PregenListener, PregenRenderSource {
public void onRegionGenerated(int x, int z) {
shouldGc();
rgc++;
broadcastRegionDelta(x, z, IrisMessage.PregenRegionDelta.STATE_DONE);
}
private void shouldGc() {
@@ -353,9 +357,17 @@ public class PregeneratorJob implements PregenListener, PregenRenderSource {
}
}
private void broadcastRegionDelta(int regionX, int regionZ, int state) {
IrisProtocolServer protocolServer = IrisServices.getOrNull(IrisProtocolServer.class);
if (protocolServer == null) {
return;
}
protocolServer.broadcastPregenRegionDelta(pregenerator.getJobId(), regionX, regionZ, state);
}
@Override
public void onRegionGenerating(int x, int z) {
broadcastRegionDelta(x, z, IrisMessage.PregenRegionDelta.STATE_GENERATING);
}
@Override
@@ -21,6 +21,8 @@ package art.arcane.iris.core.gui;
import art.arcane.iris.engine.framework.render.IrisRenderer;
import art.arcane.iris.engine.framework.render.RenderType;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.framework.PreservationRegistry;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.volmlib.util.collection.KList;
@@ -154,6 +156,11 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
});
public VisionGUI(JFrame frame) {
PreservationRegistry preservation = IrisServices.getOrNull(PreservationRegistry.class);
if (preservation != null) {
preservation.register(e);
preservation.register(eh);
}
m.set(8);
rs.put(1);
setBackground(BG);
@@ -22,7 +22,11 @@ import org.bukkit.event.EventHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
@@ -18,7 +18,13 @@
package art.arcane.iris.core.loader;
import com.google.gson.*;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.Strictness;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
@@ -27,7 +33,22 @@ import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.object.*;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisBlockData;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisEntity;
import art.arcane.iris.engine.object.IrisExpression;
import art.arcane.iris.engine.object.IrisGenerator;
import art.arcane.iris.engine.object.IrisImage;
import art.arcane.iris.engine.object.IrisJigsawPiece;
import art.arcane.iris.engine.object.IrisJigsawPool;
import art.arcane.iris.engine.object.IrisLootTable;
import art.arcane.iris.engine.object.IrisMarker;
import art.arcane.iris.engine.object.IrisMod;
import art.arcane.iris.engine.object.IrisObject;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.iris.engine.object.IrisSpawner;
import art.arcane.iris.engine.object.IrisStructure;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.engine.object.matter.IrisMatterObject;
import art.arcane.volmlib.util.collection.KList;
@@ -48,7 +69,11 @@ import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@Data
public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
@@ -25,7 +25,7 @@ import art.arcane.iris.util.common.plugin.VolmitSender;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.awt.*;
import java.awt.Desktop;
import java.io.File;
@Data
@@ -46,13 +46,19 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.io.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@@ -74,6 +80,7 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
return thread;
});
private static final Set<String> schemaBuildQueue = ConcurrentHashMap.newKeySet();
private static final AtomicBoolean schemaBuildExecutorRegistered = new AtomicBoolean();
protected final AtomicCache<KList<File>> folderCache;
protected KSet<String> firstAccess;
protected File root;
@@ -101,6 +108,10 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
loadCache = new KCache<>(this::loadRaw, IrisSettings.get().getPerformance().getResourceLoaderCacheSize());
IrisLogging.debug("Loader<" + C.GREEN + resourceTypeName + C.LIGHT_PURPLE + "> created in " + C.RED + "IDM/" + manager.getId() + C.LIGHT_PURPLE + " on " + C.GRAY + manager.getDataFolder().getPath());
IrisServices.get(PreservationRegistry.class).registerCache(this);
PreservationRegistry preservation = IrisServices.getOrNull(PreservationRegistry.class);
if (preservation != null && schemaBuildExecutorRegistered.compareAndSet(false, true)) {
preservation.register(schemaBuildExecutor);
}
}
public JSONObject buildSchema() {
@@ -4,7 +4,13 @@ import art.arcane.volmlib.util.json.JSONArray;
import art.arcane.volmlib.util.json.JSONObject;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
public class BlockProperty {
@@ -1,5 +1,7 @@
package art.arcane.iris.core.nms.datapack.v1192;
import static art.arcane.iris.engine.object.IrisDimensionTypeOptions.TriState.FALSE;
import static art.arcane.iris.engine.object.IrisDimensionTypeOptions.TriState.TRUE;
import art.arcane.iris.core.nms.datapack.IDataFixer;
import art.arcane.iris.engine.object.IrisDimensionTypeOptions;
import art.arcane.volmlib.util.json.JSONObject;
@@ -7,7 +9,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.Map;
import static art.arcane.iris.engine.object.IrisDimensionTypeOptions.TriState.*;
public class DataFixerV1192 implements IDataFixer {
private static final Map<Dimension, IrisDimensionTypeOptions> OPTIONS = Map.of(
@@ -32,7 +32,11 @@ import art.arcane.volmlib.util.math.Vector3d;
import art.arcane.volmlib.util.nbt.mca.palette.MCABiomeContainer;
import art.arcane.volmlib.util.nbt.mca.palette.MCAPaletteAccess;
import art.arcane.volmlib.util.nbt.tag.CompoundTag;
import org.bukkit.*;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Registry;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
@@ -0,0 +1,224 @@
/*
* 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.core.pack;
import art.arcane.iris.spi.PlatformRegistries;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
public final class ContentKeyValidator {
private static final int MAX_SUGGESTION_SCANS = 4096;
private static final String DEFAULT_NAMESPACE = "minecraft";
private ContentKeyValidator() {
}
public enum ContentRegistry {
BLOCK,
ITEM,
ENTITY;
public String label() {
return name().toLowerCase(Locale.ROOT);
}
}
public record ContentKeyError(String key, ContentRegistry registry, boolean namespaceLoaded, String suggestion) {
public String message() {
StringBuilder sb = new StringBuilder(64);
sb.append("Unknown ").append(registry.label()).append(" key '").append(key).append('\'');
sb.append(" (missing from the ").append(registry.label()).append(" registry");
if (!namespaceLoaded) {
sb.append("; namespace '").append(namespaceOf(key)).append("' is not loaded on this server");
}
sb.append(')');
if (suggestion != null) {
sb.append(" - did you mean '").append(suggestion).append("'?");
}
return sb.toString();
}
}
public static List<ContentKeyError> validate(PlatformRegistries registries,
Collection<String> referencedBlocks,
Collection<String> referencedItems,
Collection<String> referencedEntities) {
if (registries == null) {
return List.of();
}
List<String> blockKeys = normalizeKeyList(registries.blockKeys());
List<String> itemKeys = normalizeKeyList(registries.itemKeys());
List<String> entityKeys = normalizeKeyList(registries.entityKeys());
Set<String> knownBlocks = new HashSet<>(blockKeys);
Set<String> knownItems = new HashSet<>(itemKeys);
Set<String> knownEntities = new HashSet<>(entityKeys);
Set<String> loadedNamespaces = new HashSet<>();
addNamespaces(blockKeys, loadedNamespaces);
addNamespaces(itemKeys, loadedNamespaces);
addNamespaces(entityKeys, loadedNamespaces);
Map<String, ContentKeyError> errors = new LinkedHashMap<>();
validateCategory(referencedBlocks, ContentRegistry.BLOCK, knownBlocks, blockKeys, loadedNamespaces, errors);
validateCategory(referencedItems, ContentRegistry.ITEM, knownItems, itemKeys, loadedNamespaces, errors);
validateCategory(referencedEntities, ContentRegistry.ENTITY, knownEntities, entityKeys, loadedNamespaces, errors);
return List.copyOf(errors.values());
}
static String namespaceOf(String key) {
int colon = key.indexOf(':');
return colon < 0 ? DEFAULT_NAMESPACE : key.substring(0, colon);
}
private static void validateCategory(Collection<String> referenced,
ContentRegistry registry,
Set<String> known,
List<String> candidatePool,
Set<String> loadedNamespaces,
Map<String, ContentKeyError> errors) {
if (referenced == null || referenced.isEmpty()) {
return;
}
for (String raw : referenced) {
String normalized = normalizeKey(raw);
if (normalized == null || known.contains(normalized)) {
continue;
}
String dedupKey = registry.name() + '|' + normalized;
if (errors.containsKey(dedupKey)) {
continue;
}
boolean namespaceLoaded = loadedNamespaces.contains(namespaceOf(normalized));
String suggestion = nearestKey(normalized, candidatePool);
errors.put(dedupKey, new ContentKeyError(normalized, registry, namespaceLoaded, suggestion));
}
}
private static List<String> normalizeKeyList(List<String> keys) {
if (keys == null || keys.isEmpty()) {
return List.of();
}
List<String> out = new ArrayList<>(keys.size());
for (String key : keys) {
if (key == null || key.isEmpty()) {
continue;
}
String value = key.trim().toLowerCase(Locale.ROOT);
if (!value.isEmpty()) {
out.add(value.indexOf(':') < 0 ? DEFAULT_NAMESPACE + ':' + value : value);
}
}
return out;
}
private static void addNamespaces(List<String> keys, Set<String> namespaces) {
for (String key : keys) {
namespaces.add(namespaceOf(key));
}
}
private static String normalizeKey(String raw) {
if (raw == null) {
return null;
}
String value = raw.trim().toLowerCase(Locale.ROOT);
int bracket = value.indexOf('[');
if (bracket >= 0) {
value = value.substring(0, bracket).trim();
}
if (value.isEmpty()) {
return null;
}
return value.indexOf(':') < 0 ? DEFAULT_NAMESPACE + ':' + value : value;
}
private static String nearestKey(String key, List<String> candidatePool) {
String path = pathOf(key);
int maxDistance = Math.max(2, path.length() / 3);
int bestDistance = Integer.MAX_VALUE;
String best = null;
int scans = 0;
for (String candidate : candidatePool) {
String candidatePath = pathOf(candidate);
if (Math.abs(candidatePath.length() - path.length()) > maxDistance) {
continue;
}
if (scans++ >= MAX_SUGGESTION_SCANS) {
break;
}
int distance = boundedLevenshtein(path, candidatePath, maxDistance);
if (distance < bestDistance) {
bestDistance = distance;
best = candidate;
if (distance <= 1) {
break;
}
}
}
return bestDistance <= maxDistance ? best : null;
}
private static String pathOf(String key) {
int colon = key.indexOf(':');
return colon < 0 ? key : key.substring(colon + 1);
}
private static int boundedLevenshtein(String a, String b, int max) {
int la = a.length();
int lb = b.length();
if (Math.abs(la - lb) > max) {
return max + 1;
}
int[] prev = new int[lb + 1];
int[] curr = new int[lb + 1];
for (int j = 0; j <= lb; j++) {
prev[j] = j;
}
for (int i = 1; i <= la; i++) {
curr[0] = i;
int rowMin = curr[0];
char ca = a.charAt(i - 1);
for (int j = 1; j <= lb; j++) {
int cost = ca == b.charAt(j - 1) ? 0 : 1;
curr[j] = Math.min(Math.min(prev[j] + 1, curr[j - 1] + 1), prev[j - 1] + cost);
if (curr[j] < rowMin) {
rowMin = curr[j];
}
}
if (rowMin > max) {
return max + 1;
}
int[] tmp = prev;
prev = curr;
curr = tmp;
}
return prev[lb];
}
}
@@ -19,6 +19,8 @@
package art.arcane.iris.core.pack;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.spi.PlatformRegistries;
import art.arcane.volmlib.util.json.JSONArray;
import art.arcane.volmlib.util.json.JSONObject;
@@ -35,6 +37,7 @@ import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Stream;
@@ -98,9 +101,126 @@ public final class PackValidator {
warnings.add("Unused-resource GC pass failed: " + e.getMessage());
}
runContentKeyValidation(packFolder, warnings);
return new PackValidationResult(packName, blockingErrors, warnings, removedUnusedFiles, validatedAt);
}
private static void runContentKeyValidation(File packFolder, List<String> warnings) {
try {
if (!IrisPlatforms.isBound()) {
return;
}
PlatformRegistries registries = IrisPlatforms.get().registries();
if (registries == null) {
return;
}
List<String> blockKeys = registries.blockKeys();
List<String> itemKeys = registries.itemKeys();
List<String> entityKeys = registries.entityKeys();
if (blockKeys == null || blockKeys.isEmpty() || itemKeys == null || itemKeys.isEmpty() || entityKeys == null || entityKeys.isEmpty()) {
return;
}
ReferencedContentKeys referenced = collectReferencedContentKeys(packFolder);
List<ContentKeyValidator.ContentKeyError> errors = ContentKeyValidator.validate(
registries, referenced.blocks(), referenced.items(), referenced.entities());
for (ContentKeyValidator.ContentKeyError error : errors) {
warnings.add(error.message());
}
} catch (Throwable e) {
IrisLogging.reportError("PackValidator content-key validation failed for pack '" + packFolder.getName() + "'", e);
}
}
private static ReferencedContentKeys collectReferencedContentKeys(File packFolder) {
Set<String> blocks = new HashSet<>();
Set<String> items = new HashSet<>();
Set<String> entities = new HashSet<>();
Set<String> customBlocks = deriveRegistrantKeys(new File(packFolder, "blocks"));
try (Stream<Path> stream = Files.walk(packFolder.toPath())) {
List<Path> files = stream.filter(Files::isRegularFile)
.filter(PackValidator::isScannableJsonPath)
.toList();
for (Path path : files) {
String relative = packFolder.toPath().relativize(path).toString().replace(File.separatorChar, '/');
boolean inLoot = relative.startsWith("loot/");
boolean inEntities = relative.startsWith("entities/");
JSONObject json;
try {
json = new JSONObject(Files.readString(path, StandardCharsets.UTF_8));
} catch (Throwable ignored) {
continue;
}
collectFromNode(json, blocks, inLoot ? items : null, inEntities ? entities : null, customBlocks);
}
} catch (Throwable e) {
IrisLogging.reportError("PackValidator failed to walk pack for content-key extraction", e);
}
return new ReferencedContentKeys(blocks, items, entities);
}
private static void collectFromNode(Object node, Set<String> blocks, Set<String> items, Set<String> entities, Set<String> customBlocks) {
if (node instanceof JSONObject obj) {
for (String key : obj.keySet()) {
Object value = obj.get(key);
if (value instanceof String str) {
if ("block".equals(key)) {
addBlockRef(str, blocks, customBlocks);
} else if (items != null && "type".equals(key)) {
addSimpleRef(str, items);
} else if (entities != null && "type".equals(key)) {
addSimpleRef(str, entities);
}
} else {
collectFromNode(value, blocks, items, entities, customBlocks);
}
}
} else if (node instanceof JSONArray arr) {
for (int i = 0; i < arr.length(); i++) {
collectFromNode(arr.get(i), blocks, items, entities, customBlocks);
}
}
}
private static void addBlockRef(String raw, Set<String> blocks, Set<String> customBlocks) {
String value = raw.trim().toLowerCase(Locale.ROOT);
int bracket = value.indexOf('[');
if (bracket >= 0) {
value = value.substring(0, bracket).trim();
}
if (value.isEmpty() || customBlocks.contains(value)) {
return;
}
blocks.add(value);
}
private static void addSimpleRef(String raw, Set<String> target) {
String value = raw.trim().toLowerCase(Locale.ROOT);
if (!value.isEmpty()) {
target.add(value);
}
}
private static Set<String> deriveRegistrantKeys(File folder) {
Set<String> keys = new HashSet<>();
if (!folder.isDirectory()) {
return keys;
}
for (File file : listJsonRecursive(folder)) {
String key = deriveKey(folder, file);
if (key != null && !key.isBlank()) {
keys.add(key.toLowerCase(Locale.ROOT));
}
}
return keys;
}
private record ReferencedContentKeys(Set<String> blocks, Set<String> items, Set<String> entities) {
}
private static void validateDimensions(File packFolder, File[] dimensionFiles, List<String> blockingErrors, List<String> warnings) {
File regionsFolder = new File(packFolder, "regions");
File biomesFolder = new File(packFolder, "biomes");
@@ -19,6 +19,9 @@
package art.arcane.iris.core.pregenerator;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.spi.protocol.IrisMessage;
import art.arcane.iris.core.protocol.IrisProtocolServer;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.tools.IrisPackBenchmarking;
import art.arcane.volmlib.util.collection.KList;
@@ -41,6 +44,8 @@ import java.util.concurrent.atomic.AtomicReference;
public class IrisPregenerator {
private static final double INVALID = 9223372036854775807d;
private static final AtomicLong JOB_SEQUENCE = new AtomicLong(0L);
private final long jobId;
private final PregenTask task;
private final PregeneratorMethod generator;
private final PregenListener listener;
@@ -72,6 +77,7 @@ public class IrisPregenerator {
private final IrisPackBenchmarking benchmarking;
public IrisPregenerator(PregenTask task, PregeneratorMethod generator, PregenListener listener) {
this.jobId = JOB_SEQUENCE.incrementAndGet();
benchmarking = IrisPackBenchmarking.getInstance();
this.listener = listenify(listener);
cl = new ChronoLatch(10000);
@@ -138,6 +144,17 @@ public class IrisPregenerator {
totalChunks.get() - generated.get(), eta, M.ms() - startTime.get(), currentGeneratorMethod.get(),
cached);
IrisProtocolServer protocolServer = IrisServices.getOrNull(IrisProtocolServer.class);
if (protocolServer != null) {
protocolServer.broadcastPregenProgress(
jobId,
generated.get(),
totalChunks.get(),
cached ? cachedPerSecond.getAverage() : chunksPerSecond.getAverage(),
eta,
paused.get() ? IrisMessage.PregenProgress.STATE_PAUSED : IrisMessage.PregenProgress.STATE_RUNNING);
}
if (cl.flip()) {
double percentage = ((double) generated.get() / (double) totalChunks.get()) * 100;
@@ -172,6 +189,10 @@ public class IrisPregenerator {
}
public long getJobId() {
return jobId;
}
public void close() {
shutdown.set(true);
}
@@ -219,6 +240,11 @@ public class IrisPregenerator {
generator.close();
ticker.interrupt();
listener.onClose();
IrisProtocolServer protocolServer = IrisServices.getOrNull(IrisProtocolServer.class);
if (protocolServer != null) {
long total = totalChunks.get();
protocolServer.pregenEnd(jobId, total > 0 && generated.get() >= total);
}
Mantle mantle = getMantle();
if (mantle != null) {
reclaimTectonicPlates(mantle);
@@ -1,6 +1,8 @@
package art.arcane.iris.core.pregenerator.cache;
import art.arcane.iris.engine.framework.PreservationRegistry;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.IrisServices;
import art.arcane.volmlib.util.data.Varint;
import art.arcane.volmlib.util.documentation.ChunkCoordinates;
import art.arcane.volmlib.util.documentation.RegionCoordinates;
@@ -23,9 +25,11 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
public class PregenCacheImpl implements PregenCache {
private static final ExecutorService DISPATCHER = Executors.newFixedThreadPool(4);
private static final AtomicBoolean DISPATCHER_REGISTERED = new AtomicBoolean();
private static final short SIZE = 1024;
private final File directory;
@@ -35,6 +39,10 @@ public class PregenCacheImpl implements PregenCache {
public PregenCacheImpl(File directory, int maxSize) {
this.directory = directory;
this.maxSize = maxSize;
PreservationRegistry preservation = IrisServices.getOrNull(PreservationRegistry.class);
if (preservation != null && DISPATCHER_REGISTERED.compareAndSet(false, true)) {
preservation.register(DISPATCHER);
}
}
@Override
@@ -23,7 +23,9 @@ import art.arcane.iris.core.pregenerator.PregenListener;
import art.arcane.iris.core.pregenerator.PregeneratorMethod;
import art.arcane.iris.core.tools.IrisToolbelt;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.framework.PreservationRegistry;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.util.project.context.ChunkContext;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.mantle.runtime.Mantle;
@@ -63,6 +65,10 @@ public class MedievalPregenMethod implements PregeneratorMethod {
this.prefetchDisabled = new AtomicBoolean(J.isFolia());
int prefetchThreads = J.isFolia() ? 0 : Math.max(2, Math.min(16, configuredThreads));
this.prefetchPool = prefetchThreads > 0 ? newPrefetchPool(prefetchThreads) : null;
PreservationRegistry preservation = IrisServices.getOrNull(PreservationRegistry.class);
if (preservation != null && prefetchPool != null) {
preservation.register(prefetchPool);
}
}
private static ExecutorService newPrefetchPool(int threads) {
@@ -27,7 +27,16 @@ import art.arcane.iris.core.loader.IrisRegistrant;
import art.arcane.iris.core.loader.ResourceLoader;
import art.arcane.iris.core.runtime.StudioOpenCoordinator;
import art.arcane.iris.core.tools.IrisToolbelt;
import art.arcane.iris.engine.object.*;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisBlockData;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisEntity;
import art.arcane.iris.engine.object.IrisGenerator;
import art.arcane.iris.engine.object.IrisLootTable;
import art.arcane.iris.engine.object.IrisObject;
import art.arcane.iris.engine.object.IrisObjectPlacement;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.iris.engine.object.IrisSpawner;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
import art.arcane.volmlib.util.collection.KList;
@@ -56,7 +65,8 @@ import org.dom4j.Document;
import org.dom4j.Element;
import org.zeroturnaround.zip.ZipUtil;
import java.awt.*;
import java.awt.Desktop;
import java.awt.GraphicsEnvironment;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
@@ -18,10 +18,11 @@
package art.arcane.iris.core.project;
import art.arcane.iris.platform.bukkit.BukkitBlockResolution;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.spi.PlatformBlockProperty;
import art.arcane.iris.spi.PlatformNumericRange;
import art.arcane.iris.core.link.Identifier;
import art.arcane.iris.core.link.data.DataType;
import art.arcane.iris.core.loader.IrisData;
@@ -29,23 +30,37 @@ import art.arcane.iris.core.loader.IrisRegistrant;
import art.arcane.iris.core.loader.ResourceLoader;
import art.arcane.iris.core.service.ExternalDataSVC;
import art.arcane.iris.core.structure.StructureSchemaKeys;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.core.nms.INMS;
import art.arcane.iris.engine.framework.ListFunction;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListBlockType;
import art.arcane.iris.engine.object.annotations.RegistryListEnchantment;
import art.arcane.iris.engine.object.annotations.RegistryListEntityType;
import art.arcane.iris.engine.object.annotations.RegistryListFont;
import art.arcane.iris.engine.object.annotations.RegistryListFunction;
import art.arcane.iris.engine.object.annotations.RegistryListItemType;
import art.arcane.iris.engine.object.annotations.RegistryListPotionEffect;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.RegistryListSpecialEntity;
import art.arcane.iris.engine.object.annotations.RegistryListStructure;
import art.arcane.iris.engine.object.annotations.RegistryListVanillaStructure;
import art.arcane.iris.engine.object.annotations.RegistryListVanillaStructureSet;
import art.arcane.iris.engine.object.annotations.RegistryMapBlockState;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.collection.KMap;
import art.arcane.volmlib.util.json.JSONArray;
import art.arcane.volmlib.util.json.JSONObject;
import art.arcane.iris.util.common.reflect.KeyedType;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.awt.GraphicsEnvironment;
import java.lang.reflect.Field;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@@ -55,13 +70,14 @@ import java.util.function.Function;
public class SchemaBuilder {
private static final String SYMBOL_LIMIT__N = "*";
private static final String SYMBOL_TYPE__N = "";
private static final JSONArray POTION_TYPES = getPotionTypes();
private static final JSONArray ENCHANT_TYPES = getEnchantTypes();
private static final String MINECRAFT_NAMESPACE = "minecraft:";
private static final JSONArray FONT_TYPES = new JSONArray(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames());
private final KMap<String, JSONObject> definitions;
private final Class<?> root;
private final KList<String> warnings;
private final IrisData data;
private JSONArray potionTypes;
private JSONArray enchantTypes;
public SchemaBuilder(Class<?> root, IrisData data) {
this.data = data;
@@ -70,30 +86,6 @@ public class SchemaBuilder {
this.root = root;
}
private static JSONArray getPotionTypes() {
JSONArray a = new JSONArray();
for (PotionEffectType gg : Registry.EFFECT) {
NamespacedKey key = KeyedType.getKey(gg);
if (key != null) {
a.put(key.getKey().toUpperCase(Locale.ROOT).replaceAll("\\Q \\E", "_"));
}
}
return a;
}
private static JSONArray getEnchantTypes() {
JSONArray array = new JSONArray();
for (Enchantment e : Registry.ENCHANTMENT) {
NamespacedKey key = KeyedType.getKey(e);
if (key != null) {
array.put(key.getKey());
}
}
return array;
}
public JSONObject construct() {
JSONObject schema = new JSONObject();
schema.put("$schema", "http://json-schema.org/draft-07/schema#");
@@ -122,6 +114,52 @@ public class SchemaBuilder {
return schema;
}
private JSONArray potionTypes() {
if (potionTypes == null) {
JSONArray a = new JSONArray();
for (String key : IrisPlatforms.get().registries().potionEffectKeys()) {
a.put(stripNamespace(key).toUpperCase(Locale.ROOT).replace(" ", "_"));
}
potionTypes = a;
}
return potionTypes;
}
private JSONArray enchantTypes() {
if (enchantTypes == null) {
JSONArray a = new JSONArray();
for (String key : IrisPlatforms.get().registries().enchantmentKeys()) {
a.put(stripNamespace(key));
}
enchantTypes = a;
}
return enchantTypes;
}
private JSONArray itemTypes() {
JSONArray a = new JSONArray();
for (String key : IrisPlatforms.get().registries().itemKeys()) {
a.put(key.startsWith(MINECRAFT_NAMESPACE) ? key.substring(MINECRAFT_NAMESPACE.length()) : key);
}
return a;
}
private JSONArray blockTypes() {
JSONArray a = new JSONArray();
for (String i : data.getBlockLoader().getPossibleKeys()) {
a.put(i);
}
for (String i : IrisPlatforms.get().registries().blockTypeKeys()) {
a.put(i);
}
return a;
}
private static String stripNamespace(String key) {
int idx = key.indexOf(':');
return idx < 0 ? key : key.substring(idx + 1);
}
private JSONObject buildProperties(Class<?> c) {
JSONObject o = new JSONObject();
JSONObject properties = new JSONObject();
@@ -132,7 +170,7 @@ public class SchemaBuilder {
JSONArray required = new JSONArray();
JSONArray extended = new JSONArray();
var parent = c.getSuperclass();
Class<?> parent = c.getSuperclass();
while (parent != null && IrisRegistrant.class.isAssignableFrom(parent)) {
buildProperties(properties, required, extended, parent);
parent = parent.getSuperclass();
@@ -255,7 +293,7 @@ public class SchemaBuilder {
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", new JSONArray(StructureSchemaKeys.collect(
INMS.get().getStructureKeys(),
IrisPlatforms.get().registries().structureKeys(),
Arrays.asList(data.getStructureLoader().getPossibleKeys()),
Arrays.asList(data.getJigsawPieceLoader().getPossibleKeys())).toArray(new String[0])));
definitions.put(key, j);
@@ -270,17 +308,7 @@ public class SchemaBuilder {
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
JSONArray ja = new JSONArray();
for (String i : data.getBlockLoader().getPossibleKeys()) {
ja.put(i);
}
for (String i : BukkitBlockResolution.getBlockTypes()) {
ja.put(i);
}
j.put("enum", ja);
j.put("enum", blockTypes());
definitions.put(key, j);
}
@@ -295,7 +323,7 @@ public class SchemaBuilder {
JSONObject j = new JSONObject();
JSONArray ja = new JSONArray();
for (String i : INMS.get().getStructureKeys()) {
for (String i : IrisPlatforms.get().registries().structureKeys()) {
ja.put(i);
}
@@ -314,7 +342,7 @@ public class SchemaBuilder {
JSONObject j = new JSONObject();
JSONArray ja = new JSONArray();
for (String i : INMS.get().getStructureSetKeys()) {
for (String i : IrisPlatforms.get().structureHooks().structureSetKeys()) {
ja.put(i);
}
@@ -331,7 +359,7 @@ public class SchemaBuilder {
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", BukkitBlockResolution.getItemTypes());
j.put("enum", itemTypes());
definitions.put(key, j);
}
@@ -339,6 +367,25 @@ public class SchemaBuilder {
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Item Type (use ctrl+space for auto complete!)");
} else if (k.isAnnotationPresent(RegistryListEntityType.class)) {
String key = "enum-entity-type";
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
JSONArray ja = new JSONArray();
for (String i : IrisPlatforms.get().registries().entityKeys()) {
ja.put(i);
}
j.put("enum", ja);
definitions.put(key, j);
}
fancyType = "Entity Type";
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Entity Type (use ctrl+space for auto complete!)");
} else if (k.isAnnotationPresent(RegistryListSpecialEntity.class)) {
String key = "enum-reg-specialentity";
@@ -374,7 +421,7 @@ public class SchemaBuilder {
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", ENCHANT_TYPES);
j.put("enum", enchantTypes());
definitions.put(key, j);
}
@@ -386,7 +433,7 @@ public class SchemaBuilder {
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", POTION_TYPES);
j.put("enum", potionTypes());
definitions.put(key, j);
}
@@ -394,9 +441,9 @@ public class SchemaBuilder {
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)");
} else if (k.isAnnotationPresent(RegistryListFunction.class)) {
var functionClass = k.getDeclaredAnnotation(RegistryListFunction.class).value();
Class<? extends ListFunction<KList<String>>> functionClass = k.getDeclaredAnnotation(RegistryListFunction.class).value();
try {
var instance = functionClass.getDeclaredConstructor().newInstance();
ListFunction<KList<String>> instance = functionClass.getDeclaredConstructor().newInstance();
String key = instance.key();
fancyType = instance.fancyName();
@@ -411,27 +458,13 @@ public class SchemaBuilder {
} catch (Throwable e) {
IrisLogging.error("Could not execute apply method in " + functionClass.getName());
}
} else if (k.getType().equals(PotionEffectType.class)) {
String key = "enum-potion-effect-type";
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", POTION_TYPES);
definitions.put(key, j);
}
fancyType = "Potion Effect Type";
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)");
} else if (KeyedType.isKeyed(k.getType())) {
fancyType = addEnum(k.getType(), prop, description, KeyedType.values(k.getType()), Function.identity());
} else if (SchemaKeyedTypes.isKeyed(k.getType())) {
fancyType = addEnum(k.getType(), prop, description, SchemaKeyedTypes.values(k.getType()), Function.identity());
} else if (k.getType().isEnum()) {
fancyType = addEnum(k.getType(), prop, description, k.getType().getEnumConstants(), o -> ((Enum<?>) o).name());
}
}
case "object" -> {
//TODO add back descriptions
if (k.isAnnotationPresent(RegistryMapBlockState.class)) {
String blockType = k.getDeclaredAnnotation(RegistryMapBlockState.class).value();
fancyType = "Block State";
@@ -439,10 +472,13 @@ public class SchemaBuilder {
JSONArray any = new JSONArray();
prop.put("anyOf", any);
BukkitBlockResolution.getBlockStates().forEach((blocks, properties) -> {
if (blocks.isEmpty()) return;
for (BlockStateGroup group : reconstructBlockStateGroups()) {
List<String> blocks = group.blocks();
if (blocks.isEmpty()) {
continue;
}
String raw = blocks.getFirst().replace(':', '_');
String raw = blocks.get(0).replace(':', '_');
String enumKey = "enum-block-state-" + raw;
String propertiesKey = "obj-block-state-" + raw;
@@ -470,15 +506,15 @@ public class SchemaBuilder {
if (!definitions.containsKey(propertiesKey)) {
JSONObject props = new JSONObject();
properties.forEach(property -> {
props.put(property.name(), property.buildJson());
});
for (PlatformBlockProperty property : group.properties()) {
props.put(property.name(), buildBlockPropertyJson(property));
}
definitions.put(propertiesKey, new JSONObject()
.put("type", "object")
.put("properties", props));
}
});
}
} else {
fancyType = k.getType().getSimpleName().replaceAll("\\QIris\\E", "") + " (Object)";
String key = "obj-" + k.getType().getCanonicalName().replaceAll("\\Q.\\E", "-").toLowerCase();
@@ -549,7 +585,7 @@ public class SchemaBuilder {
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", new JSONArray(StructureSchemaKeys.collect(
INMS.get().getStructureKeys(),
IrisPlatforms.get().registries().structureKeys(),
Arrays.asList(data.getStructureLoader().getPossibleKeys()),
Arrays.asList(data.getJigsawPieceLoader().getPossibleKeys())).toArray(new String[0])));
definitions.put(key, j);
@@ -565,17 +601,7 @@ public class SchemaBuilder {
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
JSONArray ja = new JSONArray();
for (String i : data.getBlockLoader().getPossibleKeys()) {
ja.put(i);
}
for (String i : BukkitBlockResolution.getBlockTypes()) {
ja.put(i);
}
j.put("enum", ja);
j.put("enum", blockTypes());
definitions.put(key, j);
}
@@ -589,7 +615,7 @@ public class SchemaBuilder {
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", BukkitBlockResolution.getItemTypes());
j.put("enum", itemTypes());
definitions.put(key, j);
}
@@ -597,6 +623,26 @@ public class SchemaBuilder {
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid Item Type (use ctrl+space for auto complete!)");
} else if (k.isAnnotationPresent(RegistryListEntityType.class)) {
fancyType = "List of Entity Types";
String key = "enum-entity-type";
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
JSONArray ja = new JSONArray();
for (String i : IrisPlatforms.get().registries().entityKeys()) {
ja.put(i);
}
j.put("enum", ja);
definitions.put(key, j);
}
JSONObject items = new JSONObject();
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid Entity Type (use ctrl+space for auto complete!)");
} else if (k.isAnnotationPresent(RegistryListFont.class)) {
String key = "enum-font";
fancyType = "List of Font Families";
@@ -617,7 +663,7 @@ public class SchemaBuilder {
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", ENCHANT_TYPES);
j.put("enum", enchantTypes());
definitions.put(key, j);
}
@@ -631,7 +677,7 @@ public class SchemaBuilder {
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", POTION_TYPES);
j.put("enum", potionTypes());
definitions.put(key, j);
}
@@ -640,9 +686,9 @@ public class SchemaBuilder {
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)");
} else if (k.isAnnotationPresent(RegistryListFunction.class)) {
var functionClass = k.getDeclaredAnnotation(RegistryListFunction.class).value();
Class<? extends ListFunction<KList<String>>> functionClass = k.getDeclaredAnnotation(RegistryListFunction.class).value();
try {
var instance = functionClass.getDeclaredConstructor().newInstance();
ListFunction<KList<String>> instance = functionClass.getDeclaredConstructor().newInstance();
String key = instance.key();
fancyType = instance.fancyName();
@@ -659,22 +705,8 @@ public class SchemaBuilder {
} catch (Throwable e) {
IrisLogging.error("Could not execute apply method in " + functionClass.getName());
}
} else if (t.type().equals(PotionEffectType.class)) {
fancyType = "List of Potion Effect Types";
String key = "enum-potion-effect-type";
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", POTION_TYPES);
definitions.put(key, j);
}
JSONObject items = new JSONObject();
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)");
} else if (KeyedType.isKeyed(t.type())) {
fancyType = addEnumList(prop, description, t, KeyedType.values(t.type()), Function.identity());
} else if (SchemaKeyedTypes.isKeyed(t.type())) {
fancyType = addEnumList(prop, description, t, SchemaKeyedTypes.values(t.type()), Function.identity());
} else if (t.type().isEnum()) {
fancyType = addEnumList(prop, description, t, t.type().getEnumConstants(), o -> ((Enum<?>) o).name());
}
@@ -719,7 +751,7 @@ public class SchemaBuilder {
if (present) d.add(" ");
if (value instanceof List) {
d.add(SYMBOL_LIMIT__N + " Default Value is an empty list");
} else if (!k.getType().isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(value instanceof Enum<?>) && !KeyedType.isKeyed(k.getType())) {
} else if (!k.getType().isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(value instanceof Enum<?>) && !SchemaKeyedTypes.isKeyed(k.getType())) {
d.add(SYMBOL_LIMIT__N + " Default Value is a default object (create this object to see default properties)");
} else {
d.add(SYMBOL_LIMIT__N + " Default Value is " + value);
@@ -783,7 +815,7 @@ public class SchemaBuilder {
@NotNull
private <T> String addEnumList(JSONObject prop, KList<String> description, ArrayType t, T[] values, Function<T, String> function) {
JSONObject items = new JSONObject();
var s = addEnum(t.type(), items, description, values, function);
String s = addEnum(t.type(), items, description, values, function);
prop.put("items", items);
return "List of " + s + "s";
@@ -826,6 +858,47 @@ public class SchemaBuilder {
return type.getSimpleName().replaceAll("\\QIris\\E", "");
}
private JSONObject buildBlockPropertyJson(PlatformBlockProperty property) {
JSONObject json = new JSONObject();
json.put("type", property.jsonType());
json.put("default", property.defaultValue());
List<Object> allowed = property.allowedValues();
if (!allowed.isEmpty()) {
json.put("enum", new JSONArray(allowed));
}
if (property.hasNumericRange()) {
PlatformNumericRange range = property.numericRange();
if ("integer".equals(property.jsonType())) {
json.put("minimum", (long) range.minimum());
json.put("maximum", (long) range.maximum());
} else {
json.put("minimum", range.minimum());
json.put("maximum", range.maximum());
}
json.put("exclusiveMinimum", range.exclusiveMinimum());
json.put("exclusiveMaximum", range.exclusiveMaximum());
}
return json;
}
private List<BlockStateGroup> reconstructBlockStateGroups() {
List<BlockStateGroup> groups = new ArrayList<>();
List<PlatformBlockProperty> currentProperties = null;
List<String> currentBlocks = null;
for (Map.Entry<String, List<PlatformBlockProperty>> entry : IrisPlatforms.get().registries().blockStateProperties().entrySet()) {
List<PlatformBlockProperty> value = entry.getValue();
if (currentProperties != null && value == currentProperties) {
currentBlocks.add(entry.getKey());
} else {
currentBlocks = new ArrayList<>();
currentBlocks.add(entry.getKey());
currentProperties = value;
groups.add(new BlockStateGroup(currentBlocks, value));
}
}
return groups;
}
private String getType(Class<?> c) {
if (c.equals(int.class) || c.equals(Integer.class) || c.equals(long.class) || c.equals(Long.class)) {
return "integer";
@@ -839,7 +912,7 @@ public class SchemaBuilder {
return "boolean";
}
if (c.equals(String.class) || c.isEnum() || KeyedType.isKeyed(c)) {
if (c.equals(String.class) || c.isEnum() || SchemaKeyedTypes.isKeyed(c)) {
return "string";
}
@@ -864,11 +937,6 @@ public class SchemaBuilder {
return r.getDeclaredAnnotation(Desc.class).value();
}
// suppress warnings on bukkit classes
if (r.getDeclaringClass().getName().startsWith("org.bukkit.")) {
return "Bukkit package classes and enums have no descriptions";
}
warnings.addIfMissing("Missing @Desc on field " + r.getName() + " (" + r.getType() + ") in " + r.getDeclaringClass().getCanonicalName());
return "No Field Description";
}
@@ -883,4 +951,7 @@ public class SchemaBuilder {
}
return "";
}
private record BlockStateGroup(List<String> blocks, List<PlatformBlockProperty> properties) {
}
}
@@ -0,0 +1,34 @@
/*
* Iris is a World Generator for Minecraft 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.core.project;
import art.arcane.iris.util.common.reflect.KeyedType;
final class SchemaKeyedTypes {
private SchemaKeyedTypes() {
}
static boolean isKeyed(Class<?> type) {
return KeyedType.isKeyed(type);
}
static String[] values(Class<?> type) {
return KeyedType.values(type);
}
}
@@ -0,0 +1,26 @@
/*
* 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.core.protocol;
import art.arcane.iris.engine.framework.Engine;
@FunctionalInterface
public interface EngineResolver {
Engine resolve(String sessionId);
}
@@ -0,0 +1,45 @@
/*
* 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.core.protocol;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.iris.spi.protocol.IrisMessage;
public final class IrisCursorResolver {
private IrisCursorResolver() {
}
public static IrisMessage.CursorInfo resolve(Engine engine, int blockX, int blockZ) {
IrisBiome surfaceBiome = engine.getSurfaceBiome(blockX, blockZ);
IrisRegion region = engine.getRegion(blockX, blockZ);
IrisBiome caveBiome = engine.getCaveBiome(blockX, blockZ);
int height = engine.getHeight(blockX, blockZ);
String biomeKey = keyOf(surfaceBiome == null ? null : surfaceBiome.getLoadKey());
String regionKey = keyOf(region == null ? null : region.getLoadKey());
String caveBiomeKey = keyOf(caveBiome == null ? null : caveBiome.getLoadKey());
String dimensionKey = keyOf(engine.getDimension().getLoadKey());
return new IrisMessage.CursorInfo(blockX, blockZ, biomeKey, regionKey, caveBiomeKey, height, dimensionKey);
}
private static String keyOf(String value) {
return value == null ? "" : value;
}
}
@@ -0,0 +1,348 @@
/*
* 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.core.protocol;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.spi.protocol.IrisMessage;
import art.arcane.iris.spi.protocol.IrisMessageCodec;
import art.arcane.iris.spi.protocol.IrisProtocol;
import art.arcane.iris.spi.protocol.ProtocolException;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.LongSupplier;
public final class IrisProtocolServer {
private final IrisSessionRegistry registry;
private final long serverCapabilities;
private final String serverBrand;
private final boolean irisActive;
private final LongSupplier clock;
private final AtomicLong droppedBeforeHello;
private final AtomicLong rateLimitedFrames;
private final AtomicLong rejectedFrames;
private final AtomicLong versionMismatches;
private final AtomicLong capabilityRejected;
private final AtomicLong noEngineDrops;
private final AtomicLong cursorInfoServed;
private final AtomicLong visionTileForwarded;
private final AtomicLong visionRateLimited;
private final AtomicLong pregenRegionDeltasBroadcast;
private final AtomicLong studioHotloadsBroadcast;
private final AtomicLong toastsBroadcast;
private final AtomicLong toastsSent;
private volatile EngineResolver engineResolver;
private volatile VisionTileRequestHandler visionTileHandler;
public IrisProtocolServer(IrisSessionRegistry registry, long serverCapabilities, String serverBrand, boolean irisActive) {
this(registry, serverCapabilities, serverBrand, irisActive, System::currentTimeMillis);
}
IrisProtocolServer(IrisSessionRegistry registry, long serverCapabilities, String serverBrand, boolean irisActive, LongSupplier clock) {
this.registry = Objects.requireNonNull(registry, "session registry");
this.serverCapabilities = serverCapabilities;
this.serverBrand = Objects.requireNonNull(serverBrand, "server brand");
this.irisActive = irisActive;
this.clock = Objects.requireNonNull(clock, "clock");
this.droppedBeforeHello = new AtomicLong(0L);
this.rateLimitedFrames = new AtomicLong(0L);
this.rejectedFrames = new AtomicLong(0L);
this.versionMismatches = new AtomicLong(0L);
this.capabilityRejected = new AtomicLong(0L);
this.noEngineDrops = new AtomicLong(0L);
this.cursorInfoServed = new AtomicLong(0L);
this.visionTileForwarded = new AtomicLong(0L);
this.visionRateLimited = new AtomicLong(0L);
this.pregenRegionDeltasBroadcast = new AtomicLong(0L);
this.studioHotloadsBroadcast = new AtomicLong(0L);
this.toastsBroadcast = new AtomicLong(0L);
this.toastsSent = new AtomicLong(0L);
}
public IrisSessionRegistry registry() {
return registry;
}
public void setEngineResolver(EngineResolver engineResolver) {
this.engineResolver = engineResolver;
}
public void setVisionTileHandler(VisionTileRequestHandler visionTileHandler) {
this.visionTileHandler = visionTileHandler;
}
public void onClientFrame(String sessionId, byte[] frame) {
IrisSession session = registry.get(sessionId);
if (session == null) {
return;
}
if (!session.allowInbound(clock.getAsLong())) {
rateLimitedFrames.incrementAndGet();
return;
}
IrisMessage message;
try {
message = IrisMessageCodec.decode(frame);
} catch (ProtocolException rejected) {
rejectedFrames.incrementAndGet();
return;
}
if (message == null) {
return;
}
dispatch(session, message);
}
public void broadcastPregenProgress(long jobId, long chunksDone, long chunksTotal, double chunksPerSecond, long etaMillis, int state) {
if (registry.isEmpty()) {
return;
}
byte[] frame = null;
for (IrisSession session : registry.all()) {
if (!session.isReady() || !session.hasCapability(IrisProtocol.CAPABILITY_PREGEN)) {
continue;
}
if (frame == null) {
frame = IrisMessageCodec.encode(new IrisMessage.PregenProgress(jobId, chunksDone, chunksTotal, chunksPerSecond, etaMillis, state));
}
session.sendRaw(frame);
}
}
public void pregenEnd(long jobId, boolean completed) {
if (registry.isEmpty()) {
return;
}
byte[] frame = null;
for (IrisSession session : registry.all()) {
if (!session.isReady() || !session.hasCapability(IrisProtocol.CAPABILITY_PREGEN)) {
continue;
}
if (frame == null) {
frame = IrisMessageCodec.encode(new IrisMessage.PregenEnd(jobId, completed));
}
session.sendRaw(frame);
}
}
public void broadcastDimensionStatus(String dimensionKey, String packKey, long seed, int minY, int maxY, boolean irisWorld) {
if (registry.isEmpty()) {
return;
}
byte[] frame = null;
for (IrisSession session : registry.all()) {
if (!session.isReady()) {
continue;
}
if (frame == null) {
frame = IrisMessageCodec.encode(new IrisMessage.DimensionStatus(dimensionKey, packKey, seed, minY, maxY, irisWorld));
}
session.sendRaw(frame);
}
}
public void sendDimensionStatus(String sessionId, String dimensionKey, String packKey, long seed, int minY, int maxY, boolean irisWorld) {
IrisSession session = registry.get(sessionId);
if (session == null || !session.isReady()) {
return;
}
session.send(new IrisMessage.DimensionStatus(dimensionKey, packKey, seed, minY, maxY, irisWorld));
}
public void broadcastPregenRegionDelta(long jobId, int regionX, int regionZ, int state) {
if (registry.isEmpty()) {
return;
}
byte[] frame = null;
for (IrisSession session : registry.all()) {
if (!session.isReady() || !session.hasCapability(IrisProtocol.CAPABILITY_PREGEN)) {
continue;
}
if (frame == null) {
frame = IrisMessageCodec.encode(new IrisMessage.PregenRegionDelta(jobId, regionX, regionZ, state));
}
session.sendRaw(frame);
}
if (frame != null) {
pregenRegionDeltasBroadcast.incrementAndGet();
}
}
public void broadcastStudioHotload(String packKey, int changedFiles, boolean failed, String message) {
if (registry.isEmpty()) {
return;
}
byte[] frame = null;
for (IrisSession session : registry.all()) {
if (!session.isReady() || !session.hasCapability(IrisProtocol.CAPABILITY_STUDIO)) {
continue;
}
if (frame == null) {
frame = IrisMessageCodec.encode(new IrisMessage.StudioHotload(packKey, changedFiles, failed, message));
}
session.sendRaw(frame);
}
if (frame != null) {
studioHotloadsBroadcast.incrementAndGet();
}
}
public void broadcastToast(int kind, String title, String body) {
if (registry.isEmpty()) {
return;
}
byte[] frame = null;
for (IrisSession session : registry.all()) {
if (!session.isReady() || !session.hasCapability(IrisProtocol.CAPABILITY_STUDIO)) {
continue;
}
if (frame == null) {
frame = IrisMessageCodec.encode(new IrisMessage.Toast(kind, title, body));
}
session.sendRaw(frame);
}
if (frame != null) {
toastsBroadcast.incrementAndGet();
}
}
public void sendToast(String sessionId, int kind, String title, String body) {
IrisSession session = registry.get(sessionId);
if (session == null || !session.isReady() || !session.hasCapability(IrisProtocol.CAPABILITY_STUDIO)) {
return;
}
session.send(new IrisMessage.Toast(kind, title, body));
toastsSent.incrementAndGet();
}
public long droppedBeforeHelloCount() {
return droppedBeforeHello.get();
}
public long rateLimitedFrameCount() {
return rateLimitedFrames.get();
}
public long rejectedFrameCount() {
return rejectedFrames.get();
}
public long versionMismatchCount() {
return versionMismatches.get();
}
public long capabilityRejectedCount() {
return capabilityRejected.get();
}
public long noEngineDropCount() {
return noEngineDrops.get();
}
public long cursorInfoServedCount() {
return cursorInfoServed.get();
}
public long visionTileForwardedCount() {
return visionTileForwarded.get();
}
public long visionRateLimitedCount() {
return visionRateLimited.get();
}
public long pregenRegionDeltasBroadcastCount() {
return pregenRegionDeltasBroadcast.get();
}
public long studioHotloadsBroadcastCount() {
return studioHotloadsBroadcast.get();
}
public long toastsBroadcastCount() {
return toastsBroadcast.get();
}
public long toastsSentCount() {
return toastsSent.get();
}
private void dispatch(IrisSession session, IrisMessage message) {
if (session.state() == IrisSession.State.AWAITING_HELLO) {
if (message instanceof IrisMessage.ClientHello clientHello) {
onClientHello(session, clientHello);
return;
}
droppedBeforeHello.incrementAndGet();
return;
}
switch (message) {
case IrisMessage.CursorInfoRequest cursorInfoRequest -> onCursorInfoRequest(session, cursorInfoRequest);
case IrisMessage.VisionTileRequest visionTileRequest -> onVisionTileRequest(session, visionTileRequest);
default -> {
}
}
}
private void onClientHello(IrisSession session, IrisMessage.ClientHello clientHello) {
if (clientHello.protocolVersion() != IrisProtocol.PROTOCOL_VERSION) {
versionMismatches.incrementAndGet();
return;
}
session.markReady(clientHello.protocolVersion(), clientHello.capabilities());
session.send(new IrisMessage.ServerHello(IrisProtocol.PROTOCOL_VERSION, serverCapabilities, serverBrand, irisActive));
}
private void onCursorInfoRequest(IrisSession session, IrisMessage.CursorInfoRequest request) {
if (!session.hasCapability(IrisProtocol.CAPABILITY_CURSOR)) {
capabilityRejected.incrementAndGet();
return;
}
EngineResolver resolver = engineResolver;
if (resolver == null) {
noEngineDrops.incrementAndGet();
return;
}
Engine engine = resolver.resolve(session.id());
if (engine == null) {
noEngineDrops.incrementAndGet();
return;
}
session.send(IrisCursorResolver.resolve(engine, request.blockX(), request.blockZ()));
cursorInfoServed.incrementAndGet();
}
private void onVisionTileRequest(IrisSession session, IrisMessage.VisionTileRequest request) {
if (!session.hasCapability(IrisProtocol.CAPABILITY_VISION)) {
capabilityRejected.incrementAndGet();
return;
}
if (!session.allowVisionTile(clock.getAsLong())) {
visionRateLimited.incrementAndGet();
return;
}
VisionTileRequestHandler handler = visionTileHandler;
if (handler == null) {
noEngineDrops.incrementAndGet();
return;
}
handler.handle(session.id(), request.tileX(), request.tileZ(), request.zoomLevel());
visionTileForwarded.incrementAndGet();
}
}
@@ -0,0 +1,23 @@
/*
* 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.core.protocol;
public interface IrisServerTransport {
void sendToClient(String sessionId, byte[] frame);
}
@@ -0,0 +1,116 @@
/*
* 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.core.protocol;
import art.arcane.iris.spi.protocol.IrisMessage;
import art.arcane.iris.spi.protocol.IrisMessageCodec;
import art.arcane.iris.spi.protocol.IrisProtocol;
import java.util.Objects;
public final class IrisSession {
private final String id;
private final IrisServerTransport transport;
private volatile State state;
private volatile long capabilities;
private volatile int remoteProtocolVersion;
private long inboundWindowStartMillis;
private int inboundFramesInWindow;
private long visionTileWindowStartMillis;
private int visionTileRequestsInWindow;
public IrisSession(String id, IrisServerTransport transport) {
this.id = Objects.requireNonNull(id, "session id");
this.transport = Objects.requireNonNull(transport, "session transport");
this.state = State.AWAITING_HELLO;
this.capabilities = 0L;
this.remoteProtocolVersion = 0;
this.inboundWindowStartMillis = 0L;
this.inboundFramesInWindow = 0;
this.visionTileWindowStartMillis = 0L;
this.visionTileRequestsInWindow = 0;
}
public String id() {
return id;
}
public State state() {
return state;
}
public long capabilities() {
return capabilities;
}
public int remoteProtocolVersion() {
return remoteProtocolVersion;
}
public boolean isReady() {
return state == State.READY;
}
public boolean hasCapability(long capabilityMask) {
return (capabilities & capabilityMask) != 0L;
}
public void markReady(int protocolVersion, long negotiatedCapabilities) {
this.remoteProtocolVersion = protocolVersion;
this.capabilities = negotiatedCapabilities;
this.state = State.READY;
}
public synchronized boolean allowInbound(long nowMillis) {
if (nowMillis - inboundWindowStartMillis >= 1000L) {
inboundWindowStartMillis = nowMillis;
inboundFramesInWindow = 0;
}
if (inboundFramesInWindow >= IrisProtocol.MAX_INBOUND_FRAMES_PER_SECOND) {
return false;
}
inboundFramesInWindow++;
return true;
}
public synchronized boolean allowVisionTile(long nowMillis) {
if (nowMillis - visionTileWindowStartMillis >= 1000L) {
visionTileWindowStartMillis = nowMillis;
visionTileRequestsInWindow = 0;
}
if (visionTileRequestsInWindow >= IrisProtocol.MAX_VISION_TILE_REQUESTS_PER_SECOND) {
return false;
}
visionTileRequestsInWindow++;
return true;
}
public void send(IrisMessage message) {
sendRaw(IrisMessageCodec.encode(message));
}
public void sendRaw(byte[] frame) {
transport.sendToClient(id, frame);
}
public enum State {
AWAITING_HELLO,
READY
}
}
@@ -0,0 +1,53 @@
/*
* 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.core.protocol;
import java.util.concurrent.ConcurrentHashMap;
public final class IrisSessionRegistry {
private final ConcurrentHashMap<String, IrisSession> sessions;
public IrisSessionRegistry() {
this.sessions = new ConcurrentHashMap<>();
}
public void register(IrisSession session) {
sessions.put(session.id(), session);
}
public IrisSession unregister(String sessionId) {
return sessions.remove(sessionId);
}
public IrisSession get(String sessionId) {
return sessions.get(sessionId);
}
public boolean isEmpty() {
return sessions.isEmpty();
}
public int size() {
return sessions.size();
}
public Iterable<IrisSession> all() {
return sessions.values();
}
}
@@ -0,0 +1,138 @@
/*
* 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.core.protocol;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.framework.render.IrisRenderer;
import art.arcane.iris.engine.framework.render.RenderType;
import art.arcane.iris.spi.protocol.IrisMessage;
import art.arcane.iris.spi.protocol.IrisProtocol;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.Deflater;
public final class IrisTileEncoder {
public static final int TILE_PIXELS = 128;
public static final int MAX_ZOOM_LEVEL = 8;
public static final int MODE_RAW_RGB = 0;
public static final int MODE_PALETTE = 1;
private static final int MAX_PALETTE_COLORS = 256;
private static final int RGB_MASK = 0xFFFFFF;
private IrisTileEncoder() {
}
public static List<IrisMessage.VisionTile> encode(Engine engine, int tileX, int tileZ, int zoomLevel, int sequence) {
int zoom = clampZoom(zoomLevel);
int blocksPerPixel = 1 << zoom;
double size = (double) TILE_PIXELS * blocksPerPixel;
double sx = (double) tileX * size;
double sz = (double) tileZ * size;
BufferedImage image = new IrisRenderer(engine).render(sx, sz, size, TILE_PIXELS, RenderType.BIOME);
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
byte[] blob = encodePixels(pixels, TILE_PIXELS, TILE_PIXELS);
return splitIntoChunks(blob, tileX, tileZ, zoom, sequence);
}
public static byte[] encodePixels(int[] pixels, int width, int height) {
Map<Integer, Integer> palette = buildPalette(pixels);
ByteArrayOutputStream raw = new ByteArrayOutputStream(pixels.length);
try (DataOutputStream out = new DataOutputStream(raw)) {
out.writeInt(width);
out.writeInt(height);
if (palette != null) {
out.writeByte(MODE_PALETTE);
out.writeInt(palette.size());
for (Integer color : palette.keySet()) {
out.writeByte(color >> 16 & 0xFF);
out.writeByte(color >> 8 & 0xFF);
out.writeByte(color & 0xFF);
}
for (int pixel : pixels) {
out.writeByte(palette.get(pixel & RGB_MASK));
}
} else {
out.writeByte(MODE_RAW_RGB);
for (int pixel : pixels) {
out.writeByte(pixel >> 16 & 0xFF);
out.writeByte(pixel >> 8 & 0xFF);
out.writeByte(pixel & 0xFF);
}
}
} catch (IOException failure) {
throw new UncheckedIOException("vision tile pixel encode failed", failure);
}
return deflate(raw.toByteArray());
}
public static List<IrisMessage.VisionTile> splitIntoChunks(byte[] blob, int tileX, int tileZ, int zoomLevel, int sequence) {
int chunkBytes = IrisProtocol.VISION_TILE_MAX_CHUNK_BYTES;
int chunkCount = Math.max(1, (blob.length + chunkBytes - 1) / chunkBytes);
List<IrisMessage.VisionTile> chunks = new ArrayList<>(chunkCount);
for (int index = 0; index < chunkCount; index++) {
int start = index * chunkBytes;
int end = Math.min(start + chunkBytes, blob.length);
byte[] slice = new byte[end - start];
System.arraycopy(blob, start, slice, 0, slice.length);
chunks.add(new IrisMessage.VisionTile(tileX, tileZ, zoomLevel, sequence, index, chunkCount, slice));
}
return chunks;
}
private static Map<Integer, Integer> buildPalette(int[] pixels) {
LinkedHashMap<Integer, Integer> palette = new LinkedHashMap<>();
for (int pixel : pixels) {
int color = pixel & RGB_MASK;
if (!palette.containsKey(color)) {
if (palette.size() >= MAX_PALETTE_COLORS) {
return null;
}
palette.put(color, palette.size());
}
}
return palette;
}
private static byte[] deflate(byte[] input) {
Deflater deflater = new Deflater(Deflater.BEST_SPEED);
deflater.setInput(input);
deflater.finish();
ByteArrayOutputStream out = new ByteArrayOutputStream(Math.max(64, input.length / 2));
byte[] buffer = new byte[8192];
while (!deflater.finished()) {
int produced = deflater.deflate(buffer);
out.write(buffer, 0, produced);
}
deflater.end();
return out.toByteArray();
}
private static int clampZoom(int zoomLevel) {
return Math.max(0, Math.min(zoomLevel, MAX_ZOOM_LEVEL));
}
}
@@ -0,0 +1,154 @@
/*
* 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.core.protocol;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.framework.PreservationRegistry;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.spi.protocol.IrisMessage;
import art.arcane.iris.spi.protocol.IrisProtocol;
import java.util.ArrayDeque;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
public final class IrisVisionRequestService implements VisionTileRequestHandler {
private static final int DEFAULT_MAX_PENDING = 64;
private final EngineResolver engineResolver;
private final IrisSessionRegistry registry;
private final Executor executor;
private final int maxPending;
private final ArrayDeque<PendingRequest> pending;
private final ConcurrentHashMap<String, Integer> sequences;
private final AtomicLong droppedSaturated;
private final AtomicLong droppedNoEngine;
private final AtomicLong droppedNoSession;
private final AtomicLong tilesEncoded;
IrisVisionRequestService(EngineResolver engineResolver, IrisSessionRegistry registry, Executor executor, int maxPending) {
this.engineResolver = Objects.requireNonNull(engineResolver, "engine resolver");
this.registry = Objects.requireNonNull(registry, "session registry");
this.executor = Objects.requireNonNull(executor, "executor");
this.maxPending = Math.max(1, maxPending);
this.pending = new ArrayDeque<>();
this.sequences = new ConcurrentHashMap<>();
this.droppedSaturated = new AtomicLong(0L);
this.droppedNoEngine = new AtomicLong(0L);
this.droppedNoSession = new AtomicLong(0L);
this.tilesEncoded = new AtomicLong(0L);
}
public static IrisVisionRequestService create(EngineResolver engineResolver, IrisSessionRegistry registry) {
AtomicInteger threadIndex = new AtomicInteger(0);
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 30L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), runnable -> {
Thread thread = new Thread(runnable);
thread.setName("Iris Vision Tile " + threadIndex.incrementAndGet());
thread.setDaemon(true);
thread.setPriority(Thread.MIN_PRIORITY);
return thread;
});
executor.allowCoreThreadTimeOut(true);
PreservationRegistry preservation = IrisServices.getOrNull(PreservationRegistry.class);
if (preservation != null) {
preservation.register(executor);
}
return new IrisVisionRequestService(engineResolver, registry, executor, DEFAULT_MAX_PENDING);
}
@Override
public void handle(String sessionId, int tileX, int tileZ, int zoomLevel) {
PendingRequest request = new PendingRequest(sessionId, tileX, tileZ, zoomLevel);
synchronized (pending) {
while (pending.size() >= maxPending) {
pending.pollFirst();
droppedSaturated.incrementAndGet();
}
pending.addLast(request);
}
executor.execute(this::drainOne);
}
public long droppedSaturatedCount() {
return droppedSaturated.get();
}
public long droppedNoEngineCount() {
return droppedNoEngine.get();
}
public long droppedNoSessionCount() {
return droppedNoSession.get();
}
public long tilesEncodedCount() {
return tilesEncoded.get();
}
public int pendingSize() {
synchronized (pending) {
return pending.size();
}
}
private void drainOne() {
PendingRequest request;
synchronized (pending) {
request = pending.pollFirst();
}
if (request == null) {
return;
}
process(request);
}
private void process(PendingRequest request) {
IrisSession session = registry.get(request.sessionId());
if (session == null || !session.isReady() || !session.hasCapability(IrisProtocol.CAPABILITY_VISION)) {
droppedNoSession.incrementAndGet();
return;
}
Engine engine = engineResolver.resolve(request.sessionId());
if (engine == null) {
droppedNoEngine.incrementAndGet();
return;
}
int sequence = nextSequence(request);
List<IrisMessage.VisionTile> chunks = IrisTileEncoder.encode(engine, request.tileX(), request.tileZ(), request.zoomLevel(), sequence);
for (IrisMessage.VisionTile chunk : chunks) {
session.send(chunk);
}
tilesEncoded.incrementAndGet();
}
private int nextSequence(PendingRequest request) {
String key = request.sessionId() + ":" + request.tileX() + ":" + request.tileZ() + ":" + request.zoomLevel();
return sequences.merge(key, 1, Integer::sum);
}
private record PendingRequest(String sessionId, int tileX, int tileZ, int zoomLevel) {
}
}
@@ -0,0 +1,24 @@
/*
* 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.core.protocol;
@FunctionalInterface
public interface VisionTileRequestHandler {
void handle(String sessionId, int tileX, int tileZ, int zoomLevel);
}
@@ -1,5 +1,6 @@
package art.arcane.iris.core.safeguard.task;
import art.arcane.iris.BuildConstants;
import art.arcane.iris.platform.bukkit.BukkitPlatform;
import art.arcane.iris.core.IrisWorlds;
import art.arcane.iris.core.nms.INMS;
@@ -94,7 +95,7 @@ public final class Tasks {
} else if (parts.length >= 2) {
supportedVersions = parts[1];
} else {
supportedVersions = "26.2";
supportedVersions = BuildConstants.MINECRAFT_VERSION;
}
if (!(INMS.get() instanceof NMSBinding1X)) {
@@ -21,7 +21,8 @@ package art.arcane.iris.core.service;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.platform.bukkit.BukkitPlatform;
import art.arcane.iris.core.link.*;
import art.arcane.iris.core.link.ExternalDataProvider;
import art.arcane.iris.core.link.Identifier;
import art.arcane.iris.core.link.data.DataType;
import art.arcane.iris.core.nms.container.BlockProperty;
import art.arcane.iris.core.nms.container.Pair;
@@ -42,7 +43,11 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.inventory.ItemStack;
import java.util.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
import java.util.Optional;
import java.util.stream.Collectors;
@Data
@@ -23,7 +23,15 @@ import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.core.tools.IrisToolbelt;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.object.*;
import art.arcane.iris.engine.object.IObjectPlacer;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisObject;
import art.arcane.iris.engine.object.IrisObjectPlacement;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.iris.engine.object.IrisTreeModes;
import art.arcane.iris.engine.object.IrisTreeSize;
import art.arcane.iris.engine.object.TileData;
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
import art.arcane.iris.platform.bukkit.BukkitBlockState;
import art.arcane.iris.spi.PlatformBlockState;
@@ -35,7 +43,12 @@ import art.arcane.volmlib.util.math.BlockPosition;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.iris.util.common.plugin.IrisService;
import art.arcane.iris.util.common.scheduling.J;
import org.bukkit.*;
import org.bukkit.Bukkit;
import org.bukkit.HeightMap;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.TreeType;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
@@ -2,13 +2,17 @@ package art.arcane.iris.core.tools;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.engine.object.*;
import art.arcane.iris.engine.object.IrisObject;
import art.arcane.volmlib.util.data.Varint;
import art.arcane.iris.util.common.format.C;
import art.arcane.volmlib.util.format.Form;
import art.arcane.volmlib.util.nbt.io.NBTUtil;
import art.arcane.volmlib.util.nbt.io.NamedTag;
import art.arcane.volmlib.util.nbt.tag.*;
import art.arcane.volmlib.util.nbt.tag.ByteArrayTag;
import art.arcane.volmlib.util.nbt.tag.CompoundTag;
import art.arcane.volmlib.util.nbt.tag.IntTag;
import art.arcane.volmlib.util.nbt.tag.ShortTag;
import art.arcane.volmlib.util.nbt.tag.Tag;
import art.arcane.iris.util.common.plugin.VolmitSender;
import art.arcane.iris.util.common.scheduling.J;
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
@@ -16,8 +20,13 @@ import org.apache.commons.io.FileUtils;
import org.bukkit.Bukkit;
import org.bukkit.block.data.BlockData;
import java.io.*;
import java.util.*;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
@@ -44,7 +44,9 @@ import art.arcane.iris.util.common.scheduling.J;
import art.arcane.volmlib.util.scheduling.FoliaScheduler;
import lombok.Data;
import lombok.experimental.Accessors;
import org.bukkit.*;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
@@ -241,6 +243,7 @@ public class IrisCreator {
} catch (Throwable e) {
dx.set(true);
cancelRepeatingTask(pregenProgressTask);
IrisLogging.reportError(e);
e.printStackTrace();
}
}
@@ -401,6 +404,7 @@ public class IrisCreator {
IrisLogging.info("Registered \"" + name + "\" in bukkit.yml");
} catch (IOException e) {
IrisLogging.error("Failed to update bukkit.yml!");
IrisLogging.reportError(e);
e.printStackTrace();
}
}
@@ -19,7 +19,8 @@
package art.arcane.iris.core.tools;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.object.*;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisWorld;
import art.arcane.iris.engine.platform.BukkitChunkGenerator;
import org.bukkit.Bukkit;
import org.bukkit.World;
@@ -22,7 +22,14 @@ import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.data.cache.Cache;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.object.*;
import art.arcane.iris.engine.object.InferredType;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisDecorationPart;
import art.arcane.iris.engine.object.IrisDecorator;
import art.arcane.iris.engine.object.IrisGenerator;
import art.arcane.iris.engine.object.IrisInterpolator;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.iris.engine.object.IrisShapedGeneratorStyle;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.PlatformBiome;
@@ -41,7 +48,13 @@ import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.io.File;
import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@Data
@EqualsAndHashCode(exclude = "data")
@@ -18,16 +18,40 @@
package art.arcane.iris.engine;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.framework.EngineEffects;
import art.arcane.iris.engine.framework.EngineMetrics;
import art.arcane.iris.engine.framework.EngineMode;
import art.arcane.iris.engine.framework.EngineTarget;
import art.arcane.iris.engine.framework.EngineWorldManager;
import art.arcane.iris.engine.framework.EngineWorldManagerProvider;
import art.arcane.iris.engine.framework.GenerationSessionException;
import art.arcane.iris.engine.framework.GenerationSessionLease;
import art.arcane.iris.engine.framework.GenerationSessionManager;
import art.arcane.iris.engine.framework.PreservationRegistry;
import art.arcane.iris.engine.framework.SeedManager;
import art.arcane.iris.engine.framework.WrongEngineBroException;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisBiomePaletteLayer;
import art.arcane.iris.engine.object.IrisDecorator;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisDimensionMode;
import art.arcane.iris.engine.object.IrisDimensionModeType;
import art.arcane.iris.engine.object.IrisEngineData;
import art.arcane.iris.engine.object.IrisObjectPlacement;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.iris.spi.IrisLogging;
import com.google.common.util.concurrent.AtomicDouble;
import com.google.gson.Gson;
import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.spi.IrisServices;
import art.arcane.iris.spi.protocol.IrisMessage;
import art.arcane.iris.core.ServerConfigurator;
import art.arcane.iris.core.events.IrisEngineHotloadEvent;
import art.arcane.iris.core.datapack.DatapackIngestService;
import art.arcane.iris.core.gui.PregeneratorJob;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.core.protocol.IrisProtocolServer;
import art.arcane.iris.core.loader.ResourceLoader;
import art.arcane.iris.core.nms.container.BlockPos;
import art.arcane.iris.core.nms.container.Pair;
@@ -35,9 +59,7 @@ import art.arcane.iris.core.project.IrisProject;
import art.arcane.iris.core.structure.StructureIndexService;
import art.arcane.iris.core.tools.IrisToolbelt;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.framework.*;
import art.arcane.iris.engine.mantle.EngineMantle;
import art.arcane.iris.engine.object.*;
import art.arcane.iris.util.common.data.B;
import art.arcane.iris.util.common.plugin.VolmitSender;
import art.arcane.iris.spi.PlatformBiome;
@@ -264,6 +286,7 @@ public class IrisEngine implements Engine {
J.a(() -> DatapackIngestService.refreshWorkspace(getData()));
} catch (Throwable e) {
IrisLogging.error("FAILED TO SETUP ENGINE!");
IrisLogging.reportError(e);
e.printStackTrace();
}
@@ -403,20 +426,40 @@ public class IrisEngine implements Engine {
}
public void hotloadSilently() {
getData().dump();
getData().clearLists();
getTarget().setDimension(getData().getDimensionLoader().load(getDimension().getLoadKey()));
prehotload();
setupEngine();
if (getWorld().hasRealWorld()) {
J.a(() -> {
synchronized (ServerConfigurator.class) {
ServerConfigurator.installDataPacks(false);
}
});
try {
getData().dump();
getData().clearLists();
getTarget().setDimension(getData().getDimensionLoader().load(getDimension().getLoadKey()));
prehotload();
setupEngine();
if (getWorld().hasRealWorld()) {
J.a(() -> {
synchronized (ServerConfigurator.class) {
ServerConfigurator.installDataPacks(false);
}
});
}
broadcastStudioHotload(false, "");
} catch (RuntimeException | Error e) {
broadcastStudioHotload(true, e.getClass().getSimpleName() + ": " + e.getMessage());
throw e;
}
}
private void broadcastStudioHotload(boolean failed, String message) {
IrisProtocolServer protocolServer = IrisServices.getOrNull(IrisProtocolServer.class);
if (protocolServer == null) {
return;
}
IrisDimension dimension = getDimension();
String packKey = dimension == null ? "" : dimension.getLoadKey();
protocolServer.broadcastStudioHotload(packKey, 0, failed, message);
protocolServer.broadcastToast(
failed ? IrisMessage.Toast.KIND_ERROR : IrisMessage.Toast.KIND_SUCCESS,
"Studio Hotload",
failed ? packKey + " failed" : packKey);
}
@Override
public IrisEngineData getEngineData() {
return engineData.aquire(() -> {
@@ -431,6 +474,7 @@ public class IrisEngine implements Engine {
IrisLogging.error("Failed to read Engine Data! Corrupted File? recreating...");
}
} catch (IOException e) {
IrisLogging.reportError(e);
e.printStackTrace();
}
}
@@ -448,6 +492,7 @@ public class IrisEngine implements Engine {
try {
IO.writeAll(f, new Gson().toJson(data));
} catch (IOException e) {
IrisLogging.reportError(e);
e.printStackTrace();
}
} else {
@@ -724,6 +769,7 @@ public class IrisEngine implements Engine {
IrisLogging.debug("Saved Engine Data");
} catch (IOException e) {
IrisLogging.error("Failed to save Engine Data");
IrisLogging.reportError(e);
e.printStackTrace();
}
}
@@ -755,6 +801,7 @@ public class IrisEngine implements Engine {
public void fail(String error, Throwable e) {
failing = true;
IrisLogging.error(error);
IrisLogging.reportError(e);
e.printStackTrace();
}
@@ -54,7 +54,11 @@ 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.MultiBurst;
import lombok.*;
import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import java.io.File;
import java.io.IOException;
@@ -26,7 +26,14 @@ import art.arcane.iris.engine.data.cache.Cache;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.framework.EngineAssignedWorldManager;
import art.arcane.iris.engine.platform.EngineBukkitOps;
import art.arcane.iris.engine.object.*;
import art.arcane.iris.engine.object.IRare;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisBlockDrops;
import art.arcane.iris.engine.object.IrisEntitySpawn;
import art.arcane.iris.engine.object.IrisMarker;
import art.arcane.iris.engine.object.IrisPosition;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.iris.engine.object.IrisSpawner;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.collection.KMap;
@@ -63,7 +70,14 @@ import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -145,7 +159,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
engine.getEngineData().cleanup(getEngine());
}
if (!IrisSettings.get().getWorld().isMarkerEntitySpawningSystem() && !IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()) {
if (!IrisSettings.get().getWorld().isMarkerEntitySpawningSystem() && !IrisSettings.get().getWorld().isAmbientEntitySpawningSystem()) {
return 3000;
}
@@ -576,7 +590,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
});
}
if (!IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()) {
if (!IrisSettings.get().getWorld().isAmbientEntitySpawningSystem()) {
return;
}
@@ -1018,6 +1032,9 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
public void close() {
super.close();
looper.interrupt();
if (cleanupService != null) {
cleanupService.shutdownNow();
}
}
@Override
@@ -2,7 +2,13 @@ package art.arcane.iris.engine;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.object.*;
import art.arcane.iris.engine.object.InferredType;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisGenerator;
import art.arcane.iris.engine.object.IrisInterpolator;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.iris.engine.object.IrisShapedGeneratorStyle;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.iris.util.common.data.DataProvider;
@@ -13,7 +19,12 @@ import art.arcane.iris.spi.PlatformBlockState;
import art.arcane.iris.util.project.stream.ProceduralStream;
import art.arcane.iris.util.project.stream.interpolation.Interpolated;
import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
public class UpperDimensionContext implements DataProvider {
private static final NoiseBounds ZERO_NOISE_BOUNDS = new NoiseBounds(0D, 0D);
@@ -18,7 +18,11 @@
package art.arcane.iris.engine.actuator;
import art.arcane.iris.engine.decorator.*;
import art.arcane.iris.engine.decorator.IrisCeilingDecorator;
import art.arcane.iris.engine.decorator.IrisSeaFloorDecorator;
import art.arcane.iris.engine.decorator.IrisSeaSurfaceDecorator;
import art.arcane.iris.engine.decorator.IrisShoreLineDecorator;
import art.arcane.iris.engine.decorator.IrisSurfaceDecorator;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.framework.EngineAssignedActuator;
import art.arcane.iris.engine.framework.EngineDecorator;
@@ -18,7 +18,12 @@
package art.arcane.iris.engine.data.io;
import java.io.*;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
public interface Deserializer<T> {
@@ -18,7 +18,12 @@
package art.arcane.iris.engine.data.io;
import java.io.*;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public interface Serializer<T> {
@@ -18,7 +18,13 @@
package art.arcane.iris.engine.data.io;
import java.io.*;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
public interface StringDeserializer<T> extends Deserializer<T> {
@@ -18,7 +18,13 @@
package art.arcane.iris.engine.data.io;
import java.io.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
public interface StringSerializer<T> extends Serializer<T> {
@@ -32,7 +32,19 @@ import art.arcane.iris.engine.IrisComplex;
import art.arcane.iris.engine.UpperDimensionContext;
import art.arcane.iris.engine.data.chunk.TerrainChunk;
import art.arcane.iris.engine.mantle.EngineMantle;
import art.arcane.iris.engine.object.*;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisColor;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisDimensionCarvingEntry;
import art.arcane.iris.engine.object.IrisDimensionCarvingResolver;
import art.arcane.iris.engine.object.IrisEngineData;
import art.arcane.iris.engine.object.IrisLootMode;
import art.arcane.iris.engine.object.IrisLootReference;
import art.arcane.iris.engine.object.IrisLootTable;
import art.arcane.iris.engine.object.IrisObjectPlacement;
import art.arcane.iris.engine.object.IrisPosition;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.iris.engine.object.IrisWorld;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.PlatformBiome;
import art.arcane.iris.spi.PlatformBlockState;
@@ -23,7 +23,7 @@ import art.arcane.iris.core.events.IrisEngineHotloadEvent;
import art.arcane.iris.util.common.format.C;
import art.arcane.iris.util.common.plugin.VolmitSender;
import art.arcane.iris.util.common.scheduling.J;
import org.bukkit.*;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -60,32 +60,6 @@ public abstract class EngineAssignedWorldManager extends EngineAssignedComponent
}
}
// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
// public void on(PlayerTeleportEvent e) {
// if(ignoreTP.get()) {
// System.out.println("IgTP1");
// return;
// }
//
// if(!PaperLib.isPaper() || e.getTo() == null) {
// System.out.println("IgTP2");
//
//// return;
// }
//
//// try {
//// System.out.println("IgTP3");
////
//// if(e.getTo().getWorld().equals(getTarget().getWorld().realWorld())) {
//// System.out.println("IgTP4");
////
//// getEngine().getWorldManager().teleportAsync(e);
//// }
//// } catch(Throwable ex) {
////
//// }
// }
@EventHandler
public void on(WorldSaveEvent e) {
if (e.getWorld().equals(getTarget().getWorld().realWorld())) {
@@ -18,9 +18,13 @@
package art.arcane.iris.engine.framework;
import java.util.concurrent.ExecutorService;
public interface PreservationRegistry {
void register(Thread thread);
void register(ExecutorService service);
void registerCache(MeteredCache cache);
void dereference();
@@ -23,7 +23,7 @@ import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisBiomeGeneratorLink;
import art.arcane.iris.util.project.interpolation.IrisInterpolation;
import java.awt.*;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.util.function.BiFunction;
@@ -18,7 +18,7 @@
package art.arcane.iris.engine.framework.render;
import java.awt.*;
import java.awt.Color;
@FunctionalInterface
public interface Renderer {
@@ -51,7 +51,10 @@ import art.arcane.iris.spi.PlatformBlockState;
import art.arcane.iris.util.common.data.B;
import org.bukkit.util.Vector;
import java.util.*;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static art.arcane.iris.engine.mantle.EngineMantle.AIR;
@@ -30,7 +30,25 @@ import art.arcane.iris.engine.mantle.IrisMantleComponent;
import art.arcane.iris.engine.mantle.MantleWriter;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.object.*;
import art.arcane.iris.engine.object.CarvingMode;
import art.arcane.iris.engine.object.DecayControlPlacer;
import art.arcane.iris.engine.object.IObjectPlacer;
import art.arcane.iris.engine.object.IrisAxisRotationClamp;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisCaveAnchorMode;
import art.arcane.iris.engine.object.IrisCaveProfile;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisObject;
import art.arcane.iris.engine.object.IrisObjectPlacement;
import art.arcane.iris.engine.object.IrisObjectRotation;
import art.arcane.iris.engine.object.IrisObjectScale;
import art.arcane.iris.engine.object.IrisObjectTranslate;
import art.arcane.iris.engine.object.IrisObjectVacuum;
import art.arcane.iris.engine.object.IrisProceduralObjects;
import art.arcane.iris.engine.object.IrisProceduralPlacement;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.iris.engine.object.ObjectPlaceMode;
import art.arcane.iris.engine.object.TileData;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.collection.KMap;
@@ -26,7 +26,12 @@ import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.framework.EngineMode;
import art.arcane.iris.engine.framework.EngineStage;
import art.arcane.iris.engine.framework.IrisEngineMode;
import art.arcane.iris.engine.modifier.*;
import art.arcane.iris.engine.modifier.IrisCarveModifier;
import art.arcane.iris.engine.modifier.IrisCustomModifier;
import art.arcane.iris.engine.modifier.IrisDepositModifier;
import art.arcane.iris.engine.modifier.IrisFloatingChildBiomeModifier;
import art.arcane.iris.engine.modifier.IrisPerfectionModifier;
import art.arcane.iris.engine.modifier.IrisPostModifier;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.util.common.scheduling.J;
@@ -20,7 +20,13 @@ package art.arcane.iris.engine.modifier;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.framework.EngineAssignedModifier;
import art.arcane.iris.engine.object.*;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisDepositGenerator;
import art.arcane.iris.engine.object.IrisDepositVariant;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisObject;
import art.arcane.iris.engine.object.IrisProceduralBlocks;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.iris.util.project.context.ChunkContext;
import art.arcane.volmlib.util.data.HeightMap;
import art.arcane.iris.util.project.hunk.Hunk;
@@ -18,7 +18,11 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.volmlib.util.math.RNG;
import lombok.AllArgsConstructor;
@@ -18,7 +18,12 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.DependsOn;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.math.M;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -24,7 +24,13 @@ import art.arcane.iris.core.loader.IrisRegistrant;
import art.arcane.iris.engine.IrisComplex;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.DependsOn;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.collection.KMap;
@@ -46,7 +52,7 @@ import art.arcane.iris.spi.PlatformBlockState;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Biome;
import java.awt.*;
import java.awt.Color;
import java.util.EnumMap;
@Accessors(chain = true)
@@ -19,7 +19,13 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.core.nms.datapack.IDataFixer;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.DependsOn;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.collection.KMap;
@@ -30,7 +36,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.awt.*;
import java.awt.Color;
import java.util.Locale;
@Snippet("custom-biome")
@@ -19,7 +19,11 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.util.common.data.registry.RegistryUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -19,7 +19,11 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.util.common.data.registry.RegistryUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -19,10 +19,18 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.DependsOn;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.util.common.data.DataProvider;
import art.arcane.iris.util.project.interpolation.IrisInterpolation;
import lombok.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Snippet("generator-layer")
@@ -20,7 +20,13 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.DependsOn;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.iris.util.project.noise.CNG;
@@ -23,7 +23,12 @@ import art.arcane.iris.core.link.Identifier;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.core.loader.IrisRegistrant;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListBlockType;
import art.arcane.iris.engine.object.annotations.RegistryMapBlockState;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.PlatformBlockState;
import art.arcane.volmlib.util.collection.KList;
@@ -2,7 +2,11 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.util.common.math.IrisBlockVector;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KMap;
import art.arcane.volmlib.util.collection.KSet;
import art.arcane.volmlib.util.math.M;
@@ -28,7 +28,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.awt.*;
import java.awt.Color;
@Snippet("color")
@Accessors(chain = true)
@@ -18,7 +18,13 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.DependsOn;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.platform.bukkit.BukkitWorld;
import art.arcane.iris.spi.PlatformWorld;
import art.arcane.volmlib.util.collection.KList;
@@ -20,7 +20,13 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.DependsOn;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.math.RNG;
@@ -21,7 +21,12 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.util.common.math.IrisBlockVector;
import art.arcane.iris.util.common.math.Vector3i;
import art.arcane.volmlib.util.collection.KList;
@@ -28,7 +28,13 @@ import art.arcane.iris.core.loader.IrisRegistrant;
import art.arcane.iris.core.nms.datapack.IDataFixer;
import art.arcane.iris.core.nms.datapack.IDataFixer.Dimension;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListFunction;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.functions.ComponentFlagFunction;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.collection.KSet;
@@ -48,7 +54,8 @@ import lombok.experimental.Accessors;
import org.bukkit.World.Environment;
import org.bukkit.block.Biome;
import java.io.*;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -3,10 +3,17 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.core.nms.datapack.IDataFixer;
import art.arcane.volmlib.util.data.Varint;
import art.arcane.volmlib.util.io.IO;
import lombok.*;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@Getter
@ToString
@@ -1,11 +1,16 @@
package art.arcane.iris.engine.object;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import static art.arcane.iris.engine.object.IrisDimensionTypeOptions.TriState.DEFAULT;
import static art.arcane.iris.engine.object.IrisDimensionTypeOptions.TriState.FALSE;
import static art.arcane.iris.engine.object.IrisDimensionTypeOptions.TriState.TRUE;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.volmlib.util.data.Varint;
import art.arcane.volmlib.util.json.JSONObject;
import lombok.*;
import lombok.experimental.Accessors;
import org.jetbrains.annotations.Nullable;
@@ -14,7 +19,6 @@ import java.io.DataOutput;
import java.io.IOException;
import java.util.Arrays;
import static art.arcane.iris.engine.object.IrisDimensionTypeOptions.TriState.*;
@Data
@NoArgsConstructor
@@ -20,7 +20,13 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.DependsOn;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListPotionEffect;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.volmlib.util.scheduling.ChronoLatch;
@@ -18,7 +18,12 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListEnchantment;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.volmlib.util.math.RNG;
import lombok.AllArgsConstructor;
@@ -25,8 +25,13 @@ import art.arcane.iris.core.loader.IrisRegistrant;
import art.arcane.iris.core.service.ExternalDataSVC;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.platform.EngineBukkitOps;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.RegistryListEntityType;
import art.arcane.iris.engine.object.annotations.RegistryListSpecialEntity;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.platform.bukkit.BukkitPlatform;
import art.arcane.iris.util.common.data.registry.RegistryUtil;
import art.arcane.iris.platform.bukkit.BukkitWorld;
import art.arcane.iris.spi.PlatformWorld;
import art.arcane.volmlib.util.collection.KList;
@@ -42,9 +47,18 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.bukkit.*;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.bukkit.attribute.Attributable;
import org.bukkit.entity.*;
import org.bukkit.entity.Ageable;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Mob;
import org.bukkit.entity.Panda;
import org.bukkit.entity.Villager;
import org.bukkit.entity.Panda.Gene;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.inventory.Inventory;
@@ -55,6 +69,7 @@ import org.bukkit.loot.Lootable;
import org.bukkit.util.Vector;
import java.util.Collection;
import java.util.Locale;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
@@ -71,11 +86,12 @@ import static art.arcane.iris.util.common.data.registry.Particles.ITEM;
@EqualsAndHashCode(callSuper = false)
public class IrisEntity extends IrisRegistrant {
@Required
@Desc("The type of entity to spawn. To spawn a mythic mob, set this type to unknown and define mythic type.")
private EntityType type = null;
@RegistryListEntityType
@Desc("The namespaced key of the entity type to spawn, such as minecraft:zombie or alexsmobs:grizzly_bear. To spawn a mob from another plugin or provider, set this type to unknown and define the special type.")
private String type = null;
@Desc("The SpawnReason to spawn the entity with.")
private CreatureSpawnEvent.SpawnReason reason = null;
@Desc("The SpawnReason name to spawn the entity with, such as NATURAL or COMMAND.")
private String reason = null;
@Desc("The custom name of this entity")
private String customName = "";
@@ -145,11 +161,11 @@ public class IrisEntity extends IrisRegistrant {
@Desc("Simply moves the entity from below the surface slowly out of the ground as a spawn-in effect")
private boolean spawnEffectRiseOutOfGround = false;
@Desc("The main gene for a panda if the entity type is a panda")
private Gene pandaMainGene = null;
@Desc("The main gene for a panda if the entity type is a panda. One of NORMAL, LAZY, WORRIED, PLAYFUL, BROWN, WEAK or AGGRESSIVE.")
private String pandaMainGene = null;
@Desc("The hidden gene for a panda if the entity type is a panda")
private Gene pandaHiddenGene = null;
@Desc("The hidden gene for a panda if the entity type is a panda. One of NORMAL, LAZY, WORRIED, PLAYFUL, BROWN, WEAK or AGGRESSIVE.")
private String pandaHiddenGene = null;
@Desc("The this entity is ageable, set it's baby status")
private boolean baby = false;
@@ -171,20 +187,51 @@ public class IrisEntity extends IrisRegistrant {
@Desc("Run raw commands when this entity is spawned. Use {x}, {y}, and {z} for location. /summon pig {x} {y} {z}")
private KList<IrisCommand> rawCommands = new KList<>();
public EntityType getType() {
return type == null ? EntityType.UNKNOWN : type;
public EntityType getBukkitType() {
if (type == null || type.isBlank()) {
return EntityType.UNKNOWN;
}
NamespacedKey key = NamespacedKey.fromString(type.trim().toLowerCase(Locale.ROOT));
if (key == null) {
return EntityType.UNKNOWN;
}
EntityType entityType = RegistryUtil.lookup(EntityType.class).get(key);
return entityType == null ? EntityType.UNKNOWN : entityType;
}
public CreatureSpawnEvent.SpawnReason getReason() {
return reason == null ? CreatureSpawnEvent.SpawnReason.NATURAL : reason;
public CreatureSpawnEvent.SpawnReason getBukkitReason() {
if (reason == null || reason.isBlank()) {
return CreatureSpawnEvent.SpawnReason.NATURAL;
}
try {
return CreatureSpawnEvent.SpawnReason.valueOf(reason.trim().toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException e) {
return CreatureSpawnEvent.SpawnReason.NATURAL;
}
}
public Gene getPandaMainGene() {
return pandaMainGene == null ? Gene.NORMAL : pandaMainGene;
public Gene getBukkitPandaMainGene() {
return resolveGene(pandaMainGene);
}
public Gene getPandaHiddenGene() {
return pandaHiddenGene == null ? Gene.NORMAL : pandaHiddenGene;
public Gene getBukkitPandaHiddenGene() {
return resolveGene(pandaHiddenGene);
}
private static Gene resolveGene(String gene) {
if (gene == null || gene.isBlank()) {
return Gene.NORMAL;
}
try {
return Gene.valueOf(gene.trim().toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException e) {
return Gene.NORMAL;
}
}
public Entity spawn(Engine gen, Location at) {
@@ -307,8 +354,8 @@ public class IrisEntity extends IrisRegistrant {
}
if (e instanceof Panda) {
((Panda) e).setMainGene(getPandaMainGene());
((Panda) e).setMainGene(getPandaHiddenGene());
((Panda) e).setMainGene(getBukkitPandaMainGene());
((Panda) e).setHiddenGene(getBukkitPandaHiddenGene());
}
if (e instanceof Villager) {
@@ -401,7 +448,7 @@ public class IrisEntity extends IrisRegistrant {
return null;
}
if (EntityType.UNKNOWN.equals(getType()) && !isSpecialType()) {
if (EntityType.UNKNOWN.equals(getBukkitType()) && !isSpecialType()) {
return null;
}
@@ -435,7 +482,7 @@ public class IrisEntity extends IrisRegistrant {
}
return BukkitPlatform.spawnEntity(at, getType(), getReason());
return BukkitPlatform.spawnEntity(at, getBukkitType(), getBukkitReason());
}
public boolean isSpecialType() {
@@ -21,7 +21,11 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.platform.bukkit.BukkitPlatform;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.util.common.format.C;
import art.arcane.volmlib.util.math.RNG;
@@ -177,7 +181,7 @@ public class IrisEntitySpawn implements IRare {
return null;
}
Vector3d boundingBox = BukkitPlatform.entityBoundingBox(irisEntity.getType());
Vector3d boundingBox = BukkitPlatform.entityBoundingBox(irisEntity.getBukkitType());
if (!ignoreSurfaces && boundingBox != null) {
boolean isClearForSpawn = isAreaClearForSpawn(at, boundingBox);
if (!isClearForSpawn) {
@@ -10,7 +10,14 @@ import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KMap;
import art.arcane.volmlib.util.math.RNG;
import lombok.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -27,7 +27,13 @@ import art.arcane.volmlib.util.collection.KMap;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.iris.util.project.noise.CNG;
import art.arcane.iris.util.project.stream.ProceduralStream;
import lombok.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
@Snippet("expression-load")
@@ -20,7 +20,11 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisRegistrant;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.iris.util.project.interpolation.IrisInterpolation;
import art.arcane.volmlib.util.json.JSONObject;
@@ -20,7 +20,11 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.iris.util.project.noise.CNG;
@@ -24,7 +24,7 @@ import art.arcane.volmlib.util.json.JSONObject;
import art.arcane.iris.util.common.plugin.VolmitSender;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
@@ -18,7 +18,11 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.function.NoiseProvider3;
import art.arcane.iris.util.project.interpolation.InterpolationMethod3D;
import art.arcane.iris.util.project.interpolation.IrisInterpolation;
@@ -21,7 +21,11 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.mantle.MantleWriter;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.math.RNG;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -24,7 +24,13 @@ 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;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListItemType;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.platform.bukkit.BukkitPlatform;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.volmlib.util.collection.KList;
@@ -49,7 +55,7 @@ import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.bukkit.inventory.meta.components.CustomModelDataComponent;
import org.bukkit.material.Colorable;
import java.awt.*;
import java.awt.Color;
import java.util.List;
import java.util.Optional;
@@ -19,7 +19,11 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.iris.util.common.data.DataProvider;
import lombok.AllArgsConstructor;
@@ -20,7 +20,11 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.iris.util.project.noise.CNG;
@@ -19,7 +19,12 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisRegistrant;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.json.JSONObject;
import art.arcane.iris.util.common.plugin.VolmitSender;
@@ -18,7 +18,11 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KList;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -18,7 +18,11 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KList;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -18,7 +18,11 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -18,7 +18,11 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KList;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -18,7 +18,11 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KList;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -18,7 +18,11 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KList;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -18,7 +18,11 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KList;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -20,7 +20,12 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.iris.util.project.interpolation.IrisInterpolation;
@@ -39,7 +39,10 @@ import art.arcane.volmlib.util.json.JSONObject;
import art.arcane.volmlib.util.math.BlockPosition;
import art.arcane.volmlib.util.math.Position2;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.iris.util.common.math.*;
import art.arcane.iris.util.common.math.AxisAlignedBB;
import art.arcane.iris.util.common.math.IrisBlockVector;
import art.arcane.iris.util.common.math.IrisVector;
import art.arcane.iris.util.common.math.Vector3i;
import art.arcane.volmlib.util.matter.MatterMarker;
import art.arcane.iris.util.common.parallel.BurstExecutor;
import art.arcane.iris.util.common.parallel.MultiBurst;
@@ -56,8 +59,19 @@ import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import java.io.*;
import java.util.*;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -502,7 +516,10 @@ public class IrisObject extends IrisRegistrant {
try {
latch.await();
} catch (InterruptedException ignored) {}
} catch (InterruptedException interrupted) {
Thread.currentThread().interrupt();
throw new IOException("Interrupted while writing object", interrupted);
}
if (ref.get() != null)
throw ref.get();
}
@@ -20,7 +20,11 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.util.common.data.B;
import art.arcane.volmlib.util.collection.KList;
import lombok.AllArgsConstructor;
@@ -20,7 +20,13 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KList;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -23,7 +23,13 @@ import art.arcane.iris.platform.bukkit.BukkitBlockResolution;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.iris.spi.IrisLogging;
import art.arcane.iris.spi.PlatformBlockState;
import art.arcane.volmlib.util.collection.KList;
@@ -20,7 +20,12 @@ package art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.Required;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.iris.util.project.noise.CNG;

Some files were not shown because too many files have changed in this diff Show More