diff --git a/src/main/java/com/volmit/iris/core/IrisDataManager.java b/src/main/java/com/volmit/iris/core/IrisDataManager.java index 0007d6e53..f13d820fc 100644 --- a/src/main/java/com/volmit/iris/core/IrisDataManager.java +++ b/src/main/java/com/volmit/iris/core/IrisDataManager.java @@ -40,6 +40,7 @@ public class IrisDataManager { private ResourceLoader jigsawPoolLoader; private ResourceLoader jigsawStructureLoader; private ResourceLoader entityLoader; + private ResourceLoader spawnerLoader; private ResourceLoader modLoader; private ResourceLoader blockLoader; private ObjectResourceLoader objectLoader; @@ -67,6 +68,7 @@ public class IrisDataManager { this.biomeLoader = null; this.modLoader = null; this.dimensionLoader = null; + this.spawnerLoader = null; this.jigsawPoolLoader = null; this.jigsawPieceLoader = null; this.generatorLoader = null; @@ -91,6 +93,7 @@ public class IrisDataManager { File packs = dataFolder; packs.mkdirs(); this.lootLoader = new ResourceLoader<>(packs, this, "loot", "Loot", IrisLootTable.class); + this.spawnerLoader = new ResourceLoader<>(packs, this, "spawners", "Spawner", IrisSpawner.class); this.entityLoader = new ResourceLoader<>(packs, this, "entities", "Entity", IrisEntity.class); this.regionLoader = new ResourceLoader<>(packs, this, "regions", "Region", IrisRegion.class); this.biomeLoader = new ResourceLoader<>(packs, this, "biomes", "Biome", IrisBiome.class); @@ -112,6 +115,7 @@ public class IrisDataManager { blockLoader.clearCache(); lootLoader.clearCache(); objectLoader.clearCache(); + spawnerLoader.clearCache(); jigsawPieceLoader.clearCache(); jigsawPoolLoader.clearCache(); modLoader.clearCache(); @@ -132,6 +136,7 @@ public class IrisDataManager { entityLoader.clearList(); biomeLoader.clearList(); modLoader.clearList(); + spawnerLoader.clearList(); regionLoader.clearList(); dimensionLoader.clearList(); generatorLoader.clearList(); @@ -173,6 +178,10 @@ public class IrisDataManager { return loadAny(key, (dm) -> dm.getBlockLoader().load(key, false)); } + public static IrisSpawner loadAnySpaner(String key) { + return loadAny(key, (dm) -> dm.getSpawnerLoader().load(key, false)); + } + public static IrisRegion loadAnyRegion(String key) { return loadAny(key, (dm) -> dm.getRegionLoader().load(key, false)); } diff --git a/src/main/java/com/volmit/iris/core/IrisProject.java b/src/main/java/com/volmit/iris/core/IrisProject.java index 03542b0e4..7e3d40fad 100644 --- a/src/main/java/com/volmit/iris/core/IrisProject.java +++ b/src/main/java/com/volmit/iris/core/IrisProject.java @@ -474,6 +474,7 @@ public class IrisProject { KSet regions = new KSet<>(); KSet biomes = new KSet<>(); KSet entities = new KSet<>(); + KSet spawners = new KSet<>(); KSet generators = new KSet<>(); KSet loot = new KSet<>(); KSet blocks = new KSet<>(); @@ -503,13 +504,9 @@ public class IrisProject { }); dimension.getLoot().getTables().forEach((i) -> loot.add(dm.getLootLoader().load(i))); regions.forEach((i) -> biomes.addAll(i.getAllBiomes(null))); - biomes.forEach((i) -> i.getGenerators().forEach((j) -> generators.add(j.getCachedGenerator(null)))); regions.forEach((r) -> r.getLoot().getTables().forEach((i) -> loot.add(dm.getLootLoader().load(i)))); - biomes.forEach((r) -> r.getLoot().getTables().forEach((i) -> loot.add(dm.getLootLoader().load(i)))); - biomes.forEach((r) -> r.getEntitySpawnOverrides().forEach((sp) -> entities.add(dm.getEntityLoader().load(sp.getEntity())))); - regions.forEach((r) -> r.getEntitySpawnOverrides().forEach((sp) -> entities.add(dm.getEntityLoader().load(sp.getEntity())))); - dimension.getEntitySpawnOverrides().forEach((sp) -> entities.add(dm.getEntityLoader().load(sp.getEntity()))); - biomes.forEach((r) -> r.getEntityInitialSpawns().forEach((sp) -> entities.add(dm.getEntityLoader().load(sp.getEntity())))); + regions.forEach((r) -> r.getEntitySpawners().forEach((sp) -> spawners.add(dm.getSpawnerLoader().load(sp)))); + dimension.getEntitySpawners().forEach((sp) -> spawners.add(dm.getSpawnerLoader().load(sp))); for (int f = 0; f < IrisSettings.get().getGenerator().getMaxBiomeChildDepth(); f++) { biomes.copy().forEach((r) -> { @@ -521,8 +518,10 @@ public class IrisProject { }); } - regions.forEach((r) -> r.getEntityInitialSpawns().forEach((sp) -> entities.add(dm.getEntityLoader().load(sp.getEntity())))); - dimension.getEntityInitialSpawns().forEach((sp) -> entities.add(dm.getEntityLoader().load(sp.getEntity()))); + biomes.forEach((i) -> i.getGenerators().forEach((j) -> generators.add(j.getCachedGenerator(null)))); + biomes.forEach((r) -> r.getLoot().getTables().forEach((i) -> loot.add(dm.getLootLoader().load(i)))); + biomes.forEach((r) -> r.getEntitySpawners().forEach((sp) -> spawners.add(dm.getSpawnerLoader().load(sp)))); + spawners.forEach((i) -> i.getSpawns().forEach((j) -> entities.add(dm.getEntityLoader().load(j.getEntity())))); KMap renameObjects = new KMap<>(); String a; StringBuilder b = new StringBuilder(); diff --git a/src/main/java/com/volmit/iris/core/SchemaBuilder.java b/src/main/java/com/volmit/iris/core/SchemaBuilder.java index be0630679..317b72ba4 100644 --- a/src/main/java/com/volmit/iris/core/SchemaBuilder.java +++ b/src/main/java/com/volmit/iris/core/SchemaBuilder.java @@ -187,7 +187,21 @@ public class SchemaBuilder { fancyType = "Mythic Mob Type"; prop.put("$ref", "#/definitions/" + key); description.add(SYMBOL_TYPE__N + " Must be a valid Mythic Mob Type (use ctrl+space for auto complete!) Define mythic mobs with the mythic mobs plugin configuration files."); - } else if (k.isAnnotationPresent(RegistryListBlockType.class)) { + } + else if (k.isAnnotationPresent(RegistryListSpawner.class)) { + String key = "enum-reg-spawner"; + + if (!definitions.containsKey(key)) { + JSONObject j = new JSONObject(); + j.put("enum", new JSONArray(data.getSpawnerLoader().getPossibleKeys())); + definitions.put(key, j); + } + + fancyType = "Iris Spawner"; + prop.put("$ref", "#/definitions/" + key); + description.add(SYMBOL_TYPE__N + " Must be a valid Spawner (use ctrl+space for auto complete!)"); + } + else if (k.isAnnotationPresent(RegistryListBlockType.class)) { String key = "enum-block-type"; if (!definitions.containsKey(key)) { @@ -463,7 +477,23 @@ public class SchemaBuilder { items.put("$ref", "#/definitions/" + key); prop.put("items", items); description.add(SYMBOL_TYPE__N + " Must be a valid Biome (use ctrl+space for auto complete!)"); - } else if (k.isAnnotationPresent(RegistryListMythical.class)) { + } + else if (k.isAnnotationPresent(RegistryListSpawner.class)) { + fancyType = "List of Iris Spawners"; + String key = "enum-reg-spawner"; + + if (!definitions.containsKey(key)) { + JSONObject j = new JSONObject(); + j.put("enum", new JSONArray(data.getSpawnerLoader().getPossibleKeys())); + definitions.put(key, j); + } + + JSONObject items = new JSONObject(); + items.put("$ref", "#/definitions/" + key); + prop.put("items", items); + description.add(SYMBOL_TYPE__N + " Must be a valid Spawner (use ctrl+space for auto complete!)"); + } + else if (k.isAnnotationPresent(RegistryListMythical.class)) { fancyType = "List of Mythic Mob Types"; String key = "enum-reg-mythical"; diff --git a/src/main/java/com/volmit/iris/engine/IrisComplex.java b/src/main/java/com/volmit/iris/engine/IrisComplex.java index 497f69250..72cb185ca 100644 --- a/src/main/java/com/volmit/iris/engine/IrisComplex.java +++ b/src/main/java/com/volmit/iris/engine/IrisComplex.java @@ -210,7 +210,7 @@ public class IrisComplex implements DataProvider { baseBiomeStream = focus != null ? ProceduralStream.of((x, z) -> focus, Interpolated.of(a -> 0D, a -> focus)) : bridgeStream.convertAware2D((t, x, z) -> inferredStreams.get(t).get(x, z)) - .cache2D(cacheSize); + .convertAware2D(this::implode).cache2D(cacheSize); heightStream = ProceduralStream.of((x, z) -> { IrisBiome b = focus != null ? focus : baseBiomeStream.get(x, z); return getHeight(engine, b, x, z, engine.getWorld().seed(), true); @@ -470,4 +470,29 @@ public class IrisComplex implements DataProvider { generators.add(cachedGenerator); } + + private IrisBiome implode(IrisBiome b, Double x, Double z) { + if (b.getChildren().isEmpty()) { + return b; + } + + return implode(b, x, z, 3); + } + + private IrisBiome implode(IrisBiome b, Double x, Double z, int max) { + if (max < 0) { + return b; + } + + if (b.getChildren().isEmpty()) { + return b; + } + + CNG childCell = b.getChildrenGenerator(rng, 123, b.getChildShrinkFactor()); + KList chx = b.getRealChildren(this).copy(); + chx.add(b); + IrisBiome biome = childCell.fitRarity(chx, x, z); + biome.setInferredType(b.getInferredType()); + return implode(biome, x, z, max - 1); + } } diff --git a/src/main/java/com/volmit/iris/engine/IrisEngine.java b/src/main/java/com/volmit/iris/engine/IrisEngine.java index 4fec0f9fc..a2a473169 100644 --- a/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -221,7 +221,6 @@ public class IrisEngine extends BlockPopulator implements Engine { @ChunkCoordinates @Override public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk c) { - getWorldManager().spawnInitialEntities(c); updateChunk(c); placeTiles(c); } diff --git a/src/main/java/com/volmit/iris/engine/IrisWorldManager.java b/src/main/java/com/volmit/iris/engine/IrisWorldManager.java index 0126e0cd2..6c4ac4c88 100644 --- a/src/main/java/com/volmit/iris/engine/IrisWorldManager.java +++ b/src/main/java/com/volmit/iris/engine/IrisWorldManager.java @@ -19,28 +19,129 @@ package com.volmit.iris.engine; import com.volmit.iris.Iris; -import com.volmit.iris.core.IrisSettings; -import com.volmit.iris.engine.cache.Cache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.EngineAssignedWorldManager; import com.volmit.iris.engine.object.*; import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.documentation.ChunkCoordinates; +import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.scheduling.J; import org.bukkit.Chunk; -import org.bukkit.Location; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.EntitySpawnEvent; import org.bukkit.inventory.ItemStack; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Supplier; + public class IrisWorldManager extends EngineAssignedWorldManager { private boolean spawnable; + private final int art; + private final KMap spawnCooldowns; public IrisWorldManager(Engine engine) { super(engine); + spawnCooldowns = new KMap<>(); spawnable = true; + art = J.ar(this::onAsyncTick, 200); + } + + private void onAsyncTick() { + int biomeBaseCooldownMinutes = 2; + int biomeSpawnedCooldownMinutes = 3; + int biomeNotSpawnedCooldownMinutes = 5; + + for(UUID i : spawnCooldowns.k()) + { + if(M.ms() - spawnCooldowns.get(i) > TimeUnit.MINUTES.toMillis(biomeBaseCooldownMinutes)) + { + spawnCooldowns.remove(i); + } + } + + KMap> data = new KMap<>(); + int spawnBuffer = 8; + + for(UUID i : data.k().shuffleCopy(RNG.r)) + { + if(spawnCooldowns.containsKey(i)) + { + continue; + } + + if(spawnBuffer-- < 0) + { + break; + } + + spawnCooldowns.put(i, spawnIn(data.get(i).getRandom(), i) ? + (M.ms() + TimeUnit.MINUTES.toMillis(biomeSpawnedCooldownMinutes)) : + (M.ms() + TimeUnit.MINUTES.toMillis(biomeNotSpawnedCooldownMinutes))); + } + } + + private boolean spawnIn(Chunk c, UUID id) { + if(c.getEntities().length > 16) + { + return false; + } + + return new KList>(() -> { + IrisBiome biome = getEngine().getSurfaceBiome(c.getX() << 4, c.getZ() << 4); + + for(IrisSpawner i : getData().getSpawnerLoader().loadAll(biome.getEntitySpawners()).shuffleCopy(RNG.r)) + { + if(i.spawnInChunk(getEngine(), c)) + { + Iris.debug("Spawning Biome Entities in Chunk " + c.getX() + "," + c.getZ() + " Biome ID: " + id); + return true; + } + } + + return false; + }, () -> { + IrisRegion region = getEngine().getRegion(c.getX() << 4, c.getZ() << 4); + + for(IrisSpawner i : getData().getSpawnerLoader().loadAll(region.getEntitySpawners()).shuffleCopy(RNG.r)) + { + if(i.spawnInChunk(getEngine(), c)) + { + Iris.debug("Spawning Region Entities in Chunk " + c.getX() + "," + c.getZ() + " Biome ID: " + id); + return true; + } + } + + return false; + }, () -> { + for(IrisSpawner i : getData().getSpawnerLoader().loadAll(getDimension().getEntitySpawners()).shuffleCopy(RNG.r)) + { + if(i.spawnInChunk(getEngine(), c)) + { + Iris.debug("Spawning Dimension Entities in Chunk " + c.getX() + "," + c.getZ() + " Biome ID: " + id); + return true; + } + } + + return false; + }).getRandom().get(); + } + + public KMap> mapChunkBiomes() + { + KMap> data = new KMap<>(); + + for(Chunk i : getEngine().getWorld().realWorld().getLoadedChunks()) + { + data.compute(getEngine().getBiomeID(i.getX() << 4, i.getZ() << 4), + (k,v) -> v != null ? v : new KList<>()).add(i); + } + + return data; } @Override @@ -53,87 +154,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager { getEngine().getParallax().saveAll(); } - @ChunkCoordinates - @Override - public void spawnInitialEntities(Chunk c) { - RNG rng = new RNG(Cache.key(c)); - - getEngine().getParallaxAccess().getEntitiesR(c.getX(), c.getZ()).iterateSync((x, y, z, e) -> { - if (e != null) { - IrisEntity en = getData().getEntityLoader().load(e); - - if (en != null) { - en.spawn(getEngine(), new Location(c.getWorld(), x + (c.getX() << 4), y, z + (c.getZ() << 4))); - } - } - }); - - int x = (c.getX() * 16) + rng.nextInt(15); - int z = (c.getZ() * 16) + rng.nextInt(15); - int y = getEngine().getHeight(x, z) + 1; - IrisDimension dim = getDimension(); - IrisRegion region = getEngine().getRegion(x, z); - IrisBiome above = getEngine().getSurfaceBiome(x, z); - trySpawn(above.getEntityInitialSpawns(), c, rng); - trySpawn(region.getEntityInitialSpawns(), c, rng); - trySpawn(dim.getEntityInitialSpawns(), c, rng); - } - - @Override - public void onEntitySpawn(EntitySpawnEvent e) { - if (getTarget().getWorld() == null || !e.getEntity().getWorld().equals(getTarget().getWorld().realWorld())) { - return; - } - - try { - if (!IrisSettings.get().getGenerator().isSystemEntitySpawnOverrides()) { - return; - } - - int x = e.getEntity().getLocation().getBlockX(); - int y = e.getEntity().getLocation().getBlockY(); - int z = e.getEntity().getLocation().getBlockZ(); - - J.a(() -> - { - if (spawnable) { - IrisDimension dim = getDimension(); - IrisRegion region = getEngine().getRegion(x, z); - IrisBiome above = getEngine().getSurfaceBiome(x, z); - IrisBiome bbelow = getEngine().getBiome(x, y, z); - if (above.getLoadKey().equals(bbelow.getLoadKey())) { - bbelow = null; - } - - IrisBiome below = bbelow; - - J.s(() -> - { - if (below != null) { - if (trySpawn(below.getEntitySpawnOverrides(), e)) { - return; - } - } - - if (trySpawn(above.getEntitySpawnOverrides(), e)) { - return; - } - - if (trySpawn(region.getEntitySpawnOverrides(), e)) { - return; - } - - if (trySpawn(dim.getEntitySpawnOverrides(), e)) { - return; - } - }); - } - }); - } catch (Throwable ee) { - Iris.reportError(ee); - } - } - private boolean trySpawn(KList s, EntitySpawnEvent e) { for (IrisEntitySpawnOverride i : s) { spawnable = false; @@ -151,8 +171,8 @@ public class IrisWorldManager extends EngineAssignedWorldManager { } @ChunkCoordinates - private void trySpawn(KList s, Chunk c, RNG rng) { - for (IrisEntityInitialSpawn i : s) { + private void trySpawn(KList s, Chunk c, RNG rng) { + for (IrisEntitySpawn i : s) { i.spawn(getEngine(), c, rng); } } @@ -230,4 +250,11 @@ public class IrisWorldManager extends EngineAssignedWorldManager { public void onBlockPlace(BlockPlaceEvent e) { } + + @Override + public void close() + { + super.close(); + J.car(art); + } } 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 31d529b9c..9620cff6c 100644 --- a/src/main/java/com/volmit/iris/engine/framework/Engine.java +++ b/src/main/java/com/volmit/iris/engine/framework/Engine.java @@ -49,6 +49,7 @@ import org.bukkit.inventory.ItemStack; import java.awt.*; import java.util.Arrays; +import java.util.UUID; public interface Engine extends DataProvider, Fallible, GeneratorAccess, LootProvider, BlockUpdater, Renderer, Hotloadable { void close(); @@ -65,6 +66,11 @@ public interface Engine extends DataProvider, Fallible, GeneratorAccess, LootPro void setParallelism(int parallelism); + default UUID getBiomeID(int x, int z) + { + return getFramework().getComplex().getBaseBiomeIDStream().get(x, z); + } + int getParallelism(); EngineTarget getTarget(); diff --git a/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java b/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java index 353268453..d80742272 100644 --- a/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java +++ b/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java @@ -51,13 +51,6 @@ public abstract class EngineAssignedWorldManager extends EngineAssignedComponent } } - @EventHandler - public void on(EntitySpawnEvent e) { - if (e.getEntity().getWorld().equals(getTarget().getWorld().realWorld())) { - onEntitySpawn(e); - } - } - @EventHandler public void on(BlockBreakEvent e) { if (e.getPlayer().getWorld().equals(getTarget().getWorld().realWorld())) { diff --git a/src/main/java/com/volmit/iris/engine/framework/EngineWorldManager.java b/src/main/java/com/volmit/iris/engine/framework/EngineWorldManager.java index c39cf6f5f..188245ba4 100644 --- a/src/main/java/com/volmit/iris/engine/framework/EngineWorldManager.java +++ b/src/main/java/com/volmit/iris/engine/framework/EngineWorldManager.java @@ -18,23 +18,17 @@ package com.volmit.iris.engine.framework; -import org.bukkit.Chunk; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.entity.EntitySpawnEvent; @SuppressWarnings("EmptyMethod") public interface EngineWorldManager { void close(); - void onEntitySpawn(EntitySpawnEvent e); - void onTick(); void onSave(); - void spawnInitialEntities(Chunk chunk); - void onBlockBreak(BlockBreakEvent e); void onBlockPlace(BlockPlaceEvent e); diff --git a/src/main/java/com/volmit/iris/engine/framework/GeneratorAccess.java b/src/main/java/com/volmit/iris/engine/framework/GeneratorAccess.java index a824fe71e..16d3b9b60 100644 --- a/src/main/java/com/volmit/iris/engine/framework/GeneratorAccess.java +++ b/src/main/java/com/volmit/iris/engine/framework/GeneratorAccess.java @@ -26,6 +26,8 @@ import com.volmit.iris.engine.object.IrisObjectPlacement; import com.volmit.iris.engine.object.IrisRegion; import com.volmit.iris.engine.parallax.ParallaxAccess; +import java.util.UUID; + public interface GeneratorAccess extends DataProvider, Renderer { IrisRegion getRegion(int x, int z); diff --git a/src/main/java/com/volmit/iris/engine/object/IrisBiome.java b/src/main/java/com/volmit/iris/engine/object/IrisBiome.java index 42f0f3934..16f3f318d 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisBiome.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisBiome.java @@ -64,17 +64,15 @@ public class IrisBiome extends IrisRegistrant implements IRare { @Desc("If the biome type custom is defined, specify this") private KList customDerivitives; - @Desc("Entity spawns to override or add to this biome. Anytime an entity spawns, it has a chance to be replaced as one of these overrides.") - @ArrayType(min = 1, type = IrisEntitySpawnOverride.class) - private KList entitySpawnOverrides = new KList<>(); + @Desc("Spawn Entities in this area over time. Iris will continually replenish these mobs just like vanilla does.") + @ArrayType(min = 1, type = String.class) + @RegistryListSpawner + private KList entitySpawners = new KList<>(); @Desc("Add random chances for terrain features") @ArrayType(min = 1, type = IrisFeaturePotential.class) private KList features = new KList<>(); - @Desc("Entity spawns during generation") - @ArrayType(min = 1, type = IrisEntityInitialSpawn.class) - private KList entityInitialSpawns = new KList<>(); @ArrayType(min = 1, type = IrisEffect.class) @Desc("Effects are ambient effects such as potion effects, random sounds, or even particles around each player. All of these effects are played via packets so two players won't see/hear each others effects.\nDue to performance reasons, effects will play around the player even if where the effect was played is no longer in the biome the player is in.") diff --git a/src/main/java/com/volmit/iris/engine/object/IrisDimension.java b/src/main/java/com/volmit/iris/engine/object/IrisDimension.java index cfff66894..723d72554 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisDimension.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisDimension.java @@ -80,18 +80,15 @@ public class IrisDimension extends IrisRegistrant { @Desc("Upon joining this world, Iris will send a resource pack request to the client. If they have previously selected yes, it will auto-switch depending on which dimension they go to.") private String resourcePack = ""; - @Desc("Entity spawns to override or add to this dimension") - @ArrayType(min = 1, type = IrisEntitySpawnOverride.class) - private KList entitySpawnOverrides = new KList<>(); + @Desc("Spawn Entities in this dimension over time. Iris will continually replenish these mobs just like vanilla does.") + @ArrayType(min = 1, type = String.class) + @RegistryListSpawner + private KList entitySpawners = new KList<>(); @Desc("Add specific features in exact positions") @ArrayType(min = 1, type = IrisFeaturePositional.class) private KList specificFeatures = new KList<>(); - @Desc("Entity spawns during generation") - @ArrayType(min = 1, type = IrisEntityInitialSpawn.class) - private KList entityInitialSpawns = new KList<>(); - @Desc("Add random chances for terrain features") @ArrayType(min = 1, type = IrisFeaturePotential.class) private KList features = new KList<>(); diff --git a/src/main/java/com/volmit/iris/engine/object/IrisEntityInitialSpawn.java b/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java similarity index 86% rename from src/main/java/com/volmit/iris/engine/object/IrisEntityInitialSpawn.java rename to src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java index f3d4b3141..46fad67d4 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisEntityInitialSpawn.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java @@ -39,7 +39,7 @@ import org.bukkit.entity.Entity; @AllArgsConstructor @Desc("Represents an entity spawn during initial chunk generation") @Data -public class IrisEntityInitialSpawn { +public class IrisEntitySpawn { @RegistryListEntity @Required @Desc("The entity") @@ -60,7 +60,7 @@ public class IrisEntityInitialSpawn { private final transient AtomicCache rng = new AtomicCache<>(); private final transient AtomicCache ent = new AtomicCache<>(); - public void spawn(Engine gen, Chunk c, RNG rng) { + public boolean spawn(Engine gen, Chunk c, RNG rng) { int spawns = rng.i(1, rarity) == 1 ? rng.i(minSpawns, maxSpawns) : 0; if (spawns > 0) { @@ -70,7 +70,11 @@ public class IrisEntityInitialSpawn { int h = gen.getHeight(x, z) + gen.getMinHeight(); spawn100(gen, new Location(c.getWorld(), x, h, z)); } + + return true; } + + return false; } public IrisEntity getRealEntity(Engine g) { @@ -91,10 +95,12 @@ public class IrisEntityInitialSpawn { private Entity spawn100(Engine g, Location at) { try { - return getRealEntity(g).spawn(g, at.clone().add(0.5, 1, 0.5), rng.aquire(() -> new RNG(g.getTarget().getWorld().seed() + 4))); + Location l = at.clone().add(0.5, 1, 0.5); + Iris.debug(" Spawned " + "Entity<" + getEntity() + "> at " + l.getBlockX() + "," + l.getBlockY() + "," + l.getBlockZ()); + return getRealEntity(g).spawn(g, l, rng.aquire(() -> new RNG(g.getTarget().getWorld().seed() + 4))); } catch (Throwable e) { Iris.reportError(e); - Iris.debug("Failed to retrieve real entity @ " + at); + Iris.error("Failed to retrieve real entity @ " + at); return null; } } diff --git a/src/main/java/com/volmit/iris/engine/object/IrisRegion.java b/src/main/java/com/volmit/iris/engine/object/IrisRegion.java index eaf4d34ae..ebb85d622 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisRegion.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisRegion.java @@ -67,13 +67,10 @@ public class IrisRegion extends IrisRegistrant implements IRare { @Desc("Effects are ambient effects such as potion effects, random sounds, or even particles around each player. All of these effects are played via packets so two players won't see/hear each others effects.\nDue to performance reasons, effects will play arround the player even if where the effect was played is no longer in the biome the player is in.") private KList effects = new KList<>(); - @Desc("Entity spawns to override or add to this region") - @ArrayType(min = 1, type = IrisEntitySpawnOverride.class) - private KList entitySpawnOverrides = new KList<>(); - - @Desc("Entity spawns during generation") - @ArrayType(min = 1, type = IrisEntityInitialSpawn.class) - private KList entityInitialSpawns = new KList<>(); + @Desc("Spawn Entities in this region over time. Iris will continually replenish these mobs just like vanilla does.") + @ArrayType(min = 1, type = String.class) + @RegistryListSpawner + private KList entitySpawners = new KList<>(); @MinNumber(1) @MaxNumber(128) diff --git a/src/main/java/com/volmit/iris/engine/object/IrisSpawner.java b/src/main/java/com/volmit/iris/engine/object/IrisSpawner.java new file mode 100644 index 000000000..da3e7096d --- /dev/null +++ b/src/main/java/com/volmit/iris/engine/object/IrisSpawner.java @@ -0,0 +1,51 @@ +/* + * 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.framework.Engine; +import com.volmit.iris.engine.object.annotations.*; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.math.RNG; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import org.bukkit.Chunk; + +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +@Desc("Represents an entity spawn during initial chunk generation") +@Data +public class IrisSpawner extends IrisRegistrant { + @ArrayType(min = 1, type = IrisEntitySpawn.class) + @Desc("The entity spawns to add") + private KList spawns = new KList<>(); + + public boolean spawnInChunk(Engine engine, Chunk c) { + if(spawns.isEmpty()) + { + return false; + } + + return spawns.getRandom().spawn(engine, c, RNG.r); + } +} diff --git a/src/main/java/com/volmit/iris/engine/object/annotations/RegistryListSpawner.java b/src/main/java/com/volmit/iris/engine/object/annotations/RegistryListSpawner.java new file mode 100644 index 000000000..2f372ae59 --- /dev/null +++ b/src/main/java/com/volmit/iris/engine/object/annotations/RegistryListSpawner.java @@ -0,0 +1,31 @@ +/* + * 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.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Retention(RUNTIME) +@Target({PARAMETER, TYPE, FIELD}) +public @interface RegistryListSpawner { + +}