From a09e77a17db9882df8845f2c90933a83e432a137 Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Wed, 18 Aug 2021 14:08:13 -0400 Subject: [PATCH 01/13] Fix odd color negative -> ? --- src/main/java/com/volmit/iris/util/plugin/VolmitSender.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java b/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java index b211bc62d..4ccdc31e3 100644 --- a/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java +++ b/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java @@ -224,7 +224,7 @@ public class VolmitSender implements CommandSender { } public static String pulse(double speed) { - return Form.f(invertSpread((((getTick() * 15D * speed) % 1000D) / 1000D)), 3).replaceAll("\\Q,\\E", "."); + return Form.f(invertSpread((((getTick() * 15D * speed) % 1000D) / 1000D)), 3).replaceAll("\\Q,\\E", ".").replaceAll("\\Q?\\E", "-"); } public static double invertSpread(double v) { From 059d5542c9fcc9980637bf1d950878e58fc7b3d1 Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Wed, 18 Aug 2021 14:08:28 -0400 Subject: [PATCH 02/13] Post shutdown fixes --- src/main/java/com/volmit/iris/Iris.java | 19 +++++++--------- .../volmit/iris/util/parallel/MultiBurst.java | 22 +++++++++++++++---- .../volmit/iris/util/plugin/IrisService.java | 6 +++++ 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/volmit/iris/Iris.java b/src/main/java/com/volmit/iris/Iris.java index 7ce94e736..fd93d97a8 100644 --- a/src/main/java/com/volmit/iris/Iris.java +++ b/src/main/java/com/volmit/iris/Iris.java @@ -75,7 +75,6 @@ import java.util.Map; @SuppressWarnings("CanBeFinal") public class Iris extends VolmitPlugin implements Listener { private KMap, IrisService> services; - public static KList executors = new KList<>(); public static Iris instance; public static BukkitAudiences audiences; public static MultiverseCoreLink linkMultiverseCore; @@ -85,6 +84,7 @@ public class Iris extends VolmitPlugin implements Listener { public static IrisCompat compat; public static FileWatcher configWatcher; private static VolmitSender sender; + private final KList postShutdown = new KList<>(); @Permission public static PermissionIris perm; @@ -126,6 +126,11 @@ public class Iris extends VolmitPlugin implements Listener { services.values().forEach(this::registerListener); } + public void postShutdown(Runnable r) + { + postShutdown.add(r); + } + private void postEnable() { J.a(() -> PaperLib.suggestPaper(this)); J.a(() -> IO.delete(getTemp())); @@ -155,18 +160,10 @@ public class Iris extends VolmitPlugin implements Listener { } public void onDisable() { - for (GroupedExecutor i : executors) { - Iris.debug("Closing Executor " + i.toString()); - i.closeNow(); - } - - executors.clear(); - + services.values().forEach(IrisService::onDisable); Bukkit.getScheduler().cancelTasks(this); HandlerList.unregisterAll((Plugin) this); - MultiBurst.burst.shutdown(); - - services.values().forEach(IrisService::onDisable); + postShutdown.forEach(Runnable::run); services.clear(); super.onDisable(); } 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 29440720a..6b55ac000 100644 --- a/src/main/java/com/volmit/iris/util/parallel/MultiBurst.java +++ b/src/main/java/com/volmit/iris/util/parallel/MultiBurst.java @@ -159,16 +159,30 @@ public class MultiBurst { public void shutdownLater() { if (service != null) { - service.submit(() -> { - J.sleep(3000); + try + { + service.submit(() -> { + J.sleep(3000); + Iris.debug("Shutting down MultiBurst Pool " + heartbeat.getName() + "."); + + if (service != null) { + service.shutdown(); + } + }); + + heartbeat.interrupt(); + } + + catch(Throwable e) + { Iris.debug("Shutting down MultiBurst Pool " + heartbeat.getName() + "."); if (service != null) { service.shutdown(); } - }); - heartbeat.interrupt(); + heartbeat.interrupt(); + } } } diff --git a/src/main/java/com/volmit/iris/util/plugin/IrisService.java b/src/main/java/com/volmit/iris/util/plugin/IrisService.java index 34c222de4..b9068f79e 100644 --- a/src/main/java/com/volmit/iris/util/plugin/IrisService.java +++ b/src/main/java/com/volmit/iris/util/plugin/IrisService.java @@ -18,10 +18,16 @@ package com.volmit.iris.util.plugin; +import com.volmit.iris.Iris; import org.bukkit.event.Listener; public interface IrisService extends Listener { void onEnable(); void onDisable(); + + default void postShutdown(Runnable r) + { + Iris.instance.postShutdown(r); + } } From 5286a69c340a440ec67a413e6fd83859a2ea0758 Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Wed, 18 Aug 2021 14:08:43 -0400 Subject: [PATCH 03/13] More shutdown fixes --- .../com/volmit/iris/core/service/EditSVC.java | 1 - .../iris/core/service/PreservationSVC.java | 69 ++++++++++--------- .../engine/platform/BukkitChunkGenerator.java | 3 +- .../com/volmit/iris/util/mantle/Mantle.java | 11 ++- 4 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/volmit/iris/core/service/EditSVC.java b/src/main/java/com/volmit/iris/core/service/EditSVC.java index ce7ce1be5..1012c7eea 100644 --- a/src/main/java/com/volmit/iris/core/service/EditSVC.java +++ b/src/main/java/com/volmit/iris/core/service/EditSVC.java @@ -37,7 +37,6 @@ public class EditSVC implements IrisService { @Override public void onEnable() { this.editors = new KMap<>(); - Iris.info("EDIT SVC ENABLED!"); Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::update, 1000, 1000); } diff --git a/src/main/java/com/volmit/iris/core/service/PreservationSVC.java b/src/main/java/com/volmit/iris/core/service/PreservationSVC.java index b6123d28d..49a7a8ad0 100644 --- a/src/main/java/com/volmit/iris/core/service/PreservationSVC.java +++ b/src/main/java/com/volmit/iris/core/service/PreservationSVC.java @@ -74,52 +74,53 @@ public class PreservationSVC implements IrisService @Override public void onDisable() { dereferencer.interrupt(); + dereference(); - for(Thread i : threads) - { - if(i.isAlive()) + postShutdown(() -> { + for(Thread i : threads) + { + if(i.isAlive()) + { + try + { + i.interrupt(); + Iris.info("Shutdown Thread " + i.getName()); + } + + catch(Throwable e) + { + Iris.reportError(e); + } + } + } + + for(MultiBurst i : bursts) { try { - i.interrupt(); - Iris.info("Shutdown Thread " + i.getName()); + i.shutdownNow(); + Iris.info("Shutdown Multiburst " + i); } catch(Throwable e) { - + Iris.reportError(e); } } - } - for(MultiBurst i : bursts) - { - try + for(ExecutorService i : services) { - i.shutdownNow(); - Iris.info("Shutdown Multiburst " + i); + try + { + i.shutdownNow(); + Iris.info("Shutdown Executor Service " + i); + } + + catch(Throwable e) + { + Iris.reportError(e); + } } - - catch(Throwable e) - { - - } - } - - for(ExecutorService i : services) - { - try - { - i.shutdownNow(); - Iris.info("Shutdown Executor Service " + i); - } - - catch(Throwable e) - { - - } - } - - dereference(); + }); } } 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 7ec34124a..5f2c46928 100644 --- a/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -29,6 +29,7 @@ import com.volmit.iris.engine.framework.WrongEngineBroException; import com.volmit.iris.engine.object.common.IrisWorld; import com.volmit.iris.engine.object.dimensional.IrisDimension; import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.format.C; import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.io.ReactiveFolder; import com.volmit.iris.util.scheduling.ChronoLatch; @@ -161,7 +162,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun r.run(); loadLock.release(LOAD_LOCKS); } catch (Throwable e) { - e.printStackTrace(); + Iris.reportError(e); } }); } 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 afdae0de8..256d68cb1 100644 --- a/src/main/java/com/volmit/iris/util/mantle/Mantle.java +++ b/src/main/java/com/volmit/iris/util/mantle/Mantle.java @@ -207,7 +207,16 @@ public class Mantle { }); } - b.complete(); + try + { + b.complete(); + } + + catch(Throwable e) + { + Iris.reportError(e); + } + ioBurst.shutdownNow(); Iris.debug("The Mantle has Closed " + C.DARK_AQUA + dataFolder.getAbsolutePath()); } From 4396ca94201a3cba6de0defadce5bbe1dbac81b8 Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Wed, 18 Aug 2021 14:24:03 -0400 Subject: [PATCH 04/13] Light level for spawns closes #558 --- .../iris/engine/object/basic/IrisRange.java | 4 ++++ .../engine/object/entity/IrisEntitySpawn.java | 20 +++++++++++++++++-- .../engine/object/spawners/IrisSpawner.java | 5 +++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/volmit/iris/engine/object/basic/IrisRange.java b/src/main/java/com/volmit/iris/engine/object/basic/IrisRange.java index b065d2e62..e1c962e2b 100644 --- a/src/main/java/com/volmit/iris/engine/object/basic/IrisRange.java +++ b/src/main/java/com/volmit/iris/engine/object/basic/IrisRange.java @@ -44,4 +44,8 @@ public class IrisRange { return rng.d(min, max); } + + public boolean contains(int v) { + return v >= min && v <= max; + } } diff --git a/src/main/java/com/volmit/iris/engine/object/entity/IrisEntitySpawn.java b/src/main/java/com/volmit/iris/engine/object/entity/IrisEntitySpawn.java index 8c2532115..3ae2d9d39 100644 --- a/src/main/java/com/volmit/iris/engine/object/entity/IrisEntitySpawn.java +++ b/src/main/java/com/volmit/iris/engine/object/entity/IrisEntitySpawn.java @@ -105,8 +105,24 @@ public class IrisEntitySpawn implements IRare { }; if (l != null) { - if (spawn100(gen, l) != null) - s++; + if(referenceSpawner.getAllowedLightLevels().getMin() > 0 || referenceSpawner.getAllowedLightLevels().getMax() < 15) + { + if(referenceSpawner.getAllowedLightLevels().contains(l.getBlock().getLightLevel())) + { + if (spawn100(gen, l) != null) + { + s++; + } + } + } + + else + { + if (spawn100(gen, l) != null) + { + s++; + } + } } } } diff --git a/src/main/java/com/volmit/iris/engine/object/spawners/IrisSpawner.java b/src/main/java/com/volmit/iris/engine/object/spawners/IrisSpawner.java index a7773979e..ece3c420c 100644 --- a/src/main/java/com/volmit/iris/engine/object/spawners/IrisSpawner.java +++ b/src/main/java/com/volmit/iris/engine/object/spawners/IrisSpawner.java @@ -21,6 +21,7 @@ package com.volmit.iris.engine.object.spawners; import com.volmit.iris.core.project.loader.IrisRegistrant; import com.volmit.iris.engine.object.annotations.ArrayType; import com.volmit.iris.engine.object.annotations.Desc; +import com.volmit.iris.engine.object.basic.IrisRange; import com.volmit.iris.engine.object.basic.IrisRate; import com.volmit.iris.engine.object.basic.IrisTimeBlock; import com.volmit.iris.engine.object.basic.IrisWeather; @@ -32,6 +33,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; +import org.bukkit.Bukkit; import org.bukkit.World; @EqualsAndHashCode(callSuper = true) @@ -67,6 +69,9 @@ public class IrisSpawner extends IrisRegistrant { @Desc("The maximum rate this spawner can fire on a specific chunk") private IrisRate maximumRatePerChunk = new IrisRate(); + @Desc("The light levels this spawn is allowed to run in (0-15 inclusive)") + private IrisRange allowedLightLevels = new IrisRange(0, 15); + @Desc("Where should these spawns be placed") private IrisSpawnGroup group = IrisSpawnGroup.NORMAL; From 630b6e6313ce76122426c26a705e37543023d999 Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Wed, 18 Aug 2021 14:58:23 -0400 Subject: [PATCH 05/13] MVC Fixes --- .../com/volmit/iris/core/IrisSettings.java | 1 + .../volmit/iris/core/service/StudioSVC.java | 22 ++++-- .../volmit/iris/core/tools/IrisToolbelt.java | 8 +++ .../engine/platform/BukkitChunkGenerator.java | 67 ++++++++++++++----- 4 files changed, 78 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/volmit/iris/core/IrisSettings.java b/src/main/java/com/volmit/iris/core/IrisSettings.java index 4a87206e7..7c72ea270 100644 --- a/src/main/java/com/volmit/iris/core/IrisSettings.java +++ b/src/main/java/com/volmit/iris/core/IrisSettings.java @@ -104,6 +104,7 @@ public class IrisSettings { public boolean verbose = false; public boolean ignoreWorldEdit = false; public boolean disableNMS = false; + public boolean keepProductionOnReload = false; public boolean pluginMetrics = true; public boolean splashLogoStartup = true; public String forceMainWorld = ""; diff --git a/src/main/java/com/volmit/iris/core/service/StudioSVC.java b/src/main/java/com/volmit/iris/core/service/StudioSVC.java index 063891ccb..5adadda95 100644 --- a/src/main/java/com/volmit/iris/core/service/StudioSVC.java +++ b/src/main/java/com/volmit/iris/core/service/StudioSVC.java @@ -73,15 +73,27 @@ public class StudioSVC implements IrisService { @Override public void onDisable() { - if (IrisSettings.get().isStudio()) { - Iris.debug("Studio Mode Active: Closing Projects"); + Iris.debug("Studio Mode Active: Closing Projects"); - for (World i : Bukkit.getWorlds()) { - if (IrisToolbelt.isIrisWorld(i)) { + for (World i : Bukkit.getWorlds()) { + if (IrisToolbelt.isIrisWorld(i)) { + if(IrisToolbelt.isStudio(i)) + { IrisToolbelt.evacuate(i); - Iris.debug("Closing Platform Generator " + i.getName()); IrisToolbelt.access(i).close(); } + + else + { + if(!IrisSettings.get().getGeneral().isKeepProductionOnReload()) + { + IrisToolbelt.evacuate(i); + IrisToolbelt.access(i).close(); + Iris.error("You cannot reload Iris while production worlds are active!"); + Iris.error("To prevent corrupted chunks, Iris is shutting the server down now!"); + Bukkit.shutdown(); + } + } } } } 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 530dbde40..8277f117b 100644 --- a/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java +++ b/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java @@ -189,4 +189,12 @@ public class IrisToolbelt { return false; } + + public static boolean isStudio(World i) { + return isIrisWorld(i) && access(i).isStudio(); + } + + public static boolean isHeadless(World i) { + return isIrisWorld(i) && access(i).isHeadless(); + } } 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 5f2c46928..907dd6572 100644 --- a/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -48,6 +48,7 @@ import org.bukkit.generator.ChunkGenerator; import org.jetbrains.annotations.NotNull; import javax.management.RuntimeErrorException; +import javax.swing.text.TableView; import java.io.File; import java.util.List; import java.util.Random; @@ -58,7 +59,7 @@ import java.util.concurrent.Semaphore; public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChunkGenerator { private static final int LOAD_LOCKS = 1_000_000; private final Semaphore loadLock; - private final Engine engine; + private Engine engine; private final IrisWorld world; private final File dataLocation; private final String dimensionKey; @@ -67,9 +68,11 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun private final ChronoLatch hotloadChecker; private final Looper hotloader; private final boolean studio; + private long lastSeed; public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) { populators = new KList<>(); + lastSeed = world.seed(); loadLock = new Semaphore(LOAD_LOCKS); this.world = world; this.hotloadChecker = new ChronoLatch(1000, false); @@ -77,6 +80,23 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun this.dataLocation = dataLocation; this.dimensionKey = dimensionKey; this.folder = new ReactiveFolder(dataLocation, (_a, _b, _c) -> hotload()); + setupEngine(); + this.hotloader = new Looper() { + @Override + protected long loop() { + if (hotloadChecker.flip()) { + folder.check(); + } + + return 250; + } + }; + hotloader.setPriority(Thread.MIN_PRIORITY); + hotloader.start(); + hotloader.setName(getTarget().getWorld().name() + " Hotloader"); + } + + private void setupEngine() { IrisData data = IrisData.get(dataLocation); IrisDimension dimension = data.getDimensionLoader().load(dimensionKey); @@ -114,21 +134,9 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun } } - this.engine = new IrisEngine(new EngineTarget(world, dimension, data), studio); + engine = new IrisEngine(new EngineTarget(world, dimension, data), studio); + populators.clear(); populators.add((BlockPopulator) engine); - this.hotloader = new Looper() { - @Override - protected long loop() { - if (hotloadChecker.flip()) { - folder.check(); - } - - return 250; - } - }; - hotloader.setPriority(Thread.MIN_PRIORITY); - hotloader.start(); - hotloader.setName(getTarget().getWorld().name() + " Hotloader"); } @Override @@ -170,6 +178,15 @@ 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()) + { + Iris.warn("Seed for engine " + lastSeed + " does not match world seed if " + world.getSeed()); + lastSeed = world.getSeed(); + engine.getTarget().getWorld().seed(lastSeed); + engine.hotload(); + Iris.success("Updated Engine seed to " + lastSeed); + } + loadLock.acquire(); PrecisionStopwatch ps = PrecisionStopwatch.start(); TerrainChunk tc = TerrainChunk.create(world, biome); @@ -183,6 +200,26 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun return c; } + catch (WrongEngineBroException e) + { + Iris.warn("Trying to generate with a shut-down engine! Did you reload? Attempting to resolve this..."); + + try + { + setupEngine(); + Iris.success("Resolved! Should generate now!"); + } + + catch(Throwable fe) + { + Iris.error("FATAL! Iris cannot generate in this world since it was reloaded! This will cause a crash, with missing chunks, so we're crashing right now!"); + Bukkit.shutdown(); + throw new RuntimeException(); + } + + return generateChunkData(world, ignored, x, z, biome); + } + catch (Throwable e) { loadLock.release(); Iris.error("======================================"); From 23f5b84c5e61bb86eab3719aaebcbfa64d5b8122 Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Wed, 18 Aug 2021 15:03:34 -0400 Subject: [PATCH 06/13] No spam --- src/main/java/com/volmit/iris/util/parallel/BurstExecutor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/volmit/iris/util/parallel/BurstExecutor.java b/src/main/java/com/volmit/iris/util/parallel/BurstExecutor.java index 642e15f6c..2dfc6b6aa 100644 --- a/src/main/java/com/volmit/iris/util/parallel/BurstExecutor.java +++ b/src/main/java/com/volmit/iris/util/parallel/BurstExecutor.java @@ -75,7 +75,6 @@ public class BurstExecutor { CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(); futures.clear(); } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); Iris.reportError(e); } } From 39142909f64257e7dae0cc3a9f6751aba3c0a3c0 Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Wed, 18 Aug 2021 15:03:59 -0400 Subject: [PATCH 07/13] V+ --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7a9b56801..fc5a8fed1 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ plugins { } group 'com.volmit.iris' -version '1.7.3' +version '1.7.4' def apiVersion = '1.17' def name = getRootProject().getName() // See settings.gradle def main = 'com.volmit.iris.Iris' From 7f7397f68400d19c0c662d9d2b6371479651f111 Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Wed, 18 Aug 2021 17:23:54 -0400 Subject: [PATCH 08/13] Legacy objects copy --- .../object/objects/IrisObjectLegacy.java | 997 ++++++++++++++++++ 1 file changed, 997 insertions(+) create mode 100644 src/main/java/com/volmit/iris/engine/object/objects/IrisObjectLegacy.java diff --git a/src/main/java/com/volmit/iris/engine/object/objects/IrisObjectLegacy.java b/src/main/java/com/volmit/iris/engine/object/objects/IrisObjectLegacy.java new file mode 100644 index 000000000..9b2e1ab6d --- /dev/null +++ b/src/main/java/com/volmit/iris/engine/object/objects/IrisObjectLegacy.java @@ -0,0 +1,997 @@ +/* + * 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.object.objects; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.project.loader.IrisData; +import com.volmit.iris.core.project.loader.IrisRegistrant; +import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.engine.framework.placer.HeightmapObjectPlacer; +import com.volmit.iris.engine.object.basic.IrisPosition; +import com.volmit.iris.engine.object.common.CarveResult; +import com.volmit.iris.engine.object.common.IObjectPlacer; +import com.volmit.iris.engine.object.tile.TileData; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.data.B; +import com.volmit.iris.util.interpolation.IrisInterpolation; +import com.volmit.iris.util.math.AxisAlignedBB; +import com.volmit.iris.util.math.BlockPosition; +import com.volmit.iris.util.math.Position2; +import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.scheduling.IrisLock; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.TileState; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.block.data.type.Leaves; +import org.bukkit.util.BlockVector; +import org.bukkit.util.Vector; + +import java.io.*; +import java.util.*; +import java.util.function.Consumer; + +@SuppressWarnings("DefaultAnnotationParam") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +public class IrisObjectLegacy extends IrisRegistrant { + protected static final Vector HALF = new Vector(0.5, 0.5, 0.5); + protected static final BlockData AIR = B.get("CAVE_AIR"); + protected static final BlockData VAIR = B.get("VOID_AIR"); + protected static final BlockData VAIR_DEBUG = B.get("COBWEB"); + protected static final BlockData[] SNOW_LAYERS = new BlockData[]{B.get("minecraft:snow[layers=1]"), B.get("minecraft:snow[layers=2]"), B.get("minecraft:snow[layers=3]"), B.get("minecraft:snow[layers=4]"), B.get("minecraft:snow[layers=5]"), B.get("minecraft:snow[layers=6]"), B.get("minecraft:snow[layers=7]"), B.get("minecraft:snow[layers=8]")}; + + private KMap blocks; + private KMap> states; + @Getter + @Setter + private int w; + @Getter + @Setter + private int d; + @Getter + @Setter + private int h; + protected transient final IrisLock readLock = new IrisLock("read-conclock"); + @Getter + @Setter + private transient BlockVector center; + @Getter + @Setter + protected transient volatile boolean smartBored = false; + @Getter + @Setter + protected transient IrisLock lock = new IrisLock("Preloadcache"); + @Setter + protected transient AtomicCache aabb = new AtomicCache<>(); + + public IrisObjectLegacy(int w, int h, int d) { + blocks = new KMap<>(); + states = new KMap<>(); + this.w = w; + this.h = h; + this.d = d; + center = new BlockVector(w / 2, h / 2, d / 2); + } + + public IrisObjectLegacy() { + this(0, 0, 0); + } + + public AxisAlignedBB getAABB() { + return aabb.aquire(() -> getAABBFor(new BlockVector(w, h, d))); + } + + public static BlockVector getCenterForSize(BlockVector size) { + return new BlockVector(size.getX() / 2, size.getY() / 2, size.getZ() / 2); + } + + public static AxisAlignedBB getAABBFor(BlockVector size) { + BlockVector center = new BlockVector(size.getX() / 2, size.getY() / 2, size.getZ() / 2); + return new AxisAlignedBB(new IrisPosition(new BlockVector(0, 0, 0).subtract(center).toBlockVector()), + new IrisPosition(new BlockVector(size.getX() - 1, size.getY() - 1, size.getZ() - 1).subtract(center).toBlockVector())); + } + + public void ensureSmartBored(boolean debug) { + if (smartBored) { + return; + } + + lock.lock(); + int applied = 0; + if (getBlocks().isEmpty()) { + lock.unlock(); + Iris.warn("Cannot Smart Bore " + getLoadKey() + " because it has 0 blocks in it."); + smartBored = true; + return; + } + + BlockVector max = new BlockVector(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE); + BlockVector min = new BlockVector(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE); + + for (BlockVector i : getBlocks().keySet()) { + max.setX(Math.max(i.getX(), max.getX())); + min.setX(Math.min(i.getX(), min.getX())); + max.setY(Math.max(i.getY(), max.getY())); + min.setY(Math.min(i.getY(), min.getY())); + max.setZ(Math.max(i.getZ(), max.getZ())); + min.setZ(Math.min(i.getZ(), min.getZ())); + } + + // Smash X + for (int rayY = min.getBlockY(); rayY <= max.getBlockY(); rayY++) { + for (int rayZ = min.getBlockZ(); rayZ <= max.getBlockZ(); rayZ++) { + int start = Integer.MAX_VALUE; + int end = Integer.MIN_VALUE; + + for (int ray = min.getBlockX(); ray <= max.getBlockX(); ray++) { + if (getBlocks().containsKey(new BlockVector(ray, rayY, rayZ))) { + start = Math.min(ray, start); + end = Math.max(ray, end); + } + } + + if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) { + for (int i = start; i <= end; i++) { + BlockVector v = new BlockVector(i, rayY, rayZ); + + if (!getBlocks().containsKey(v) || B.isAir(getBlocks().get(v))) { + getBlocks().put(v, debug ? VAIR_DEBUG : VAIR); + applied++; + } + } + } + } + } + + // Smash Y + for (int rayX = min.getBlockX(); rayX <= max.getBlockX(); rayX++) { + for (int rayZ = min.getBlockZ(); rayZ <= max.getBlockZ(); rayZ++) { + int start = Integer.MAX_VALUE; + int end = Integer.MIN_VALUE; + + for (int ray = min.getBlockY(); ray <= max.getBlockY(); ray++) { + if (getBlocks().containsKey(new BlockVector(rayX, ray, rayZ))) { + start = Math.min(ray, start); + end = Math.max(ray, end); + } + } + + if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) { + for (int i = start; i <= end; i++) { + BlockVector v = new BlockVector(rayX, i, rayZ); + + if (!getBlocks().containsKey(v) || B.isAir(getBlocks().get(v))) { + getBlocks().put(v, debug ? VAIR_DEBUG : VAIR); + applied++; + } + } + } + } + } + + // Smash Z + for (int rayX = min.getBlockX(); rayX <= max.getBlockX(); rayX++) { + for (int rayY = min.getBlockY(); rayY <= max.getBlockY(); rayY++) { + int start = Integer.MAX_VALUE; + int end = Integer.MIN_VALUE; + + for (int ray = min.getBlockZ(); ray <= max.getBlockZ(); ray++) { + if (getBlocks().containsKey(new BlockVector(rayX, rayY, ray))) { + start = Math.min(ray, start); + end = Math.max(ray, end); + } + } + + if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) { + for (int i = start; i <= end; i++) { + BlockVector v = new BlockVector(rayX, rayY, i); + + if (!getBlocks().containsKey(v) || B.isAir(getBlocks().get(v))) { + getBlocks().put(v, debug ? VAIR_DEBUG : VAIR); + applied++; + } + } + } + } + } + + Iris.verbose("- Applied Smart Bore to " + getLoadKey() + " Filled with " + applied + " VOID_AIR blocks."); + + smartBored = true; + lock.unlock(); + } + + public synchronized IrisObjectLegacy copy() { + IrisObjectLegacy o = new IrisObjectLegacy(w, h, d); + o.setLoadKey(o.getLoadKey()); + o.setCenter(getCenter().clone()); + + for (BlockVector i : getBlocks().keySet()) { + o.getBlocks().put(i.clone(), Objects.requireNonNull(getBlocks().get(i)).clone()); + } + + for (BlockVector i : getStates().keySet()) { + o.getStates().put(i.clone(), Objects.requireNonNull(getStates().get(i)).clone()); + } + + return o; + } + + @SuppressWarnings({"resource", "RedundantSuppression"}) + public static BlockVector sampleSize(File file) throws IOException { + FileInputStream in = new FileInputStream(file); + DataInputStream din = new DataInputStream(in); + BlockVector bv = new BlockVector(din.readInt(), din.readInt(), din.readInt()); + Iris.later(din::close); + return bv; + } + + public void readLegacy(InputStream in) throws IOException { + DataInputStream din = new DataInputStream(in); + this.w = din.readInt(); + this.h = din.readInt(); + this.d = din.readInt(); + center = new BlockVector(w / 2, h / 2, d / 2); + int s = din.readInt(); + + for (int i = 0; i < s; i++) { + getBlocks().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), B.get(din.readUTF())); + } + + try { + int size = din.readInt(); + + for (int i = 0; i < size; i++) { + getStates().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), TileData.read(din)); + } + } catch (Throwable e) { + Iris.reportError(e); + + } + } + + public void read(InputStream in) throws Throwable { + DataInputStream din = new DataInputStream(in); + this.w = din.readInt(); + this.h = din.readInt(); + this.d = din.readInt(); + if (!din.readUTF().equals("Iris V2 IOB;")) { + throw new IOException("Not V2 Format"); + } + center = new BlockVector(w / 2, h / 2, d / 2); + int s = din.readShort(); + int i; + KList palette = new KList<>(); + + for (i = 0; i < s; i++) { + palette.add(din.readUTF()); + } + + s = din.readInt(); + + for (i = 0; i < s; i++) { + getBlocks().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), B.get(palette.get(din.readShort()))); + } + + s = din.readInt(); + + for (i = 0; i < s; i++) { + getStates().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), TileData.read(din)); + } + } + + public void write(OutputStream o) throws IOException { + DataOutputStream dos = new DataOutputStream(o); + dos.writeInt(w); + dos.writeInt(h); + dos.writeInt(d); + dos.writeUTF("Iris V2 IOB;"); + KList palette = new KList<>(); + + for (BlockData i : getBlocks().values()) { + palette.addIfMissing(i.getAsString()); + } + + dos.writeShort(palette.size()); + + for (String i : palette) { + dos.writeUTF(i); + } + + dos.writeInt(getBlocks().size()); + + for (BlockVector i : getBlocks().keySet()) { + dos.writeShort(i.getBlockX()); + dos.writeShort(i.getBlockY()); + dos.writeShort(i.getBlockZ()); + dos.writeShort(palette.indexOf(getBlocks().get(i).getAsString())); + } + + dos.writeInt(getStates().size()); + for (BlockVector i : getStates().keySet()) { + dos.writeShort(i.getBlockX()); + dos.writeShort(i.getBlockY()); + dos.writeShort(i.getBlockZ()); + getStates().get(i).toBinary(dos); + } + } + + public void read(File file) throws IOException { + FileInputStream fin = new FileInputStream(file); + try { + read(fin); + fin.close(); + } catch (Throwable e) { + Iris.reportError(e); + fin.close(); + fin = new FileInputStream(file); + readLegacy(fin); + fin.close(); + } + } + + public void write(File file) throws IOException { + if (file == null) { + return; + } + + FileOutputStream out = new FileOutputStream(file); + write(out); + out.close(); + } + + public void clean() { + KMap d = new KMap<>(); + + for (BlockVector i : getBlocks().keySet()) { + d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i))); + } + + KMap> dx = new KMap<>(); + + for (BlockVector i : getBlocks().keySet()) { + d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i))); + } + + for (BlockVector i : getStates().keySet()) { + dx.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getStates().get(i))); + } + + blocks = d; + states = dx; + } + + public BlockVector getSigned(int x, int y, int z) { + if (x >= w || y >= h || z >= d) { + throw new RuntimeException(x + " " + y + " " + z + " exceeds limit of " + w + " " + h + " " + d); + } + + return new BlockVector(x, y, z).subtract(center).toBlockVector(); + } + + public void setUnsigned(int x, int y, int z, BlockData block) { + BlockVector v = getSigned(x, y, z); + + if (block == null) { + getBlocks().remove(v); + getStates().remove(v); + } else { + getBlocks().put(v, block); + } + } + + public void setUnsigned(int x, int y, int z, Block block) { + BlockVector v = getSigned(x, y, z); + + if (block == null) { + getBlocks().remove(v); + getStates().remove(v); + } else { + BlockData data = block.getBlockData(); + getBlocks().put(v, data); + TileData state = TileData.getTileState(block); + if (state != null) { + Iris.info("Saved State " + v); + getStates().put(v, state); + } + } + } + + public int place(int x, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng, IrisData rdata) { + return place(x, -1, z, placer, config, rng, rdata); + } + + public int place(int x, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng, CarveResult c, IrisData rdata) { + return place(x, -1, z, placer, config, rng, null, c, rdata); + } + + public int place(int x, int yv, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng, IrisData rdata) { + return place(x, yv, z, placer, config, rng, null, null, rdata); + } + + public int place(Location loc, IObjectPlacer placer, IrisObjectPlacement config, RNG rng, IrisData rdata) { + return place(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), placer, config, rng, rdata); + } + + public int place(int x, int yv, int z, IObjectPlacer oplacer, IrisObjectPlacement config, RNG rng, Consumer listener, CarveResult c, IrisData rdata) { + IObjectPlacer placer = (config.getHeightmap() != null) ? new HeightmapObjectPlacer(rng, x, yv, z, config, oplacer) : oplacer; + + if (config.isSmartBore()) { + ensureSmartBored(placer.isDebugSmartBore()); + } + + boolean warped = !config.getWarp().isFlat(); + boolean stilting = (config.getMode().equals(ObjectPlaceMode.STILT) || config.getMode().equals(ObjectPlaceMode.FAST_STILT)); + KMap heightmap = config.getSnow() > 0 ? new KMap<>() : null; + int spinx = rng.imax() / 1000; + int spiny = rng.imax() / 1000; + int spinz = rng.imax() / 1000; + int rty = config.getRotation().rotate(new BlockVector(0, getCenter().getBlockY(), 0), spinx, spiny, spinz).getBlockY(); + int ty = config.getTranslate().translate(new BlockVector(0, getCenter().getBlockY(), 0), config.getRotation(), spinx, spiny, spinz).getBlockY(); + int y = -1; + int xx, zz; + int yrand = config.getTranslate().getYRandom(); + yrand = yrand > 0 ? rng.i(0, yrand) : yrand < 0 ? rng.i(yrand, 0) : yrand; + + if (yv < 0) { + if (config.getMode().equals(ObjectPlaceMode.CENTER_HEIGHT)) { + y = (c != null ? c.getSurface() : placer.getHighest(x, z, getLoader(), config.isUnderwater())) + rty; + } else if (config.getMode().equals(ObjectPlaceMode.MAX_HEIGHT) || config.getMode().equals(ObjectPlaceMode.STILT)) { + BlockVector offset = new BlockVector(config.getTranslate().getX(), config.getTranslate().getY(), config.getTranslate().getZ()); + BlockVector rotatedDimensions = config.getRotation().rotate(new BlockVector(getW(), getH(), getD()), spinx, spiny, spinz).clone(); + + for (int i = x - (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i <= x + (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i++) { + for (int j = z - (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j <= z + (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j++) { + int h = placer.getHighest(i, j, getLoader(), config.isUnderwater()) + rty; + + if (h > y) { + y = h; + } + } + } + } else if (config.getMode().equals(ObjectPlaceMode.FAST_MAX_HEIGHT) || config.getMode().equals(ObjectPlaceMode.VACUUM) || config.getMode().equals(ObjectPlaceMode.FAST_STILT)) { + BlockVector offset = new BlockVector(config.getTranslate().getX(), config.getTranslate().getY(), config.getTranslate().getZ()); + BlockVector rotatedDimensions = config.getRotation().rotate(new BlockVector(getW(), getH(), getD()), spinx, spiny, spinz).clone(); + + for (int i = x - (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i <= x + (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i += (rotatedDimensions.getBlockX() / 2) + 1) { + for (int j = z - (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j <= z + (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j += (rotatedDimensions.getBlockZ() / 2) + 1) { + int h = placer.getHighest(i, j, getLoader(), config.isUnderwater()) + rty; + + if (h > y) { + y = h; + } + } + } + } else if (config.getMode().equals(ObjectPlaceMode.MIN_HEIGHT)) { + y = 257; + BlockVector offset = new BlockVector(config.getTranslate().getX(), config.getTranslate().getY(), config.getTranslate().getZ()); + BlockVector rotatedDimensions = config.getRotation().rotate(new BlockVector(getW(), getH(), getD()), spinx, spiny, spinz).clone(); + + for (int i = x - (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i <= x + (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i++) { + for (int j = z - (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j <= z + (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j++) { + int h = placer.getHighest(i, j, getLoader(), config.isUnderwater()) + rty; + + if (h < y) { + y = h; + } + } + } + } else if (config.getMode().equals(ObjectPlaceMode.FAST_MIN_HEIGHT)) { + y = 257; + BlockVector offset = new BlockVector(config.getTranslate().getX(), config.getTranslate().getY(), config.getTranslate().getZ()); + BlockVector rotatedDimensions = config.getRotation().rotate(new BlockVector(getW(), getH(), getD()), spinx, spiny, spinz).clone(); + + for (int i = x - (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i <= x + (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i += (rotatedDimensions.getBlockX() / 2) + 1) { + for (int j = z - (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j <= z + (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j += (rotatedDimensions.getBlockZ() / 2) + 1) { + int h = placer.getHighest(i, j, getLoader(), config.isUnderwater()) + rty; + + if (h < y) { + y = h; + } + } + } + } else if (config.getMode().equals(ObjectPlaceMode.PAINT)) { + y = placer.getHighest(x, z, getLoader(), config.isUnderwater()) + rty; + } + } else { + y = yv; + } + + if (yv >= 0 && config.isBottom()) { + y += Math.floorDiv(h, 2); + } + + if (yv < 0) { + if (!config.isUnderwater() && !config.isOnwater() && placer.isUnderwater(x, z)) { + return -1; + } + } + + if (c != null && Math.max(0, h + yrand + ty) + 1 >= c.getHeight()) { + return -1; + } + + if (config.isUnderwater() && y + rty + ty >= placer.getFluidHeight()) { + return -1; + } + + if (!config.getClamp().canPlace(y + rty + ty, y - rty + ty)) { + return -1; + } + + if (config.isBore()) { + BlockVector offset = new BlockVector(config.getTranslate().getX(), config.getTranslate().getY(), config.getTranslate().getZ()); + for (int i = x - Math.floorDiv(w, 2) + (int) offset.getX(); i <= x + Math.floorDiv(w, 2) - (w % 2 == 0 ? 1 : 0) + (int) offset.getX(); i++) { + for (int j = y - Math.floorDiv(h, 2) - config.getBoreExtendMinY() + (int) offset.getY(); j <= y + Math.floorDiv(h, 2) + config.getBoreExtendMaxY() - (h % 2 == 0 ? 1 : 0) + (int) offset.getY(); j++) { + for (int k = z - Math.floorDiv(d, 2) + (int) offset.getZ(); k <= z + Math.floorDiv(d, 2) - (d % 2 == 0 ? 1 : 0) + (int) offset.getX(); k++) { + placer.set(i, j, k, AIR); + } + } + } + } + + int lowest = Integer.MAX_VALUE; + y += yrand; + readLock.lock(); + try { + for (BlockVector g : getBlocks().keySet()) { + BlockData d; + TileData tile = null; + + try { + d = getBlocks().get(g); + tile = getStates().get(g); + } catch (Throwable e) { + Iris.reportError(e); + Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (cme)"); + d = AIR; + } + + if (d == null) { + Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (null)"); + d = AIR; + } + + BlockVector i = g.clone(); + BlockData data = d.clone(); + i = config.getRotation().rotate(i.clone(), spinx, spiny, spinz).clone(); + i = config.getTranslate().translate(i.clone(), config.getRotation(), spinx, spiny, spinz).clone(); + + if (stilting && i.getBlockY() < lowest && !B.isAir(data)) { + lowest = i.getBlockY(); + } + + if (placer.isPreventingDecay() && (data) instanceof Leaves && !((Leaves) (data)).isPersistent()) { + ((Leaves) data).setPersistent(true); + } + + for (IrisObjectReplace j : config.getEdit()) { + if (rng.chance(j.getChance())) { + for (BlockData k : j.getFind(rdata)) { + if (j.isExact() ? k.matches(data) : k.getMaterial().equals(data.getMaterial())) { + BlockData newData = j.getReplace(rng, i.getX() + x, i.getY() + y, i.getZ() + z, rdata).clone(); + + if (newData.getMaterial() == data.getMaterial()) { + data = data.merge(newData); + } else { + data = newData; + } + } + } + } + } + + data = config.getRotation().rotate(data, spinx, spiny, spinz); + xx = x + (int) Math.round(i.getX()); + int yy = y + (int) Math.round(i.getY()); + zz = z + (int) Math.round(i.getZ()); + + if (warped) { + xx += config.warp(rng, i.getX() + x, i.getY() + y, i.getZ() + z, getLoader()); + zz += config.warp(rng, i.getZ() + z, i.getY() + y, i.getX() + x, getLoader()); + } + + if (yv < 0 && (config.getMode().equals(ObjectPlaceMode.PAINT))) { + yy = (int) Math.round(i.getY()) + Math.floorDiv(h, 2) + placer.getHighest(xx, zz, getLoader(), config.isUnderwater()); + } + + if (heightmap != null) { + Position2 pos = new Position2(xx, zz); + + if (!heightmap.containsKey(pos)) { + heightmap.put(pos, yy); + } + + if (heightmap.get(pos) < yy) { + heightmap.put(pos, yy); + } + } + + if (config.isMeld() && !placer.isSolid(xx, yy, zz)) { + continue; + } + + if (config.isWaterloggable() && yy <= placer.getFluidHeight() && data instanceof Waterlogged) { + ((Waterlogged) data).setWaterlogged(true); + } + + if (listener != null) { + listener.accept(new BlockPosition(xx, yy, zz)); + } + + if (!data.getMaterial().equals(Material.AIR) && !data.getMaterial().equals(Material.CAVE_AIR)) { + placer.set(xx, yy, zz, data); + + if (tile != null) { + placer.setTile(xx, yy, zz, tile); + } + } + } + } catch (Throwable e) { + Iris.reportError(e); + } + readLock.unlock(); + + if (stilting) { + readLock.lock(); + for (BlockVector g : getBlocks().keySet()) { + BlockData d; + + try { + d = getBlocks().get(g); + } catch (Throwable e) { + Iris.reportError(e); + Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (stilt cme)"); + d = AIR; + } + + if (d == null) { + Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (stilt null)"); + d = AIR; + } + + BlockVector i = g.clone(); + i = config.getRotation().rotate(i.clone(), spinx, spiny, spinz).clone(); + i = config.getTranslate().translate(i.clone(), config.getRotation(), spinx, spiny, spinz).clone(); + + if (i.getBlockY() != lowest) { + continue; + } + + + if (d == null || B.isAir(d)) { + continue; + } + + xx = x + (int) Math.round(i.getX()); + zz = z + (int) Math.round(i.getZ()); + + if (warped) { + xx += config.warp(rng, i.getX() + x, i.getY() + y, i.getZ() + z, getLoader()); + zz += config.warp(rng, i.getZ() + z, i.getY() + y, i.getX() + x, getLoader()); + } + + int yg = placer.getHighest(xx, zz, getLoader(), config.isUnderwater()); + + if (yv >= 0 && config.isBottom()) { + y += Math.floorDiv(h, 2); + } + + for (int j = lowest + y; j > yg - config.getOverStilt() - 1; j--) { + placer.set(xx, j, zz, d); + } + } + + readLock.unlock(); + } + + if (heightmap != null) { + RNG rngx = rng.nextParallelRNG(3468854); + + for (Position2 i : heightmap.k()) { + int vx = i.getX(); + int vy = heightmap.get(i); + int vz = i.getZ(); + + if (config.getSnow() > 0) { + int height = rngx.i(0, (int) (config.getSnow() * 7)); + placer.set(vx, vy + 1, vz, SNOW_LAYERS[Math.max(Math.min(height, 7), 0)]); + } + } + } + + return y; + } + + public IrisObjectLegacy rotateCopy(IrisObjectRotation rt) { + IrisObjectLegacy copy = copy(); + copy.rotate(rt, 0, 0, 0); + return copy; + } + + public void rotate(IrisObjectRotation r, int spinx, int spiny, int spinz) { + KMap d = new KMap<>(); + + for (BlockVector i : getBlocks().keySet()) { + d.put(r.rotate(i.clone(), spinx, spiny, spinz), r.rotate(getBlocks().get(i).clone(), + spinx, spiny, spinz)); + } + + KMap> dx = new KMap<>(); + + for (BlockVector i : getStates().keySet()) { + dx.put(r.rotate(i.clone(), spinx, spiny, spinz), getStates().get(i)); + } + + blocks = d; + states = dx; + } + + public void place(Location at) { + for (BlockVector i : getBlocks().keySet()) { + Block b = at.clone().add(0, getCenter().getY(), 0).add(i).getBlock(); + b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false); + + if (getStates().containsKey(i)) { + Iris.info(Objects.requireNonNull(states.get(i)).toString()); + BlockState st = b.getState(); + Objects.requireNonNull(getStates().get(i)).toBukkitTry(st); + st.update(); + } + } + } + + public void placeCenterY(Location at) { + for (BlockVector i : getBlocks().keySet()) { + Block b = at.clone().add(getCenter().getX(), getCenter().getY(), getCenter().getZ()).add(i).getBlock(); + b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false); + + if (getStates().containsKey(i)) { + Objects.requireNonNull(getStates().get(i)).toBukkitTry(b.getState()); + } + } + } + + public synchronized KMap getBlocks() { + return blocks; + } + + public synchronized KMap> getStates() { + return states; + } + + public void unplaceCenterY(Location at) { + for (BlockVector i : getBlocks().keySet()) { + at.clone().add(getCenter().getX(), getCenter().getY(), getCenter().getZ()).add(i).getBlock().setBlockData(AIR, false); + } + } + + public IrisObjectLegacy scaled(double scale, IrisObjectPlacementScaleInterpolator interpolation) { + Vector sm1 = new Vector(scale - 1, scale - 1, scale - 1); + scale = Math.max(0.001, Math.min(50, scale)); + if (scale < 1) { + scale = scale - 0.0001; + } + + IrisPosition l1 = getAABB().max(); + IrisPosition l2 = getAABB().min(); + @SuppressWarnings({"unchecked", "rawtypes"}) HashMap placeBlock = new HashMap(); + + Vector center = getCenter(); + if (getH() == 2) { + center = center.setY(center.getBlockY() + 0.5); + } + if (getW() == 2) { + center = center.setX(center.getBlockX() + 0.5); + } + if (getD() == 2) { + center = center.setZ(center.getBlockZ() + 0.5); + } + + IrisObjectLegacy oo = new IrisObjectLegacy((int) Math.ceil((w * scale) + (scale * 2)), (int) Math.ceil((h * scale) + (scale * 2)), (int) Math.ceil((d * scale) + (scale * 2))); + + for (Map.Entry entry : blocks.entrySet()) { + BlockData bd = entry.getValue(); + placeBlock.put(entry.getKey().clone().add(HALF).subtract(center) + .multiply(scale).add(sm1).toBlockVector(), bd); + } + + for (Map.Entry entry : placeBlock.entrySet()) { + BlockVector v = entry.getKey(); + if (scale > 1) { + for (BlockVector vec : blocksBetweenTwoPoints(v.clone().add(center), v.clone().add(center).add(sm1))) { + oo.getBlocks().put(vec, entry.getValue()); + } + } else { + oo.setUnsigned(v.getBlockX(), v.getBlockY(), v.getBlockZ(), entry.getValue()); + } + } + + if (scale > 1) { + switch (interpolation) { + case TRILINEAR -> oo.trilinear((int) Math.round(scale)); + case TRICUBIC -> oo.tricubic((int) Math.round(scale)); + case TRIHERMITE -> oo.trihermite((int) Math.round(scale)); + } + } + + return oo; + } + + public void trilinear(int rad) { + KMap v = getBlocks().copy(); + KMap b = new KMap<>(); + BlockVector min = getAABB().minbv(); + BlockVector max = getAABB().maxbv(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { + for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { + if (IrisInterpolation.getTrilinear(x, y, z, rad, (xx, yy, zz) -> { + BlockData data = v.get(new BlockVector((int) xx, (int) yy, (int) zz)); + + if (data == null || data.getMaterial().isAir()) { + return 0; + } + + return 1; + }) >= 0.5) { + b.put(new BlockVector(x, y, z), nearestBlockData(x, y, z)); + } else { + b.put(new BlockVector(x, y, z), AIR); + } + } + } + } + + blocks = b; + } + + public void tricubic(int rad) { + KMap v = getBlocks().copy(); + KMap b = new KMap<>(); + BlockVector min = getAABB().minbv(); + BlockVector max = getAABB().maxbv(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { + for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { + if (IrisInterpolation.getTricubic(x, y, z, rad, (xx, yy, zz) -> { + BlockData data = v.get(new BlockVector((int) xx, (int) yy, (int) zz)); + + if (data == null || data.getMaterial().isAir()) { + return 0; + } + + return 1; + }) >= 0.5) { + b.put(new BlockVector(x, y, z), nearestBlockData(x, y, z)); + } else { + b.put(new BlockVector(x, y, z), AIR); + } + } + } + } + + blocks = b; + } + + public void trihermite(int rad) { + trihermite(rad, 0D, 0D); + } + + public void trihermite(int rad, double tension, double bias) { + KMap v = getBlocks().copy(); + KMap b = new KMap<>(); + BlockVector min = getAABB().minbv(); + BlockVector max = getAABB().maxbv(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { + for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { + if (IrisInterpolation.getTrihermite(x, y, z, rad, (xx, yy, zz) -> { + BlockData data = v.get(new BlockVector((int) xx, (int) yy, (int) zz)); + + if (data == null || data.getMaterial().isAir()) { + return 0; + } + + return 1; + }, tension, bias) >= 0.5) { + b.put(new BlockVector(x, y, z), nearestBlockData(x, y, z)); + } else { + b.put(new BlockVector(x, y, z), AIR); + } + } + } + } + + blocks = b; + } + + private BlockData nearestBlockData(int x, int y, int z) { + BlockVector vv = new BlockVector(x, y, z); + BlockData r = getBlocks().get(vv); + + if (r != null && !r.getMaterial().isAir()) { + return r; + } + + double d = Double.MAX_VALUE; + + for (Map.Entry entry : blocks.entrySet()) { + BlockData dat = entry.getValue(); + + if (dat.getMaterial().isAir()) { + continue; + } + + double dx = entry.getKey().distanceSquared(vv); + + if (dx < d) { + d = dx; + r = dat; + } + } + + return r; + } + + private static List blocksBetweenTwoPoints(Vector loc1, Vector loc2) { + List locations = new ArrayList<>(); + int topBlockX = Math.max(loc1.getBlockX(), loc2.getBlockX()); + int bottomBlockX = Math.min(loc1.getBlockX(), loc2.getBlockX()); + int topBlockY = Math.max(loc1.getBlockY(), loc2.getBlockY()); + int bottomBlockY = Math.min(loc1.getBlockY(), loc2.getBlockY()); + int topBlockZ = Math.max(loc1.getBlockZ(), loc2.getBlockZ()); + int bottomBlockZ = Math.min(loc1.getBlockZ(), loc2.getBlockZ()); + + for (int x = bottomBlockX; x <= topBlockX; x++) { + for (int z = bottomBlockZ; z <= topBlockZ; z++) { + for (int y = bottomBlockY; y <= topBlockY; y++) { + locations.add(new BlockVector(x, y, z)); + } + } + } + return locations; + } + + public int volume() { + return blocks.size(); + } + + @Override + public String getFolderName() { + return "objects"; + } + + @Override + public String getTypeName() { + return "Object"; + } +} From b19a7d45d886d7e99424f2bf1bcb5dfd81064cb7 Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Wed, 18 Aug 2021 23:26:30 -0400 Subject: [PATCH 09/13] Unfuck the decorator stacks --- .../volmit/iris/engine/actuator/IrisDecorantActuator.java | 1 + .../volmit/iris/engine/decorator/IrisSurfaceDecorator.java | 4 ---- .../volmit/iris/engine/object/decoration/IrisDecorator.java | 5 ++++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/volmit/iris/engine/actuator/IrisDecorantActuator.java b/src/main/java/com/volmit/iris/engine/actuator/IrisDecorantActuator.java index 6184b62a6..1701a779d 100644 --- a/src/main/java/com/volmit/iris/engine/actuator/IrisDecorantActuator.java +++ b/src/main/java/com/volmit/iris/engine/actuator/IrisDecorantActuator.java @@ -18,6 +18,7 @@ package com.volmit.iris.engine.actuator; +import com.volmit.iris.Iris; import com.volmit.iris.engine.decorator.*; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.EngineAssignedActuator; diff --git a/src/main/java/com/volmit/iris/engine/decorator/IrisSurfaceDecorator.java b/src/main/java/com/volmit/iris/engine/decorator/IrisSurfaceDecorator.java index 38351ea8a..3a66a28ac 100644 --- a/src/main/java/com/volmit/iris/engine/decorator/IrisSurfaceDecorator.java +++ b/src/main/java/com/volmit/iris/engine/decorator/IrisSurfaceDecorator.java @@ -77,10 +77,6 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator { } int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData()); - if (decorator.isScaleStack()) { - int maxStack = max - height; - stack = (int) Math.ceil((double) maxStack * ((double) stack / 100)); - } else stack = Math.min(height - max, stack); if (stack == 1) { data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())); diff --git a/src/main/java/com/volmit/iris/engine/object/decoration/IrisDecorator.java b/src/main/java/com/volmit/iris/engine/object/decoration/IrisDecorator.java index f5795fafc..99ce1e2d7 100644 --- a/src/main/java/com/volmit/iris/engine/object/decoration/IrisDecorator.java +++ b/src/main/java/com/volmit/iris/engine/object/decoration/IrisDecorator.java @@ -107,7 +107,10 @@ public class IrisDecorator { return stackMin; } - return getHeightGenerator(rng, data).fit(stackMin, stackMax, x / heightVariance.getZoom(), z / heightVariance.getZoom()) + 1; + return getHeightGenerator(rng, data) + .fit(stackMin, stackMax, + x / heightVariance.getZoom(), + z / heightVariance.getZoom()) + 1; } public CNG getHeightGenerator(RNG rng, IrisData data) { From c486f65e74fa670605f0efa61dc8c27cebdd726a Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Wed, 18 Aug 2021 17:23:54 -0400 Subject: [PATCH 10/13] Revert "Legacy objects copy" This reverts commit 7f7397f68400d19c0c662d9d2b6371479651f111. --- .../object/objects/IrisObjectLegacy.java | 997 ------------------ 1 file changed, 997 deletions(-) delete mode 100644 src/main/java/com/volmit/iris/engine/object/objects/IrisObjectLegacy.java diff --git a/src/main/java/com/volmit/iris/engine/object/objects/IrisObjectLegacy.java b/src/main/java/com/volmit/iris/engine/object/objects/IrisObjectLegacy.java deleted file mode 100644 index 9b2e1ab6d..000000000 --- a/src/main/java/com/volmit/iris/engine/object/objects/IrisObjectLegacy.java +++ /dev/null @@ -1,997 +0,0 @@ -/* - * 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.object.objects; - -import com.volmit.iris.Iris; -import com.volmit.iris.core.project.loader.IrisData; -import com.volmit.iris.core.project.loader.IrisRegistrant; -import com.volmit.iris.engine.data.cache.AtomicCache; -import com.volmit.iris.engine.framework.placer.HeightmapObjectPlacer; -import com.volmit.iris.engine.object.basic.IrisPosition; -import com.volmit.iris.engine.object.common.CarveResult; -import com.volmit.iris.engine.object.common.IObjectPlacer; -import com.volmit.iris.engine.object.tile.TileData; -import com.volmit.iris.util.collection.KList; -import com.volmit.iris.util.collection.KMap; -import com.volmit.iris.util.data.B; -import com.volmit.iris.util.interpolation.IrisInterpolation; -import com.volmit.iris.util.math.AxisAlignedBB; -import com.volmit.iris.util.math.BlockPosition; -import com.volmit.iris.util.math.Position2; -import com.volmit.iris.util.math.RNG; -import com.volmit.iris.util.scheduling.IrisLock; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; -import lombok.experimental.Accessors; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.block.TileState; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.Leaves; -import org.bukkit.util.BlockVector; -import org.bukkit.util.Vector; - -import java.io.*; -import java.util.*; -import java.util.function.Consumer; - -@SuppressWarnings("DefaultAnnotationParam") -@Accessors(chain = true) -@EqualsAndHashCode(callSuper = false) -public class IrisObjectLegacy extends IrisRegistrant { - protected static final Vector HALF = new Vector(0.5, 0.5, 0.5); - protected static final BlockData AIR = B.get("CAVE_AIR"); - protected static final BlockData VAIR = B.get("VOID_AIR"); - protected static final BlockData VAIR_DEBUG = B.get("COBWEB"); - protected static final BlockData[] SNOW_LAYERS = new BlockData[]{B.get("minecraft:snow[layers=1]"), B.get("minecraft:snow[layers=2]"), B.get("minecraft:snow[layers=3]"), B.get("minecraft:snow[layers=4]"), B.get("minecraft:snow[layers=5]"), B.get("minecraft:snow[layers=6]"), B.get("minecraft:snow[layers=7]"), B.get("minecraft:snow[layers=8]")}; - - private KMap blocks; - private KMap> states; - @Getter - @Setter - private int w; - @Getter - @Setter - private int d; - @Getter - @Setter - private int h; - protected transient final IrisLock readLock = new IrisLock("read-conclock"); - @Getter - @Setter - private transient BlockVector center; - @Getter - @Setter - protected transient volatile boolean smartBored = false; - @Getter - @Setter - protected transient IrisLock lock = new IrisLock("Preloadcache"); - @Setter - protected transient AtomicCache aabb = new AtomicCache<>(); - - public IrisObjectLegacy(int w, int h, int d) { - blocks = new KMap<>(); - states = new KMap<>(); - this.w = w; - this.h = h; - this.d = d; - center = new BlockVector(w / 2, h / 2, d / 2); - } - - public IrisObjectLegacy() { - this(0, 0, 0); - } - - public AxisAlignedBB getAABB() { - return aabb.aquire(() -> getAABBFor(new BlockVector(w, h, d))); - } - - public static BlockVector getCenterForSize(BlockVector size) { - return new BlockVector(size.getX() / 2, size.getY() / 2, size.getZ() / 2); - } - - public static AxisAlignedBB getAABBFor(BlockVector size) { - BlockVector center = new BlockVector(size.getX() / 2, size.getY() / 2, size.getZ() / 2); - return new AxisAlignedBB(new IrisPosition(new BlockVector(0, 0, 0).subtract(center).toBlockVector()), - new IrisPosition(new BlockVector(size.getX() - 1, size.getY() - 1, size.getZ() - 1).subtract(center).toBlockVector())); - } - - public void ensureSmartBored(boolean debug) { - if (smartBored) { - return; - } - - lock.lock(); - int applied = 0; - if (getBlocks().isEmpty()) { - lock.unlock(); - Iris.warn("Cannot Smart Bore " + getLoadKey() + " because it has 0 blocks in it."); - smartBored = true; - return; - } - - BlockVector max = new BlockVector(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE); - BlockVector min = new BlockVector(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE); - - for (BlockVector i : getBlocks().keySet()) { - max.setX(Math.max(i.getX(), max.getX())); - min.setX(Math.min(i.getX(), min.getX())); - max.setY(Math.max(i.getY(), max.getY())); - min.setY(Math.min(i.getY(), min.getY())); - max.setZ(Math.max(i.getZ(), max.getZ())); - min.setZ(Math.min(i.getZ(), min.getZ())); - } - - // Smash X - for (int rayY = min.getBlockY(); rayY <= max.getBlockY(); rayY++) { - for (int rayZ = min.getBlockZ(); rayZ <= max.getBlockZ(); rayZ++) { - int start = Integer.MAX_VALUE; - int end = Integer.MIN_VALUE; - - for (int ray = min.getBlockX(); ray <= max.getBlockX(); ray++) { - if (getBlocks().containsKey(new BlockVector(ray, rayY, rayZ))) { - start = Math.min(ray, start); - end = Math.max(ray, end); - } - } - - if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) { - for (int i = start; i <= end; i++) { - BlockVector v = new BlockVector(i, rayY, rayZ); - - if (!getBlocks().containsKey(v) || B.isAir(getBlocks().get(v))) { - getBlocks().put(v, debug ? VAIR_DEBUG : VAIR); - applied++; - } - } - } - } - } - - // Smash Y - for (int rayX = min.getBlockX(); rayX <= max.getBlockX(); rayX++) { - for (int rayZ = min.getBlockZ(); rayZ <= max.getBlockZ(); rayZ++) { - int start = Integer.MAX_VALUE; - int end = Integer.MIN_VALUE; - - for (int ray = min.getBlockY(); ray <= max.getBlockY(); ray++) { - if (getBlocks().containsKey(new BlockVector(rayX, ray, rayZ))) { - start = Math.min(ray, start); - end = Math.max(ray, end); - } - } - - if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) { - for (int i = start; i <= end; i++) { - BlockVector v = new BlockVector(rayX, i, rayZ); - - if (!getBlocks().containsKey(v) || B.isAir(getBlocks().get(v))) { - getBlocks().put(v, debug ? VAIR_DEBUG : VAIR); - applied++; - } - } - } - } - } - - // Smash Z - for (int rayX = min.getBlockX(); rayX <= max.getBlockX(); rayX++) { - for (int rayY = min.getBlockY(); rayY <= max.getBlockY(); rayY++) { - int start = Integer.MAX_VALUE; - int end = Integer.MIN_VALUE; - - for (int ray = min.getBlockZ(); ray <= max.getBlockZ(); ray++) { - if (getBlocks().containsKey(new BlockVector(rayX, rayY, ray))) { - start = Math.min(ray, start); - end = Math.max(ray, end); - } - } - - if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) { - for (int i = start; i <= end; i++) { - BlockVector v = new BlockVector(rayX, rayY, i); - - if (!getBlocks().containsKey(v) || B.isAir(getBlocks().get(v))) { - getBlocks().put(v, debug ? VAIR_DEBUG : VAIR); - applied++; - } - } - } - } - } - - Iris.verbose("- Applied Smart Bore to " + getLoadKey() + " Filled with " + applied + " VOID_AIR blocks."); - - smartBored = true; - lock.unlock(); - } - - public synchronized IrisObjectLegacy copy() { - IrisObjectLegacy o = new IrisObjectLegacy(w, h, d); - o.setLoadKey(o.getLoadKey()); - o.setCenter(getCenter().clone()); - - for (BlockVector i : getBlocks().keySet()) { - o.getBlocks().put(i.clone(), Objects.requireNonNull(getBlocks().get(i)).clone()); - } - - for (BlockVector i : getStates().keySet()) { - o.getStates().put(i.clone(), Objects.requireNonNull(getStates().get(i)).clone()); - } - - return o; - } - - @SuppressWarnings({"resource", "RedundantSuppression"}) - public static BlockVector sampleSize(File file) throws IOException { - FileInputStream in = new FileInputStream(file); - DataInputStream din = new DataInputStream(in); - BlockVector bv = new BlockVector(din.readInt(), din.readInt(), din.readInt()); - Iris.later(din::close); - return bv; - } - - public void readLegacy(InputStream in) throws IOException { - DataInputStream din = new DataInputStream(in); - this.w = din.readInt(); - this.h = din.readInt(); - this.d = din.readInt(); - center = new BlockVector(w / 2, h / 2, d / 2); - int s = din.readInt(); - - for (int i = 0; i < s; i++) { - getBlocks().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), B.get(din.readUTF())); - } - - try { - int size = din.readInt(); - - for (int i = 0; i < size; i++) { - getStates().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), TileData.read(din)); - } - } catch (Throwable e) { - Iris.reportError(e); - - } - } - - public void read(InputStream in) throws Throwable { - DataInputStream din = new DataInputStream(in); - this.w = din.readInt(); - this.h = din.readInt(); - this.d = din.readInt(); - if (!din.readUTF().equals("Iris V2 IOB;")) { - throw new IOException("Not V2 Format"); - } - center = new BlockVector(w / 2, h / 2, d / 2); - int s = din.readShort(); - int i; - KList palette = new KList<>(); - - for (i = 0; i < s; i++) { - palette.add(din.readUTF()); - } - - s = din.readInt(); - - for (i = 0; i < s; i++) { - getBlocks().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), B.get(palette.get(din.readShort()))); - } - - s = din.readInt(); - - for (i = 0; i < s; i++) { - getStates().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), TileData.read(din)); - } - } - - public void write(OutputStream o) throws IOException { - DataOutputStream dos = new DataOutputStream(o); - dos.writeInt(w); - dos.writeInt(h); - dos.writeInt(d); - dos.writeUTF("Iris V2 IOB;"); - KList palette = new KList<>(); - - for (BlockData i : getBlocks().values()) { - palette.addIfMissing(i.getAsString()); - } - - dos.writeShort(palette.size()); - - for (String i : palette) { - dos.writeUTF(i); - } - - dos.writeInt(getBlocks().size()); - - for (BlockVector i : getBlocks().keySet()) { - dos.writeShort(i.getBlockX()); - dos.writeShort(i.getBlockY()); - dos.writeShort(i.getBlockZ()); - dos.writeShort(palette.indexOf(getBlocks().get(i).getAsString())); - } - - dos.writeInt(getStates().size()); - for (BlockVector i : getStates().keySet()) { - dos.writeShort(i.getBlockX()); - dos.writeShort(i.getBlockY()); - dos.writeShort(i.getBlockZ()); - getStates().get(i).toBinary(dos); - } - } - - public void read(File file) throws IOException { - FileInputStream fin = new FileInputStream(file); - try { - read(fin); - fin.close(); - } catch (Throwable e) { - Iris.reportError(e); - fin.close(); - fin = new FileInputStream(file); - readLegacy(fin); - fin.close(); - } - } - - public void write(File file) throws IOException { - if (file == null) { - return; - } - - FileOutputStream out = new FileOutputStream(file); - write(out); - out.close(); - } - - public void clean() { - KMap d = new KMap<>(); - - for (BlockVector i : getBlocks().keySet()) { - d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i))); - } - - KMap> dx = new KMap<>(); - - for (BlockVector i : getBlocks().keySet()) { - d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i))); - } - - for (BlockVector i : getStates().keySet()) { - dx.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getStates().get(i))); - } - - blocks = d; - states = dx; - } - - public BlockVector getSigned(int x, int y, int z) { - if (x >= w || y >= h || z >= d) { - throw new RuntimeException(x + " " + y + " " + z + " exceeds limit of " + w + " " + h + " " + d); - } - - return new BlockVector(x, y, z).subtract(center).toBlockVector(); - } - - public void setUnsigned(int x, int y, int z, BlockData block) { - BlockVector v = getSigned(x, y, z); - - if (block == null) { - getBlocks().remove(v); - getStates().remove(v); - } else { - getBlocks().put(v, block); - } - } - - public void setUnsigned(int x, int y, int z, Block block) { - BlockVector v = getSigned(x, y, z); - - if (block == null) { - getBlocks().remove(v); - getStates().remove(v); - } else { - BlockData data = block.getBlockData(); - getBlocks().put(v, data); - TileData state = TileData.getTileState(block); - if (state != null) { - Iris.info("Saved State " + v); - getStates().put(v, state); - } - } - } - - public int place(int x, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng, IrisData rdata) { - return place(x, -1, z, placer, config, rng, rdata); - } - - public int place(int x, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng, CarveResult c, IrisData rdata) { - return place(x, -1, z, placer, config, rng, null, c, rdata); - } - - public int place(int x, int yv, int z, IObjectPlacer placer, IrisObjectPlacement config, RNG rng, IrisData rdata) { - return place(x, yv, z, placer, config, rng, null, null, rdata); - } - - public int place(Location loc, IObjectPlacer placer, IrisObjectPlacement config, RNG rng, IrisData rdata) { - return place(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), placer, config, rng, rdata); - } - - public int place(int x, int yv, int z, IObjectPlacer oplacer, IrisObjectPlacement config, RNG rng, Consumer listener, CarveResult c, IrisData rdata) { - IObjectPlacer placer = (config.getHeightmap() != null) ? new HeightmapObjectPlacer(rng, x, yv, z, config, oplacer) : oplacer; - - if (config.isSmartBore()) { - ensureSmartBored(placer.isDebugSmartBore()); - } - - boolean warped = !config.getWarp().isFlat(); - boolean stilting = (config.getMode().equals(ObjectPlaceMode.STILT) || config.getMode().equals(ObjectPlaceMode.FAST_STILT)); - KMap heightmap = config.getSnow() > 0 ? new KMap<>() : null; - int spinx = rng.imax() / 1000; - int spiny = rng.imax() / 1000; - int spinz = rng.imax() / 1000; - int rty = config.getRotation().rotate(new BlockVector(0, getCenter().getBlockY(), 0), spinx, spiny, spinz).getBlockY(); - int ty = config.getTranslate().translate(new BlockVector(0, getCenter().getBlockY(), 0), config.getRotation(), spinx, spiny, spinz).getBlockY(); - int y = -1; - int xx, zz; - int yrand = config.getTranslate().getYRandom(); - yrand = yrand > 0 ? rng.i(0, yrand) : yrand < 0 ? rng.i(yrand, 0) : yrand; - - if (yv < 0) { - if (config.getMode().equals(ObjectPlaceMode.CENTER_HEIGHT)) { - y = (c != null ? c.getSurface() : placer.getHighest(x, z, getLoader(), config.isUnderwater())) + rty; - } else if (config.getMode().equals(ObjectPlaceMode.MAX_HEIGHT) || config.getMode().equals(ObjectPlaceMode.STILT)) { - BlockVector offset = new BlockVector(config.getTranslate().getX(), config.getTranslate().getY(), config.getTranslate().getZ()); - BlockVector rotatedDimensions = config.getRotation().rotate(new BlockVector(getW(), getH(), getD()), spinx, spiny, spinz).clone(); - - for (int i = x - (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i <= x + (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i++) { - for (int j = z - (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j <= z + (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j++) { - int h = placer.getHighest(i, j, getLoader(), config.isUnderwater()) + rty; - - if (h > y) { - y = h; - } - } - } - } else if (config.getMode().equals(ObjectPlaceMode.FAST_MAX_HEIGHT) || config.getMode().equals(ObjectPlaceMode.VACUUM) || config.getMode().equals(ObjectPlaceMode.FAST_STILT)) { - BlockVector offset = new BlockVector(config.getTranslate().getX(), config.getTranslate().getY(), config.getTranslate().getZ()); - BlockVector rotatedDimensions = config.getRotation().rotate(new BlockVector(getW(), getH(), getD()), spinx, spiny, spinz).clone(); - - for (int i = x - (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i <= x + (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i += (rotatedDimensions.getBlockX() / 2) + 1) { - for (int j = z - (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j <= z + (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j += (rotatedDimensions.getBlockZ() / 2) + 1) { - int h = placer.getHighest(i, j, getLoader(), config.isUnderwater()) + rty; - - if (h > y) { - y = h; - } - } - } - } else if (config.getMode().equals(ObjectPlaceMode.MIN_HEIGHT)) { - y = 257; - BlockVector offset = new BlockVector(config.getTranslate().getX(), config.getTranslate().getY(), config.getTranslate().getZ()); - BlockVector rotatedDimensions = config.getRotation().rotate(new BlockVector(getW(), getH(), getD()), spinx, spiny, spinz).clone(); - - for (int i = x - (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i <= x + (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i++) { - for (int j = z - (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j <= z + (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j++) { - int h = placer.getHighest(i, j, getLoader(), config.isUnderwater()) + rty; - - if (h < y) { - y = h; - } - } - } - } else if (config.getMode().equals(ObjectPlaceMode.FAST_MIN_HEIGHT)) { - y = 257; - BlockVector offset = new BlockVector(config.getTranslate().getX(), config.getTranslate().getY(), config.getTranslate().getZ()); - BlockVector rotatedDimensions = config.getRotation().rotate(new BlockVector(getW(), getH(), getD()), spinx, spiny, spinz).clone(); - - for (int i = x - (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i <= x + (rotatedDimensions.getBlockX() / 2) + offset.getBlockX(); i += (rotatedDimensions.getBlockX() / 2) + 1) { - for (int j = z - (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j <= z + (rotatedDimensions.getBlockZ() / 2) + offset.getBlockZ(); j += (rotatedDimensions.getBlockZ() / 2) + 1) { - int h = placer.getHighest(i, j, getLoader(), config.isUnderwater()) + rty; - - if (h < y) { - y = h; - } - } - } - } else if (config.getMode().equals(ObjectPlaceMode.PAINT)) { - y = placer.getHighest(x, z, getLoader(), config.isUnderwater()) + rty; - } - } else { - y = yv; - } - - if (yv >= 0 && config.isBottom()) { - y += Math.floorDiv(h, 2); - } - - if (yv < 0) { - if (!config.isUnderwater() && !config.isOnwater() && placer.isUnderwater(x, z)) { - return -1; - } - } - - if (c != null && Math.max(0, h + yrand + ty) + 1 >= c.getHeight()) { - return -1; - } - - if (config.isUnderwater() && y + rty + ty >= placer.getFluidHeight()) { - return -1; - } - - if (!config.getClamp().canPlace(y + rty + ty, y - rty + ty)) { - return -1; - } - - if (config.isBore()) { - BlockVector offset = new BlockVector(config.getTranslate().getX(), config.getTranslate().getY(), config.getTranslate().getZ()); - for (int i = x - Math.floorDiv(w, 2) + (int) offset.getX(); i <= x + Math.floorDiv(w, 2) - (w % 2 == 0 ? 1 : 0) + (int) offset.getX(); i++) { - for (int j = y - Math.floorDiv(h, 2) - config.getBoreExtendMinY() + (int) offset.getY(); j <= y + Math.floorDiv(h, 2) + config.getBoreExtendMaxY() - (h % 2 == 0 ? 1 : 0) + (int) offset.getY(); j++) { - for (int k = z - Math.floorDiv(d, 2) + (int) offset.getZ(); k <= z + Math.floorDiv(d, 2) - (d % 2 == 0 ? 1 : 0) + (int) offset.getX(); k++) { - placer.set(i, j, k, AIR); - } - } - } - } - - int lowest = Integer.MAX_VALUE; - y += yrand; - readLock.lock(); - try { - for (BlockVector g : getBlocks().keySet()) { - BlockData d; - TileData tile = null; - - try { - d = getBlocks().get(g); - tile = getStates().get(g); - } catch (Throwable e) { - Iris.reportError(e); - Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (cme)"); - d = AIR; - } - - if (d == null) { - Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (null)"); - d = AIR; - } - - BlockVector i = g.clone(); - BlockData data = d.clone(); - i = config.getRotation().rotate(i.clone(), spinx, spiny, spinz).clone(); - i = config.getTranslate().translate(i.clone(), config.getRotation(), spinx, spiny, spinz).clone(); - - if (stilting && i.getBlockY() < lowest && !B.isAir(data)) { - lowest = i.getBlockY(); - } - - if (placer.isPreventingDecay() && (data) instanceof Leaves && !((Leaves) (data)).isPersistent()) { - ((Leaves) data).setPersistent(true); - } - - for (IrisObjectReplace j : config.getEdit()) { - if (rng.chance(j.getChance())) { - for (BlockData k : j.getFind(rdata)) { - if (j.isExact() ? k.matches(data) : k.getMaterial().equals(data.getMaterial())) { - BlockData newData = j.getReplace(rng, i.getX() + x, i.getY() + y, i.getZ() + z, rdata).clone(); - - if (newData.getMaterial() == data.getMaterial()) { - data = data.merge(newData); - } else { - data = newData; - } - } - } - } - } - - data = config.getRotation().rotate(data, spinx, spiny, spinz); - xx = x + (int) Math.round(i.getX()); - int yy = y + (int) Math.round(i.getY()); - zz = z + (int) Math.round(i.getZ()); - - if (warped) { - xx += config.warp(rng, i.getX() + x, i.getY() + y, i.getZ() + z, getLoader()); - zz += config.warp(rng, i.getZ() + z, i.getY() + y, i.getX() + x, getLoader()); - } - - if (yv < 0 && (config.getMode().equals(ObjectPlaceMode.PAINT))) { - yy = (int) Math.round(i.getY()) + Math.floorDiv(h, 2) + placer.getHighest(xx, zz, getLoader(), config.isUnderwater()); - } - - if (heightmap != null) { - Position2 pos = new Position2(xx, zz); - - if (!heightmap.containsKey(pos)) { - heightmap.put(pos, yy); - } - - if (heightmap.get(pos) < yy) { - heightmap.put(pos, yy); - } - } - - if (config.isMeld() && !placer.isSolid(xx, yy, zz)) { - continue; - } - - if (config.isWaterloggable() && yy <= placer.getFluidHeight() && data instanceof Waterlogged) { - ((Waterlogged) data).setWaterlogged(true); - } - - if (listener != null) { - listener.accept(new BlockPosition(xx, yy, zz)); - } - - if (!data.getMaterial().equals(Material.AIR) && !data.getMaterial().equals(Material.CAVE_AIR)) { - placer.set(xx, yy, zz, data); - - if (tile != null) { - placer.setTile(xx, yy, zz, tile); - } - } - } - } catch (Throwable e) { - Iris.reportError(e); - } - readLock.unlock(); - - if (stilting) { - readLock.lock(); - for (BlockVector g : getBlocks().keySet()) { - BlockData d; - - try { - d = getBlocks().get(g); - } catch (Throwable e) { - Iris.reportError(e); - Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (stilt cme)"); - d = AIR; - } - - if (d == null) { - Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (stilt null)"); - d = AIR; - } - - BlockVector i = g.clone(); - i = config.getRotation().rotate(i.clone(), spinx, spiny, spinz).clone(); - i = config.getTranslate().translate(i.clone(), config.getRotation(), spinx, spiny, spinz).clone(); - - if (i.getBlockY() != lowest) { - continue; - } - - - if (d == null || B.isAir(d)) { - continue; - } - - xx = x + (int) Math.round(i.getX()); - zz = z + (int) Math.round(i.getZ()); - - if (warped) { - xx += config.warp(rng, i.getX() + x, i.getY() + y, i.getZ() + z, getLoader()); - zz += config.warp(rng, i.getZ() + z, i.getY() + y, i.getX() + x, getLoader()); - } - - int yg = placer.getHighest(xx, zz, getLoader(), config.isUnderwater()); - - if (yv >= 0 && config.isBottom()) { - y += Math.floorDiv(h, 2); - } - - for (int j = lowest + y; j > yg - config.getOverStilt() - 1; j--) { - placer.set(xx, j, zz, d); - } - } - - readLock.unlock(); - } - - if (heightmap != null) { - RNG rngx = rng.nextParallelRNG(3468854); - - for (Position2 i : heightmap.k()) { - int vx = i.getX(); - int vy = heightmap.get(i); - int vz = i.getZ(); - - if (config.getSnow() > 0) { - int height = rngx.i(0, (int) (config.getSnow() * 7)); - placer.set(vx, vy + 1, vz, SNOW_LAYERS[Math.max(Math.min(height, 7), 0)]); - } - } - } - - return y; - } - - public IrisObjectLegacy rotateCopy(IrisObjectRotation rt) { - IrisObjectLegacy copy = copy(); - copy.rotate(rt, 0, 0, 0); - return copy; - } - - public void rotate(IrisObjectRotation r, int spinx, int spiny, int spinz) { - KMap d = new KMap<>(); - - for (BlockVector i : getBlocks().keySet()) { - d.put(r.rotate(i.clone(), spinx, spiny, spinz), r.rotate(getBlocks().get(i).clone(), - spinx, spiny, spinz)); - } - - KMap> dx = new KMap<>(); - - for (BlockVector i : getStates().keySet()) { - dx.put(r.rotate(i.clone(), spinx, spiny, spinz), getStates().get(i)); - } - - blocks = d; - states = dx; - } - - public void place(Location at) { - for (BlockVector i : getBlocks().keySet()) { - Block b = at.clone().add(0, getCenter().getY(), 0).add(i).getBlock(); - b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false); - - if (getStates().containsKey(i)) { - Iris.info(Objects.requireNonNull(states.get(i)).toString()); - BlockState st = b.getState(); - Objects.requireNonNull(getStates().get(i)).toBukkitTry(st); - st.update(); - } - } - } - - public void placeCenterY(Location at) { - for (BlockVector i : getBlocks().keySet()) { - Block b = at.clone().add(getCenter().getX(), getCenter().getY(), getCenter().getZ()).add(i).getBlock(); - b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false); - - if (getStates().containsKey(i)) { - Objects.requireNonNull(getStates().get(i)).toBukkitTry(b.getState()); - } - } - } - - public synchronized KMap getBlocks() { - return blocks; - } - - public synchronized KMap> getStates() { - return states; - } - - public void unplaceCenterY(Location at) { - for (BlockVector i : getBlocks().keySet()) { - at.clone().add(getCenter().getX(), getCenter().getY(), getCenter().getZ()).add(i).getBlock().setBlockData(AIR, false); - } - } - - public IrisObjectLegacy scaled(double scale, IrisObjectPlacementScaleInterpolator interpolation) { - Vector sm1 = new Vector(scale - 1, scale - 1, scale - 1); - scale = Math.max(0.001, Math.min(50, scale)); - if (scale < 1) { - scale = scale - 0.0001; - } - - IrisPosition l1 = getAABB().max(); - IrisPosition l2 = getAABB().min(); - @SuppressWarnings({"unchecked", "rawtypes"}) HashMap placeBlock = new HashMap(); - - Vector center = getCenter(); - if (getH() == 2) { - center = center.setY(center.getBlockY() + 0.5); - } - if (getW() == 2) { - center = center.setX(center.getBlockX() + 0.5); - } - if (getD() == 2) { - center = center.setZ(center.getBlockZ() + 0.5); - } - - IrisObjectLegacy oo = new IrisObjectLegacy((int) Math.ceil((w * scale) + (scale * 2)), (int) Math.ceil((h * scale) + (scale * 2)), (int) Math.ceil((d * scale) + (scale * 2))); - - for (Map.Entry entry : blocks.entrySet()) { - BlockData bd = entry.getValue(); - placeBlock.put(entry.getKey().clone().add(HALF).subtract(center) - .multiply(scale).add(sm1).toBlockVector(), bd); - } - - for (Map.Entry entry : placeBlock.entrySet()) { - BlockVector v = entry.getKey(); - if (scale > 1) { - for (BlockVector vec : blocksBetweenTwoPoints(v.clone().add(center), v.clone().add(center).add(sm1))) { - oo.getBlocks().put(vec, entry.getValue()); - } - } else { - oo.setUnsigned(v.getBlockX(), v.getBlockY(), v.getBlockZ(), entry.getValue()); - } - } - - if (scale > 1) { - switch (interpolation) { - case TRILINEAR -> oo.trilinear((int) Math.round(scale)); - case TRICUBIC -> oo.tricubic((int) Math.round(scale)); - case TRIHERMITE -> oo.trihermite((int) Math.round(scale)); - } - } - - return oo; - } - - public void trilinear(int rad) { - KMap v = getBlocks().copy(); - KMap b = new KMap<>(); - BlockVector min = getAABB().minbv(); - BlockVector max = getAABB().maxbv(); - - for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { - for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { - for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { - if (IrisInterpolation.getTrilinear(x, y, z, rad, (xx, yy, zz) -> { - BlockData data = v.get(new BlockVector((int) xx, (int) yy, (int) zz)); - - if (data == null || data.getMaterial().isAir()) { - return 0; - } - - return 1; - }) >= 0.5) { - b.put(new BlockVector(x, y, z), nearestBlockData(x, y, z)); - } else { - b.put(new BlockVector(x, y, z), AIR); - } - } - } - } - - blocks = b; - } - - public void tricubic(int rad) { - KMap v = getBlocks().copy(); - KMap b = new KMap<>(); - BlockVector min = getAABB().minbv(); - BlockVector max = getAABB().maxbv(); - - for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { - for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { - for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { - if (IrisInterpolation.getTricubic(x, y, z, rad, (xx, yy, zz) -> { - BlockData data = v.get(new BlockVector((int) xx, (int) yy, (int) zz)); - - if (data == null || data.getMaterial().isAir()) { - return 0; - } - - return 1; - }) >= 0.5) { - b.put(new BlockVector(x, y, z), nearestBlockData(x, y, z)); - } else { - b.put(new BlockVector(x, y, z), AIR); - } - } - } - } - - blocks = b; - } - - public void trihermite(int rad) { - trihermite(rad, 0D, 0D); - } - - public void trihermite(int rad, double tension, double bias) { - KMap v = getBlocks().copy(); - KMap b = new KMap<>(); - BlockVector min = getAABB().minbv(); - BlockVector max = getAABB().maxbv(); - - for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { - for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { - for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { - if (IrisInterpolation.getTrihermite(x, y, z, rad, (xx, yy, zz) -> { - BlockData data = v.get(new BlockVector((int) xx, (int) yy, (int) zz)); - - if (data == null || data.getMaterial().isAir()) { - return 0; - } - - return 1; - }, tension, bias) >= 0.5) { - b.put(new BlockVector(x, y, z), nearestBlockData(x, y, z)); - } else { - b.put(new BlockVector(x, y, z), AIR); - } - } - } - } - - blocks = b; - } - - private BlockData nearestBlockData(int x, int y, int z) { - BlockVector vv = new BlockVector(x, y, z); - BlockData r = getBlocks().get(vv); - - if (r != null && !r.getMaterial().isAir()) { - return r; - } - - double d = Double.MAX_VALUE; - - for (Map.Entry entry : blocks.entrySet()) { - BlockData dat = entry.getValue(); - - if (dat.getMaterial().isAir()) { - continue; - } - - double dx = entry.getKey().distanceSquared(vv); - - if (dx < d) { - d = dx; - r = dat; - } - } - - return r; - } - - private static List blocksBetweenTwoPoints(Vector loc1, Vector loc2) { - List locations = new ArrayList<>(); - int topBlockX = Math.max(loc1.getBlockX(), loc2.getBlockX()); - int bottomBlockX = Math.min(loc1.getBlockX(), loc2.getBlockX()); - int topBlockY = Math.max(loc1.getBlockY(), loc2.getBlockY()); - int bottomBlockY = Math.min(loc1.getBlockY(), loc2.getBlockY()); - int topBlockZ = Math.max(loc1.getBlockZ(), loc2.getBlockZ()); - int bottomBlockZ = Math.min(loc1.getBlockZ(), loc2.getBlockZ()); - - for (int x = bottomBlockX; x <= topBlockX; x++) { - for (int z = bottomBlockZ; z <= topBlockZ; z++) { - for (int y = bottomBlockY; y <= topBlockY; y++) { - locations.add(new BlockVector(x, y, z)); - } - } - } - return locations; - } - - public int volume() { - return blocks.size(); - } - - @Override - public String getFolderName() { - return "objects"; - } - - @Override - public String getTypeName() { - return "Object"; - } -} From 59244950356bc3fffe5817974ae9ce4b2fabd91e Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Wed, 18 Aug 2021 23:41:51 -0400 Subject: [PATCH 11/13] Fix sea surface --- .../engine/actuator/IrisDecorantActuator.java | 21 ++++++++++++------- .../decorator/IrisSeaSurfaceDecorator.java | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/volmit/iris/engine/actuator/IrisDecorantActuator.java b/src/main/java/com/volmit/iris/engine/actuator/IrisDecorantActuator.java index 1701a779d..000c4ff5e 100644 --- a/src/main/java/com/volmit/iris/engine/actuator/IrisDecorantActuator.java +++ b/src/main/java/com/volmit/iris/engine/actuator/IrisDecorantActuator.java @@ -23,8 +23,11 @@ import com.volmit.iris.engine.decorator.*; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.EngineAssignedActuator; import com.volmit.iris.engine.framework.EngineDecorator; +import com.volmit.iris.engine.object.biome.InferredType; import com.volmit.iris.engine.object.biome.IrisBiome; import com.volmit.iris.engine.object.carve.IrisCaveLayer; +import com.volmit.iris.engine.object.decoration.IrisDecorationPart; +import com.volmit.iris.engine.object.decoration.IrisDecorator; import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.math.RNG; @@ -108,18 +111,22 @@ public class IrisDecorantActuator extends EngineAssignedActuator { continue; } + if(height < getDimension().getFluidHeight()) + { + getSeaSurfaceDecorator().decorate(i, j, + realX, (int) Math.round(modX(x + i + 1)), (int) Math.round(modX(x + i - 1)), + realZ, (int) Math.round(modZ(z + j + 1)), (int) Math.round(modZ(z + j - 1)), + output, biome, getDimension().getFluidHeight(), getEngine().getHeight()); + getSeaFloorDecorator().decorate(i, j, + realX, realZ, output, biome, height + 1, + getDimension().getFluidHeight() + 1); + } + if (height == getDimension().getFluidHeight()) { getShoreLineDecorator().decorate(i, j, realX, (int) Math.round(modX(x + i + 1)), (int) Math.round(modX(x + i - 1)), realZ, (int) Math.round(modZ(z + j + 1)), (int) Math.round(modZ(z + j - 1)), output, biome, height, getEngine().getHeight()); - } else if (height == getDimension().getFluidHeight() + 1) { - getSeaSurfaceDecorator().decorate(i, j, - realX, (int) Math.round(modX(x + i + 1)), (int) Math.round(modX(x + i - 1)), - realZ, (int) Math.round(modZ(z + j + 1)), (int) Math.round(modZ(z + j - 1)), - output, biome, height, getEngine().getHeight()); - } else if (height < getDimension().getFluidHeight()) { - getSeaFloorDecorator().decorate(i, j, realX, realZ, output, biome, height + 1, getDimension().getFluidHeight() + 1); } getSurfaceDecorator().decorate(i, j, realX, realZ, output, biome, height, getEngine().getHeight() - height); diff --git a/src/main/java/com/volmit/iris/engine/decorator/IrisSeaSurfaceDecorator.java b/src/main/java/com/volmit/iris/engine/decorator/IrisSeaSurfaceDecorator.java index 0a4298c2c..24bb11171 100644 --- a/src/main/java/com/volmit/iris/engine/decorator/IrisSeaSurfaceDecorator.java +++ b/src/main/java/com/volmit/iris/engine/decorator/IrisSeaSurfaceDecorator.java @@ -18,6 +18,7 @@ package com.volmit.iris.engine.decorator; +import com.volmit.iris.Iris; import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.biome.IrisBiome; From f5f4c5c6727309289f329d7b04fa1e75a8046d84 Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Thu, 19 Aug 2021 03:26:45 -0400 Subject: [PATCH 12/13] Performance improvements --- .../com/volmit/iris/engine/IrisEngine.java | 4 +- .../engine/actuator/IrisBiomeActuator.java | 54 ++++---- .../engine/actuator/IrisDecorantActuator.java | 118 +++++++++--------- .../engine/framework/EngineComponent.java | 6 + .../iris/engine/mantle/EngineMantle.java | 16 ++- .../engine/modifier/IrisDepositModifier.java | 18 ++- .../engine/modifier/IrisPostModifier.java | 35 ++++-- .../java/com/volmit/iris/util/hunk/Hunk.java | 5 + .../com/volmit/iris/util/mantle/Mantle.java | 11 ++ .../volmit/iris/util/mantle/MantleChunk.java | 22 ++++ .../iris/util/parallel/BurstExecutor.java | 39 ++++++ .../volmit/iris/util/parallel/MultiBurst.java | 7 ++ 12 files changed, 238 insertions(+), 97 deletions(-) diff --git a/src/main/java/com/volmit/iris/engine/IrisEngine.java b/src/main/java/com/volmit/iris/engine/IrisEngine.java index 5bea6a8dc..0e6fdff5e 100644 --- a/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -412,14 +412,14 @@ public class IrisEngine extends BlockPopulator implements Engine { switch (getDimension().getTerrainMode()) { case NORMAL -> { - getMantle().generateMatter(x >> 4, z >> 4); + getMantle().generateMatter(x >> 4, z >> 4, multicore); getTerrainActuator().actuate(x, z, vblocks, multicore); getBiomeActuator().actuate(x, z, vbiomes, multicore); getCaveModifier().modify(x, z, vblocks, multicore); getRavineModifier().modify(x, z, vblocks, multicore); getPostModifier().modify(x, z, vblocks, multicore); getDecorantActuator().actuate(x, z, blocks, multicore); - getMantle().insertMatter(x >> 4, z >> 4, BlockData.class, blocks); + getMantle().insertMatter(x >> 4, z >> 4, BlockData.class, blocks, multicore); getDepositModifier().modify(x, z, blocks, multicore); } case ISLANDS -> { diff --git a/src/main/java/com/volmit/iris/engine/actuator/IrisBiomeActuator.java b/src/main/java/com/volmit/iris/engine/actuator/IrisBiomeActuator.java index b78f27264..45b8fd31c 100644 --- a/src/main/java/com/volmit/iris/engine/actuator/IrisBiomeActuator.java +++ b/src/main/java/com/volmit/iris/engine/actuator/IrisBiomeActuator.java @@ -26,9 +26,12 @@ import com.volmit.iris.engine.framework.EngineAssignedActuator; import com.volmit.iris.engine.object.biome.IrisBiome; import com.volmit.iris.engine.object.biome.IrisBiomeCustom; import com.volmit.iris.util.documentation.BlockCoordinates; +import com.volmit.iris.util.format.Form; import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.view.BiomeGridHunkView; import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.parallel.BurstExecutor; +import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.scheduling.PrecisionStopwatch; import org.bukkit.block.Biome; import org.bukkit.generator.ChunkGenerator; @@ -65,41 +68,46 @@ public class IrisBiomeActuator extends EngineAssignedActuator { @Override public void onActuate(int x, int z, Hunk h, boolean multicore) { PrecisionStopwatch p = PrecisionStopwatch.start(); - int zf, maxHeight; - IrisBiome ib; + BurstExecutor burst = burst().burst(); + burst.setMulticore(multicore); for (int xf = 0; xf < h.getWidth(); xf++) { - for (zf = 0; zf < h.getDepth(); zf++) { - ib = getComplex().getTrueBiomeStream().get(modX(xf + x), modZ(zf + z)); - maxHeight = (int) (getComplex().getFluidHeight() + ib.getMaxWithObjectHeight(getData())); - if (ib.isCustom()) { - try { - IrisBiomeCustom custom = ib.getCustomBiome(rng, x, 0, z); - Object biomeBase = INMS.get().getCustomBiomeBaseFor(getDimension().getLoadKey() + ":" + custom.getId()); + int finalXf = xf; + burst.queue(() -> { + IrisBiome ib; + for (int zf = 0; zf < h.getDepth(); zf++) { + ib = getComplex().getTrueBiomeStream().get(modX(finalXf + x), modZ(zf + z)); + int maxHeight = (int) (getComplex().getFluidHeight() + ib.getMaxWithObjectHeight(getData())); + if (ib.isCustom()) { + try { + IrisBiomeCustom custom = ib.getCustomBiome(rng, x, 0, z); + Object biomeBase = INMS.get().getCustomBiomeBaseFor(getDimension().getLoadKey() + ":" + custom.getId()); - if (biomeBase == null || !injectBiome(h, x, 0, z, biomeBase)) { - throw new RuntimeException("Cant inject biome!"); - } + if (biomeBase == null || !injectBiome(h, x, 0, z, biomeBase)) { + throw new RuntimeException("Cant inject biome!"); + } - for (int i = 0; i < maxHeight; i++) { - injectBiome(h, xf, i, zf, biomeBase); + for (int i = 0; i < maxHeight; i++) { + injectBiome(h, finalXf, i, zf, biomeBase); + } + } catch (Throwable e) { + Iris.reportError(e); + Biome v = ib.getSkyBiome(rng, x, 0, z); + for (int i = 0; i < maxHeight; i++) { + h.set(finalXf, i, zf, v); + } } - } catch (Throwable e) { - Iris.reportError(e); + } else { Biome v = ib.getSkyBiome(rng, x, 0, z); for (int i = 0; i < maxHeight; i++) { - h.set(xf, i, zf, v); + h.set(finalXf, i, zf, v); } } - } else { - Biome v = ib.getSkyBiome(rng, x, 0, z); - for (int i = 0; i < maxHeight; i++) { - h.set(xf, i, zf, v); - } } - } + }); } + burst.complete(); getEngine().getMetrics().getBiome().put(p.getMilliseconds()); } } diff --git a/src/main/java/com/volmit/iris/engine/actuator/IrisDecorantActuator.java b/src/main/java/com/volmit/iris/engine/actuator/IrisDecorantActuator.java index 000c4ff5e..744f30048 100644 --- a/src/main/java/com/volmit/iris/engine/actuator/IrisDecorantActuator.java +++ b/src/main/java/com/volmit/iris/engine/actuator/IrisDecorantActuator.java @@ -23,19 +23,19 @@ import com.volmit.iris.engine.decorator.*; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.EngineAssignedActuator; import com.volmit.iris.engine.framework.EngineDecorator; -import com.volmit.iris.engine.object.biome.InferredType; import com.volmit.iris.engine.object.biome.IrisBiome; import com.volmit.iris.engine.object.carve.IrisCaveLayer; -import com.volmit.iris.engine.object.decoration.IrisDecorationPart; -import com.volmit.iris.engine.object.decoration.IrisDecorator; import com.volmit.iris.util.documentation.BlockCoordinates; +import com.volmit.iris.util.format.Form; import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.scheduling.PrecisionStopwatch; import lombok.Getter; import org.bukkit.Material; import org.bukkit.block.data.BlockData; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiPredicate; import java.util.function.Predicate; @@ -90,76 +90,82 @@ public class IrisDecorantActuator extends EngineAssignedActuator { } PrecisionStopwatch p = PrecisionStopwatch.start(); - - int j, realX, realZ, height; - IrisBiome biome, cave; - + BurstExecutor burst = burst().burst(); + burst.setMulticore(multicore); for (int i = 0; i < output.getWidth(); i++) { - for (j = 0; j < output.getDepth(); j++) { - boolean solid, liquid; - int emptyFor = 0; - int liquidFor = 0; - int lastSolid = 0; - realX = (int) Math.round(modX(x + i)); - realZ = (int) Math.round(modZ(z + j)); - height = (int) Math.round(getComplex().getHeightStream().get(realX, realZ)); - biome = getComplex().getTrueBiomeStream().get(realX, realZ); - cave = shouldRay ? getComplex().getCaveBiomeStream().get(realX, realZ) : null; + int finalI = i; + burst.queue(() -> { + int height; + int realX = (int) Math.round(modX(x + finalI)); + int realZ; + IrisBiome biome, cave; + for (int j=0; j < output.getDepth(); j++) { + boolean solid, liquid; + int emptyFor = 0; + int liquidFor = 0; + int lastSolid = 0; + realZ = (int) Math.round(modZ(z + j)); + height = (int) Math.round(getComplex().getHeightStream().get(realX, realZ)); + biome = getComplex().getTrueBiomeStream().get(realX, realZ); + cave = shouldRay ? getComplex().getCaveBiomeStream().get(realX, realZ) : null; - if (biome.getDecorators().isEmpty() && (cave == null || cave.getDecorators().isEmpty())) { - continue; - } + if (biome.getDecorators().isEmpty() && (cave == null || cave.getDecorators().isEmpty())) { + continue; + } - if(height < getDimension().getFluidHeight()) - { - getSeaSurfaceDecorator().decorate(i, j, - realX, (int) Math.round(modX(x + i + 1)), (int) Math.round(modX(x + i - 1)), - realZ, (int) Math.round(modZ(z + j + 1)), (int) Math.round(modZ(z + j - 1)), - output, biome, getDimension().getFluidHeight(), getEngine().getHeight()); - getSeaFloorDecorator().decorate(i, j, - realX, realZ, output, biome, height + 1, - getDimension().getFluidHeight() + 1); - } + if(height < getDimension().getFluidHeight()) + { + getSeaSurfaceDecorator().decorate(finalI, j, + realX, (int) Math.round(modX(x + finalI + 1)), (int) Math.round(modX(x + finalI - 1)), + realZ, (int) Math.round(modZ(z + j + 1)), (int) Math.round(modZ(z + j - 1)), + output, biome, getDimension().getFluidHeight(), getEngine().getHeight()); + getSeaFloorDecorator().decorate(finalI, j, + realX, realZ, output, biome, height + 1, + getDimension().getFluidHeight() + 1); + } - if (height == getDimension().getFluidHeight()) { - getShoreLineDecorator().decorate(i, j, - realX, (int) Math.round(modX(x + i + 1)), (int) Math.round(modX(x + i - 1)), - realZ, (int) Math.round(modZ(z + j + 1)), (int) Math.round(modZ(z + j - 1)), - output, biome, height, getEngine().getHeight()); - } + if (height == getDimension().getFluidHeight()) { + getShoreLineDecorator().decorate(finalI, j, + realX, (int) Math.round(modX(x + finalI + 1)), (int) Math.round(modX(x + finalI - 1)), + realZ, (int) Math.round(modZ(z + j + 1)), (int) Math.round(modZ(z + j - 1)), + output, biome, height, getEngine().getHeight()); + } - getSurfaceDecorator().decorate(i, j, realX, realZ, output, biome, height, getEngine().getHeight() - height); + getSurfaceDecorator().decorate(finalI, j, realX, realZ, output, biome, height, getEngine().getHeight() - height); - if (cave != null && cave.getDecorators().isNotEmpty()) { - for (int k = height; k > 0; k--) { - solid = PREDICATE_SOLID.test(output.get(i, k, j)); - liquid = PREDICATE_CAVELIQUID.test(output.get(i, k + 1, j), k + 1); + if (cave != null && cave.getDecorators().isNotEmpty()) { + for (int k = height; k > 0; k--) { + solid = PREDICATE_SOLID.test(output.get(finalI, k, j)); + liquid = PREDICATE_CAVELIQUID.test(output.get(finalI, k + 1, j), k + 1); - if (solid) { - if (emptyFor > 0) { - if (liquid) { - getSeaFloorDecorator().decorate(i, j, realX, realZ, output, cave, k + 1, liquidFor + lastSolid - emptyFor + 1); - getSeaSurfaceDecorator().decorate(i, j, realX, realZ, output, cave, k + liquidFor + 1, emptyFor - liquidFor + lastSolid); - } else { - getSurfaceDecorator().decorate(i, j, realX, realZ, output, cave, k, lastSolid); - getCeilingDecorator().decorate(i, j, realX, realZ, output, cave, lastSolid - 1, emptyFor); + if (solid) { + if (emptyFor > 0) { + if (liquid) { + getSeaFloorDecorator().decorate(finalI, j, realX, realZ, output, cave, k + 1, liquidFor + lastSolid - emptyFor + 1); + getSeaSurfaceDecorator().decorate(finalI, j, realX, realZ, output, cave, k + liquidFor + 1, emptyFor - liquidFor + lastSolid); + } else { + getSurfaceDecorator().decorate(finalI, j, realX, realZ, output, cave, k, lastSolid); + getCeilingDecorator().decorate(finalI, j, realX, realZ, output, cave, lastSolid - 1, emptyFor); + } + emptyFor = 0; + liquidFor = 0; } - emptyFor = 0; - liquidFor = 0; + lastSolid = k; + } else { + emptyFor++; + if (liquid) liquidFor++; } - lastSolid = k; - } else { - emptyFor++; - if (liquid) liquidFor++; } } } - } + }); } + burst.complete(); getEngine().getMetrics().getDecoration().put(p.getMilliseconds()); + } private boolean shouldRayDecorate() { diff --git a/src/main/java/com/volmit/iris/engine/framework/EngineComponent.java b/src/main/java/com/volmit/iris/engine/framework/EngineComponent.java index 389f52910..fb4b0a1af 100644 --- a/src/main/java/com/volmit/iris/engine/framework/EngineComponent.java +++ b/src/main/java/com/volmit/iris/engine/framework/EngineComponent.java @@ -23,6 +23,7 @@ import com.volmit.iris.core.project.loader.IrisData; import com.volmit.iris.engine.IrisComplex; import com.volmit.iris.engine.object.dimensional.IrisDimension; import com.volmit.iris.util.math.RollingSequence; +import com.volmit.iris.util.parallel.MultiBurst; import org.bukkit.event.Listener; public interface EngineComponent { @@ -32,6 +33,11 @@ public interface EngineComponent { String getName(); + default MultiBurst burst() + { + return getEngine().burst(); + } + default void close() { try { if (this instanceof Listener) { 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 37d34a44f..3046f8d3c 100644 --- a/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java +++ b/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java @@ -184,7 +184,7 @@ public interface EngineMantle extends IObjectPlacer { @ChunkCoordinates - default void generateMatter(int x, int z) { + default void generateMatter(int x, int z, boolean multicore) { if (!getEngine().getDimension().isUseMantle()) { return; } @@ -199,6 +199,7 @@ public interface EngineMantle extends IObjectPlacer { }; int s = getRealRadius(); BurstExecutor burst = burst().burst(); + burst.setMulticore(multicore); for (int i = -s; i <= s; i++) { int xx = i + x; @@ -216,7 +217,16 @@ public interface EngineMantle extends IObjectPlacer { { KList px = post.copy(); post.clear(); - burst().burst(px); + + if(multicore) + { + burst().burst(px); + } + + else + { + burst().sync(px); + } } } @@ -225,7 +235,7 @@ public interface EngineMantle extends IObjectPlacer { } @ChunkCoordinates - default void insertMatter(int x, int z, Class t, Hunk blocks) { + default void insertMatter(int x, int z, Class t, Hunk blocks, boolean multicore) { if (!getEngine().getDimension().isUseMantle()) { return; } diff --git a/src/main/java/com/volmit/iris/engine/modifier/IrisDepositModifier.java b/src/main/java/com/volmit/iris/engine/modifier/IrisDepositModifier.java index 2bf4694e2..c3402d5d6 100644 --- a/src/main/java/com/volmit/iris/engine/modifier/IrisDepositModifier.java +++ b/src/main/java/com/volmit/iris/engine/modifier/IrisDepositModifier.java @@ -18,6 +18,7 @@ package com.volmit.iris.engine.modifier; +import com.volmit.iris.Iris; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.EngineAssignedModifier; import com.volmit.iris.engine.object.biome.IrisBiome; @@ -25,8 +26,11 @@ import com.volmit.iris.engine.object.deposits.IrisDepositGenerator; import com.volmit.iris.engine.object.objects.IrisObject; import com.volmit.iris.engine.object.regional.IrisRegion; import com.volmit.iris.util.data.HeightMap; +import com.volmit.iris.util.format.Form; import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.parallel.BurstExecutor; +import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.scheduling.PrecisionStopwatch; import org.bukkit.block.data.BlockData; import org.bukkit.util.BlockVector; @@ -42,30 +46,32 @@ public class IrisDepositModifier extends EngineAssignedModifier { @Override public void onModify(int x, int z, Hunk output, boolean multicore) { PrecisionStopwatch p = PrecisionStopwatch.start(); - generateDeposits(rng, output, Math.floorDiv(x, 16), Math.floorDiv(z, 16)); + generateDeposits(rng, output, Math.floorDiv(x, 16), Math.floorDiv(z, 16), multicore); getEngine().getMetrics().getDeposit().put(p.getMilliseconds()); } - public void generateDeposits(RNG rx, Hunk terrain, int x, int z) { + public void generateDeposits(RNG rx, Hunk terrain, int x, int z, boolean multicore) { RNG ro = rx.nextParallelRNG(x * x).nextParallelRNG(z * z); IrisRegion region = getComplex().getRegionStream().get((x * 16) + 7, (z * 16) + 7); IrisBiome biome = getComplex().getTrueBiomeStream().get((x * 16) + 7, (z * 16) + 7); - + BurstExecutor burst = burst().burst(); + burst.setMulticore(multicore); for (IrisDepositGenerator k : getDimension().getDeposits()) { - generate(k, terrain, ro, x, z, false); + burst.queue(() -> generate(k, terrain, ro, x, z, false)); } for (IrisDepositGenerator k : region.getDeposits()) { for (int l = 0; l < ro.i(k.getMinPerChunk(), k.getMaxPerChunk()); l++) { - generate(k, terrain, ro, x, z, false); + burst.queue(() -> generate(k, terrain, ro, x, z, false)); } } for (IrisDepositGenerator k : biome.getDeposits()) { for (int l = 0; l < ro.i(k.getMinPerChunk(), k.getMaxPerChunk()); l++) { - generate(k, terrain, ro, x, z, false); + burst.queue(() -> generate(k, terrain, ro, x, z, false)); } } + burst.complete(); } public void generate(IrisDepositGenerator k, Hunk data, RNG rng, int cx, int cz, boolean safe) { diff --git a/src/main/java/com/volmit/iris/engine/modifier/IrisPostModifier.java b/src/main/java/com/volmit/iris/engine/modifier/IrisPostModifier.java index d2a5bd818..fee01f68a 100644 --- a/src/main/java/com/volmit/iris/engine/modifier/IrisPostModifier.java +++ b/src/main/java/com/volmit/iris/engine/modifier/IrisPostModifier.java @@ -19,14 +19,26 @@ package com.volmit.iris.engine.modifier; import com.volmit.iris.Iris; +import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.EngineAssignedModifier; import com.volmit.iris.engine.object.biome.IrisBiome; import com.volmit.iris.engine.object.common.CaveResult; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.data.B; +import com.volmit.iris.util.format.Form; +import com.volmit.iris.util.function.*; import com.volmit.iris.util.hunk.Hunk; +import com.volmit.iris.util.hunk.storage.ArrayHunk; +import com.volmit.iris.util.math.Average; import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.math.RollingSequence; +import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.scheduling.PrecisionStopwatch; +import com.volmit.iris.util.stream.ProceduralStream; +import com.volmit.iris.util.stream.interpolation.Interpolated; import org.bukkit.Material; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Levelled; @@ -34,9 +46,11 @@ import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.Slab; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.function.Supplier; public class IrisPostModifier extends EngineAssignedModifier { - private static final BlockData AIR = B.get("CAVE_AIR"); + private static final BlockData AIR = B.get("AIR"); private static final BlockData WATER = B.get("WATER"); private final RNG rng; @@ -48,15 +62,22 @@ public class IrisPostModifier extends EngineAssignedModifier { @Override public void onModify(int x, int z, Hunk output, boolean multicore) { PrecisionStopwatch p = PrecisionStopwatch.start(); - int i; + AtomicInteger i = new AtomicInteger(); AtomicInteger j = new AtomicInteger(); - - for (i = 0; i < output.getWidth(); i++) { - for (j.set(0); j.get() < output.getDepth(); j.getAndIncrement()) { - post(i, j.get(), output, i + x, j.get() + z); - } + BurstExecutor burst = burst().burst(); + burst.setMulticore(multicore); + Hunk sync = output.synchronize(); + for (i.set(0); i.get() < output.getWidth(); i.getAndIncrement()) { + burst.queue(() -> { + for (j.set(0); j.get() < output.getDepth(); j.getAndIncrement()) { + int ii = i.get(); + int jj = j.get(); + post(ii, jj, sync, ii + x, jj + z); + } + }); } + burst.complete(); getEngine().getMetrics().getPost().put(p.getMilliseconds()); } diff --git a/src/main/java/com/volmit/iris/util/hunk/Hunk.java b/src/main/java/com/volmit/iris/util/hunk/Hunk.java index e81c9673c..291b2b0e1 100644 --- a/src/main/java/com/volmit/iris/util/hunk/Hunk.java +++ b/src/main/java/com/volmit/iris/util/hunk/Hunk.java @@ -1449,4 +1449,9 @@ public interface Hunk { default boolean isEmpty() { return false; } + + default boolean contains(int x, int y, int z) + { + return x < getWidth() && x >= 0 && y < getHeight() && y >= 0 && z < getDepth() && z >= 0; + } } 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 256d68cb1..06a8a8e4c 100644 --- a/src/main/java/com/volmit/iris/util/mantle/Mantle.java +++ b/src/main/java/com/volmit/iris/util/mantle/Mantle.java @@ -111,6 +111,17 @@ public class Mantle { get(x >> 5, z >> 5).getOrCreate(x & 31, z & 31).iterate(type, iterator); } + @ChunkCoordinates + public void iterateChunk(int x, int z, Class type, Consumer4 iterator, BurstExecutor e, MantleFlag... requiredFlags) { + for (MantleFlag i : requiredFlags) { + if (!hasFlag(x, z, i)) { + return; + } + } + + get(x >> 5, z >> 5).getOrCreate(x & 31, z & 31).iterate(type, iterator, e); + } + @ChunkCoordinates public boolean hasFlag(int x, int z, MantleFlag flag) { return get(x >> 5, z >> 5).getOrCreate(x & 31, z & 31).isFlagged(flag); diff --git a/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java b/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java index ba3940d2a..85d248508 100644 --- a/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java +++ b/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java @@ -23,6 +23,8 @@ import com.volmit.iris.util.function.Consumer4; import com.volmit.iris.util.matter.IrisMatter; import com.volmit.iris.util.matter.Matter; import com.volmit.iris.util.matter.MatterSlice; +import com.volmit.iris.util.parallel.BurstExecutor; +import com.volmit.iris.util.parallel.MultiBurst; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -184,6 +186,26 @@ public class MantleChunk { } } + public void iterate(Class type, Consumer4 iterator, BurstExecutor burst) { + for (int i = 0; i < sections.length(); i++) { + int finalI = i; + burst.queue(() -> { + int bs = (finalI << 4); + Matter matter = get(finalI); + + if (matter != null) { + MatterSlice t = matter.getSlice(type); + + if (t != null) { + t.iterateSync((a, b, c, f) -> iterator.accept(a, b + bs, c, f)); + } + } + }); + } + + burst.complete(); + } + public void iterate(Class type, Consumer4 iterator) { for (int i = 0; i < sections.length(); i++) { int bs = (i << 4); diff --git a/src/main/java/com/volmit/iris/util/parallel/BurstExecutor.java b/src/main/java/com/volmit/iris/util/parallel/BurstExecutor.java index 2dfc6b6aa..ef6935a97 100644 --- a/src/main/java/com/volmit/iris/util/parallel/BurstExecutor.java +++ b/src/main/java/com/volmit/iris/util/parallel/BurstExecutor.java @@ -20,6 +20,7 @@ package com.volmit.iris.util.parallel; import com.volmit.iris.Iris; import com.volmit.iris.util.collection.KList; +import lombok.Setter; import java.util.List; import java.util.concurrent.*; @@ -28,6 +29,8 @@ import java.util.concurrent.*; public class BurstExecutor { private final ExecutorService executor; private final KList> futures; + @Setter + private boolean multicore = true; public BurstExecutor(ExecutorService executor, int burstSizeEstimate) { this.executor = executor; @@ -36,6 +39,12 @@ public class BurstExecutor { @SuppressWarnings("UnusedReturnValue") public CompletableFuture queue(Runnable r) { + if(!multicore) + { + r.run(); + return null; + } + synchronized (futures) { CompletableFuture c = CompletableFuture.runAsync(r, executor); futures.add(c); @@ -44,6 +53,16 @@ public class BurstExecutor { } public BurstExecutor queue(List r) { + if(!multicore) + { + for(Runnable i : r) + { + i.run(); + } + + return this; + } + synchronized (futures) { for (Runnable i : new KList<>(r)) { CompletableFuture c = CompletableFuture.runAsync(i, executor); @@ -55,6 +74,16 @@ public class BurstExecutor { } public BurstExecutor queue(Runnable[] r) { + if(!multicore) + { + for(Runnable i : r) + { + i.run(); + } + + return this; + } + synchronized (futures) { for (Runnable i : r) { CompletableFuture c = CompletableFuture.runAsync(i, executor); @@ -66,6 +95,11 @@ public class BurstExecutor { } public void complete() { + if(!multicore) + { + return; + } + synchronized (futures) { if (futures.isEmpty()) { return; @@ -81,6 +115,11 @@ public class BurstExecutor { } public boolean complete(long maxDur) { + if(!multicore) + { + return true; + } + synchronized (futures) { if (futures.isEmpty()) { return true; 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 6b55ac000..92a07825e 100644 --- a/src/main/java/com/volmit/iris/util/parallel/MultiBurst.java +++ b/src/main/java/com/volmit/iris/util/parallel/MultiBurst.java @@ -21,6 +21,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.io.InstanceState; import com.volmit.iris.util.math.M; import com.volmit.iris.util.scheduling.J; @@ -111,6 +112,12 @@ public class MultiBurst { } } + public void sync(KList r) { + for (Runnable i : r) { + i.run(); + } + } + public BurstExecutor burst(int estimate) { return new BurstExecutor(getService(), estimate); } From 957de5d6f77ae2990c6bb1b1463136f52073f319 Mon Sep 17 00:00:00 2001 From: cyberpwn Date: Thu, 19 Aug 2021 03:38:07 -0400 Subject: [PATCH 13/13] Cleanup terrain actuator --- .../actuator/IrisTerrainNormalActuator.java | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/volmit/iris/engine/actuator/IrisTerrainNormalActuator.java b/src/main/java/com/volmit/iris/engine/actuator/IrisTerrainNormalActuator.java index 36b50ee35..3c46dde05 100644 --- a/src/main/java/com/volmit/iris/engine/actuator/IrisTerrainNormalActuator.java +++ b/src/main/java/com/volmit/iris/engine/actuator/IrisTerrainNormalActuator.java @@ -57,20 +57,15 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator public void onActuate(int x, int z, Hunk h, boolean multicore) { PrecisionStopwatch p = PrecisionStopwatch.start(); - if (multicore) { - BurstExecutor e = getEngine().burst().burst(h.getWidth()); - for (int xf = 0; xf < h.getWidth(); xf++) { - int finalXf = xf; - e.queue(() -> terrainSliver(x, z, finalXf, h)); - } - - e.complete(); - } else { - for (int xf = 0; xf < h.getWidth(); xf++) { - terrainSliver(x, z, xf, h); - } + BurstExecutor e = getEngine().burst().burst(h.getWidth()); + e.setMulticore(multicore); + for (int xf = 0; xf < h.getWidth(); xf++) { + int finalXf = xf; + e.queue(() -> terrainSliver(x, z, finalXf, h)); } + e.complete(); + getEngine().getMetrics().getTerrain().put(p.getMilliseconds()); }