From c5ac34753848e88583eda3ceeea63146112986e2 Mon Sep 17 00:00:00 2001 From: Daniel Mills Date: Wed, 4 Aug 2021 01:07:07 -0400 Subject: [PATCH] Entity logic --- .../volmit/iris/core/IrisBoardManager.java | 23 ++- .../volmit/iris/engine/IrisWorldManager.java | 147 ++++++++++++++---- .../framework/EngineAssignedWorldManager.java | 14 ++ .../engine/framework/EngineWorldManager.java | 11 ++ .../iris/engine/object/IrisEntitySpawn.java | 7 +- .../iris/engine/object/IrisSpawner.java | 3 + .../engine/parallax/ParallaxChunkMeta.java | 12 +- 7 files changed, 172 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/volmit/iris/core/IrisBoardManager.java b/src/main/java/com/volmit/iris/core/IrisBoardManager.java index 8709ac0b5..a505d1b02 100644 --- a/src/main/java/com/volmit/iris/core/IrisBoardManager.java +++ b/src/main/java/com/volmit/iris/core/IrisBoardManager.java @@ -33,7 +33,11 @@ import com.volmit.iris.util.format.Form; import com.volmit.iris.util.math.RollingSequence; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; +import org.bukkit.Bukkit; import org.bukkit.World; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarStyle; +import org.bukkit.boss.BossBar; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -43,12 +47,13 @@ import java.util.List; public class IrisBoardManager implements BoardProvider, Listener { + private BossBar energyBar; private final BoardManager manager; private String mem = "..."; public final RollingSequence hits = new RollingSequence(20); public final RollingSequence tp = new RollingSequence(100); private final ChronoLatch cl = new ChronoLatch(1000); - + private final ChronoLatch ecl = new ChronoLatch(50); public IrisBoardManager() { Iris.instance.registerListener(this); @@ -57,6 +62,7 @@ public class IrisBoardManager implements BoardProvider, Listener { .boardProvider(this) .scoreDirection(ScoreDirection.DOWN) .build()); + energyBar = Bukkit.createBossBar("Spawner Energy " + 0, BarColor.BLUE, BarStyle.SOLID); //@done } @@ -74,8 +80,11 @@ public class IrisBoardManager implements BoardProvider, Listener { if (isIrisWorld(p.getWorld())) { manager.remove(p); manager.setup(p); + energyBar.removePlayer(p); + energyBar.addPlayer(p); } else { manager.remove(p); + energyBar.removePlayer(p); } } @@ -110,6 +119,11 @@ public class IrisBoardManager implements BoardProvider, Listener { } Engine engine = g.getCompound().getEngineForHeight(y); + if(ecl.flip()) + { + energyBar.setProgress(Math.min(1000D, engine.getWorldManager().getEnergy()) / 1000D); + energyBar.setTitle("Spawner Energy: " + Form.f((int)Math.min(1000D, engine.getWorldManager().getEnergy()))); + } int parallaxChunks = 0; int parallaxRegions = 0; @@ -141,9 +155,9 @@ public class IrisBoardManager implements BoardProvider, Listener { v.add(C.AQUA + "Biome" + C.GRAY + ": " + engine.getBiome(x, y, z).getName()); v.add(C.AQUA + "Height" + C.GRAY + ": " + Math.round(engine.getHeight(x, z))); v.add(C.AQUA + "Slope" + C.GRAY + ": " + Form.f(engine.getFramework().getComplex().getSlopeStream().get(x, z), 2)); - v.add(C.AQUA + "Features " + C.GRAY + ": " + Form.f(f.size())); - v.add(C.AQUA + "R: " + C.GRAY + ": " + engine.getFramework().getComplex().getRegionIDStream().get(x, z).toString().replaceAll("\\Q-\\E", "")); - v.add(C.AQUA + "B: " + C.GRAY + ": " + engine.getFramework().getComplex().getBaseBiomeIDStream().get(x, z).toString().replaceAll("\\Q-\\E", "")); + v.add(C.AQUA + "Features" + C.GRAY + ": " + Form.f(f.size())); + v.add(C.AQUA + "Energy" + C.GRAY + ": " + Form.f(engine.getWorldManager().getEnergy(), 0)); + v.add(C.AQUA + "Sat" + C.GRAY + ": " + Form.f(engine.getWorldManager().getEntityCount()) + "e / " + Form.f(engine.getWorldManager().getChunkCount()) + "c (" + Form.pc(engine.getWorldManager().getEntitySaturation(), 0) + ")"); } if (Iris.jobCount() > 0) { @@ -159,5 +173,6 @@ public class IrisBoardManager implements BoardProvider, Listener { public void disable() { manager.onDisable(); + energyBar.removeAll(); } } diff --git a/src/main/java/com/volmit/iris/engine/IrisWorldManager.java b/src/main/java/com/volmit/iris/engine/IrisWorldManager.java index a92eec0e4..0b6d1774a 100644 --- a/src/main/java/com/volmit/iris/engine/IrisWorldManager.java +++ b/src/main/java/com/volmit/iris/engine/IrisWorldManager.java @@ -18,7 +18,7 @@ package com.volmit.iris.engine; -import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.Iris; import com.volmit.iris.engine.cache.Cache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.EngineAssignedWorldManager; @@ -28,11 +28,17 @@ import com.volmit.iris.engine.object.engine.IrisEngineData; import com.volmit.iris.engine.object.engine.IrisEngineSpawnerCooldown; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.format.Form; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; +import com.volmit.iris.util.scheduling.Looper; +import lombok.Data; +import lombok.EqualsAndHashCode; import org.bukkit.Chunk; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.inventory.ItemStack; @@ -43,35 +49,81 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; +@EqualsAndHashCode(callSuper = true) +@Data public class IrisWorldManager extends EngineAssignedWorldManager { - private final int art; + private final Looper looper; private final KMap chunkCooldowns; + private double energy = 25; private int entityCount = 0; private final ChronoLatch cl; + private final ChronoLatch ecl; private int actuallySpawned = 0; + private int cooldown = 0; + + public IrisWorldManager() { + super(null); + cl = null; + ecl = null; + chunkCooldowns = null; + looper = null; + } public IrisWorldManager(Engine engine) { super(engine); - cl = new ChronoLatch(5000); + cl = new ChronoLatch(1000); + ecl = new ChronoLatch(250); chunkCooldowns = new KMap<>(); - art = J.ar(this::onAsyncTick, 7); + energy = 25; + looper = new Looper() { + @Override + protected long loop() { + if(energy < 650) + { + if(ecl.flip()) + { + energy *= 1.03; + fixEnergy(); + } + } + + onAsyncTick(); + + return 50; + } + }; + looper.setPriority(Thread.MIN_PRIORITY); + looper.setName("Iris World Manager"); + looper.start(); } - private void onAsyncTick() { + private boolean onAsyncTick() { actuallySpawned = 0; - if (!getEngine().getWorld().hasRealWorld()) { - return; + + if(energy < 35) + { + J.sleep(200); + return false; } - if ((double) entityCount / (getEngine().getWorld().realWorld().getLoadedChunks().length + 1) > 1) { - return; + if (!getEngine().getWorld().hasRealWorld()) { + Iris.debug("Can't spawn. No real world"); + J.sleep(10000); + return false; + } + + double epx = getEntitySaturation(); + if (epx > 1) { + Iris.debug("Can't spawn. The entity per chunk ratio is at " + Form.pc(epx, 2) + " > 100% (total entities " + entityCount + ")"); + J.sleep(5000); + return false; } if (cl.flip()) { J.s(() -> entityCount = getEngine().getWorld().realWorld().getEntities().size()); } - int maxGroups = 3; + int maxGroups = 1; int chunkCooldownSeconds = 60; for (Long i : chunkCooldowns.k()) { @@ -80,28 +132,39 @@ public class IrisWorldManager extends EngineAssignedWorldManager { } } - int spawnBuffer = 32; + int spawnBuffer = RNG.r.i(2, 12); - for (Chunk c : getEngine().getWorld().realWorld().getLoadedChunks()) { - - if (spawnBuffer-- < 0) { - break; + Chunk[] cc = getEngine().getWorld().realWorld().getLoadedChunks(); + while(spawnBuffer-- > 0) + { + if(cc.length == 0) + { + Iris.debug("Can't spawn. No chunks!"); + return false; } + Chunk c = cc[RNG.r.nextInt(cc.length)]; IrisBiome biome = getEngine().getSurfaceBiome(c); IrisRegion region = getEngine().getRegion(c); spawnIn(c, biome, region, maxGroups); chunkCooldowns.put(Cache.key(c), M.ms()); } - if (actuallySpawned <= 0) { - J.sleep(5000); - } + energy -= (actuallySpawned / 2D); + return actuallySpawned > 0; + } + + private void fixEnergy() { + energy = M.clip(energy, 1D, 1000D); } private void spawnIn(Chunk c, IrisBiome biome, IrisRegion region, int max) { - if (c.getEntities().length > 2) { - return; + for(Entity i : c.getEntities()) + { + if(i instanceof LivingEntity) + { + return; + } } //@builder @@ -129,9 +192,11 @@ public class IrisWorldManager extends EngineAssignedWorldManager { } private void spawn(Chunk c, IrisEntitySpawn i) { - if (i.spawn(getEngine(), c, RNG.r)) { - actuallySpawned++; + 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) - 1); } } @@ -182,17 +247,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager { return cd; } - 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 public void onTick() { @@ -203,6 +257,21 @@ public class IrisWorldManager extends EngineAssignedWorldManager { getEngine().getParallax().saveAll(); } + @Override + public void onChunkLoad(Chunk e, boolean generated) { + if(generated) + { + energy += 1.2; + } + + else + { + energy += 0.3; + } + + fixEnergy(); + } + @Override public void onBlockBreak(BlockBreakEvent e) { if (e.getBlock().getWorld().equals(getTarget().getWorld().realWorld()) && getEngine().contains(e.getBlock().getLocation())) { @@ -267,6 +336,16 @@ public class IrisWorldManager extends EngineAssignedWorldManager { @Override public void close() { super.close(); - J.car(art); + looper.interrupt(); + } + + @Override + public int getChunkCount() { + return getEngine().getWorld().realWorld().getLoadedChunks().length; + } + + @Override + public double getEntitySaturation() { + return (double) entityCount / (getEngine().getWorld().realWorld().getLoadedChunks().length + 1) * 1.665; } } 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 5df4beec9..1ec7d839f 100644 --- a/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java +++ b/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java @@ -20,16 +20,23 @@ package com.volmit.iris.engine.framework; import com.volmit.iris.Iris; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.WorldSaveEvent; import org.bukkit.event.world.WorldUnloadEvent; public abstract class EngineAssignedWorldManager extends EngineAssignedComponent implements EngineWorldManager, Listener { private final int taskId; + public EngineAssignedWorldManager() { + super(null, null); + taskId = -1; + } + public EngineAssignedWorldManager(Engine engine) { super(engine, "World"); Iris.instance.registerListener(this); @@ -64,6 +71,13 @@ public abstract class EngineAssignedWorldManager extends EngineAssignedComponent } } + @EventHandler + public void on(ChunkLoadEvent e) { + if (e.getChunk().getWorld().equals(getTarget().getWorld().realWorld())) { + onChunkLoad(e.getChunk(), e.isNewChunk()); + } + } + @Override public void close() { super.close(); 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 188245ba4..e025f23ac 100644 --- a/src/main/java/com/volmit/iris/engine/framework/EngineWorldManager.java +++ b/src/main/java/com/volmit/iris/engine/framework/EngineWorldManager.java @@ -18,6 +18,7 @@ package com.volmit.iris.engine.framework; +import org.bukkit.Chunk; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; @@ -25,6 +26,14 @@ import org.bukkit.event.block.BlockPlaceEvent; public interface EngineWorldManager { void close(); + double getEnergy(); + + int getEntityCount(); + + int getChunkCount(); + + double getEntitySaturation(); + void onTick(); void onSave(); @@ -32,4 +41,6 @@ public interface EngineWorldManager { void onBlockBreak(BlockBreakEvent e); void onBlockPlace(BlockPlaceEvent e); + + void onChunkLoad(Chunk e, boolean generated); } 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 3b837b948..6314f50a5 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java @@ -52,6 +52,9 @@ public class IrisEntitySpawn implements IRare { @Desc("The entity") private String entity = ""; + @Desc("The energy multiplier when calculating spawn energy usage") + private double energyMultiplier = 1; + @MinNumber(1) @Desc("The 1 in RARITY chance for this entity to spawn") private int rarity = 1; @@ -68,7 +71,7 @@ public class IrisEntitySpawn implements IRare { private final transient AtomicCache rng = new AtomicCache<>(); private final transient AtomicCache ent = new AtomicCache<>(); - public boolean spawn(Engine gen, Chunk c, RNG rng) { + public int 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; @@ -108,7 +111,7 @@ public class IrisEntitySpawn implements IRare { } } - return s > 0; + return s; } public IrisEntity getRealEntity(Engine g) { 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 7aa668bc9..45e68c4a8 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisSpawner.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisSpawner.java @@ -39,6 +39,9 @@ public class IrisSpawner extends IrisRegistrant { @Desc("The entity spawns to add") private KList spawns = new KList<>(); + @Desc("The energy multiplier when calculating spawn energy usage") + private double energyMultiplier = 1; + @Desc("The block of 24 hour time to contain this spawn in.") private IrisTimeBlock timeBlock = new IrisTimeBlock(); diff --git a/src/main/java/com/volmit/iris/engine/parallax/ParallaxChunkMeta.java b/src/main/java/com/volmit/iris/engine/parallax/ParallaxChunkMeta.java index ac7941042..d3ff3d156 100644 --- a/src/main/java/com/volmit/iris/engine/parallax/ParallaxChunkMeta.java +++ b/src/main/java/com/volmit/iris/engine/parallax/ParallaxChunkMeta.java @@ -30,7 +30,9 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.List; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; import java.util.function.Function; @AllArgsConstructor @@ -68,7 +70,7 @@ public class ParallaxChunkMeta { pcm.setMaxObject(din.readInt()); pcm.setMinObject(din.readInt()); pcm.setCount(din.readInt()); - pcm.setFeatures(newList()); + pcm.setFeatures(newSet()); int c = din.readInt(); for (int i = 0; i < c; i++) { @@ -88,13 +90,13 @@ public class ParallaxChunkMeta { private int maxObject = -1; private int minObject = -1; private int count; - private List features; + private Set features; - private static List newList() { - return new CopyOnWriteArrayList<>(); + private static Set newSet() { + return new CopyOnWriteArraySet<>(); } public ParallaxChunkMeta() { - this(false, false, false, false, false, false, -1, -1, 0, newList()); + this(false, false, false, false, false, false, -1, -1, 0, newSet()); } }