diff --git a/src/main/java/com/volmit/iris/Iris.java b/src/main/java/com/volmit/iris/Iris.java index 34c048d17..4526292e9 100644 --- a/src/main/java/com/volmit/iris/Iris.java +++ b/src/main/java/com/volmit/iris/Iris.java @@ -22,6 +22,7 @@ import com.volmit.iris.core.*; import com.volmit.iris.core.command.CommandIris; import com.volmit.iris.core.command.PermissionIris; import com.volmit.iris.core.command.world.CommandLocate; +import com.volmit.iris.core.events.IrisEngineHotloadEvent; import com.volmit.iris.core.link.IrisPapiExpansion; import com.volmit.iris.core.link.MultiverseCoreLink; import com.volmit.iris.core.link.OraxenLink; @@ -57,6 +58,7 @@ import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.generator.ChunkGenerator; @@ -95,6 +97,10 @@ public class Iris extends VolmitPlugin implements Listener { installDataPacks(); } + public static void callEvent(Event e) { + J.s(() -> Bukkit.getPluginManager().callEvent(e)); + } + public void onEnable() { instance = this; diff --git a/src/main/java/com/volmit/iris/core/command/studio/CommandIrisStudioExplorerGenerator.java b/src/main/java/com/volmit/iris/core/command/studio/CommandIrisStudioExplorerGenerator.java index 5faec01f4..dd73dc29e 100644 --- a/src/main/java/com/volmit/iris/core/command/studio/CommandIrisStudioExplorerGenerator.java +++ b/src/main/java/com/volmit/iris/core/command/studio/CommandIrisStudioExplorerGenerator.java @@ -25,10 +25,14 @@ import com.volmit.iris.core.project.loader.IrisData; import com.volmit.iris.core.tools.IrisWorlds; import com.volmit.iris.engine.object.IrisGenerator; import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.function.Function2; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.plugin.MortarCommand; import com.volmit.iris.util.plugin.VolmitSender; +import java.util.function.Consumer; +import java.util.function.Supplier; + public class CommandIrisStudioExplorerGenerator extends MortarCommand { public CommandIrisStudioExplorerGenerator() { super("generator", "gen"); @@ -68,26 +72,30 @@ public class CommandIrisStudioExplorerGenerator extends MortarCommand { return true; } - IrisGenerator generator; - long seed = 12345; - if (Iris.proj.isProjectOpen()) { - generator = Iris.proj.getActiveProject().getActiveProvider().getData().getGeneratorLoader().load(args[0]); - seed = Iris.proj.getActiveProject().getActiveProvider().getTarget().getWorld().seed(); - } else { - generator = IrisData.loadAnyGenerator(args[0]); - } - if (generator != null) { + Supplier> l = () -> { + long seed = 12345; + IrisGenerator generator; + if (Iris.proj.isProjectOpen()) { + generator = Iris.proj.getActiveProject().getActiveProvider().getData().getGeneratorLoader().load(args[0]); + seed = Iris.proj.getActiveProject().getActiveProvider().getTarget().getWorld().seed(); + } else { + generator = IrisData.loadAnyGenerator(args[0]); + } + + if(generator == null) + { + return (x, z) -> 0D; + } + long finalSeed = seed; - NoiseExplorerGUI.launch((x, z) -> - generator.getHeight(x, z, new RNG(finalSeed).nextParallelRNG(3245).lmax()), "Gen: " + generator.getLoadKey()); + return (x, z) -> generator.getHeight(x, z, new RNG(finalSeed).nextParallelRNG(3245).lmax()); + }; - sender.sendMessage("Opening Noise Explorer for gen " + generator.getLoadKey() + " (" + generator.getLoader().getDataFolder().getName() + ")"); - return true; - } else { - sender.sendMessage("Invalid Generator"); - } + + + NoiseExplorerGUI.launch(l, "Custom Generator"); return true; } diff --git a/src/main/java/com/volmit/iris/core/events/IrisEngineEvent.java b/src/main/java/com/volmit/iris/core/events/IrisEngineEvent.java new file mode 100644 index 000000000..11f2c1d4f --- /dev/null +++ b/src/main/java/com/volmit/iris/core/events/IrisEngineEvent.java @@ -0,0 +1,43 @@ +/* + * 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.core.events; + +import com.volmit.iris.engine.framework.Engine; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +@EqualsAndHashCode(callSuper = true) +@Data +@AllArgsConstructor +public class IrisEngineEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + private Engine engine; + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/src/main/java/com/volmit/iris/core/events/IrisEngineHotloadEvent.java b/src/main/java/com/volmit/iris/core/events/IrisEngineHotloadEvent.java new file mode 100644 index 000000000..cebbfc532 --- /dev/null +++ b/src/main/java/com/volmit/iris/core/events/IrisEngineHotloadEvent.java @@ -0,0 +1,39 @@ +/* + * 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.core.events; + +import com.volmit.iris.engine.framework.Engine; +import org.bukkit.event.HandlerList; + +public class IrisEngineHotloadEvent extends IrisEngineEvent { + private static final HandlerList handlers = new HandlerList(); + + public IrisEngineHotloadEvent(Engine engine) { + super(engine); + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/src/main/java/com/volmit/iris/core/gui/NoiseExplorerGUI.java b/src/main/java/com/volmit/iris/core/gui/NoiseExplorerGUI.java index 81c9a958c..10a13e141 100644 --- a/src/main/java/com/volmit/iris/core/gui/NoiseExplorerGUI.java +++ b/src/main/java/com/volmit/iris/core/gui/NoiseExplorerGUI.java @@ -19,6 +19,7 @@ package com.volmit.iris.core.gui; import com.volmit.iris.Iris; +import com.volmit.iris.core.events.IrisEngineHotloadEvent; import com.volmit.iris.engine.noise.CNG; import com.volmit.iris.engine.object.NoiseStyle; import com.volmit.iris.engine.parallel.BurstExecutor; @@ -30,6 +31,8 @@ import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RollingSequence; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.PrecisionStopwatch; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; import javax.imageio.ImageIO; import javax.swing.*; @@ -39,8 +42,10 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; +import java.util.function.Supplier; -public class NoiseExplorerGUI extends JPanel implements MouseWheelListener { +public class NoiseExplorerGUI extends JPanel implements MouseWheelListener, Listener { private static final long serialVersionUID = 2094606939770332040L; @@ -61,6 +66,7 @@ public class NoiseExplorerGUI extends JPanel implements MouseWheelListener { int w = 0; int h = 0; Function2 generator; + Supplier> loader; static double oxp = 0; static double ozp = 0; double ox = 0; //Offset X @@ -77,6 +83,7 @@ public class NoiseExplorerGUI extends JPanel implements MouseWheelListener { double tz; public NoiseExplorerGUI() { + Iris.instance.registerListener(this); addMouseWheelListener(this); addMouseMotionListener(new MouseMotionListener() { @Override @@ -100,6 +107,12 @@ public class NoiseExplorerGUI extends JPanel implements MouseWheelListener { }); } + @EventHandler + public void on(IrisEngineHotloadEvent e) + { + generator = loader.get(); + } + public void mouseWheelMoved(MouseWheelEvent e) { int notches = e.getWheelRotation(); @@ -229,14 +242,15 @@ public class NoiseExplorerGUI extends JPanel implements MouseWheelListener { }); } - private static void createAndShowGUI(Function2 gen, String genName) { + private static void createAndShowGUI(Supplier> loader, String genName) { JFrame frame = new JFrame("Noise Explorer: " + genName); NoiseExplorerGUI nv = new NoiseExplorerGUI(); frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); JLayeredPane pane = new JLayeredPane(); nv.setSize(new Dimension(1440, 820)); pane.add(nv, 1, 0); - nv.generator = gen; + nv.loader = loader; + nv.generator = loader.get(); frame.add(pane); File file = Iris.getCached("Iris Icon", "https://raw.githubusercontent.com/VolmitSoftware/Iris/master/icon.png"); @@ -287,11 +301,12 @@ public class NoiseExplorerGUI extends JPanel implements MouseWheelListener { @Override public void windowClosing(java.awt.event.WindowEvent windowEvent) { nv.gx.shutdownLater(); + Iris.instance.unregisterListener(nv); } }); } - public static void launch(Function2 gen, String genName) { + public static void launch(Supplier> gen, String genName) { EventQueue.invokeLater(() -> createAndShowGUI(gen, genName)); } diff --git a/src/main/java/com/volmit/iris/core/project/loader/ResourceLoader.java b/src/main/java/com/volmit/iris/core/project/loader/ResourceLoader.java index 65351a053..8f0a0b413 100644 --- a/src/main/java/com/volmit/iris/core/project/loader/ResourceLoader.java +++ b/src/main/java/com/volmit/iris/core/project/loader/ResourceLoader.java @@ -41,6 +41,7 @@ import java.io.File; import java.util.Locale; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Predicate; +import java.util.stream.Stream; @Data public class ResourceLoader { @@ -194,6 +195,11 @@ public class ResourceLoader { } } + public Stream streamAll(Stream s) + { + return s.map(this::load); + } + public KList loadAll(KList s) { KList m = new KList<>(); diff --git a/src/main/java/com/volmit/iris/engine/IrisEngine.java b/src/main/java/com/volmit/iris/engine/IrisEngine.java index 868f21fa0..7fa004512 100644 --- a/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -21,6 +21,7 @@ package com.volmit.iris.engine; import com.google.gson.Gson; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.events.IrisEngineHotloadEvent; import com.volmit.iris.engine.cache.AtomicCache; import com.volmit.iris.engine.framework.*; import com.volmit.iris.engine.hunk.Hunk; @@ -113,6 +114,7 @@ public class IrisEngine extends BlockPopulator implements Engine { effects = new IrisEngineEffects(this); art = J.ar(effects::tickRandomPlayer, 0); J.a(this::computeBiomeMaxes); + Iris.callEvent(new IrisEngineHotloadEvent(this)); } @Override @@ -289,6 +291,7 @@ public class IrisEngine extends BlockPopulator implements Engine { @Override public void hotload() { + Iris.callEvent(new IrisEngineHotloadEvent(this)); getEngineData().getStatistics().hotloaded(); cacheId = RNG.r.nextInt(); } diff --git a/src/main/java/com/volmit/iris/engine/IrisWorldManager.java b/src/main/java/com/volmit/iris/engine/IrisWorldManager.java index 1c48c7801..e8e931512 100644 --- a/src/main/java/com/volmit/iris/engine/IrisWorldManager.java +++ b/src/main/java/com/volmit/iris/engine/IrisWorldManager.java @@ -91,7 +91,10 @@ public class IrisWorldManager extends EngineAssignedWorldManager { } for (int ig = 0; ig < data.get(i).size() / 8; ig++) { - spawnIn(data.get(i).getRandom(), i, maxGroups); + Chunk c = data.get(i).getRandom(); + IrisBiome biome = getEngine().getSurfaceBiome(c); + IrisRegion region = getEngine().getRegion(c); + spawnIn(c, biome, region, i, maxGroups); spawnCooldowns.put(i, M.ms()); } } @@ -101,25 +104,32 @@ public class IrisWorldManager extends EngineAssignedWorldManager { } } - private void spawnIn(Chunk c, UUID id, int max) { + private void spawnIn(Chunk c, IrisBiome biome, IrisRegion region, UUID id, int max) { if (c.getEntities().length > 2) { return; } //@builder - puffen(Stream.concat(getData().getSpawnerLoader().loadAll(getDimension().getEntitySpawners()) - .shuffleCopy(RNG.r).stream().filter(this::canSpawn) - .flatMap(this::stream), - Stream.concat(getData().getSpawnerLoader() - .loadAll(getEngine().getRegion(c.getX() << 4, c.getZ() << 4).getEntitySpawners()) - .shuffleCopy(RNG.r).stream().filter(this::canSpawn) - .flatMap(this::stream), - getData().getSpawnerLoader() - .loadAll(getEngine().getSurfaceBiome(c.getX() << 4, c.getZ() << 4).getEntitySpawners()) - .shuffleCopy(RNG.r).stream().filter(this::canSpawn) - .flatMap(this::stream))) - .collect(Collectors.toList())) - .popRandom(RNG.r, max).forEach((i) -> spawn(c, id, i)); + spawnRandomly(Stream.concat(Stream.concat( + getData().getSpawnerLoader() + .loadAll(getDimension().getEntitySpawners()) + .shuffleCopy(RNG.r).stream().filter(this::canSpawn), + getData().getSpawnerLoader().streamAll(getEngine().getFramework().getEngineParallax() + .getFeaturesInChunk(c).stream() + .flatMap((o) -> o.getFeature().getEntitySpawners().stream())) + .filter(this::canSpawn)) + .filter((i) -> i.isValid(biome)) + .flatMap(this::stream), + Stream.concat(getData().getSpawnerLoader() + .loadAll(getEngine().getRegion(c.getX() << 4, c.getZ() << 4).getEntitySpawners()) + .shuffleCopy(RNG.r).stream().filter(this::canSpawn) + .flatMap(this::stream), + getData().getSpawnerLoader() + .loadAll(getEngine().getSurfaceBiome(c.getX() << 4, c.getZ() << 4).getEntitySpawners()) + .shuffleCopy(RNG.r).stream().filter(this::canSpawn) + .flatMap(this::stream))) + .collect(Collectors.toList())) + .popRandom(RNG.r, max).forEach((i) -> spawn(c, id, i)); //@done } @@ -138,7 +148,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager { return s.getSpawns().stream(); } - private KList puffen(List types) { + private KList spawnRandomly(List types) { KList rarityTypes = new KList<>(); int totalRarity = 0; for (IrisEntitySpawn i : types) { @@ -153,7 +163,8 @@ public class IrisWorldManager extends EngineAssignedWorldManager { } public boolean canSpawn(IrisSpawner i) { - return i.isValid(getEngine().getWorld().realWorld()) && getCooldown(i).canSpawn(i.getMaximumRate()); + return i.isValid(getEngine().getWorld().realWorld()) + && getCooldown(i).canSpawn(i.getMaximumRate()); } private IrisEngineSpawnerCooldown getCooldown(IrisSpawner i) { diff --git a/src/main/java/com/volmit/iris/engine/framework/Engine.java b/src/main/java/com/volmit/iris/engine/framework/Engine.java index e74e1e978..e0191544e 100644 --- a/src/main/java/com/volmit/iris/engine/framework/Engine.java +++ b/src/main/java/com/volmit/iris/engine/framework/Engine.java @@ -174,7 +174,12 @@ public interface Engine extends DataProvider, Fallible, GeneratorAccess, LootPro @BlockCoordinates @Override default int getHeight(int x, int z) { - return getFramework().getEngineParallax().getHighest(x, z, getData(), true); + return getHeight(x, z, true); + } + + @BlockCoordinates + default int getHeight(int x, int z, boolean ignoreFluid) { + return getFramework().getEngineParallax().getHighest(x, z, getData(), ignoreFluid); } @BlockCoordinates @@ -407,4 +412,14 @@ public interface Engine extends DataProvider, Fallible, GeneratorAccess, LootPro IrisBiome getFocus(); IrisEngineData getEngineData(); + + default IrisBiome getSurfaceBiome(Chunk c) + { + return getSurfaceBiome((c.getX()<<4) + 8, (c.getZ()<<4) + 8); + } + + default IrisRegion getRegion(Chunk c) + { + return getRegion((c.getX()<<4) + 8, (c.getZ()<<4) + 8); + } } diff --git a/src/main/java/com/volmit/iris/engine/framework/EngineParallaxManager.java b/src/main/java/com/volmit/iris/engine/framework/EngineParallaxManager.java index 6d22645a3..6d7f4d521 100644 --- a/src/main/java/com/volmit/iris/engine/framework/EngineParallaxManager.java +++ b/src/main/java/com/volmit/iris/engine/framework/EngineParallaxManager.java @@ -197,6 +197,26 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer { } } + @ChunkCoordinates + default KList getFeaturesInChunk(int x, int z) + { + KList pos = new KList<>(); + + for (IrisFeaturePositional i : getEngine().getDimension().getSpecificFeatures()) { + if (i.shouldFilter((x<<4) + 8, (z<<4) + 8, getEngine().getFramework().getComplex().getRng(), getData())) { + pos.add(i); + } + } + + for (IrisFeaturePositional i : getParallaxAccess().getMetaR(x, z).getFeatures()) { + if (i.shouldFilter((x<<4) + 8, (z<<4) + 8, getEngine().getFramework().getComplex().getRng(), getData())) { + pos.add(i); + } + } + + return pos; + } + @BlockCoordinates default KList forEachFeature(double x, double z) { KList pos = new KList<>(); @@ -456,10 +476,10 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer { return placeAfter; } - default void generateParallaxSurface(RNG rng, int x, int z, IrisBiome biome, IrisRegion region, boolean vacuum) { + default void generateParallaxSurface(RNG rng, int x, int z, IrisBiome biome, IrisRegion region, boolean useFeatures) { for (IrisObjectPlacement i : biome.getSurfaceObjects()) { - if (i.isVacuum() != vacuum) { + if (i.usesFeatures() != useFeatures) { continue; } @@ -477,7 +497,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer { } for (IrisObjectPlacement i : region.getSurfaceObjects()) { - if (i.isVacuum() != vacuum) { + if (i.usesFeatures() != useFeatures) { continue; } @@ -495,7 +515,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer { } } - default void generateParallaxMutations(RNG rng, int x, int z, boolean vacuum) { + default void generateParallaxMutations(RNG rng, int x, int z, boolean useFeatures) { if (getEngine().getDimension().getMutations().isEmpty()) { return; } @@ -512,7 +532,7 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer { if (k.getRealSideA(this).contains(sa.getLoadKey()) && k.getRealSideB(this).contains(sb.getLoadKey())) { for (IrisObjectPlacement m : k.getObjects()) { - if (m.isVacuum() != vacuum) { + if (m.usesFeatures() != useFeatures) { continue; } @@ -547,16 +567,43 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer { }, null, getData()); - if (p.isVacuum()) { - double a = Math.max(v.getW(), v.getD()); - IrisFeature f = new IrisFeature(); - f.setConvergeToHeight(h - (v.getH() >> 1)); - f.setBlockRadius(a); - f.setInterpolationRadius(a / 4); - f.setInterpolator(InterpolationMethod.BILINEAR_STARCAST_9); - f.setStrength(1D); - getParallaxAccess().getMetaRW(xx >> 4, zz >> 4).getFeatures().add(new IrisFeaturePositional(xx, zz, f)); + if(p.usesFeatures()) + { + if (p.isVacuum()) { + ParallaxChunkMeta rw = getParallaxAccess().getMetaRW(xx >> 4, zz >> 4); + double a = Math.max(v.getW(), v.getD()); + IrisFeature f = new IrisFeature(); + f.setConvergeToHeight(h - (v.getH() >> 1)); + f.setBlockRadius(a); + f.setInterpolationRadius(p.getVacuumInterpolationRadius()); + f.setInterpolator(p.getVacuumInterpolationMethod()); + f.setStrength(1D); + + for (IrisFeaturePositional j : rw.getFeatures()) { + if (j.getX() == xx && j.getZ() == zz) { + break; + } + } + + rw.getFeatures().add(new IrisFeaturePositional(xx, zz, f)); + } + + for(IrisFeaturePotential j : p.getAddFeatures()) + { + ParallaxChunkMeta rw = getParallaxAccess().getMetaRW(xx >> 4, zz >> 4); + double a = Math.max(v.getW(), v.getD()); + + for (IrisFeaturePositional k : rw.getFeatures()) { + if (k.getX() == xx && k.getZ() == zz) { + break; + } + } + + rw.getFeatures().add(new IrisFeaturePositional(xx, zz, j.getZone())); + } } + + } default void place(RNG rng, int x, int forceY, int z, IrisObjectPlacement objectPlacement) { @@ -582,23 +629,40 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer { }, null, getData()); - if (objectPlacement.isVacuum()) { - ParallaxChunkMeta rw = getParallaxAccess().getMetaRW(xx >> 4, zz >> 4); - double a = Math.max(v.getW(), v.getD()); - IrisFeature f = new IrisFeature(); - f.setConvergeToHeight(h - (v.getH() >> 1)); - f.setBlockRadius(a); - f.setInterpolationRadius(objectPlacement.getVacuumInterpolationRadius()); - f.setInterpolator(objectPlacement.getVacuumInterpolationMethod()); - f.setStrength(1D); + if(objectPlacement.usesFeatures()) + { + if (objectPlacement.isVacuum()) { + ParallaxChunkMeta rw = getParallaxAccess().getMetaRW(xx >> 4, zz >> 4); + double a = Math.max(v.getW(), v.getD()); + IrisFeature f = new IrisFeature(); + f.setConvergeToHeight(h - (v.getH() >> 1)); + f.setBlockRadius(a); + f.setInterpolationRadius(objectPlacement.getVacuumInterpolationRadius()); + f.setInterpolator(objectPlacement.getVacuumInterpolationMethod()); + f.setStrength(1D); - for (IrisFeaturePositional j : rw.getFeatures()) { - if (j.getX() == xx && j.getZ() == zz) { - continue placing; + for (IrisFeaturePositional j : rw.getFeatures()) { + if (j.getX() == xx && j.getZ() == zz) { + continue placing; + } } + + rw.getFeatures().add(new IrisFeaturePositional(xx, zz, f)); } - rw.getFeatures().add(new IrisFeaturePositional(xx, zz, f)); + for(IrisFeaturePotential j : objectPlacement.getAddFeatures()) + { + ParallaxChunkMeta rw = getParallaxAccess().getMetaRW(xx >> 4, zz >> 4); + double a = Math.max(v.getW(), v.getD()); + + for (IrisFeaturePositional k : rw.getFeatures()) { + if (k.getX() == xx && k.getZ() == zz) { + continue placing; + } + } + + rw.getFeatures().add(new IrisFeaturePositional(xx, zz, j.getZone())); + } } } } @@ -886,4 +950,10 @@ public interface EngineParallaxManager extends DataProvider, IObjectPlacer { default void close() { } + + @ChunkCoordinates + default KList getFeaturesInChunk(Chunk c) + { + return getFeaturesInChunk(c.getX(), c.getZ()); + } } diff --git a/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java b/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java index 8eda27b1e..1414e2ec7 100644 --- a/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java +++ b/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java @@ -70,6 +70,7 @@ public class PlannedStructure { } public KList place(IObjectPlacer placer, EngineParallaxManager e) { + Iris.info("PLACED JIGSAW"); KList after = new KList<>(); IrisObjectPlacement options = new IrisObjectPlacement(); options.getRotation().setEnabled(false); diff --git a/src/main/java/com/volmit/iris/engine/modifier/IrisCaveModifier.java b/src/main/java/com/volmit/iris/engine/modifier/IrisCaveModifier.java index 1c4551f60..406592399 100644 --- a/src/main/java/com/volmit/iris/engine/modifier/IrisCaveModifier.java +++ b/src/main/java/com/volmit/iris/engine/modifier/IrisCaveModifier.java @@ -105,6 +105,10 @@ public class IrisCaveModifier extends EngineAssignedModifier { } } + public KList genCaves(double wxx, double wzz) { + return genCaves(wxx, wzz, 0, 0, null); + } + public KList genCaves(double wxx, double wzz, int x, int z, Hunk data) { if (!getDimension().isCaves()) { return EMPTY; diff --git a/src/main/java/com/volmit/iris/engine/object/InferredType.java b/src/main/java/com/volmit/iris/engine/object/InferredType.java index 4946f28f7..e157151bf 100644 --- a/src/main/java/com/volmit/iris/engine/object/InferredType.java +++ b/src/main/java/com/volmit/iris/engine/object/InferredType.java @@ -38,10 +38,8 @@ public enum InferredType { RIVER, @Desc("Represents any lake biome type") - LAKE, @Desc("Defers the type to whatever another biome type that already exists is.") - DEFER } diff --git a/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java b/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java index 66902d85f..77c592d59 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java @@ -19,13 +19,20 @@ package com.volmit.iris.engine.object; import com.volmit.iris.Iris; +import com.volmit.iris.engine.IrisComplex; import com.volmit.iris.engine.cache.AtomicCache; +import com.volmit.iris.engine.data.B; import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.framework.EngineFramework; +import com.volmit.iris.engine.modifier.IrisCaveModifier; +import com.volmit.iris.engine.modifier.IrisPostModifier; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.MinNumber; import com.volmit.iris.engine.object.annotations.RegistryListResource; import com.volmit.iris.engine.object.annotations.Required; +import com.volmit.iris.engine.object.common.CaveResult; import com.volmit.iris.engine.object.common.IRare; +import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.format.C; import com.volmit.iris.util.math.RNG; import lombok.AllArgsConstructor; @@ -34,7 +41,14 @@ import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import org.bukkit.Chunk; import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.Slab; import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; @Accessors(chain = true) @NoArgsConstructor @@ -65,19 +79,47 @@ public class IrisEntitySpawn implements IRare { public boolean spawn(Engine gen, Chunk c, RNG rng) { int spawns = minSpawns == maxSpawns ? minSpawns : rng.i(Math.min(minSpawns, maxSpawns), Math.max(minSpawns, maxSpawns)); + int s = 0; if (spawns > 0) { - for (int i = 0; i < spawns; i++) { + for (int id = 0; id < spawns; id++) { int x = (c.getX() * 16) + rng.i(15); int z = (c.getZ() * 16) + rng.i(15); - int h = c.getWorld().getHighestBlockYAt(x, z); - spawn100(gen, new Location(c.getWorld(), x, h, z)); - } + int h = gen.getHeight(x, z, true); + int hf = gen.getHeight(x, z, false); + Location l = switch(getReferenceSpawner().getGroup()) + { + case NORMAL -> new Location(c.getWorld(), x, hf+1, z); + case CAVE -> { + IrisComplex comp = gen.getFramework().getComplex(); + EngineFramework frame = gen.getFramework(); + IrisBiome cave = comp.getCaveBiomeStream().get(x, z); + KList r = new KList<>(); + if (cave != null) { + for (CaveResult i : ((IrisCaveModifier) frame.getCaveModifier()).genCaves(x, z)) { + if (i.getCeiling() >= gen.getHeight() || i.getFloor() < 0 || i.getCeiling()-2 <= i.getFloor()) { + continue; + } - return true; + r.add(new Location(c.getWorld(), x, i.getFloor(), z)); + } + } + + yield r.getRandom(rng); + } + + case UNDERWATER, BEACH -> new Location(c.getWorld(), x, rng.i(h+1, hf), z); + }; + + if(l != null) + { + spawn100(gen, l); + s++; + } + } } - return false; + return s>0; } public IrisEntity getRealEntity(Engine g) { diff --git a/src/main/java/com/volmit/iris/engine/object/IrisExpression.java b/src/main/java/com/volmit/iris/engine/object/IrisExpression.java index 368bef748..aef37c8a4 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisExpression.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisExpression.java @@ -98,8 +98,8 @@ public class IrisExpression extends IrisRegistrant { } g[m++] = x; - g[m++] = -1; - g[m] = z; + g[m++] = z; + g[m] = -1; return expression().evaluate(g); } diff --git a/src/main/java/com/volmit/iris/engine/object/IrisFeature.java b/src/main/java/com/volmit/iris/engine/object/IrisFeature.java index 0b0f17203..adc0e8ead 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisFeature.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisFeature.java @@ -23,6 +23,7 @@ import com.volmit.iris.engine.cache.AtomicCache; import com.volmit.iris.engine.interpolation.InterpolationMethod; import com.volmit.iris.engine.interpolation.IrisInterpolation; import com.volmit.iris.engine.object.annotations.*; +import com.volmit.iris.util.collection.KList; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -81,6 +82,11 @@ public class IrisFeature { @Desc("Fracture the radius ring with additional noise") private IrisGeneratorStyle fractureRadius = null; + @RegistryListResource(IrisSpawner.class) + @ArrayType(min = 1, type = String.class) + @Desc("Within this noise feature, use the following spawners") + private KList entitySpawners = new KList<>(); + private transient AtomicCache actualRadius = new AtomicCache<>(); public double getActualRadius() { diff --git a/src/main/java/com/volmit/iris/engine/object/IrisGenerator.java b/src/main/java/com/volmit/iris/engine/object/IrisGenerator.java index 17bf326c6..04a7b1759 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisGenerator.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisGenerator.java @@ -210,10 +210,15 @@ public class IrisGenerator extends IrisRegistrant { } public double getHeight(double rx, double rz, long superSeed) { - return getHeight(rx, 0, rz, superSeed); + return getHeight(rx, 0, rz, superSeed, true); } + public double getHeight(double rx, double ry, double rz, long superSeed) { + return getHeight(rx, ry, rz, superSeed, false); + } + + public double getHeight(double rx, double ry, double rz, long superSeed, boolean no3d) { if (composite.isEmpty()) { Iris.warn("Useless Generator: Composite is empty in " + getLoadKey()); return 0; @@ -235,7 +240,7 @@ public class IrisGenerator extends IrisRegistrant { double v = multiplicitive ? h * opacity : (h / tp) * opacity; if (Double.isNaN(v)) { - Iris.warn("Nan value on gen: " + getLoadKey() + ": H = " + h + " TP = " + tp + " OPACITY = " + opacity + " ZOOM = " + zoom); + v = 0; } v = hasCliffs() ? cliff(rx, rz, v, superSeed + 294596 + hc) : v; diff --git a/src/main/java/com/volmit/iris/engine/object/IrisObjectPlacement.java b/src/main/java/com/volmit/iris/engine/object/IrisObjectPlacement.java index 19c5b4411..fa0293a19 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisObjectPlacement.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisObjectPlacement.java @@ -58,6 +58,10 @@ public class IrisObjectPlacement { @Desc("Limit the max height or min height of placement.") private IrisObjectLimit clamp = new IrisObjectLimit(); + @ArrayType(min = 1, type = IrisFeaturePotential.class) + @Desc("Place additional noise features in the object's place location") + private KList addFeatures = new KList<>(); + @MinNumber(0) @MaxNumber(1) @Desc("The maximum layer level of a snow filter overtop of this placement. Set to 0 to disable. Max of 1.") @@ -161,6 +165,7 @@ public class IrisObjectPlacement { p.setWarp(warp); p.setBore(bore); p.setMeld(meld); + p.setAddFeatures(addFeatures.copy()); p.setWaterloggable(waterloggable); p.setOnwater(onwater); p.setSmartBore(smartBore); @@ -213,6 +218,11 @@ public class IrisObjectPlacement { return getMode().equals(ObjectPlaceMode.VACUUM); } + public boolean usesFeatures() + { + return isVacuum() || getAddFeatures().isNotEmpty(); + } + private transient AtomicCache cache = new AtomicCache<>(); public boolean matches(IrisTreeSize size, TreeType type) { diff --git a/src/main/java/com/volmit/iris/engine/object/IrisSpawnGroup.java b/src/main/java/com/volmit/iris/engine/object/IrisSpawnGroup.java new file mode 100644 index 000000000..2317f6a85 --- /dev/null +++ b/src/main/java/com/volmit/iris/engine/object/IrisSpawnGroup.java @@ -0,0 +1,36 @@ +/* + * 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; + +import com.volmit.iris.engine.object.annotations.Desc; + +@Desc("Terrain modes are used to decide the generator type currently used") +public enum IrisSpawnGroup { + @Desc("Spawns on the terrain surface") + NORMAL, + + @Desc("Spawns in cave-air and low light level areas") + CAVE, + + @Desc("Spawns underwater") + UNDERWATER, + + @Desc("Spawns in beaches") + BEACH +} diff --git a/src/main/java/com/volmit/iris/engine/object/IrisSpawner.java b/src/main/java/com/volmit/iris/engine/object/IrisSpawner.java index c2c1eb40e..07fc57d51 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisSpawner.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisSpawner.java @@ -26,6 +26,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; +import org.bukkit.Location; import org.bukkit.World; @EqualsAndHashCode(callSuper = true) @@ -48,6 +49,29 @@ public class IrisSpawner extends IrisRegistrant { @Desc("The maximum rate this spawner can fire") private IrisRate maximumRate = new IrisRate(); + @Desc("Where should these spawns be placed") + private IrisSpawnGroup group = IrisSpawnGroup.NORMAL; + + public boolean isValid(IrisBiome biome) + { + return switch (group) + { + case NORMAL -> switch(biome.getInferredType()) { + case SHORE, SEA, CAVE, RIVER, LAKE, DEFER -> false; + case LAND -> true; + }; + case CAVE -> true; + case UNDERWATER -> switch(biome.getInferredType()) { + case SHORE, LAND, CAVE, RIVER, LAKE, DEFER -> false; + case SEA -> true; + }; + case BEACH -> switch(biome.getInferredType()) { + case SHORE -> true; + case LAND, CAVE, RIVER, LAKE, SEA, DEFER -> false; + }; + }; + } + public boolean isValid(World world) { return timeBlock.isWithin(world) && weather.is(world); } diff --git a/src/main/java/com/volmit/iris/engine/parallax/ParallaxAccess.java b/src/main/java/com/volmit/iris/engine/parallax/ParallaxAccess.java index 45f939cc1..b8f605671 100644 --- a/src/main/java/com/volmit/iris/engine/parallax/ParallaxAccess.java +++ b/src/main/java/com/volmit/iris/engine/parallax/ParallaxAccess.java @@ -20,82 +20,103 @@ package com.volmit.iris.engine.parallax; import com.volmit.iris.engine.hunk.Hunk; import com.volmit.iris.engine.object.tile.TileData; +import com.volmit.iris.util.documentation.BlockCoordinates; +import com.volmit.iris.util.documentation.ChunkCoordinates; import org.bukkit.block.TileState; import org.bukkit.block.data.BlockData; public interface ParallaxAccess { + @BlockCoordinates default BlockData getBlock(int x, int y, int z) { return getBlocksR(x >> 4, z >> 4).get(x & 15, y, z & 15); } + @BlockCoordinates default void setBlock(int x, int y, int z, BlockData d) { getBlocksRW(x >> 4, z >> 4).set(x & 15, y, z & 15, d); } + @BlockCoordinates default TileData getTile(int x, int y, int z) { return getTilesR(x >> 4, z >> 4).get(x & 15, y, z & 15); } + @BlockCoordinates default void setTile(int x, int y, int z, TileData d) { getTilesRW(x >> 4, z >> 4).set(x & 15, y, z & 15, d); } + @BlockCoordinates default String getObject(int x, int y, int z) { return getObjectsR(x >> 4, z >> 4).get(x & 15, y, z & 15); } + @BlockCoordinates default void setObject(int x, int y, int z, String d) { getObjectsRW(x >> 4, z >> 4).set(x & 15, y, z & 15, d); } + @BlockCoordinates default String getEntity(int x, int y, int z) { return getEntitiesR(x >> 4, z >> 4).get(x & 15, y, z & 15); } + @BlockCoordinates default void setEntity(int x, int y, int z, String d) { getEntitiesRW(x >> 4, z >> 4).set(x & 15, y, z & 15, d); } + @BlockCoordinates default Boolean isUpdate(int x, int y, int z) { return getUpdatesR(x >> 4, z >> 4).get(x & 15, y, z & 15); } + @BlockCoordinates default void updateBlock(int x, int y, int z) { setUpdate(x, y, z, true); } + @BlockCoordinates default void setUpdate(int x, int y, int z, boolean d) { getUpdatesRW(x >> 4, z >> 4).set(x & 15, y, z & 15, d); } + @ChunkCoordinates default boolean isParallaxGenerated(int x, int z) { return getMetaR(x, z).isParallaxGenerated(); } + @ChunkCoordinates default boolean isChunkGenerated(int x, int z) { return getMetaR(x, z).isGenerated(); } + @ChunkCoordinates default boolean isFeatureGenerated(int x, int z) { return getMetaR(x, z).isFeatureGenerated(); } + @ChunkCoordinates default void setParallaxGenerated(int x, int z) { setParallaxGenerated(x, z, true); } + @ChunkCoordinates default void setChunkGenerated(int x, int z) { setChunkGenerated(x, z, true); } + @ChunkCoordinates default void setFeatureGenerated(int x, int z) { setFeatureGenerated(x, z, true); } + @ChunkCoordinates default void setParallaxGenerated(int x, int z, boolean v) { getMetaRW(x, z).setParallaxGenerated(v); } + @ChunkCoordinates default void maxMin(int x, int z, int value) { ParallaxChunkMeta meat = getMetaRW(x, z); @@ -112,36 +133,50 @@ public interface ParallaxAccess { } } + @ChunkCoordinates default void setChunkGenerated(int x, int z, boolean v) { getMetaRW(x, z).setGenerated(v); } + @ChunkCoordinates default void setFeatureGenerated(int x, int z, boolean v) { getMetaRW(x, z).setFeatureGenerated(v); } + @ChunkCoordinates Hunk> getTilesR(int x, int z); + @ChunkCoordinates Hunk> getTilesRW(int x, int z); + @ChunkCoordinates Hunk getBlocksR(int x, int z); + @ChunkCoordinates Hunk getBlocksRW(int x, int z); + @ChunkCoordinates Hunk getObjectsR(int x, int z); + @ChunkCoordinates Hunk getObjectsRW(int x, int z); + @ChunkCoordinates Hunk getEntitiesRW(int x, int z); + @ChunkCoordinates Hunk getEntitiesR(int x, int z); + @ChunkCoordinates Hunk getUpdatesR(int x, int z); + @ChunkCoordinates Hunk getUpdatesRW(int x, int z); + @ChunkCoordinates ParallaxChunkMeta getMetaR(int x, int z); + @ChunkCoordinates ParallaxChunkMeta getMetaRW(int x, int z); void cleanup(long regionIdle, long chunkIdle); @@ -156,6 +191,7 @@ public interface ParallaxAccess { int getChunkCount(); + @ChunkCoordinates default void delete(int x, int z) { getUpdatesRW(x, z).empty(false); getBlocksRW(x, z).empty(null); diff --git a/src/main/java/com/volmit/iris/util/math/RNG.java b/src/main/java/com/volmit/iris/util/math/RNG.java index ad669778e..d58061411 100644 --- a/src/main/java/com/volmit/iris/util/math/RNG.java +++ b/src/main/java/com/volmit/iris/util/math/RNG.java @@ -114,6 +114,11 @@ public class RNG extends Random { } public double d(double lowerBound, double upperBound) { + if(lowerBound > upperBound) + { + return M.lerp(upperBound, lowerBound, nextDouble()); + } + return M.lerp(lowerBound, upperBound, nextDouble()); }