diff --git a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java
index f63b6d12a..50206b6d1 100644
--- a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java
+++ b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java
@@ -1,413 +1,432 @@
-/*
- * Iris is a World Generator for Minecraft Bukkit Servers
- * Copyright (c) 2022 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 .
- */
-
-package com.volmit.iris.engine.platform;
-
-import com.volmit.iris.Iris;
-import com.volmit.iris.core.loader.IrisData;
-import com.volmit.iris.core.nms.INMS;
-import com.volmit.iris.core.service.StudioSVC;
-import com.volmit.iris.engine.IrisEngine;
-import com.volmit.iris.engine.data.chunk.TerrainChunk;
-import com.volmit.iris.engine.framework.Engine;
-import com.volmit.iris.engine.framework.EngineTarget;
-import com.volmit.iris.engine.object.IrisDimension;
-import com.volmit.iris.engine.object.IrisWorld;
-import com.volmit.iris.engine.object.StudioMode;
-import com.volmit.iris.engine.platform.studio.StudioGenerator;
-import com.volmit.iris.util.collection.KList;
-import com.volmit.iris.util.data.IrisBiomeStorage;
-import com.volmit.iris.util.hunk.Hunk;
-import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder;
-import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder;
-import com.volmit.iris.util.io.ReactiveFolder;
-import com.volmit.iris.util.scheduling.ChronoLatch;
-import com.volmit.iris.util.scheduling.J;
-import com.volmit.iris.util.scheduling.Looper;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.Setter;
-import org.bukkit.*;
-import org.bukkit.block.Biome;
-import org.bukkit.block.data.BlockData;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-import org.bukkit.event.world.WorldInitEvent;
-import org.bukkit.generator.BiomeProvider;
-import org.bukkit.generator.BlockPopulator;
-import org.bukkit.generator.ChunkGenerator;
-import org.bukkit.generator.WorldInfo;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.lang.reflect.Field;
-import java.util.List;
-import java.util.Random;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.function.Consumer;
-
-@EqualsAndHashCode(callSuper = true)
-@Data
-public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChunkGenerator, Listener {
- private static final int LOAD_LOCKS = Runtime.getRuntime().availableProcessors() * 4;
- private final Semaphore loadLock;
- private final IrisWorld world;
- private final File dataLocation;
- private final String dimensionKey;
- private final ReactiveFolder folder;
- private final ReentrantLock lock = new ReentrantLock();
- private final KList populators;
- private final ChronoLatch hotloadChecker;
- private final AtomicBoolean setup;
- private final boolean studio;
- private final AtomicInteger a = new AtomicInteger(0);
- private Engine engine;
- private Looper hotloader;
- private StudioMode lastMode;
- private DummyBiomeProvider dummyBiomeProvider;
- @Setter
- private StudioGenerator studioGenerator;
-
- private boolean initialized = false;
-
- public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) {
- setup = new AtomicBoolean(false);
- studioGenerator = null;
- dummyBiomeProvider = new DummyBiomeProvider();
- populators = new KList<>();
- loadLock = new Semaphore(LOAD_LOCKS);
- this.world = world;
- this.hotloadChecker = new ChronoLatch(1000, false);
- this.studio = studio;
- this.dataLocation = dataLocation;
- this.dimensionKey = dimensionKey;
- this.folder = new ReactiveFolder(dataLocation, (_a, _b, _c) -> hotload());
- Bukkit.getServer().getPluginManager().registerEvents(this, Iris.instance);
- }
-
- private static Field getField(Class clazz, String fieldName)
- throws NoSuchFieldException {
- try {
- return clazz.getDeclaredField(fieldName);
- } catch (NoSuchFieldException e) {
- Class superClass = clazz.getSuperclass();
- if (superClass == null) {
- throw e;
- } else {
- return getField(superClass, fieldName);
- }
- }
- }
-
- @EventHandler
- public void onWorldInit(WorldInitEvent event) {
- try {
- if (!initialized) {
- world.setRawWorldSeed(event.getWorld().getSeed());
- if (world.name().equals(event.getWorld().getName())) {
- INMS.get().inject(event.getWorld().getSeed(), getEngine(event.getWorld()), event.getWorld());
- Iris.info("Injected Iris Biome Source into " + event.getWorld().getName());
- initialized = true;
- }
- }
- } catch (Throwable e) {
- e.printStackTrace();
- }
- }
-
- private void setupEngine() {
- IrisData data = IrisData.get(dataLocation);
- IrisDimension dimension = data.getDimensionLoader().load(dimensionKey);
-
- if (dimension == null) {
- Iris.error("Oh No! There's no pack in " + data.getDataFolder().getPath() + " or... there's no dimension for the key " + dimensionKey);
- IrisDimension test = IrisData.loadAnyDimension(dimensionKey);
-
- if (test != null) {
- Iris.warn("Looks like " + dimensionKey + " exists in " + test.getLoadFile().getPath() + " ");
- Iris.service(StudioSVC.class).installIntoWorld(Iris.getSender(), dimensionKey, dataLocation.getParentFile().getParentFile());
- Iris.warn("Attempted to install into " + data.getDataFolder().getPath());
- data.dump();
- data.clearLists();
- test = data.getDimensionLoader().load(dimensionKey);
-
- if (test != null) {
- Iris.success("Woo! Patched the Engine!");
- dimension = test;
- } else {
- Iris.error("Failed to patch dimension!");
- throw new RuntimeException("Missing Dimension: " + dimensionKey);
- }
- } else {
- Iris.error("Nope, you don't have an installation containing " + dimensionKey + " try downloading it?");
- throw new RuntimeException("Missing Dimension: " + dimensionKey);
- }
- }
-
- lastMode = StudioMode.NORMAL;
- engine = new IrisEngine(new EngineTarget(world, dimension, data), studio);
- populators.clear();
- }
-
- @Override
- public void injectChunkReplacement(World world, int x, int z, Consumer jobs) {
- try {
- loadLock.acquire();
- IrisBiomeStorage st = new IrisBiomeStorage();
- TerrainChunk tc = TerrainChunk.createUnsafe(world, st);
- Hunk blocks = Hunk.view(tc);
- Hunk biomes = Hunk.view(tc, tc.getMinHeight(), tc.getMaxHeight());
- this.world.bind(world);
- getEngine().generate(x << 4, z << 4, blocks, biomes, true);
- Iris.debug("Regenerated " + x + " " + z);
- int t = 0;
- for (int i = getEngine().getHeight() >> 4; i >= 0; i--) {
- if (!world.isChunkLoaded(x, z)) {
- continue;
- }
-
- Chunk c = world.getChunkAt(x, z);
- for (Entity ee : c.getEntities()) {
- if (ee instanceof Player) {
- continue;
- }
-
- J.s(ee::remove);
- }
-
- J.s(() -> engine.getWorldManager().onChunkLoad(c, false));
-
- int finalI = i;
- jobs.accept(() -> {
-
- for (int xx = 0; xx < 16; xx++) {
- for (int yy = 0; yy < 16; yy++) {
- for (int zz = 0; zz < 16; zz++) {
- if (yy + (finalI << 4) >= engine.getHeight() || yy + (finalI << 4) < 0) {
- continue;
- }
- c.getBlock(xx, yy + (finalI << 4) + world.getMinHeight(), zz)
- .setBlockData(tc.getBlockData(xx, yy + (finalI << 4) + world.getMinHeight(), zz), false);
- }
- }
- }
- });
- }
-
- loadLock.release();
- } catch (Throwable e) {
- loadLock.release();
- Iris.error("======================================");
- e.printStackTrace();
- Iris.reportErrorChunk(x, z, e, "CHUNK");
- Iris.error("======================================");
-
- ChunkData d = Bukkit.createChunkData(world);
-
- for (int i = 0; i < 16; i++) {
- for (int j = 0; j < 16; j++) {
- d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData());
- }
- }
- }
- }
-
- private Engine getEngine(WorldInfo world) {
- if (setup.get()) {
- return getEngine();
- }
-
- lock.lock();
-
- if (setup.get()) {
- return getEngine();
- }
-
-
- setup.set(true);
- getWorld().setRawWorldSeed(world.getSeed());
- setupEngine();
- this.hotloader = studio ? new Looper() {
- @Override
- protected long loop() {
- if (hotloadChecker.flip()) {
- folder.check();
- }
-
- return 250;
- }
- } : null;
-
- if (studio) {
- hotloader.setPriority(Thread.MIN_PRIORITY);
- hotloader.start();
- hotloader.setName(getTarget().getWorld().name() + " Hotloader");
- }
-
- lock.unlock();
-
- return engine;
- }
-
- @Override
- public void close() {
- withExclusiveControl(() -> {
- if (isStudio()) {
- hotloader.interrupt();
- }
-
- getEngine().close();
- folder.clear();
- populators.clear();
-
- });
- }
-
- @Override
- public boolean isStudio() {
- return studio;
- }
-
- @Override
- public void hotload() {
- if (!isStudio()) {
- return;
- }
-
- withExclusiveControl(() -> getEngine().hotload());
- }
-
- public void withExclusiveControl(Runnable r) {
- J.a(() -> {
- try {
- loadLock.acquire(LOAD_LOCKS);
- r.run();
- loadLock.release(LOAD_LOCKS);
- } catch (Throwable e) {
- Iris.reportError(e);
- }
- });
- }
-
- @Override
- public void touch(World world) {
- getEngine(world);
- }
-
- @Override
- public void generateNoise(@NotNull WorldInfo world, @NotNull Random random, int x, int z, @NotNull ChunkGenerator.ChunkData d) {
- try {
- getEngine(world);
- computeStudioGenerator();
- TerrainChunk tc = TerrainChunk.create(d, new IrisBiomeStorage());
- this.world.bind(world);
- if (studioGenerator != null) {
- studioGenerator.generateChunk(getEngine(), tc, x, z);
- } else {
- ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc);
- BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight());
- getEngine().generate(x << 4, z << 4, blocks, biomes, false);
- blocks.apply();
- biomes.apply();
- }
-
- Iris.debug("Generated " + x + " " + z);
- } catch (Throwable e) {
- Iris.error("======================================");
- e.printStackTrace();
- Iris.reportErrorChunk(x, z, e, "CHUNK");
- Iris.error("======================================");
-
- for (int i = 0; i < 16; i++) {
- for (int j = 0; j < 16; j++) {
- d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData());
- }
- }
- }
- }
-
- @Override
- public int getBaseHeight(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull HeightMap heightMap) {
- return 4;
- }
-
- private void computeStudioGenerator() {
- if (!getEngine().getDimension().getStudioMode().equals(lastMode)) {
- lastMode = getEngine().getDimension().getStudioMode();
- getEngine().getDimension().getStudioMode().inject(this);
- }
- }
-
- @NotNull
- @Override
- public List getDefaultPopulators(@NotNull World world) {
- return populators;
- }
-
- @Override
- public boolean isParallelCapable() {
- return true;
- }
-
- @Override
- public boolean shouldGenerateCaves() {
- return false;
- }
-
- @Override
- public boolean shouldGenerateDecorations() {
- return false;
- }
-
- @Override
- public boolean shouldGenerateMobs() {
- return false;
- }
-
- @Override
- public boolean shouldGenerateStructures() {
- return false;
- }
-
- @Override
- public boolean shouldGenerateNoise() {
- return false;
- }
-
- @Override
- public boolean shouldGenerateSurface() {
- return false;
- }
-
- @Override
- public boolean shouldGenerateBedrock() {
- return false;
- }
-
- @Nullable
- @Override
- public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) {
- return dummyBiomeProvider;
- }
-}
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2022 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 .
+ */
+
+package com.volmit.iris.engine.platform;
+
+import com.volmit.iris.Iris;
+import com.volmit.iris.core.loader.IrisData;
+import com.volmit.iris.core.nms.INMS;
+import com.volmit.iris.core.service.StudioSVC;
+import com.volmit.iris.engine.IrisEngine;
+import com.volmit.iris.engine.data.chunk.TerrainChunk;
+import com.volmit.iris.engine.framework.Engine;
+import com.volmit.iris.engine.framework.EngineTarget;
+import com.volmit.iris.engine.object.IrisDimension;
+import com.volmit.iris.engine.object.IrisWorld;
+import com.volmit.iris.engine.object.StudioMode;
+import com.volmit.iris.engine.platform.studio.StudioGenerator;
+import com.volmit.iris.util.collection.KList;
+import com.volmit.iris.util.data.IrisBiomeStorage;
+import com.volmit.iris.util.hunk.Hunk;
+import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder;
+import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder;
+import com.volmit.iris.util.io.ReactiveFolder;
+import com.volmit.iris.util.scheduling.ChronoLatch;
+import com.volmit.iris.util.scheduling.J;
+import com.volmit.iris.util.scheduling.Looper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.Setter;
+import org.bukkit.*;
+import org.bukkit.block.Biome;
+import org.bukkit.block.data.BlockData;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.world.WorldInitEvent;
+import org.bukkit.generator.BiomeProvider;
+import org.bukkit.generator.BlockPopulator;
+import org.bukkit.generator.ChunkGenerator;
+import org.bukkit.generator.WorldInfo;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChunkGenerator, Listener {
+ private static final int LOAD_LOCKS = Runtime.getRuntime().availableProcessors() * 4;
+ private final Semaphore loadLock;
+ private final IrisWorld world;
+ private final File dataLocation;
+ private final String dimensionKey;
+ private final ReactiveFolder folder;
+ private final ReentrantLock lock = new ReentrantLock();
+ private final KList populators;
+ private final ChronoLatch hotloadChecker;
+ private final AtomicBoolean setup;
+ private final boolean studio;
+ private final AtomicInteger a = new AtomicInteger(0);
+ private Engine engine;
+ private Looper hotloader;
+ private StudioMode lastMode;
+ private DummyBiomeProvider dummyBiomeProvider;
+ @Setter
+ private StudioGenerator studioGenerator;
+
+ private boolean initialized = false;
+
+ public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) {
+ setup = new AtomicBoolean(false);
+ studioGenerator = null;
+ dummyBiomeProvider = new DummyBiomeProvider();
+ populators = new KList<>();
+ loadLock = new Semaphore(LOAD_LOCKS);
+ this.world = world;
+ this.hotloadChecker = new ChronoLatch(1000, false);
+ this.studio = studio;
+ this.dataLocation = dataLocation;
+ this.dimensionKey = dimensionKey;
+ this.folder = new ReactiveFolder(dataLocation, (_a, _b, _c) -> hotload());
+ Bukkit.getServer().getPluginManager().registerEvents(this, Iris.instance);
+ }
+
+ private static Field getField(Class clazz, String fieldName)
+ throws NoSuchFieldException {
+ try {
+ return clazz.getDeclaredField(fieldName);
+ } catch (NoSuchFieldException e) {
+ Class superClass = clazz.getSuperclass();
+ if (superClass == null) {
+ throw e;
+ } else {
+ return getField(superClass, fieldName);
+ }
+ }
+ }
+
+ @EventHandler
+ public void onWorldInit(WorldInitEvent event) {
+ try {
+ if (!initialized) {
+ world.setRawWorldSeed(event.getWorld().getSeed());
+ if (world.name().equals(event.getWorld().getName())) {
+ Engine engine = getEngine(event.getWorld());
+ if (engine == null) {
+ Iris.warn("Failed to get Engine!");
+ J.s(() -> {
+ Engine engine1 = getEngine(event.getWorld());
+ if (engine1 != null) {
+ try {
+ INMS.get().inject(event.getWorld().getSeed(), engine1, event.getWorld());
+ Iris.info("Injected Iris Biome Source into " + event.getWorld().getName());
+ initialized = true;
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+ }, 10);
+ } else {
+ INMS.get().inject(event.getWorld().getSeed(), engine, event.getWorld());
+ Iris.info("Injected Iris Biome Source into " + event.getWorld().getName());
+ initialized = true;
+ }
+ }
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void setupEngine() {
+ IrisData data = IrisData.get(dataLocation);
+ IrisDimension dimension = data.getDimensionLoader().load(dimensionKey);
+
+ if (dimension == null) {
+ Iris.error("Oh No! There's no pack in " + data.getDataFolder().getPath() + " or... there's no dimension for the key " + dimensionKey);
+ IrisDimension test = IrisData.loadAnyDimension(dimensionKey);
+
+ if (test != null) {
+ Iris.warn("Looks like " + dimensionKey + " exists in " + test.getLoadFile().getPath() + " ");
+ Iris.service(StudioSVC.class).installIntoWorld(Iris.getSender(), dimensionKey, dataLocation.getParentFile().getParentFile());
+ Iris.warn("Attempted to install into " + data.getDataFolder().getPath());
+ data.dump();
+ data.clearLists();
+ test = data.getDimensionLoader().load(dimensionKey);
+
+ if (test != null) {
+ Iris.success("Woo! Patched the Engine!");
+ dimension = test;
+ } else {
+ Iris.error("Failed to patch dimension!");
+ throw new RuntimeException("Missing Dimension: " + dimensionKey);
+ }
+ } else {
+ Iris.error("Nope, you don't have an installation containing " + dimensionKey + " try downloading it?");
+ throw new RuntimeException("Missing Dimension: " + dimensionKey);
+ }
+ }
+
+ lastMode = StudioMode.NORMAL;
+ engine = new IrisEngine(new EngineTarget(world, dimension, data), studio);
+ populators.clear();
+ }
+
+ @Override
+ public void injectChunkReplacement(World world, int x, int z, Consumer jobs) {
+ try {
+ loadLock.acquire();
+ IrisBiomeStorage st = new IrisBiomeStorage();
+ TerrainChunk tc = TerrainChunk.createUnsafe(world, st);
+ Hunk blocks = Hunk.view(tc);
+ Hunk biomes = Hunk.view(tc, tc.getMinHeight(), tc.getMaxHeight());
+ this.world.bind(world);
+ getEngine().generate(x << 4, z << 4, blocks, biomes, true);
+ Iris.debug("Regenerated " + x + " " + z);
+ int t = 0;
+ for (int i = getEngine().getHeight() >> 4; i >= 0; i--) {
+ if (!world.isChunkLoaded(x, z)) {
+ continue;
+ }
+
+ Chunk c = world.getChunkAt(x, z);
+ for (Entity ee : c.getEntities()) {
+ if (ee instanceof Player) {
+ continue;
+ }
+
+ J.s(ee::remove);
+ }
+
+ J.s(() -> engine.getWorldManager().onChunkLoad(c, false));
+
+ int finalI = i;
+ jobs.accept(() -> {
+
+ for (int xx = 0; xx < 16; xx++) {
+ for (int yy = 0; yy < 16; yy++) {
+ for (int zz = 0; zz < 16; zz++) {
+ if (yy + (finalI << 4) >= engine.getHeight() || yy + (finalI << 4) < 0) {
+ continue;
+ }
+ c.getBlock(xx, yy + (finalI << 4) + world.getMinHeight(), zz)
+ .setBlockData(tc.getBlockData(xx, yy + (finalI << 4) + world.getMinHeight(), zz), false);
+ }
+ }
+ }
+ });
+ }
+
+ loadLock.release();
+ } catch (Throwable e) {
+ loadLock.release();
+ Iris.error("======================================");
+ e.printStackTrace();
+ Iris.reportErrorChunk(x, z, e, "CHUNK");
+ Iris.error("======================================");
+
+ ChunkData d = Bukkit.createChunkData(world);
+
+ for (int i = 0; i < 16; i++) {
+ for (int j = 0; j < 16; j++) {
+ d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData());
+ }
+ }
+ }
+ }
+
+ private Engine getEngine(WorldInfo world) {
+ if (setup.get()) {
+ return getEngine();
+ }
+
+ lock.lock();
+
+ try {
+ if (setup.get()) {
+ return getEngine();
+ }
+
+
+ getWorld().setRawWorldSeed(world.getSeed());
+ setupEngine();
+ setup.set(true);
+ this.hotloader = studio ? new Looper() {
+ @Override
+ protected long loop() {
+ if (hotloadChecker.flip()) {
+ folder.check();
+ }
+
+ return 250;
+ }
+ } : null;
+
+ if (studio) {
+ hotloader.setPriority(Thread.MIN_PRIORITY);
+ hotloader.start();
+ hotloader.setName(getTarget().getWorld().name() + " Hotloader");
+ }
+
+ return engine;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public void close() {
+ withExclusiveControl(() -> {
+ if (isStudio()) {
+ hotloader.interrupt();
+ }
+
+ getEngine().close();
+ folder.clear();
+ populators.clear();
+
+ });
+ }
+
+ @Override
+ public boolean isStudio() {
+ return studio;
+ }
+
+ @Override
+ public void hotload() {
+ if (!isStudio()) {
+ return;
+ }
+
+ withExclusiveControl(() -> getEngine().hotload());
+ }
+
+ public void withExclusiveControl(Runnable r) {
+ J.a(() -> {
+ try {
+ loadLock.acquire(LOAD_LOCKS);
+ r.run();
+ loadLock.release(LOAD_LOCKS);
+ } catch (Throwable e) {
+ Iris.reportError(e);
+ }
+ });
+ }
+
+ @Override
+ public void touch(World world) {
+ getEngine(world);
+ }
+
+ @Override
+ public void generateNoise(@NotNull WorldInfo world, @NotNull Random random, int x, int z, @NotNull ChunkGenerator.ChunkData d) {
+ try {
+ getEngine(world);
+ computeStudioGenerator();
+ TerrainChunk tc = TerrainChunk.create(d, new IrisBiomeStorage());
+ this.world.bind(world);
+ if (studioGenerator != null) {
+ studioGenerator.generateChunk(getEngine(), tc, x, z);
+ } else {
+ ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc);
+ BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight());
+ getEngine().generate(x << 4, z << 4, blocks, biomes, false);
+ blocks.apply();
+ biomes.apply();
+ }
+
+ Iris.debug("Generated " + x + " " + z);
+ } catch (Throwable e) {
+ Iris.error("======================================");
+ e.printStackTrace();
+ Iris.reportErrorChunk(x, z, e, "CHUNK");
+ Iris.error("======================================");
+
+ for (int i = 0; i < 16; i++) {
+ for (int j = 0; j < 16; j++) {
+ d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData());
+ }
+ }
+ }
+ }
+
+ @Override
+ public int getBaseHeight(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull HeightMap heightMap) {
+ return 4;
+ }
+
+ private void computeStudioGenerator() {
+ if (!getEngine().getDimension().getStudioMode().equals(lastMode)) {
+ lastMode = getEngine().getDimension().getStudioMode();
+ getEngine().getDimension().getStudioMode().inject(this);
+ }
+ }
+
+ @NotNull
+ @Override
+ public List getDefaultPopulators(@NotNull World world) {
+ return populators;
+ }
+
+ @Override
+ public boolean isParallelCapable() {
+ return true;
+ }
+
+ @Override
+ public boolean shouldGenerateCaves() {
+ return false;
+ }
+
+ @Override
+ public boolean shouldGenerateDecorations() {
+ return false;
+ }
+
+ @Override
+ public boolean shouldGenerateMobs() {
+ return false;
+ }
+
+ @Override
+ public boolean shouldGenerateStructures() {
+ return false;
+ }
+
+ @Override
+ public boolean shouldGenerateNoise() {
+ return false;
+ }
+
+ @Override
+ public boolean shouldGenerateSurface() {
+ return false;
+ }
+
+ @Override
+ public boolean shouldGenerateBedrock() {
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) {
+ return dummyBiomeProvider;
+ }
+}