From 9d62113388ca015290c5f11637b960fd6533f291 Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Mon, 23 Aug 2021 03:12:17 -0400 Subject: [PATCH] Performance Improvements --- build.gradle | 2 +- .../com/volmit/iris/core/IrisSettings.java | 14 +- .../methods/AsyncPregenMethod.java | 2 +- .../methods/MedievalPregenMethod.java | 2 +- .../volmit/iris/core/tools/IrisToolbelt.java | 4 +- .../com/volmit/iris/engine/IrisEngine.java | 6 +- .../engine/data/chunk/MCATerrainChunk.java | 8 +- .../iris/engine/mantle/EngineMantle.java | 9 +- .../iris/engine/mantle/MantleComponent.java | 2 +- .../iris/engine/mantle/MantleWriter.java | 149 ++++++++++++++++++ .../components/MantleFeatureComponent.java | 17 +- .../components/MantleJigsawComponent.java | 24 ++- .../components/MantleObjectComponent.java | 21 +-- .../engine/platform/HeadlessGenerator.java | 9 +- .../com/volmit/iris/util/mantle/Mantle.java | 20 +++ .../com/volmit/iris/util/matter/Matter.java | 12 +- .../com/volmit/iris/util/nbt/mca/Chunk.java | 6 +- .../volmit/iris/util/nbt/mca/NBTWorld.java | 71 ++++----- .../com/volmit/iris/util/nbt/mca/Section.java | 17 +- .../volmit/iris/util/parallel/MultiBurst.java | 3 +- 20 files changed, 292 insertions(+), 106 deletions(-) create mode 100644 src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java diff --git a/build.gradle b/build.gradle index f3c953e31..1b677aafb 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ plugins { } group 'com.volmit.iris' -version '1.7.6' +version '1.7.7' def apiVersion = '1.17' def name = getRootProject().getName() // See settings.gradle def main = 'com.volmit.iris.Iris' diff --git a/src/main/java/com/volmit/iris/core/IrisSettings.java b/src/main/java/com/volmit/iris/core/IrisSettings.java index b69ec5b6c..7025af4e3 100644 --- a/src/main/java/com/volmit/iris/core/IrisSettings.java +++ b/src/main/java/com/volmit/iris/core/IrisSettings.java @@ -20,6 +20,7 @@ package com.volmit.iris.core; import com.google.gson.Gson; import com.volmit.iris.Iris; +import com.volmit.iris.engine.object.basic.IrisRange; import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.io.IO; import com.volmit.iris.util.json.JSONException; @@ -56,6 +57,11 @@ public class IrisSettings { return getParallax().getParallaxRegionEvictionMS(); } + public static int getPriority(int c) + { + return Math.max(Math.min(c, Thread.MAX_PRIORITY), Thread.MIN_PRIORITY); + } + public static int getThreadCount(int c) { if (c < 2 && c >= 0) { return 2; @@ -82,13 +88,7 @@ public class IrisSettings { @Data public static class IrisSettingsConcurrency { - public int engineThreadCount = -1; - public int engineThreadPriority = 6; - public int pregenThreadCount = -1; - public int pregenThreadPriority = 8; - public int miscThreadCount = -4; - public int miscThreadPriority = 3; - public boolean unstableLockingHeuristics = false; + public int parallelism = -1; } @Data diff --git a/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java b/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java index 64a1fbe53..c3f8c7169 100644 --- a/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java +++ b/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java @@ -114,7 +114,7 @@ public class AsyncPregenMethod implements PregeneratorMethod { @Override public void generateChunk(int x, int z, PregenListener listener) { - if (future.size() > IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount())) { + if (future.size() > IrisSettings.getThreadCount((int) IrisSettings.get().getConcurrency().getParallelism())) { // TODO: FIX waitForChunks(); } diff --git a/src/main/java/com/volmit/iris/core/pregenerator/methods/MedievalPregenMethod.java b/src/main/java/com/volmit/iris/core/pregenerator/methods/MedievalPregenMethod.java index 6a378f786..d796ce182 100644 --- a/src/main/java/com/volmit/iris/core/pregenerator/methods/MedievalPregenMethod.java +++ b/src/main/java/com/volmit/iris/core/pregenerator/methods/MedievalPregenMethod.java @@ -95,7 +95,7 @@ public class MedievalPregenMethod implements PregeneratorMethod { @Override public void generateChunk(int x, int z, PregenListener listener) { - if (futures.size() > IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount())) { + if (futures.size() > IrisSettings.getThreadCount((int) IrisSettings.get().getConcurrency().getParallelism())) { waitForChunks(); } 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 8277f117b..dfb0ca4b0 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,7 @@ public class IrisToolbelt { return pregenerate(task, new HeadlessPregenMethod(((HeadlessGenerator) gen).getWorld(), (HeadlessGenerator) gen)); } - return pregenerate(task, new HybridPregenMethod(gen.getEngine().getWorld().realWorld(), IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount()))); + return pregenerate(task, new HybridPregenMethod(gen.getEngine().getWorld().realWorld(), IrisSettings.getThreadCount((int) IrisSettings.get().getConcurrency().getParallelism()))); } /** @@ -144,7 +144,7 @@ public class IrisToolbelt { return pregenerate(task, access(world)); } - return pregenerate(task, new HybridPregenMethod(world, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount()))); + return pregenerate(task, new HybridPregenMethod(world, 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 69584183b..d2a5cd90a 100644 --- a/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -48,6 +48,7 @@ import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.io.IO; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.math.RollingSequence; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.PrecisionStopwatch; @@ -408,8 +409,8 @@ public class IrisEngine extends BlockPopulator implements Engine { 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) @@ -420,12 +421,11 @@ public class IrisEngine extends BlockPopulator implements Engine { () -> getRavineModifier().modify(x, z, vblocks, multicore) ); - getDecorantActuator().actuate(x, z, blocks, multicore); getPostModifier().modify(x, z, vblocks, multicore); burst().burst(multicore, () -> getMantle().insertMatter(x >> 4, z >> 4, BlockData.class, blocks, multicore), - () -> getDepositModifier().modify(x, z, blocks, multicore) + () -> getDepositModifier().modify(x, z, vblocks, multicore) ); getMetrics().getTotal().put(p.getMilliseconds()); diff --git a/src/main/java/com/volmit/iris/engine/data/chunk/MCATerrainChunk.java b/src/main/java/com/volmit/iris/engine/data/chunk/MCATerrainChunk.java index 523bb88c0..c09941c07 100644 --- a/src/main/java/com/volmit/iris/engine/data/chunk/MCATerrainChunk.java +++ b/src/main/java/com/volmit/iris/engine/data/chunk/MCATerrainChunk.java @@ -18,6 +18,7 @@ package com.volmit.iris.engine.data.chunk; +import com.volmit.iris.Iris; import com.volmit.iris.core.nms.BiomeBaseInjector; import com.volmit.iris.util.nbt.mca.Chunk; import com.volmit.iris.util.nbt.mca.NBTWorld; @@ -69,7 +70,7 @@ public class MCATerrainChunk implements TerrainChunk { @Override public void setBiome(int x, int y, int z, Biome bio) { - writer.setBiome(ox + x, y, oz + z, bio); + mcaChunk.setBiomeAt((ox + x) & 15, y, (oz + z) & 15, writer.getBiomeId(bio)); } @Override @@ -91,6 +92,11 @@ public class MCATerrainChunk implements TerrainChunk { return; } + if(blockData == null) + { + Iris.error("NULL BD"); + } + mcaChunk.setBlockStateAt(xx, y, zz, NBTWorld.getCompound(blockData), false); } diff --git a/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java b/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java index cd7a8d7be..597012502 100644 --- a/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java +++ b/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java @@ -37,6 +37,7 @@ import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.noise.CNG; import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.MultiBurst; +import com.volmit.iris.util.scheduling.PrecisionStopwatch; import org.bukkit.Chunk; import org.bukkit.block.TileState; import org.bukkit.block.data.BlockData; @@ -187,13 +188,13 @@ public interface EngineMantle extends IObjectPlacer { }; int s = getRealRadius(); BurstExecutor burst = burst().burst(multicore); - + MantleWriter writer = getMantle().write(this, x, z, s * 2); for (int i = -s; i <= s; i++) { for (int j = -s; j <= s; j++) { int xx = i + x; int zz = j + z; burst.queue(() -> { - getComponents().forEach((f) -> generateMantleComponent(xx, zz, f, c)); + getComponents().forEach((f) -> generateMantleComponent(writer, xx, zz, f, c)); }); } } @@ -208,8 +209,8 @@ public interface EngineMantle extends IObjectPlacer { } } - default void generateMantleComponent(int x, int z, MantleComponent c, Consumer post) { - getMantle().raiseFlag(x, z, c.getFlag(), () -> c.generateLayer(x, z, post)); + default void generateMantleComponent(MantleWriter writer, int x, int z, MantleComponent c, Consumer post) { + getMantle().raiseFlag(x, z, c.getFlag(), () -> c.generateLayer(writer, x, z, post)); } @ChunkCoordinates diff --git a/src/main/java/com/volmit/iris/engine/mantle/MantleComponent.java b/src/main/java/com/volmit/iris/engine/mantle/MantleComponent.java index d2755f897..7a7444250 100644 --- a/src/main/java/com/volmit/iris/engine/mantle/MantleComponent.java +++ b/src/main/java/com/volmit/iris/engine/mantle/MantleComponent.java @@ -62,5 +62,5 @@ public interface MantleComponent { MantleFlag getFlag(); @ChunkCoordinates - void generateLayer(int x, int z, Consumer post); + void generateLayer(MantleWriter writer, int x, int z, Consumer post); } diff --git a/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java b/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java new file mode 100644 index 000000000..c304c7e5d --- /dev/null +++ b/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java @@ -0,0 +1,149 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 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.mantle; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.project.loader.IrisData; +import com.volmit.iris.engine.IrisEngineMantle; +import com.volmit.iris.engine.data.cache.Cache; +import com.volmit.iris.engine.object.common.IObjectPlacer; +import com.volmit.iris.engine.object.feature.IrisFeaturePositional; +import com.volmit.iris.engine.object.tile.TileData; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.mantle.Mantle; +import com.volmit.iris.util.mantle.MantleChunk; +import com.volmit.iris.util.matter.Matter; +import lombok.Data; +import org.bukkit.block.TileState; +import org.bukkit.block.data.BlockData; + +@Data +public class MantleWriter implements IObjectPlacer +{ + private final EngineMantle engineMantle; + private final Mantle mantle; + private final KMap cachedChunks; + private final int radius; + private final int x; + private final int z; + + public MantleWriter(EngineMantle engineMantle, Mantle mantle, int x, int z, int radius) + { + this.engineMantle = engineMantle; + this.mantle = mantle; + this.cachedChunks = new KMap<>(); + this.radius = radius; + this.x = x; + this.z = z; + + for (int i = -radius; i <= radius; i++) { + for (int j = -radius; j <= radius; j++) { + cachedChunks.put(Cache.key(i + x, j + z), mantle.getChunk(i + x, j + z)); + } + } + } + + public void setData(int x, int y, int z, T t) + { + int cx = x >> 4; + int cz = z >> 4; + + if (y < 0 || y >= mantle.getWorldHeight()) { + return; + } + + if(cx >= this.x - radius && cx <= this.x + radius + && cz >= this.z - radius && cz <= this.z + radius) + { + MantleChunk chunk = cachedChunks.get(Cache.key(cx, cz)); + + if(chunk == null) + { + Iris.error("Mantle Writer Accessed " + cx + "," + cz + " and came up null (and yet within bounds!)"); + return; + } + + if(t instanceof IrisFeaturePositional) + { + chunk.addFeature((IrisFeaturePositional) t); + } + + else + { + Matter matter = chunk.getOrCreate(y >> 4); + matter.slice(matter.getClass(t)).set(x & 15, y & 15, z & 15, t); + } + } + + else + { + Iris.error("Mantle Writer[" + this.x + "," + this.z + ",R" + this.radius + "] Tried to access " + x + "," + y + "," + z + " (Chunk " + cx + "," + cz + ") which is OUT OF BOUNDS!"); + } + } + + @Override + public int getHighest(int x, int z, IrisData data) { + return engineMantle.getHighest(x, z, data); + } + + @Override + public int getHighest(int x, int z, IrisData data, boolean ignoreFluid) { + return engineMantle.getHighest(x, z, data, ignoreFluid); + } + + @Override + public void set(int x, int y, int z, BlockData d) { + setData(x, y, z, d); + } + + @Override + public BlockData get(int x, int y, int z) { + return getEngineMantle().get(x, y, z); + } + + @Override + public boolean isPreventingDecay() { + return getEngineMantle().isPreventingDecay(); + } + + @Override + public boolean isSolid(int x, int y, int z) { + return getEngineMantle().isSolid(x, y, z); + } + + @Override + public boolean isUnderwater(int x, int z) { + return getEngineMantle().isUnderwater(x, z); + } + + @Override + public int getFluidHeight() { + return getEngineMantle().getFluidHeight(); + } + + @Override + public boolean isDebugSmartBore() { + return getEngineMantle().isDebugSmartBore(); + } + + @Override + public void setTile(int xx, int yy, int zz, TileData tile) { + getEngineMantle().setTile(xx,yy,zz,tile); + } +} diff --git a/src/main/java/com/volmit/iris/engine/mantle/components/MantleFeatureComponent.java b/src/main/java/com/volmit/iris/engine/mantle/components/MantleFeatureComponent.java index 098e76ca8..eb7f29da5 100644 --- a/src/main/java/com/volmit/iris/engine/mantle/components/MantleFeatureComponent.java +++ b/src/main/java/com/volmit/iris/engine/mantle/components/MantleFeatureComponent.java @@ -21,6 +21,7 @@ package com.volmit.iris.engine.mantle.components; import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.mantle.EngineMantle; import com.volmit.iris.engine.mantle.IrisMantleComponent; +import com.volmit.iris.engine.mantle.MantleWriter; import com.volmit.iris.engine.object.biome.IrisBiome; import com.volmit.iris.engine.object.feature.IrisFeaturePositional; import com.volmit.iris.engine.object.feature.IrisFeaturePotential; @@ -38,34 +39,34 @@ public class MantleFeatureComponent extends IrisMantleComponent { } @Override - public void generateLayer(int x, int z, Consumer post) { + public void generateLayer(MantleWriter writer, int x, int z, Consumer post) { RNG rng = new RNG(Cache.key(x, z) + seed()); int xxx = 8 + (x << 4); int zzz = 8 + (z << 4); IrisRegion region = getComplex().getRegionStream().get(xxx, zzz); IrisBiome biome = getComplex().getTrueBiomeStreamNoFeatures().get(xxx, zzz); - generateFeatures(rng, x, z, region, biome); + generateFeatures(writer, rng, x, z, region, biome); } @ChunkCoordinates - private void generateFeatures(RNG rng, int cx, int cz, IrisRegion region, IrisBiome biome) { + private void generateFeatures(MantleWriter writer, RNG rng, int cx, int cz, IrisRegion region, IrisBiome biome) { for (IrisFeaturePotential i : getFeatures()) { - placeZone(rng, cx, cz, i); + placeZone(writer, rng, cx, cz, i); } for (IrisFeaturePotential i : region.getFeatures()) { - placeZone(rng, cx, cz, i); + placeZone(writer, rng, cx, cz, i); } for (IrisFeaturePotential i : biome.getFeatures()) { - placeZone(rng, cx, cz, i); + placeZone(writer, rng, cx, cz, i); } } - private void placeZone(RNG rng, int cx, int cz, IrisFeaturePotential i) { + private void placeZone(MantleWriter writer, RNG rng, int cx, int cz, IrisFeaturePotential i) { int x = (cx << 4) + rng.nextInt(16); int z = (cz << 4) + rng.nextInt(16); - getMantle().set(x, 0, z, new IrisFeaturePositional(x, z, i.getZone())); + writer.setData(x, 0, z, new IrisFeaturePositional(x, z, i.getZone())); } private KList getFeatures() { diff --git a/src/main/java/com/volmit/iris/engine/mantle/components/MantleJigsawComponent.java b/src/main/java/com/volmit/iris/engine/mantle/components/MantleJigsawComponent.java index b93907542..2a946c845 100644 --- a/src/main/java/com/volmit/iris/engine/mantle/components/MantleJigsawComponent.java +++ b/src/main/java/com/volmit/iris/engine/mantle/components/MantleJigsawComponent.java @@ -18,12 +18,10 @@ package com.volmit.iris.engine.mantle.components; -import com.google.gson.Gson; -import com.volmit.iris.Iris; -import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.jigsaw.PlannedStructure; import com.volmit.iris.engine.mantle.EngineMantle; import com.volmit.iris.engine.mantle.IrisMantleComponent; +import com.volmit.iris.engine.mantle.MantleWriter; import com.volmit.iris.engine.object.basic.IrisPosition; import com.volmit.iris.engine.object.biome.IrisBiome; import com.volmit.iris.engine.object.feature.IrisFeaturePositional; @@ -50,17 +48,17 @@ public class MantleJigsawComponent extends IrisMantleComponent { } @Override - public void generateLayer(int x, int z, Consumer post) { + public void generateLayer(MantleWriter writer, int x, int z, Consumer post) { RNG rng = new RNG(cng.fit(-Integer.MAX_VALUE, Integer.MAX_VALUE, x, z)); int xxx = 8 + (x << 4); int zzz = 8 + (z << 4); IrisRegion region = getComplex().getRegionStream().get(xxx, zzz); IrisBiome biome = getComplex().getTrueBiomeStreamNoFeatures().get(xxx, zzz); - generateJigsaw(rng, x, z, biome, region, post); + generateJigsaw(writer, rng, x, z, biome, region, post); } @ChunkCoordinates - private void generateJigsaw(RNG rng, int x, int z, IrisBiome biome, IrisRegion region, Consumer post) { + private void generateJigsaw(MantleWriter writer, RNG rng, int x, int z, IrisBiome biome, IrisRegion region, Consumer post) { boolean placed = false; if (getDimension().getStronghold() != null) { @@ -70,7 +68,7 @@ public class MantleJigsawComponent extends IrisMantleComponent { for (Position2 pos : poss) { if (x == pos.getX() >> 4 && z == pos.getZ() >> 4) { IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(getDimension().getStronghold()); - place(pos.toIris(), structure, rng, post); + place(writer, pos.toIris(), structure, rng, post); placed = true; } } @@ -82,7 +80,7 @@ public class MantleJigsawComponent extends IrisMantleComponent { if (rng.nextInt(i.getRarity()) == 0) { IrisPosition position = new IrisPosition((x << 4) + rng.nextInt(15), 0, (z << 4) + rng.nextInt(15)); IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(i.getStructure()); - place(position, structure, rng, post); + place(writer, position, structure, rng, post); placed = true; } } @@ -93,7 +91,7 @@ public class MantleJigsawComponent extends IrisMantleComponent { if (rng.nextInt(i.getRarity()) == 0) { IrisPosition position = new IrisPosition((x << 4) + rng.nextInt(15), 0, (z << 4) + rng.nextInt(15)); IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(i.getStructure()); - place(position, structure, rng, post); + place(writer, position, structure, rng, post); placed = true; } } @@ -104,22 +102,22 @@ public class MantleJigsawComponent extends IrisMantleComponent { if (rng.nextInt(i.getRarity()) == 0) { IrisPosition position = new IrisPosition((x << 4) + rng.nextInt(15), 0, (z << 4) + rng.nextInt(15)); IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(i.getStructure()); - place(position, structure, rng, post); + place(writer, position, structure, rng, post); } } } } @BlockCoordinates - private void place(IrisPosition position, IrisJigsawStructure structure, RNG rng, Consumer post) { + private void place(MantleWriter writer, IrisPosition position, IrisJigsawStructure structure, RNG rng, Consumer post) { if (structure.getFeature() != null) { if (structure.getFeature().getBlockRadius() == 32) { structure.getFeature().setBlockRadius((double) structure.getMaxDimension() / 3); } - getMantle().set(position.getX(), 0, position.getZ(), + writer.setData(position.getX(), 0, position.getZ(), new IrisFeaturePositional(position.getX(), position.getZ(), structure.getFeature())); } - post.accept(() -> new PlannedStructure(structure, position, rng).place(getEngineMantle(), getMantle(), post)); + post.accept(() -> new PlannedStructure(structure, position, rng).place(writer, getMantle(), post)); } } diff --git a/src/main/java/com/volmit/iris/engine/mantle/components/MantleObjectComponent.java b/src/main/java/com/volmit/iris/engine/mantle/components/MantleObjectComponent.java index b0eb8b7b2..13f32ca9b 100644 --- a/src/main/java/com/volmit/iris/engine/mantle/components/MantleObjectComponent.java +++ b/src/main/java/com/volmit/iris/engine/mantle/components/MantleObjectComponent.java @@ -22,6 +22,7 @@ import com.volmit.iris.Iris; import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.mantle.EngineMantle; import com.volmit.iris.engine.mantle.IrisMantleComponent; +import com.volmit.iris.engine.mantle.MantleWriter; import com.volmit.iris.engine.object.biome.IrisBiome; import com.volmit.iris.engine.object.feature.IrisFeature; import com.volmit.iris.engine.object.feature.IrisFeaturePositional; @@ -42,21 +43,21 @@ public class MantleObjectComponent extends IrisMantleComponent { } @Override - public void generateLayer(int x, int z, Consumer post) { + public void generateLayer(MantleWriter writer, int x, int z, Consumer post) { RNG rng = new RNG(Cache.key(x, z) + seed()); int xxx = 8 + (x << 4); int zzz = 8 + (z << 4); IrisRegion region = getComplex().getRegionStream().get(xxx, zzz); IrisBiome biome = getComplex().getTrueBiomeStreamNoFeatures().get(xxx, zzz); - placeObjects(rng, x, z, biome, region, post); + placeObjects(writer, rng, x, z, biome, region, post); } @ChunkCoordinates - private void placeObjects(RNG rng, int x, int z, IrisBiome biome, IrisRegion region, Consumer post) { + private void placeObjects(MantleWriter writer, RNG rng, int x, int z, IrisBiome biome, IrisRegion region, Consumer post) { for (IrisObjectPlacement i : biome.getSurfaceObjects()) { if (rng.chance(i.getChance() + rng.d(-0.005, 0.005)) && rng.chance(getComplex().getObjectChanceStream().get(x << 4, z << 4))) { try { - placeObject(rng, x << 4, z << 4, i, post); + placeObject(writer, rng, x << 4, z << 4, i, post); } catch (Throwable e) { Iris.reportError(e); Iris.error("Failed to place objects in the following biome: " + biome.getName()); @@ -70,7 +71,7 @@ public class MantleObjectComponent extends IrisMantleComponent { for (IrisObjectPlacement i : region.getSurfaceObjects()) { if (rng.chance(i.getChance() + rng.d(-0.005, 0.005)) && rng.chance(getComplex().getObjectChanceStream().get(x << 4, z << 4))) { try { - placeObject(rng, x << 4, z << 4, i, post); + placeObject(writer, rng, x << 4, z << 4, i, post); } catch (Throwable e) { Iris.reportError(e); Iris.error("Failed to place objects in the following region: " + region.getName()); @@ -83,7 +84,7 @@ public class MantleObjectComponent extends IrisMantleComponent { } @BlockCoordinates - private void placeObject(RNG rng, int x, int z, IrisObjectPlacement objectPlacement, Consumer post) { + private void placeObject(MantleWriter writer, RNG rng, int x, int z, IrisObjectPlacement objectPlacement, Consumer post) { for (int i = 0; i < objectPlacement.getDensity(); i++) { IrisObject v = objectPlacement.getScale().get(rng, objectPlacement.getObject(getComplex(), rng)); if (v == null) { @@ -94,8 +95,8 @@ public class MantleObjectComponent extends IrisMantleComponent { int id = rng.i(0, Integer.MAX_VALUE); Runnable r = () -> { - int h = v.place(xx, -1, zz, getEngineMantle(), objectPlacement, rng, - (b) -> getMantle().set(b.getX(), b.getY(), b.getZ(), + int h = v.place(xx, -1, zz, writer, objectPlacement, rng, + (b) -> writer.setData(b.getX(), b.getY(), b.getZ(), v.getLoadKey() + "@" + id), null, getData()); if (objectPlacement.usesFeatures()) { @@ -108,12 +109,12 @@ public class MantleObjectComponent extends IrisMantleComponent { f.setInterpolationRadius(objectPlacement.getVacuumInterpolationRadius()); f.setInterpolator(objectPlacement.getVacuumInterpolationMethod()); f.setStrength(1D); - getMantle().set(xx, 0, zz, new IrisFeaturePositional(xx, zz, f)); + writer.setData(xx, 0, zz, new IrisFeaturePositional(xx, zz, f)); } for (IrisFeaturePotential j : objectPlacement.getAddFeatures()) { if (j.hasZone(rng, xx >> 4, zz >> 4)) { - getMantle().set(xx, 0, zz, new IrisFeaturePositional(xx, zz, j.getZone())); + writer.setData(xx, 0, zz, new IrisFeaturePositional(xx, zz, j.getZone())); } } } 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 4def637ca..82bd57971 100644 --- a/src/main/java/com/volmit/iris/engine/platform/HeadlessGenerator.java +++ b/src/main/java/com/volmit/iris/engine/platform/HeadlessGenerator.java @@ -34,6 +34,7 @@ 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.nbt.mca.MCAFile; import com.volmit.iris.util.nbt.mca.MCAUtil; import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.tag.CompoundTag; @@ -64,12 +65,11 @@ public class HeadlessGenerator implements PlatformChunkGenerator { } @ChunkCoordinates - public void generateChunk(int x, int z) { + public void generateChunk(MCAFile file, int x, int z) { try { int ox = x << 4; int oz = z << 4; - com.volmit.iris.util.nbt.mca.Chunk chunk = writer.getChunk(x, z); - + com.volmit.iris.util.nbt.mca.Chunk chunk = writer.getChunk(file, x, z); TerrainChunk tc = MCATerrainChunk.builder() .writer(writer).ox(ox).oz(oz).mcaChunk(chunk) .minHeight(world.getWorld().minHeight()).maxHeight(world.getWorld().maxHeight()) @@ -102,11 +102,12 @@ 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); PregenTask.iterateRegion(x, z, (ii, jj) -> e.queue(() -> { if (listener != null) { listener.onChunkGenerating(ii, jj); } - generateChunk(ii, jj); + generateChunk(f, ii, jj); if (listener != null) { listener.onChunkGenerated(ii, jj); } diff --git a/src/main/java/com/volmit/iris/util/mantle/Mantle.java b/src/main/java/com/volmit/iris/util/mantle/Mantle.java index 38535fb5e..9c5dd7501 100644 --- a/src/main/java/com/volmit/iris/util/mantle/Mantle.java +++ b/src/main/java/com/volmit/iris/util/mantle/Mantle.java @@ -21,6 +21,8 @@ package com.volmit.iris.util.mantle; import com.google.common.collect.ImmutableList; import com.volmit.iris.Iris; import com.volmit.iris.engine.data.cache.Cache; +import com.volmit.iris.engine.mantle.EngineMantle; +import com.volmit.iris.engine.mantle.MantleWriter; import com.volmit.iris.engine.object.basic.IrisPosition; import com.volmit.iris.engine.object.feature.IrisFeaturePositional; import com.volmit.iris.util.collection.KMap; @@ -101,6 +103,20 @@ public class Mantle { } } + /** + * Obtain a cached writer which only contains cached chunks. + * This avoids locking on regions when writing to lots of chunks + * @param x the x chunk + * @param z the z chunk + * @param radius the radius chunks + * @return the writer + */ + @ChunkCoordinates + public MantleWriter write(EngineMantle engineMantle, int x, int z, int radius) + { + return new MantleWriter(engineMantle, this, x, z, radius); + } + /** * Lower a flag if it is raised. If the flag was lowered (meaning it was previously raised), execute the runnable * @param x the chunk x @@ -911,4 +927,8 @@ public class Mantle { private static double lengthSq(double x, double z) { return (x * x) + (z * z); } + + public int getWorldHeight() { + return worldHeight; + } } diff --git a/src/main/java/com/volmit/iris/util/matter/Matter.java b/src/main/java/com/volmit/iris/util/matter/Matter.java index 621ced544..421c9fb3f 100644 --- a/src/main/java/com/volmit/iris/util/matter/Matter.java +++ b/src/main/java/com/volmit/iris/util/matter/Matter.java @@ -27,6 +27,7 @@ import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.math.BlockPosition; import org.bukkit.World; import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_17_R1.block.data.type.CraftLeaves; import org.bukkit.entity.Entity; import java.io.*; @@ -189,7 +190,16 @@ public interface Matter { slice = (MatterSlice) createSlice(c, this); if (slice == null) { - Iris.error("Unable to find a slice for class " + C.DARK_RED + c.getCanonicalName()); + try + { + throw new RuntimeException("Bad slice " + c.getCanonicalName()); + } + + catch(Throwable e) + { + e.printStackTrace(); + } + return null; } diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java b/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java index 3d91dc202..04125982e 100644 --- a/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java +++ b/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java @@ -225,7 +225,7 @@ public class Chunk { * @param blockZ The z-coordinate of the block. * @return The biome id or -1 if the biomes are not correctly initialized. */ - public int getBiomeAt(int blockX, int blockY, int blockZ) { + public synchronized int getBiomeAt(int blockX, int blockY, int blockZ) { if (dataVersion < 2202) { if (biomes == null || biomes.length != 256) { return -1; @@ -244,7 +244,7 @@ public class Chunk { } @Deprecated - public void setBiomeAt(int blockX, int blockZ, int biomeID) { + public synchronized void setBiomeAt(int blockX, int blockZ, int biomeID) { if (dataVersion < 2202) { if (biomes == null || biomes.length != 256) { biomes = new int[256]; @@ -275,7 +275,7 @@ public class Chunk { * @param biomeID The biome id to be set. * When set to a negative number, Minecraft will replace it with the block column's default biome. */ - public void setBiomeAt(int blockX, int blockY, int blockZ, int biomeID) { + public synchronized void setBiomeAt(int blockX, int blockY, int blockZ, int biomeID) { if (dataVersion < 2202) { if (biomes == null || biomes.length != 256) { biomes = new int[256]; 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 3c278c14e..a2b858f86 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 @@ -27,6 +27,7 @@ import com.volmit.iris.util.format.C; 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; @@ -43,8 +44,8 @@ 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 HyperLock hyperLock = new HyperLock(); private final KMap lastUse; private final File worldFolder; private final ExecutorService saveQueue; @@ -62,13 +63,11 @@ public class NBTWorld { } public void close() { - regionLock.lock(); for (Long i : loadedRegions.k()) { queueSaveUnload(Cache.keyX(i), Cache.keyZ(i)); } - regionLock.unlock(); saveQueue.shutdown(); try { while (!saveQueue.awaitTermination(3, TimeUnit.SECONDS)) { @@ -80,13 +79,9 @@ public class NBTWorld { } public void flushNow() { - regionLock.lock(); - for (Long i : loadedRegions.k()) { doSaveUnload(Cache.keyX(i), Cache.keyZ(i)); } - - regionLock.unlock(); } public void queueSaveUnload(int x, int z) { @@ -103,8 +98,6 @@ public class NBTWorld { } public void save() { - regionLock.lock(); - boolean saving = true; for (Long i : loadedRegions.k()) { @@ -121,8 +114,6 @@ public class NBTWorld { } Iris.debug("Regions: " + C.GOLD + loadedRegions.size() + C.LIGHT_PURPLE); - - regionLock.unlock(); } public void queueSave() { @@ -131,10 +122,8 @@ public class NBTWorld { 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); } @@ -249,6 +238,11 @@ public class NBTWorld { getChunkSection(x >> 4, y >> 4, z >> 4).setBlockStateAt(x & 15, y & 15, z & 15, getCompound(data), false); } + public int getBiomeId(Biome b) + { + return biomeIds.get(b); + } + public void setBiome(int x, int y, int z, Biome biome) { getChunk(x >> 4, z >> 4).setBiomeAt(x & 15, y, z & 15, biomeIds.get(biome)); } @@ -265,8 +259,12 @@ public class NBTWorld { return s; } - public synchronized Chunk getChunk(int x, int z) { - MCAFile mca = getMCA(x >> 5, z >> 5); + public Chunk getChunk(int x, int z) + { + return getChunk(getMCA(x >> 5, z >> 5), x, z); + } + + public Chunk getChunk(MCAFile mca, int x, int z) { Chunk c = mca.getChunk(x & 31, z & 31); if (c == null) { @@ -278,41 +276,40 @@ public class NBTWorld { } public long getIdleDuration(int x, int z) { - Long l = lastUse.get(Cache.key(x, z)); - - return l == null ? 0 : (M.ms() - l); + return hyperLock.withResult(x, 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); - regionLock.lock(); - lastUse.put(key, M.ms()); - MCAFile mcaf = loadedRegions.get(key); - regionLock.unlock(); + return hyperLock.withResult(x, z, () -> { + lastUse.put(key, M.ms()); - if (mcaf == null) { - mcaf = new MCAFile(x, z); - regionLock.lock(); - loadedRegions.put(key, mcaf); - regionLock.unlock(); - } + MCAFile mcaf = loadedRegions.get(key); - return mcaf; + if (mcaf == null) { + mcaf = new MCAFile(x, z); + loadedRegions.put(key, mcaf); + } + + 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); - } + return hyperLock.withResult(x, z, () -> { + if (loadedRegions.containsKey(key)) { + lastUse.put(key, M.ms()); + return loadedRegions.get(key); + } - regionLock.unlock(); - return ff; + return null; + }); } public int size() { 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 901de03af..89ce29962 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 @@ -24,6 +24,7 @@ import com.volmit.iris.util.nbt.tag.ByteArrayTag; 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 java.util.ArrayList; import java.util.HashMap; @@ -170,7 +171,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 paletteSizeBefore = palette.size(); int paletteIndex = addToPalette(state); //power of 2 --> bits must increase, but only if the palette size changed @@ -223,7 +224,7 @@ public class Section { * @param paletteIndex The block state to be set (index of block data in the palette). * @param blockStates The block states to be updated. */ - public void setPaletteIndex(int blockIndex, int paletteIndex, AtomicLongArray blockStates) { + public synchronized void setPaletteIndex(int blockIndex, int paletteIndex, AtomicLongArray blockStates) { int bits = blockStates.length() >> 6; if (dataVersion < 2527) { @@ -253,7 +254,7 @@ public class Section { return palette; } - int addToPalette(CompoundTag data) { + synchronized int addToPalette(CompoundTag data) { PaletteIndex index; if ((index = getValueIndexedPalette(data)) != null) { return index.index; @@ -283,14 +284,14 @@ public class Section { * This 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 cleanupPaletteAndBlockStates() { + public synchronized void cleanupPaletteAndBlockStates() { Map oldToNewMapping = cleanupPalette(); adjustBlockStateBits(oldToNewMapping, blockStates); } - private Map cleanupPalette() { + private synchronized Map cleanupPalette() { //create index - palette mapping - Map allIndices = new HashMap<>(); + Map allIndices = new Int2IntOpenHashMap(); for (int i = 0; i < 4096; i++) { int paletteIndex = getPaletteIndex(i); allIndices.put(paletteIndex, paletteIndex); @@ -314,7 +315,7 @@ public class Section { return allIndices; } - void adjustBlockStateBits(Map oldToNewMapping, AtomicLongArray blockStates) { + synchronized void adjustBlockStateBits(Map oldToNewMapping, AtomicLongArray blockStates) { //increases or decreases the amount of bits used per BlockState //based on the size of the palette. oldToNewMapping can be used to update indices //if the palette had been cleaned up before using MCAFile#cleanupPalette(). @@ -376,7 +377,7 @@ public class Section { * @throws NullPointerException If blockStates is null * @throws IllegalArgumentException When blockStates' length is < 256 or > 4096 and is not a multiple of 64 */ - public void setBlockStates(AtomicLongArray blockStates) { + public synchronized void setBlockStates(AtomicLongArray blockStates) { if (blockStates == null) { throw new NullPointerException("BlockStates cannot be null"); } else if (blockStates.length() % 64 != 0 || blockStates.length() < 256 || blockStates.length() > 4096) { diff --git a/src/main/java/com/volmit/iris/util/parallel/MultiBurst.java b/src/main/java/com/volmit/iris/util/parallel/MultiBurst.java index 6b21ddb21..ce21c64f7 100644 --- a/src/main/java/com/volmit/iris/util/parallel/MultiBurst.java +++ b/src/main/java/com/volmit/iris/util/parallel/MultiBurst.java @@ -19,6 +19,7 @@ package com.volmit.iris.util.parallel; import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.service.PreservationSVC; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.math.M; @@ -50,7 +51,7 @@ public class MultiBurst { private synchronized ExecutorService getService() { last.set(M.ms()); if (service == null || service.isShutdown()) { - service = new ForkJoinPool(Runtime.getRuntime().availableProcessors(), + service = new ForkJoinPool(IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism()), new ForkJoinPool.ForkJoinWorkerThreadFactory() { int m = 0;