From 7b6405fba796b0c8c4647d9848f586d2533059ee Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Tue, 24 Aug 2021 08:24:36 -0400 Subject: [PATCH] Prepatch --- build.gradle | 2 + .../volmit/iris/core/tools/IrisToolbelt.java | 3 +- .../com/volmit/iris/engine/IrisEngine.java | 49 ++++--- .../iris/engine/data/cache/AtomicCache.java | 125 +++++++----------- .../iris/engine/object/biome/IrisBiome.java | 4 +- .../engine/object/common/HeadlessWorld.java | 22 ++- .../iris/engine/object/common/IrisWorld.java | 19 +++ .../engine/platform/BukkitChunkGenerator.java | 2 + .../engine/platform/HeadlessGenerator.java | 15 ++- .../volmit/iris/util/nbt/mca/NBTWorld.java | 73 +++++----- .../com/volmit/iris/util/nbt/mca/Section.java | 14 +- 11 files changed, 189 insertions(+), 139 deletions(-) diff --git a/build.gradle b/build.gradle index 9560a1d0c..3397282db 100644 --- a/build.gradle +++ b/build.gradle @@ -167,6 +167,7 @@ shadowJar include(dependency('io.papermc:paperlib')) include(dependency('com.dfsek:Paralithic')) include(dependency('net.kyori:')) + include(dependency('com.github.Querz:NBT')) } } @@ -185,6 +186,7 @@ dependencies { implementation "net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT" implementation "net.kyori:adventure-platform-bukkit:4.0.0-SNAPSHOT" implementation 'net.kyori:adventure-api:4.8.1' + implementation 'com.github.Querz:NBT:6.1' // Dynamically Loaded implementation 'io.timeandspace:smoothie-map:2.0.2' diff --git a/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java b/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java index dfb0ca4b0..d185e4427 100644 --- a/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java +++ b/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java @@ -128,7 +128,8 @@ public class IrisToolbelt { return pregenerate(task, new HeadlessPregenMethod(((HeadlessGenerator) gen).getWorld(), (HeadlessGenerator) gen)); } - return pregenerate(task, new HybridPregenMethod(gen.getEngine().getWorld().realWorld(), IrisSettings.getThreadCount((int) IrisSettings.get().getConcurrency().getParallelism()))); + return pregenerate(task, new HybridPregenMethod(gen.getEngine().getWorld().realWorld(), + IrisSettings.getThreadCount((int) IrisSettings.get().getConcurrency().getParallelism()))); } /** diff --git a/src/main/java/com/volmit/iris/engine/IrisEngine.java b/src/main/java/com/volmit/iris/engine/IrisEngine.java index 3e6e735f6..5460564f6 100644 --- a/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -54,7 +54,10 @@ import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.PrecisionStopwatch; import lombok.Data; import lombok.EqualsAndHashCode; +import net.minecraft.world.level.block.state.IBlockData; +import org.bukkit.Bukkit; import org.bukkit.Chunk; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; @@ -405,26 +408,42 @@ public class IrisEngine implements Engine { context.touch(); getEngineData().getStatistics().generatedChunk(); try { + PrecisionStopwatch p = PrecisionStopwatch.start(); Hunk blocks = vblocks.listen((xx, y, zz, t) -> catchBlockUpdates(x + xx, y + getMinHeight(), z + zz, t)); - getMantle().generateMatter(x >> 4, z >> 4, multicore); - burst().burst(multicore, - () -> getTerrainActuator().actuate(x, z, vblocks, multicore), - () -> getBiomeActuator().actuate(x, z, vbiomes, multicore) - ); - burst().burst(multicore, - () -> getCaveModifier().modify(x, z, vblocks, multicore), - () -> getDecorantActuator().actuate(x, z, blocks, multicore), - () -> getRavineModifier().modify(x, z, vblocks, multicore) - ); + if(multicore) + { + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + blocks.set(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData()); + } + } + } + + else + { + getMantle().generateMatter(x >> 4, z >> 4, multicore); + + burst().burst(multicore, + () -> getTerrainActuator().actuate(x, z, vblocks, multicore), + () -> getBiomeActuator().actuate(x, z, vbiomes, multicore) + ); + burst().burst(multicore, + () -> getCaveModifier().modify(x, z, vblocks, multicore), + () -> getDecorantActuator().actuate(x, z, blocks, multicore), + () -> getRavineModifier().modify(x, z, vblocks, multicore) + ); + + getPostModifier().modify(x, z, vblocks, multicore); + + burst().burst(multicore, + () -> getMantle().insertMatter(x >> 4, z >> 4, BlockData.class, blocks, multicore), + () -> getDepositModifier().modify(x, z, vblocks, multicore) + ); + } - getPostModifier().modify(x, z, vblocks, multicore); - burst().burst(multicore, - () -> getMantle().insertMatter(x >> 4, z >> 4, BlockData.class, blocks, multicore), - () -> getDepositModifier().modify(x, z, vblocks, multicore) - ); getMetrics().getTotal().put(p.getMilliseconds()); generated.incrementAndGet(); diff --git a/src/main/java/com/volmit/iris/engine/data/cache/AtomicCache.java b/src/main/java/com/volmit/iris/engine/data/cache/AtomicCache.java index 89f5322ac..dc9981faf 100644 --- a/src/main/java/com/volmit/iris/engine/data/cache/AtomicCache.java +++ b/src/main/java/com/volmit/iris/engine/data/cache/AtomicCache.java @@ -18,107 +18,82 @@ package com.volmit.iris.engine.data.cache; -import com.volmit.iris.util.math.M; -import com.volmit.iris.util.scheduling.IrisLock; +import com.volmit.iris.Iris; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Supplier; public class AtomicCache { - private transient volatile T t; - private transient volatile long a; - private transient volatile int validations; - private final IrisLock check; - private final IrisLock time; - private final IrisLock write; - private final boolean nullSupport; + private transient final AtomicReference t; + private transient final AtomicBoolean set; + private transient final ReentrantLock lock; + private transient final boolean nullSupport; public AtomicCache() { this(false); } public AtomicCache(boolean nullSupport) { + set = nullSupport ? new AtomicBoolean() : null; + t = new AtomicReference<>(); + lock = new ReentrantLock(); this.nullSupport = nullSupport; - check = new IrisLock("Check"); - write = new IrisLock("Write"); - time = new IrisLock("Time"); - validations = 0; - a = -1; - t = null; } public void reset() { - check.lock(); - write.lock(); - time.lock(); - a = -1; - t = null; - time.unlock(); - write.unlock(); - check.unlock(); + t.set(null); + + if(nullSupport) + { + set.set(false); + } } public T aquire(Supplier t) { - if (nullSupport) { - return aquireNull(t); + if(this.t.get() != null) + { + return this.t.get(); } - if (this.t != null && validations > 1000) { - return this.t; + else if(nullSupport && set.get()) + { + return null; } - if (this.t != null && M.ms() - a > 1000) { - if (this.t != null) { - //noinspection NonAtomicOperationOnVolatileField - validations++; + lock.lock(); + + if(this.t.get() != null) + { + lock.unlock(); + return this.t.get(); + } + + else if(nullSupport && set.get()) + { + lock.unlock(); + return null; + } + + try + { + this.t.set(t.get()); + + if(nullSupport) + { + set.set(true); } - - return this.t; } - check.lock(); - - if (this.t == null) { - write.lock(); - this.t = t.get(); - - time.lock(); - - if (a == -1) { - a = M.ms(); - } - - time.unlock(); - write.unlock(); + catch(Throwable e) + { + Iris.error("Atomic cache failure!"); + e.printStackTrace(); } - check.unlock(); - return this.t; - } + lock.unlock(); - public T aquireNull(Supplier t) { - if (validations > 1000) { - return this.t; - } - - if (M.ms() - a > 1000) { - //noinspection NonAtomicOperationOnVolatileField - validations++; - return this.t; - } - - check.lock(); - write.lock(); - this.t = t.get(); - - time.lock(); - - if (a == -1) { - a = M.ms(); - } - - time.unlock(); - write.unlock(); - check.unlock(); - return this.t; + return t.get(); } } diff --git a/src/main/java/com/volmit/iris/engine/object/biome/IrisBiome.java b/src/main/java/com/volmit/iris/engine/object/biome/IrisBiome.java index e086f36cd..c54c01a09 100644 --- a/src/main/java/com/volmit/iris/engine/object/biome/IrisBiome.java +++ b/src/main/java/com/volmit/iris/engine/object/biome/IrisBiome.java @@ -198,8 +198,8 @@ public class IrisBiome extends IrisRegistrant implements IRare { private final transient AtomicCache> genCache = new AtomicCache<>(); private final transient AtomicCache> genCacheMax = new AtomicCache<>(); private final transient AtomicCache> genCacheMin = new AtomicCache<>(); - private final transient AtomicCache> surfaceObjectsCache = new AtomicCache<>(false); - private final transient AtomicCache> carveObjectsCache = new AtomicCache<>(false); + private final transient AtomicCache> surfaceObjectsCache = new AtomicCache<>(); + private final transient AtomicCache> carveObjectsCache = new AtomicCache<>(); private final transient AtomicCache cacheColor = new AtomicCache<>(); private final transient AtomicCache cacheColorObjectDensity = new AtomicCache<>(); private final transient AtomicCache cacheColorDecoratorLoad = new AtomicCache<>(); diff --git a/src/main/java/com/volmit/iris/engine/object/common/HeadlessWorld.java b/src/main/java/com/volmit/iris/engine/object/common/HeadlessWorld.java index d5629b3c0..913c3689d 100644 --- a/src/main/java/com/volmit/iris/engine/object/common/HeadlessWorld.java +++ b/src/main/java/com/volmit/iris/engine/object/common/HeadlessWorld.java @@ -22,6 +22,7 @@ import com.volmit.iris.Iris; import com.volmit.iris.core.project.loader.IrisData; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.tools.IrisToolbelt; +import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.dimensional.IrisDimension; import com.volmit.iris.engine.platform.BukkitChunkGenerator; import com.volmit.iris.engine.platform.HeadlessGenerator; @@ -65,8 +66,24 @@ public class HeadlessWorld { } } + @SuppressWarnings("ConstantConditions") public HeadlessGenerator generate() { - return new HeadlessGenerator(this); + Engine e = null; + + if(getWorld().tryGetRealWorld()) + { + if(IrisToolbelt.isIrisWorld(getWorld().realWorld())) + { + e = IrisToolbelt.access(getWorld().realWorld()).getEngine(); + } + } + + if(e != null) + { + Iris.info("Using Existing Engine " + getWorld().name() + " for Headless Pregeneration."); + } + + return e != null ? new HeadlessGenerator(this, e) : new HeadlessGenerator(this); } public World load() { @@ -81,7 +98,8 @@ public class HeadlessWorld { } public static HeadlessWorld from(World world) { - return new HeadlessWorld(world.getName(), IrisToolbelt.access(world).getEngine().getTarget().getDimension(), world.getSeed()); + return new HeadlessWorld(world.getName(), IrisToolbelt.access(world) + .getEngine().getTarget().getDimension(), world.getSeed()); } public static HeadlessWorld from(String name, String dimension, long seed) { diff --git a/src/main/java/com/volmit/iris/engine/object/common/IrisWorld.java b/src/main/java/com/volmit/iris/engine/object/common/IrisWorld.java index 2066ca736..7ba56f9c6 100644 --- a/src/main/java/com/volmit/iris/engine/object/common/IrisWorld.java +++ b/src/main/java/com/volmit/iris/engine/object/common/IrisWorld.java @@ -24,6 +24,7 @@ import com.volmit.iris.util.collection.KList; import lombok.Builder; import lombok.Data; import lombok.experimental.Accessors; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Entity; @@ -61,6 +62,24 @@ public class IrisWorld { .environment(world.getEnvironment()); } + public boolean tryGetRealWorld() + { + if(hasRealWorld()) + { + return true; + } + + World w = Bukkit.getWorld(name); + + if(w != null) + { + realWorld = w; + return true; + } + + return false; + } + public boolean hasRealWorld() { return realWorld != null; } diff --git a/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index 36421379e..00de5822d 100644 --- a/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -176,6 +176,8 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun @Override public @NotNull ChunkData generateChunkData(@NotNull World world, @NotNull Random ignored, int x, int z, @NotNull BiomeGrid biome) { + + try { if(lastSeed != world.getSeed()) { diff --git a/src/main/java/com/volmit/iris/engine/platform/HeadlessGenerator.java b/src/main/java/com/volmit/iris/engine/platform/HeadlessGenerator.java index 82bd57971..239e96d05 100644 --- a/src/main/java/com/volmit/iris/engine/platform/HeadlessGenerator.java +++ b/src/main/java/com/volmit/iris/engine/platform/HeadlessGenerator.java @@ -24,16 +24,20 @@ import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.pregenerator.PregenListener; import com.volmit.iris.core.pregenerator.PregenTask; import com.volmit.iris.engine.IrisEngine; +import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.data.chunk.MCATerrainChunk; 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.framework.WrongEngineBroException; import com.volmit.iris.engine.object.common.HeadlessWorld; import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.RegionCoordinates; import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.math.Position2; +import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.nbt.mca.MCAFile; import com.volmit.iris.util.nbt.mca.MCAUtil; import com.volmit.iris.util.nbt.mca.NBTWorld; @@ -56,12 +60,17 @@ public class HeadlessGenerator implements PlatformChunkGenerator { private final NBTWorld writer; private final MultiBurst burst; private final Engine engine; + private final long rkey = RNG.r.lmax(); public HeadlessGenerator(HeadlessWorld world) { + this(world, new IrisEngine(new EngineTarget(world.getWorld(), world.getDimension(), world.getDimension().getLoader()), world.isStudio())); + } + + public HeadlessGenerator(HeadlessWorld world, Engine engine) { + this.engine = engine; this.world = world; burst = MultiBurst.burst; writer = new NBTWorld(world.getWorld().worldFolder()); - engine = new IrisEngine(new EngineTarget(world.getWorld(), world.getDimension(), world.getDimension().getLoader()), isStudio()); } @ChunkCoordinates @@ -79,6 +88,7 @@ public class HeadlessGenerator implements PlatformChunkGenerator { getEngine().generate(x * 16, z * 16, Hunk.view((ChunkGenerator.ChunkData) tc), Hunk.view((ChunkGenerator.BiomeGrid) tc), false); + chunk.cleanupPalettesAndBlockStates(); } catch (Throwable e) { Iris.error("======================================"); e.printStackTrace(); @@ -102,7 +112,7 @@ public class HeadlessGenerator implements PlatformChunkGenerator { @RegionCoordinates public void generateRegion(int x, int z, PregenListener listener) { BurstExecutor e = burst.burst(1024); - MCAFile f = writer.getMCA(x, x); + MCAFile f = writer.getMCA(x, z); PregenTask.iterateRegion(x, z, (ii, jj) -> e.queue(() -> { if (listener != null) { listener.onChunkGenerating(ii, jj); @@ -132,7 +142,6 @@ public class HeadlessGenerator implements PlatformChunkGenerator { } public void close() { - getEngine().close(); writer.close(); } diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/NBTWorld.java b/src/main/java/com/volmit/iris/util/nbt/mca/NBTWorld.java index a2b858f86..cc76ab1e2 100644 --- a/src/main/java/com/volmit/iris/util/nbt/mca/NBTWorld.java +++ b/src/main/java/com/volmit/iris/util/nbt/mca/NBTWorld.java @@ -28,21 +28,49 @@ import com.volmit.iris.util.math.M; import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.nbt.tag.StringTag; import com.volmit.iris.util.parallel.HyperLock; -import com.volmit.iris.util.scheduling.IrisLock; import org.bukkit.NamespacedKey; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; +import javax.management.RuntimeErrorException; import java.io.File; import java.io.IOException; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.function.Function; public class NBTWorld { private static final BlockData AIR = B.get("AIR"); - private static final Map blockDataCache = new KMap<>(); + private static final Map blockDataCache = new KMap<>(); + private static final Function BLOCK_DATA_COMPUTE = (blockData) -> { + CompoundTag s = new CompoundTag(); + String data = blockData.getAsString(true); + 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(); + if (raw.contains(",")) { + for (String i : raw.split("\\Q,\\E")) { + String[] m = i.split("\\Q=\\E"); + String k = m[0]; + String v = m[1]; + props.put(k, new StringTag(v)); + } + } else { + String[] m = raw.split("\\Q=\\E"); + String k = m[0]; + String v = m[1]; + props.put(k, new StringTag(v)); + } + s.put("Properties", props); + } + + return s; + }; private static final Map biomeIds = computeBiomeIDs(); private final KMap loadedRegions; private final HyperLock hyperLock = new HyperLock(); @@ -184,38 +212,8 @@ public class NBTWorld { return b; } - public static CompoundTag getCompound(BlockData blockData) { - String data = blockData.getAsString(true); - - if (blockDataCache.containsKey(data)) { - return blockDataCache.get(data).clone(); - } - - CompoundTag s = new CompoundTag(); - 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(); - if (raw.contains(",")) { - for (String i : raw.split("\\Q,\\E")) { - String[] m = i.split("\\Q=\\E"); - String k = m[0]; - String v = m[1]; - props.put(k, new StringTag(v)); - } - } else { - String[] m = raw.split("\\Q=\\E"); - String k = m[0]; - String v = m[1]; - props.put(k, new StringTag(v)); - } - s.put("Properties", props); - } - - blockDataCache.put(data, s.clone()); - return s; + public static CompoundTag getCompound(BlockData bd) { + return blockDataCache.computeIfAbsent(bd, BLOCK_DATA_COMPUTE).clone(); } public BlockData getBlockData(int x, int y, int z) { @@ -275,6 +273,13 @@ public class NBTWorld { return c; } + public Chunk getNewChunk(MCAFile mca, int x, int z) { + Chunk c = Chunk.newChunk(); + mca.setChunk(x & 31, z & 31, c); + + return c; + } + public long getIdleDuration(int x, int z) { return hyperLock.withResult(x, z, () -> { Long l = lastUse.get(Cache.key(x, z)); diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/Section.java b/src/main/java/com/volmit/iris/util/nbt/mca/Section.java index 9123f999f..ec6df11f1 100644 --- a/src/main/java/com/volmit/iris/util/nbt/mca/Section.java +++ b/src/main/java/com/volmit/iris/util/nbt/mca/Section.java @@ -25,6 +25,7 @@ import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.nbt.tag.ListTag; import com.volmit.iris.util.nbt.tag.LongArrayTag; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import net.minecraft.world.level.chunk.DataPaletteGlobal; import java.util.ArrayList; import java.util.HashMap; @@ -148,7 +149,7 @@ public class Section { * @param blockZ The z-coordinate of the block in this Section * @return The block state data of this block. */ - public CompoundTag getBlockStateAt(int blockX, int blockY, int blockZ) { + public synchronized CompoundTag getBlockStateAt(int blockX, int blockY, int blockZ) { try { int index = getBlockIndex(blockX, blockY, blockZ); int paletteIndex = getPaletteIndex(index); @@ -172,7 +173,7 @@ public class Section { * This option should only be used moderately to avoid unnecessary recalculation of the palette indices. * Recalculating the Palette should only be executed once right before saving the Section to file. */ - public void setBlockStateAt(int blockX, int blockY, int blockZ, CompoundTag state, boolean cleanup) { + public synchronized void setBlockStateAt(int blockX, int blockY, int blockZ, CompoundTag state, boolean cleanup) { int paletteIndex = addToPalette(state); int paletteSizeBefore = palette.size(); //power of 2 --> bits must increase, but only if the palette size changed @@ -184,7 +185,6 @@ public class Section { } setPaletteIndex(getBlockIndex(blockX, blockY, blockZ), paletteIndex, blockStates); - if (cleanup) { cleanupPaletteAndBlockStates(); } @@ -196,7 +196,7 @@ public class Section { * @param blockStateIndex The index of the block in this section, ranging from 0-4095. * @return The index of the block data in the palette. */ - public int getPaletteIndex(int blockStateIndex) { + public synchronized int getPaletteIndex(int blockStateIndex) { int bits = blockStates.length() >> 6; if (dataVersion < 2527) { @@ -251,7 +251,7 @@ public class Section { * * @return The palette of this Section. */ - public ListTag getPalette() { + public synchronized ListTag getPalette() { return palette; } @@ -367,7 +367,7 @@ public class Section { /** * @return The indices of the block states of this Section. */ - public AtomicLongArray getBlockStates() { + public synchronized AtomicLongArray getBlockStates() { return blockStates; } @@ -431,7 +431,7 @@ public class Section { * @param y The Y-value of this Section * @return A reference to the raw CompoundTag this Section is based on */ - public CompoundTag updateHandle(int y) { + public synchronized CompoundTag updateHandle(int y) { data.putByte("Y", (byte) y); if (palette != null) { data.put("Palette", palette);