diff --git a/build.gradle b/build.gradle index d37c9d9e6..f78189e2e 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'com.volmit.iris' -version '1.5.1' +version '1.5.2' def apiVersion = '1.17' def name = 'Iris' def main = 'com.volmit.iris.Iris' diff --git a/src/main/java/com/volmit/iris/core/ConversionManager.java b/src/main/java/com/volmit/iris/core/ConversionManager.java index e2b2c291e..2d7801aa7 100644 --- a/src/main/java/com/volmit/iris/core/ConversionManager.java +++ b/src/main/java/com/volmit/iris/core/ConversionManager.java @@ -20,7 +20,7 @@ package com.volmit.iris.core; import com.google.gson.Gson; import com.volmit.iris.Iris; -import com.volmit.iris.engine.data.DirectWorldWriter; +import com.volmit.iris.engine.data.mca.NBTWorld; import com.volmit.iris.engine.data.nbt.io.NBTUtil; import com.volmit.iris.engine.data.nbt.io.NamedTag; import com.volmit.iris.engine.data.nbt.tag.CompoundTag; @@ -151,7 +151,7 @@ public class ConversionManager { @SuppressWarnings("unchecked") ListTag paletteList = (ListTag) compound.getListTag("palette"); for (int i = 0; i < paletteList.size(); i++) { CompoundTag cp = paletteList.get(i); - palette.add(DirectWorldWriter.getBlockData(cp)); + palette.add(NBTWorld.getBlockData(cp)); } IrisJigsawPiece piece = new IrisJigsawPiece(); IrisObject object = new IrisObject(w, h, d); @@ -171,7 +171,7 @@ public class ConversionManager { CompoundTag finalState = new CompoundTag(); finalState.putString("Name", nbt.getString("final_state")); BlockData jd = bd.clone(); - bd = DirectWorldWriter.getBlockData(finalState); + bd = NBTWorld.getBlockData(finalState); String joint = nbt.getString("joint"); String pool = nbt.getString("pool"); String poolId = toPoolName(pool); diff --git a/src/main/java/com/volmit/iris/core/gui/Pregenerator.java b/src/main/java/com/volmit/iris/core/gui/Pregenerator.java index 73424e082..4aa0b77d8 100644 --- a/src/main/java/com/volmit/iris/core/gui/Pregenerator.java +++ b/src/main/java/com/volmit/iris/core/gui/Pregenerator.java @@ -21,8 +21,8 @@ package com.volmit.iris.core.gui; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.engine.IrisWorlds; -import com.volmit.iris.engine.data.DirectWorldWriter; import com.volmit.iris.engine.data.mca.MCAFile; +import com.volmit.iris.engine.data.mca.NBTWorld; import com.volmit.iris.engine.framework.IrisAccess; import com.volmit.iris.engine.parallel.BurstExecutor; import com.volmit.iris.engine.parallel.MultiBurst; @@ -77,7 +77,7 @@ public class Pregenerator implements Listener { private static final Color COLOR_MCA_DEFERRED = Color.decode("#3CB57A"); private final World world; private int lowestBedrock; - private final DirectWorldWriter directWriter; + private final NBTWorld directWriter; private final AtomicBoolean active; private final AtomicBoolean running; private final KList errors; @@ -89,6 +89,7 @@ public class Pregenerator implements Listener { private final AtomicInteger generated; private final AtomicInteger generatedLast; private final RollingSequence perSecond; + private final RollingSequence perMinute; private final AtomicInteger totalChunks; private final AtomicLong memory; private final AtomicReference memoryMetric; @@ -125,16 +126,17 @@ public class Pregenerator implements Listener { vmcaz = new AtomicInteger(); vcax = new AtomicInteger(); vcaz = new AtomicInteger(); + perMinute = new RollingSequence(200); perSecond = new RollingSequence(20); generatedLast = new AtomicInteger(0); totalChunks = new AtomicInteger(0); generated = new AtomicInteger(0); mcaDefer = new KList<>(); access = IrisWorlds.access(world); - this.directWriter = new DirectWorldWriter(world.getWorldFolder()); + this.directWriter = new NBTWorld(world.getWorldFolder()); this.running = new AtomicBoolean(true); this.active = new AtomicBoolean(true); - MultiBurst burst = new MultiBurst("Iris Pregenerator", 9, Runtime.getRuntime().availableProcessors() + 4); + MultiBurst burst = new MultiBurst("Iris Pregenerator", 9, Runtime.getRuntime().availableProcessors()); int mcaSize = (((blockSize >> 4) + 2) >> 5) + 1; onComplete = new KList<>(); max = new ChunkPosition(0, 0); @@ -196,7 +198,7 @@ public class Pregenerator implements Listener { } burst.shutdownNow(); - directWriter.flush(); + directWriter.close(); flushWorld(); onComplete.forEach(Runnable::run); running.set(false); @@ -214,6 +216,7 @@ public class Pregenerator implements Listener { int up = m - w; double dur = p.getMilliseconds(); perSecond.put((int) (up / (dur / 1000D))); + perSecond.put((int) (up / (dur / 60000D))); p.reset(); p.begin(); updateProgress(); @@ -239,8 +242,7 @@ public class Pregenerator implements Listener { return false; } - File mca = new File(world.getWorldFolder(), "region/r." + x + "." + z + ".mca"); - File mcg = directWriter.getMCAFile(x, z); + File mca = directWriter.getRegionFile(x, z); BurstExecutor e = burst.burst(1024); int mcaox = x << 5; int mcaoz = z << 5; @@ -255,9 +257,8 @@ public class Pregenerator implements Listener { vcaz.set(jj); })); e.complete(); - verifyMCA(x, z, burst); - directWriter.flush(); - install(mcg, mca); + //verifyMCA(x, z, burst); + directWriter.save(); } else { totalChunks.getAndAdd(1024); mcaDefer.add(new ChunkPosition(x, z)); @@ -299,27 +300,6 @@ public class Pregenerator implements Listener { } } - private boolean install(File from, File to) { - try { - Files.move(from.toPath(), to.toPath()); - return true; - } catch (Throwable e) { - Iris.reportError(e); - - } - - try { - IO.copyFile(from, to); - from.delete(); - return true; - } catch (IOException e) { - Iris.reportError(e); - - } - - return false; - } - public void updateProgress() { if (!latch.flip()) { return; @@ -335,7 +315,7 @@ public class Pregenerator implements Listener { if (PaperLib.isPaper()) { method.set("PaperAsync (Slow)"); - while (wait.size() > 32) { + while (wait.size() > 16) { J.sleep(5); } @@ -509,7 +489,8 @@ public class Pregenerator implements Listener { return new String[]{ "Progress: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (" + Form.pc((double) generated.get() / (double) totalChunks.get(), 0) + ")", "ETA: " + Form.duration(eta, 0), - "Chunks/s: " + Form.f((int) perSecond.getAverage()), + "Chunks/s: " + Form.f((int) perSecond.getAverage()) + " (" + Form.f((int)perSecond.getMax()) + " Peak)", + "Chunks/min: " + Form.f((int) perMinute.getAverage())+ " (" + Form.f((int)perMinute.getMax()) + " Peak)", "Memory: " + memoryMetric.get(), "Cursor: " + "MCA(" + vmcax.get() + ", " + vmcaz.get() + ") @ (" + vcax.get() + ", " + vcaz.get() + ")", "Gen Mode: " + method.get(), diff --git a/src/main/java/com/volmit/iris/engine/IrisComplex.java b/src/main/java/com/volmit/iris/engine/IrisComplex.java index 3659e6e3f..1d2878269 100644 --- a/src/main/java/com/volmit/iris/engine/IrisComplex.java +++ b/src/main/java/com/volmit/iris/engine/IrisComplex.java @@ -197,10 +197,15 @@ public class IrisComplex implements DataProvider { }, Interpolated.DOUBLE).cache2D(cacheSize); slopeStream = heightStream.slope(3).interpolate().bilinear(3, 3).cache2D(cacheSize); objectChanceStream = ProceduralStream.ofDouble((x, z) -> { - AtomicDouble str = new AtomicDouble(1D); - engine.getFramework().getEngineParallax().forEachFeature(x, z, (i) - -> str.set(Math.min(str.get(), i.getObjectChanceModifier(x, z)))); - return str.get(); + if(engine.getDimension().hasFeatures(engine)) + { + AtomicDouble str = new AtomicDouble(1D); + engine.getFramework().getEngineParallax().forEachFeature(x, z, (i) + -> str.set(Math.min(str.get(), i.getObjectChanceModifier(x, z)))); + return str.get(); + } + + return 1D; }); trueBiomeStream = focus != null ? ProceduralStream.of((x, y) -> focus, Interpolated.of(a -> 0D, diff --git a/src/main/java/com/volmit/iris/engine/IrisEngine.java b/src/main/java/com/volmit/iris/engine/IrisEngine.java index 706cd477b..cb66c1d98 100644 --- a/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -162,22 +162,21 @@ public class IrisEngine extends BlockPopulator implements Engine { public void generate(int x, int z, Hunk vblocks, Hunk vbiomes) { try { PrecisionStopwatch p = PrecisionStopwatch.start(); - Hunk blocks = vblocks; switch (getDimension().getTerrainMode()) { case NORMAL -> { getFramework().getEngineParallax().generateParallaxArea(x >> 4, z >> 4); getFramework().getBiomeActuator().actuate(x, z, vbiomes); - getFramework().getTerrainActuator().actuate(x, z, blocks); - getFramework().getCaveModifier().modify(x, z, blocks); - getFramework().getRavineModifier().modify(x, z, blocks); - getFramework().getPostModifier().modify(x, z, blocks); - getFramework().getDecorantActuator().actuate(x, z, blocks); - getFramework().getEngineParallax().insertParallax(x, z, blocks); - getFramework().getDepositModifier().modify(x, z, blocks); + getFramework().getTerrainActuator().actuate(x, z, vblocks); + getFramework().getCaveModifier().modify(x, z, vblocks); + getFramework().getRavineModifier().modify(x, z, vblocks); + getFramework().getPostModifier().modify(x, z, vblocks); + getFramework().getDecorantActuator().actuate(x, z, vblocks); + getFramework().getEngineParallax().insertParallax(x, z, vblocks); + getFramework().getDepositModifier().modify(x, z, vblocks); } case ISLANDS -> { - getFramework().getTerrainActuator().actuate(x, z, blocks); + getFramework().getTerrainActuator().actuate(x, z, vblocks); } } getMetrics().getTotal().put(p.getMilliseconds()); diff --git a/src/main/java/com/volmit/iris/engine/data/mca/MCAFile.java b/src/main/java/com/volmit/iris/engine/data/mca/MCAFile.java index be77a3bce..86b04fe1b 100644 --- a/src/main/java/com/volmit/iris/engine/data/mca/MCAFile.java +++ b/src/main/java/com/volmit/iris/engine/data/mca/MCAFile.java @@ -22,6 +22,7 @@ import com.volmit.iris.engine.data.nbt.tag.CompoundTag; import java.io.IOException; import java.io.RandomAccessFile; +import java.util.concurrent.atomic.AtomicReferenceArray; @SuppressWarnings("ALL") public class MCAFile { @@ -33,7 +34,7 @@ public class MCAFile { private final int regionX; private final int regionZ; - private Chunk[] chunks; + private AtomicReferenceArray chunks; /** * MCAFile represents a world save file used by Minecraft to store world @@ -69,7 +70,7 @@ public class MCAFile { * @throws IOException If something went wrong during deserialization. */ public void deserialize(RandomAccessFile raf, long loadFlags) throws IOException { - chunks = new Chunk[1024]; + chunks = new AtomicReferenceArray<>(1024); for (int i = 0; i < 1024; i++) { raf.seek(i * 4); int offset = raf.read() << 16; @@ -83,11 +84,11 @@ public class MCAFile { Chunk chunk = new Chunk(timestamp); raf.seek(4096L * offset + 4); //+4: skip data size chunk.deserialize(raf, loadFlags); - chunks[i] = chunk; + chunks.set(i, chunk); } } - public Chunk[] getChunks() { + public AtomicReferenceArray getChunks() { return chunks; } @@ -128,7 +129,7 @@ public class MCAFile { for (int cx = 0; cx < 32; cx++) { for (int cz = 0; cz < 32; cz++) { int index = getChunkIndex(cx, cz); - Chunk chunk = chunks[index]; + Chunk chunk = chunks.get(index); if (chunk == null) { continue; } @@ -175,9 +176,9 @@ public class MCAFile { public void setChunk(int index, Chunk chunk) { checkIndex(index); if (chunks == null) { - chunks = new Chunk[1024]; + chunks = new AtomicReferenceArray<>(1024); } - chunks[index] = chunk; + chunks.set(index, chunk); } /** @@ -203,7 +204,7 @@ public class MCAFile { if (chunks == null) { return null; } - return chunks[index]; + return chunks.get(index); } /** @@ -217,6 +218,11 @@ public class MCAFile { return getChunk(getChunkIndex(chunkX, chunkZ)); } + public boolean hasChunk(int chunkX, int chunkZ) + { + return getChunk(chunkX, chunkZ) != null; + } + /** * Calculates the index of a chunk from its x- and z-coordinates in this region. * This works with absolute and relative coordinates. @@ -319,15 +325,4 @@ public class MCAFile { } return chunk.getBlockStateAt(blockX, blockY, blockZ); } - - /** - * Recalculates the Palette and the BlockStates of all chunks and sections of this region. - */ - public void cleanupPalettesAndBlockStates() { - for (Chunk chunk : chunks) { - if (chunk != null) { - chunk.cleanupPalettesAndBlockStates(); - } - } - } } diff --git a/src/main/java/com/volmit/iris/engine/data/DirectWorldWriter.java b/src/main/java/com/volmit/iris/engine/data/mca/NBTWorld.java similarity index 53% rename from src/main/java/com/volmit/iris/engine/data/DirectWorldWriter.java rename to src/main/java/com/volmit/iris/engine/data/mca/NBTWorld.java index 9458ecf16..2f910e469 100644 --- a/src/main/java/com/volmit/iris/engine/data/DirectWorldWriter.java +++ b/src/main/java/com/volmit/iris/engine/data/mca/NBTWorld.java @@ -16,75 +16,160 @@ * along with this program. If not, see . */ -package com.volmit.iris.engine.data; +package com.volmit.iris.engine.data.mca; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.engine.cache.Cache; -import com.volmit.iris.engine.data.mca.Chunk; -import com.volmit.iris.engine.data.mca.MCAFile; -import com.volmit.iris.engine.data.mca.MCAUtil; -import com.volmit.iris.engine.data.mca.Section; +import com.volmit.iris.engine.data.B; import com.volmit.iris.engine.data.nbt.tag.CompoundTag; import com.volmit.iris.engine.data.nbt.tag.StringTag; -import com.volmit.iris.engine.parallel.BurstExecutor; -import com.volmit.iris.engine.parallel.MultiBurst; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.format.C; +import com.volmit.iris.util.math.M; +import com.volmit.iris.util.scheduling.IrisLock; import org.bukkit.NamespacedKey; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; import java.util.Map; +import java.util.concurrent.*; -@SuppressWarnings("EmptyMethod") -public class DirectWorldWriter { - private final File worldFolder; - private final Map writeBuffer; +public class NBTWorld { + private static final BlockData AIR = B.get("AIR"); private static final Map blockDataCache = new KMap<>(); private static final Map biomeIds = computeBiomeIDs(); + private final IrisLock regionLock = new IrisLock("Region"); + private final KMap loadedRegions; + private final KMap lastUse; + private final File worldFolder; + private final ExecutorService saveQueue; - public DirectWorldWriter(File worldFolder) { + public NBTWorld(File worldFolder) + { this.worldFolder = worldFolder; - writeBuffer = new KMap<>(); - new File(worldFolder, "iris/mca-region").mkdirs(); + this.loadedRegions = new KMap<>(); + this.lastUse = new KMap<>(); + saveQueue = Executors.newSingleThreadExecutor(r -> { + Thread t = new Thread(r); + t.setName("Iris MCA Writer"); + t.setPriority(Thread.MIN_PRIORITY); + return t; + }); } - public void flush() { - BurstExecutor ex2 = MultiBurst.burst.burst(writeBuffer.size()); + public void close() + { + regionLock.lock(); - for (Long i : new KList<>(writeBuffer.keySet())) { - ex2.queue(() -> { - int x = Cache.keyX(i); - int z = Cache.keyZ(i); - try { - File f = getMCAFile(x, z); - - if (!f.exists()) { - f.getParentFile().mkdirs(); - f.createNewFile(); - } - - MCAUtil.write(writeBuffer.get(i), f, true); - writeBuffer.remove(i); - } catch (Throwable e) { - Iris.reportError(e); - e.printStackTrace(); - } - }); + for(Long i : loadedRegions.k()) + { + queueSaveUnload(Cache.keyX(i), Cache.keyZ(i)); } - ex2.complete(); + regionLock.unlock(); + saveQueue.shutdown(); + try { + while(!saveQueue.awaitTermination(3, TimeUnit.SECONDS)) + { + Iris.info("Still Waiting to save MCA Files..."); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } } - public void optimizeChunk(int x, int z) { - getChunk(x, z).cleanupPalettesAndBlockStates(); + public void queueSaveUnload(int x, int z) + { + saveQueue.submit(() -> { + MCAFile f = getMCAOrNull(x, z); + if(f != null) + { + unloadRegion(x, z); + } + + saveRegion(x, z, f); + }); } - public File getMCAFile(int x, int z) { - return new File(worldFolder, "iris/mca-region/r." + x + "." + z + ".mca"); + public void save() + { + regionLock.lock(); + + boolean saving = true; + + for(Long i : loadedRegions.k()) + { + int x = Cache.keyX(i); + int z = Cache.keyZ(i); + + if(!lastUse.containsKey(i)) + { + lastUse.put(i, M.ms()); + } + + if(shouldUnload(x, z)) + { + queueSaveUnload(x, z); + } + } + + Iris.debug("Regions: " + C.GOLD + loadedRegions.size() + C.LIGHT_PURPLE); + + regionLock.unlock(); + } + + public void queueSave() + { + + } + + public synchronized void unloadRegion(int x, int z) + { + long key = Cache.key(x, z); + regionLock.lock(); + loadedRegions.remove(key); + lastUse.remove(key); + regionLock.unlock(); + Iris.debug("Unloaded Region " + C.GOLD + x + " " + z); + } + + public void saveRegion(int x, int z) + { + long k = Cache.key(x, z); + MCAFile mca = getMCAOrNull(x, z); + try { + MCAUtil.write(mca, getRegionFile(x, z), true); + Iris.debug("Saved Region " + C.GOLD + x + " " + z); + } catch (IOException e) { + Iris.error("Failed to save region " + getRegionFile(x, z).getPath()); + e.printStackTrace(); + } + } + + public void saveRegion(int x, int z, MCAFile mca) + { + try { + MCAUtil.write(mca, getRegionFile(x, z), true); + Iris.debug("Saved Region " + C.GOLD + x + " " + z); + } catch (IOException e) { + Iris.error("Failed to save region " + getRegionFile(x, z).getPath()); + e.printStackTrace(); + } + } + + public boolean shouldUnload(int x, int z) + { + return getIdleDuration(x, z) > 60000; + } + + public File getRegionFile(int x, int z) { + return new File(worldFolder, "region/r." + x + "." + z + ".mca"); } public static BlockData getBlockData(CompoundTag tag) { @@ -125,7 +210,6 @@ public class DirectWorldWriter { NamespacedKey key = blockData.getMaterial().getKey(); s.putString("Name", key.getNamespace() + ":" + key.getKey()); - if (data.contains("[")) { String raw = data.split("\\Q[\\E")[1].replaceAll("\\Q]\\E", ""); CompoundTag props = new CompoundTag(); @@ -154,7 +238,7 @@ public class DirectWorldWriter { CompoundTag tag = getChunkSection(x >> 4, y >> 4, z >> 4).getBlockStateAt(x & 15, y & 15, z & 15); if (tag == null) { - return B.get("AIR"); + return AIR; } return getBlockData(tag); @@ -162,7 +246,7 @@ public class DirectWorldWriter { Iris.reportError(e); } - return B.get("AIR"); + return AIR; } public void setBlockData(int x, int y, int z, BlockData data) { @@ -185,10 +269,6 @@ public class DirectWorldWriter { return s; } - public void deleteChunk(int x, int z) { - - } - public Chunk getChunk(int x, int z) { MCAFile mca = getMCA(x >> 5, z >> 5); Chunk c = mca.getChunk(x & 31, z & 31); @@ -201,28 +281,57 @@ public class DirectWorldWriter { return c; } + public long getIdleDuration(int x, int z) + { + Long l = lastUse.get(Cache.key(x, z)); + + return l == null ? 0 : (M.ms() - l); + } + public MCAFile getMCA(int x, int z) { long key = Cache.key(x, z); - MCAFile mca = writeBuffer.get(key); - if (mca != null) { - return mca; + regionLock.lock(); + lastUse.put(key, M.ms()); + MCAFile mcaf = loadedRegions.get(key); + regionLock.unlock(); + + if(mcaf == null) + { + File f = getRegionFile(x, z); + try { + mcaf = f.exists() ? MCAUtil.read(f) : new MCAFile(x, z); + } catch (IOException e) { + Iris.error("Failed to properly read MCA File " + f.getPath() + " Using a blank one."); + e.printStackTrace(); + mcaf = new MCAFile(x, z); + } + + regionLock.lock(); + loadedRegions.put(key, mcaf); + regionLock.unlock(); } - File f = getMCAFile(x, z); - try { - mca = f.exists() ? MCAUtil.read(f) : new MCAFile(x, z); - } catch (IOException e) { - e.printStackTrace(); - mca = new MCAFile(x, z); + return mcaf; + } + + public MCAFile getMCAOrNull(int x, int z) { + long key = Cache.key(x, z); + MCAFile ff = null; + regionLock.lock(); + + if(loadedRegions.containsKey(key)) + { + lastUse.put(key, M.ms()); + ff = loadedRegions.get(key); } - writeBuffer.put(key, mca); - return mca; + regionLock.unlock(); + return ff; } public int size() { - return writeBuffer.size(); + return loadedRegions.size(); } private static Map computeBiomeIDs() { @@ -236,18 +345,4 @@ public class DirectWorldWriter { return biomeIds; } - - public void verify(int mcaox, int mcaoz) { - MCAFile file = getMCA(mcaox, mcaoz); - - for (int i = 0; i < 32; i++) { - for (int j = 0; j < 32; j++) { - Chunk c = file.getChunk(i, j); - - if (c == null) { - Iris.warn("Chunk " + ((mcaox << 5) + i) + ", " + ((mcaoz << 5) + j) + " is null in MCA File " + mcaox + ", " + mcaoz); - } - } - } - } } diff --git a/src/main/java/com/volmit/iris/engine/framework/EngineCompositeGenerator.java b/src/main/java/com/volmit/iris/engine/framework/EngineCompositeGenerator.java index 710cfe7fd..0039e714a 100644 --- a/src/main/java/com/volmit/iris/engine/framework/EngineCompositeGenerator.java +++ b/src/main/java/com/volmit/iris/engine/framework/EngineCompositeGenerator.java @@ -27,8 +27,8 @@ import com.volmit.iris.engine.IrisEngineCompound; import com.volmit.iris.engine.IrisWorlds; import com.volmit.iris.engine.cache.Cache; import com.volmit.iris.engine.data.B; -import com.volmit.iris.engine.data.DirectWorldWriter; import com.volmit.iris.engine.data.chunk.TerrainChunk; +import com.volmit.iris.engine.data.mca.NBTWorld; import com.volmit.iris.engine.hunk.Hunk; import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisDimension; @@ -104,7 +104,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce populators = new KList().qadd(new BlockPopulator() { @Override public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) { - if (compound != null) { + if (compound.get() != null) { for (BlockPopulator i : compound.get().getPopulators()) { i.populate(world, random, chunk); } @@ -295,7 +295,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce } public synchronized void initialize(World world) { - if (!(world instanceof FakeWorld) && fake.get() && this.compound != null) { + if (!(world instanceof FakeWorld) && fake.get() && this.compound.get() != null) { fake.set(false); this.compound.get().updateWorld(world); getTarget().updateWorld(world); @@ -469,7 +469,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce return tc.getRaw(); } - public void directWriteMCA(World w, int x, int z, DirectWorldWriter writer, MultiBurst burst) { + public void directWriteMCA(World w, int x, int z, NBTWorld writer, MultiBurst burst) { BurstExecutor e = burst.burst(1024); int mcaox = x << 5; int mcaoz = z << 5; @@ -485,7 +485,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce e.complete(); } - public void directWriteChunk(World w, int x, int z, DirectWorldWriter writer) { + public void directWriteChunk(World w, int x, int z, NBTWorld writer) { int ox = x << 4; int oz = z << 4; com.volmit.iris.engine.data.mca.Chunk cc = writer.getChunk(x, z); @@ -543,7 +543,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce return; } - cc.setBlockStateAt(xx, y, zz, DirectWorldWriter.getCompound(blockData), false); + cc.setBlockStateAt(xx, y, zz, NBTWorld.getCompound(blockData), false); } @NotNull @@ -557,7 +557,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce y = 0; } - return DirectWorldWriter.getBlockData(cc.getBlockStateAt((x + ox) & 15, y, (z + oz) & 15)); + return NBTWorld.getBlockData(cc.getBlockStateAt((x + ox) & 15, y, (z + oz) & 15)); } @Override diff --git a/src/main/java/com/volmit/iris/engine/framework/EngineParallaxManager.java b/src/main/java/com/volmit/iris/engine/framework/EngineParallaxManager.java index 270807ab2..cea30dd0f 100644 --- a/src/main/java/com/volmit/iris/engine/framework/EngineParallaxManager.java +++ b/src/main/java/com/volmit/iris/engine/framework/EngineParallaxManager.java @@ -199,6 +199,11 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer { IrisLock getFeatureLock(); default void forEachFeature(double x, double z, Consumer f) { + if(!getEngine().getDimension().hasFeatures(getEngine())) + { + return; + } + long key = Cache.key(((int) x) >> 4, ((int) z) >> 4); for (IrisFeaturePositional ipf : getFeatureCache().compute(key, (ke, v) -> { @@ -225,17 +230,13 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer { ParallaxChunkMeta m = getParallaxAccess().getMetaR(i + cx, j + cz); try { - synchronized (m.getFeatures()) { - for (IrisFeaturePositional k : m.getFeatures()) { - if (k.shouldFilter(x, z)) { - pos.add(k); - } + for (IrisFeaturePositional k : m.getFeatures()) { + if (k.shouldFilter(x, z)) { + pos.add(k); } } } catch (Throwable e) { Iris.reportError(e); - e.printStackTrace(); - Iris.warn("Failed to read positional features in chunk " + (i + cx) + " " + (j + cz) + "(" + e.getClass().getSimpleName() + ")"); } } } diff --git a/src/main/java/com/volmit/iris/engine/framework/IrisAccess.java b/src/main/java/com/volmit/iris/engine/framework/IrisAccess.java index bfd86c43b..ebc927194 100644 --- a/src/main/java/com/volmit/iris/engine/framework/IrisAccess.java +++ b/src/main/java/com/volmit/iris/engine/framework/IrisAccess.java @@ -22,7 +22,7 @@ import com.volmit.iris.Iris; import com.volmit.iris.core.IrisDataManager; import com.volmit.iris.engine.IrisComplex; import com.volmit.iris.engine.data.DataProvider; -import com.volmit.iris.engine.data.DirectWorldWriter; +import com.volmit.iris.engine.data.mca.NBTWorld; import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisRegion; import com.volmit.iris.engine.parallel.MultiBurst; @@ -44,9 +44,9 @@ import java.util.function.Consumer; @SuppressWarnings("EmptyMethod") public interface IrisAccess extends Hotloadable, DataProvider { - void directWriteMCA(World w, int x, int z, DirectWorldWriter writer, MultiBurst burst); + void directWriteMCA(World w, int x, int z, NBTWorld writer, MultiBurst burst); - void directWriteChunk(World w, int x, int z, DirectWorldWriter writer); + void directWriteChunk(World w, int x, int z, NBTWorld writer); int getGenerated(); diff --git a/src/main/java/com/volmit/iris/engine/object/IrisDimension.java b/src/main/java/com/volmit/iris/engine/object/IrisDimension.java index 61b0c2efe..def631cf6 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisDimension.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisDimension.java @@ -349,6 +349,7 @@ public class IrisDimension extends IrisRegistrant { private final transient AtomicCache sinr = new AtomicCache<>(); private final transient AtomicCache cosr = new AtomicCache<>(); private final transient AtomicCache rad = new AtomicCache<>(); + private final transient AtomicCache featuresUsed = new AtomicCache<>(); public boolean hasSky() { return getSky() != null; @@ -517,4 +518,48 @@ public class IrisDimension extends IrisRegistrant { return changed; } + + public boolean hasFeatures(DataProvider data) { + return featuresUsed.aquire(() -> { + if(getFeatures().isNotEmpty() || getSpecificFeatures().isNotEmpty()) + { + return true; + } + + for(IrisRegion i : getAllRegions(data)) + { + if(i.getFeatures().isNotEmpty()) + { + return true; + } + + for(IrisObjectPlacement j : i.getObjects()) + { + if(j.isVacuum()) + { + return true; + } + } + + for(IrisBiome j : i.getAllBiomes(data)) + { + if(j.getFeatures().isNotEmpty()) + { + return true; + } + + for(IrisObjectPlacement k : i.getObjects()) + { + if(k.isVacuum()) + { + return true; + } + } + } + } + + Iris.verbose("Not using parallax noise features (they arent used in this dimension)"); + return false; + }); + } } diff --git a/src/main/java/com/volmit/iris/engine/parallax/ParallaxChunkMeta.java b/src/main/java/com/volmit/iris/engine/parallax/ParallaxChunkMeta.java index 9d3e10738..f9f169d8b 100644 --- a/src/main/java/com/volmit/iris/engine/parallax/ParallaxChunkMeta.java +++ b/src/main/java/com/volmit/iris/engine/parallax/ParallaxChunkMeta.java @@ -30,6 +30,7 @@ import lombok.Data; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Function; @AllArgsConstructor @@ -56,9 +57,9 @@ public class ParallaxChunkMeta { private int maxObject = -1; private int minObject = -1; private int count; - private KList features; + private CopyOnWriteArrayList features; public ParallaxChunkMeta() { - this(false, false, false, false, false, false, -1, -1, 0, new KList<>()); + this(false, false, false, false, false, false, -1, -1, 0, new CopyOnWriteArrayList<>()); } } diff --git a/src/main/java/com/volmit/iris/engine/parallax/ParallaxRegion.java b/src/main/java/com/volmit/iris/engine/parallax/ParallaxRegion.java index 5af51d6dc..9b169d18f 100644 --- a/src/main/java/com/volmit/iris/engine/parallax/ParallaxRegion.java +++ b/src/main/java/com/volmit/iris/engine/parallax/ParallaxRegion.java @@ -156,7 +156,6 @@ public class ParallaxRegion extends HunkRegion { } public synchronized void save() throws IOException { - PrecisionStopwatch p = PrecisionStopwatch.start(); blockSlice.save(); objectSlice.save(); entitySlice.save(); @@ -164,7 +163,6 @@ public class ParallaxRegion extends HunkRegion { updateSlice.save(); saveMetaHunk(); super.save(); - Iris.debug("Saved Parallax Region " + C.AQUA + getX() + "," + getZ() + C.LIGHT_PURPLE + " in " + C.RED + Form.duration(p.getMilliseconds(), 0)); } public int unload() {