diff --git a/src/main/java/com/volmit/iris/engine/IrisWorldManager.java b/src/main/java/com/volmit/iris/engine/IrisWorldManager.java index 5809b8555..c72271971 100644 --- a/src/main/java/com/volmit/iris/engine/IrisWorldManager.java +++ b/src/main/java/com/volmit/iris/engine/IrisWorldManager.java @@ -29,15 +29,21 @@ import com.volmit.iris.engine.object.IrisEngineChunkData; import com.volmit.iris.engine.object.IrisEngineData; import com.volmit.iris.engine.object.IrisEngineSpawnerCooldown; import com.volmit.iris.engine.object.IrisEntitySpawn; +import com.volmit.iris.engine.object.IrisMarker; +import com.volmit.iris.engine.object.IrisPosition; import com.volmit.iris.engine.object.IrisRegion; import com.volmit.iris.engine.object.IrisSpawner; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.format.Form; import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.MantleFlag; +import com.volmit.iris.util.math.BlockPosition; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.matter.MatterMarker; +import com.volmit.iris.util.matter.slices.MarkerMatter; import com.volmit.iris.util.plugin.Chunks; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; @@ -53,6 +59,9 @@ import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.inventory.ItemStack; import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -323,6 +332,42 @@ public class IrisWorldManager extends EngineAssignedWorldManager { } } + private void spawn(IrisPosition c, IrisEntitySpawn i) { + boolean allow = true; + + if (!i.getReferenceSpawner().getMaximumRatePerChunk().isInfinite()) { + allow = false; + IrisEngineChunkData cd = getEngine().getEngineData().getChunk(c.getX()>>4, c.getZ()>>4); + IrisEngineSpawnerCooldown sc = null; + for (IrisEngineSpawnerCooldown j : cd.getCooldowns()) { + if (j.getSpawner().equals(i.getReferenceSpawner().getLoadKey())) { + sc = j; + break; + } + } + + if (sc == null) { + sc = new IrisEngineSpawnerCooldown(); + sc.setSpawner(i.getReferenceSpawner().getLoadKey()); + cd.getCooldowns().add(sc); + } + + if (sc.canSpawn(i.getReferenceSpawner().getMaximumRatePerChunk())) { + sc.spawn(getEngine()); + allow = true; + } + } + + if (allow) { + int s = i.spawn(getEngine(), c, RNG.r); + actuallySpawned += s; + if (s > 0) { + getCooldown(i.getReferenceSpawner()).spawn(getEngine()); + energy -= s * ((i.getEnergyMultiplier() * i.getReferenceSpawner().getEnergyMultiplier() * 1)); + } + } + } + private Stream stream(IrisSpawner s, boolean initial) { for (IrisEntitySpawn i : initial ? s.getInitialSpawns() : s.getSpawns()) { i.setReferenceSpawner(s); @@ -384,7 +429,18 @@ public class IrisWorldManager extends EngineAssignedWorldManager { @Override public void onChunkLoad(Chunk e, boolean generated) { J.a(() -> getMantle().raiseFlag(e.getX(), e.getZ(), MantleFlag.INITIAL_SPAWNED, - () -> J.a(() -> spawnIn(e, true), RNG.r.i(5, 200)))); + () -> { + J.a(() -> spawnIn(e, true), RNG.r.i(5, 200)); + getSpawnersFromMarkers(e).forEach((block, spawners) -> { + if(spawners.isEmpty()) + { + return; + } + + IrisSpawner s = new KList<>(spawners).getRandom(); + spawn(block, s, true); + }); + })); energy += 0.3; fixEnergy(); if (!getMantle().hasFlag(e.getX(), e.getZ(), MantleFlag.UPDATE)) { @@ -392,6 +448,16 @@ public class IrisWorldManager extends EngineAssignedWorldManager { } } + private void spawn(IrisPosition block, IrisSpawner spawner, boolean initial) { + KList s = initial?spawner.getInitialSpawns(): spawner.getSpawns(); + if(s.isEmpty()) + { + return; + } + + spawn(block, spawnRandomly(s).getRandom()); + } + public Mantle getMantle() { return getEngine().getMantle().getMantle(); } @@ -401,9 +467,45 @@ public class IrisWorldManager extends EngineAssignedWorldManager { charge = M.ms() + 3000; } + public Map> getSpawnersFromMarkers(Chunk c) + { + Map> p = new KMap<>(); + + getMantle().iterateChunk(c.getX(), c.getZ(), MatterMarker.class, (x,y,z,t) -> { + IrisMarker mark = getData().getMarkerLoader().load(t.getTag()); + IrisPosition pos = new IrisPosition((c.getX() << 4) + x, y, (c.getZ() << 4) + z); + for(String i : mark.getSpawners()) + { + IrisSpawner m = getData().getSpawnerLoader().load(i); + + if(m != null) + { + p.computeIfAbsent(pos, (k) -> new KSet<>()).add(m); + } + } + }); + + return p; + } + @Override public void onBlockBreak(BlockBreakEvent e) { if (e.getBlock().getWorld().equals(getTarget().getWorld().realWorld())) { + + J.a(() -> { + MatterMarker marker = getMantle().get(e.getBlock().getX(),e.getBlock().getY(),e.getBlock().getZ(), MatterMarker.class); + + if(marker != null) + { + IrisMarker mark = getData().getMarkerLoader().load(marker.getTag()); + + if(mark == null || mark.isRemoveOnChange()) + { + getMantle().remove(e.getBlock().getX(),e.getBlock().getY(),e.getBlock().getZ(), MatterMarker.class); + } + } + }); + KList d = new KList<>(); Runnable drop = () -> J.s(() -> d.forEach((i) -> e.getBlock().getWorld().dropItemNaturally(e.getBlock().getLocation().clone().add(0.5, 0.5, 0.5), i))); IrisBiome b = getEngine().getBiome(e.getBlock().getLocation()); diff --git a/src/main/java/com/volmit/iris/engine/object/IRare.java b/src/main/java/com/volmit/iris/engine/object/IRare.java index f1c0dda91..3c3acebc4 100644 --- a/src/main/java/com/volmit/iris/engine/object/IRare.java +++ b/src/main/java/com/volmit/iris/engine/object/IRare.java @@ -18,6 +18,8 @@ package com.volmit.iris.engine.object; +import com.volmit.iris.util.collection.KList; + public interface IRare { static int get(Object v) { return v instanceof IRare ? Math.max(1, ((IRare) v).getRarity()) : 1; 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 3c48938ae..45f4440a2 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java @@ -27,6 +27,7 @@ import com.volmit.iris.engine.object.annotations.RegistryListResource; import com.volmit.iris.engine.object.annotations.Required; import com.volmit.iris.engine.object.annotations.Snippet; import com.volmit.iris.util.format.C; +import com.volmit.iris.util.math.BlockPosition; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.matter.slices.MarkerMatter; import lombok.AllArgsConstructor; @@ -35,6 +36,7 @@ import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import org.bukkit.Chunk; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.entity.Entity; @Snippet("entity-spawn") @@ -99,6 +101,40 @@ public class IrisEntitySpawn implements IRare { return s; } + public int spawn(Engine gen, IrisPosition c, RNG rng) { + int spawns = minSpawns == maxSpawns ? minSpawns : rng.i(Math.min(minSpawns, maxSpawns), Math.max(minSpawns, maxSpawns)); + int s = 0; + + if(!gen.getWorld().tryGetRealWorld()) + { + return 0; + } + + World world = gen.getWorld().realWorld(); + if (spawns > 0) { + for (int id = 0; id < spawns; id++) { + int x = c.getX(); + int z = c.getZ(); + int h = c.getY(); + Location l = c.toLocation(world).add(0, 1, 0); + + 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++; + } + } + } + } + + return s; + } + public IrisEntity getRealEntity(Engine g) { return ent.aquire(() -> g.getData().getEntityLoader().load(getEntity())); } diff --git a/src/main/java/com/volmit/iris/engine/object/IrisMarker.java b/src/main/java/com/volmit/iris/engine/object/IrisMarker.java index b2fa8a2db..38e12544c 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisMarker.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisMarker.java @@ -41,11 +41,14 @@ import lombok.experimental.Accessors; @Data @EqualsAndHashCode(callSuper = false) public class IrisMarker extends IrisRegistrant { - @Desc("A list of spawners to add to anywhere this marker is. Note markers can only support initial spawns!") + @Desc("A list of spawners to add to anywhere this marker is.") @RegistryListResource(IrisSpawner.class) @ArrayType(type = String.class, min = 1) private KList spawners = new KList<>(); + @Desc("Remove this marker when the block it's assigned to is changed.") + private boolean removeOnChange = true; + @Override public String getFolderName() { return "markers"; 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 6d75c129b..932a882b2 100644 --- a/src/main/java/com/volmit/iris/util/mantle/Mantle.java +++ b/src/main/java/com/volmit/iris/util/mantle/Mantle.java @@ -267,6 +267,23 @@ public class Mantle { .set(x & 15, y & 15, z & 15, t); } + @BlockCoordinates + public void remove(int x, int y, int z, Class t) { + if (closed.get()) { + throw new RuntimeException("The Mantle is closed"); + } + + if (y < 0 || y >= worldHeight) { + return; + } + + Matter matter = get((x >> 4) >> 5, (z >> 4) >> 5) + .getOrCreate((x >> 4) & 31, (z >> 4) & 31) + .getOrCreate(y >> 4); + matter.slice(t) + .set(x & 15, y & 15, z & 15, null); + } + /** * Gets the data tat the current block position This method will attempt to find a * Tectonic Plate either by loading it or creating a new one. This method uses