diff --git a/src/main/java/com/volmit/iris/Iris.java b/src/main/java/com/volmit/iris/Iris.java index bfca9c085..02f73a71e 100644 --- a/src/main/java/com/volmit/iris/Iris.java +++ b/src/main/java/com/volmit/iris/Iris.java @@ -134,6 +134,7 @@ public class Iris extends VolmitPlugin implements Listener { super.onEnable(); Bukkit.getPluginManager().registerEvents(this, this); J.s(this::lateBind); + splash(); } public static void callEvent(Event e) { @@ -165,7 +166,6 @@ public class Iris extends VolmitPlugin implements Listener { J.a(() -> PaperLib.suggestPaper(this)); J.a(() -> IO.delete(getTemp())); J.a(this::bstats); - J.a(this::splash, 20); J.ar(this::checkConfigHotload, 60); J.sr(this::tickQueue, 0); J.s(this::setupPapi); diff --git a/src/main/java/com/volmit/iris/core/command/CommandIrisDebug.java b/src/main/java/com/volmit/iris/core/command/CommandIrisDebug.java index 184948e03..838e8473d 100644 --- a/src/main/java/com/volmit/iris/core/command/CommandIrisDebug.java +++ b/src/main/java/com/volmit/iris/core/command/CommandIrisDebug.java @@ -21,10 +21,14 @@ package com.volmit.iris.core.command; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.plugin.Command; import com.volmit.iris.util.plugin.MortarCommand; import com.volmit.iris.util.plugin.VolmitSender; public class CommandIrisDebug extends MortarCommand { + @Command + private CommandIrisDebugSpawnerBoost boost; + public CommandIrisDebug() { super("debug", "dbg"); requiresPermission(Iris.perm.studio); diff --git a/src/main/java/com/volmit/iris/core/command/CommandIrisDebugSpawnerBoost.java b/src/main/java/com/volmit/iris/core/command/CommandIrisDebugSpawnerBoost.java new file mode 100644 index 000000000..67a4aed2b --- /dev/null +++ b/src/main/java/com/volmit/iris/core/command/CommandIrisDebugSpawnerBoost.java @@ -0,0 +1,54 @@ +/* + * 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.command; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.tools.IrisToolbelt; +import com.volmit.iris.engine.IrisEngine; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.plugin.MortarCommand; +import com.volmit.iris.util.plugin.VolmitSender; + +public class CommandIrisDebugSpawnerBoost extends MortarCommand { + public CommandIrisDebugSpawnerBoost() { + super("charge", "zzt"); + requiresPermission(Iris.perm.studio); + setDescription("Charge spawner energy"); + setCategory("Studio"); + } + + + @Override + public void addTabOptions(VolmitSender sender, String[] args, KList list) { + + } + + @Override + public boolean handle(VolmitSender sender, String[] args) { + ((IrisEngine) + IrisToolbelt.access(sender.player().getWorld()).getEngineAccess(sender.player().getLocation().getBlockY())).getWorldManager().chargeEnergy(); + return true; + } + + @Override + protected String getArgsUsage() { + return " [|,&,^,>>,<<,%] "; + } +} diff --git a/src/main/java/com/volmit/iris/engine/IrisWorldManager.java b/src/main/java/com/volmit/iris/engine/IrisWorldManager.java index 6a2c07bb1..916e52da0 100644 --- a/src/main/java/com/volmit/iris/engine/IrisWorldManager.java +++ b/src/main/java/com/volmit/iris/engine/IrisWorldManager.java @@ -25,6 +25,7 @@ import com.volmit.iris.engine.framework.EngineAssignedWorldManager; import com.volmit.iris.engine.object.biome.IrisBiome; import com.volmit.iris.engine.object.block.IrisBlockDrops; import com.volmit.iris.engine.object.common.IRare; +import com.volmit.iris.engine.object.engine.IrisEngineChunkData; import com.volmit.iris.engine.object.engine.IrisEngineData; import com.volmit.iris.engine.object.engine.IrisEngineSpawnerCooldown; import com.volmit.iris.engine.object.entity.IrisEntitySpawn; @@ -61,6 +62,8 @@ public class IrisWorldManager extends EngineAssignedWorldManager { private int entityCount = 0; private final ChronoLatch cl; private final ChronoLatch ecl; + private final ChronoLatch cln; + private long charge = 0; private int actuallySpawned = 0; private int cooldown = 0; private List precount = new KList<>(); @@ -69,12 +72,14 @@ public class IrisWorldManager extends EngineAssignedWorldManager { super(null); cl = null; ecl = null; + cln = null; chunkCooldowns = null; looper = null; } public IrisWorldManager(Engine engine) { super(engine); + cln = new ChronoLatch(60000); cl = new ChronoLatch(3000); ecl = new ChronoLatch(250); chunkCooldowns = new KMap<>(); @@ -82,6 +87,16 @@ public class IrisWorldManager extends EngineAssignedWorldManager { looper = new Looper() { @Override protected long loop() { + if(M.ms() < charge) + { + energy += 70; + } + + if(cln.flip()) + { + engine.getEngineData().cleanup(getEngine()); + } + if (precount != null) { entityCount = 0; for (Entity i : precount) { @@ -137,7 +152,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager { J.s(() -> precount = getEngine().getWorld().realWorld().getEntities()); } - int maxGroups = 1; int chunkCooldownSeconds = 60; for (Long i : chunkCooldowns.k()) { @@ -158,7 +172,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager { Chunk c = cc[RNG.r.nextInt(cc.length)]; IrisBiome biome = getEngine().getSurfaceBiome(c); IrisRegion region = getEngine().getRegion(c); - spawnIn(c, biome, region, maxGroups); + spawnIn(c, biome, region); chunkCooldowns.put(Cache.key(c), M.ms()); } @@ -170,15 +184,9 @@ public class IrisWorldManager extends EngineAssignedWorldManager { energy = M.clip(energy, 1D, 1000D); } - private void spawnIn(Chunk c, IrisBiome biome, IrisRegion region, int max) { - for (Entity i : c.getEntities()) { - if (i instanceof LivingEntity) { - return; - } - } - + private void spawnIn(Chunk c, IrisBiome biome, IrisRegion region) { //@builder - spawnRandomly(Stream.concat(Stream.concat( + IrisEntitySpawn v = spawnRandomly(Stream.concat(Stream.concat( getData().getSpawnerLoader() .loadAll(getDimension().getEntitySpawners()) .shuffleCopy(RNG.r).stream().filter(this::canSpawn), @@ -197,16 +205,65 @@ public class IrisWorldManager extends EngineAssignedWorldManager { .shuffleCopy(RNG.r).stream().filter(this::canSpawn) .flatMap(this::stream))) .collect(Collectors.toList())) - .popRandom(RNG.r, max).forEach((i) -> spawn(c, i)); + .popRandom(RNG.r); + + if(v != null && v.getReferenceSpawner() != null) + { + int maxEntCount = v.getReferenceSpawner().getMaxEntitiesPerChunk(); + + for (Entity i : c.getEntities()) { + if (i instanceof LivingEntity) { + if(-maxEntCount <= 0) + { + return; + } + } + } + + spawn(c, v); + } //@done } private void spawn(Chunk c, IrisEntitySpawn i) { - 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)); + boolean allow = true; + + if(!i.getReferenceSpawner().getMaximumRatePerChunk().isInfinite()) + { + allow = false; + IrisEngineChunkData cd = getEngine().getEngineData().getChunk(c.getX(), c.getZ()); + 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)); + } } } @@ -278,6 +335,11 @@ public class IrisWorldManager extends EngineAssignedWorldManager { fixEnergy(); } + @Override + public void chargeEnergy() { + charge = M.ms() + 3000; + } + @Override public void onBlockBreak(BlockBreakEvent e) { if (e.getBlock().getWorld().equals(getTarget().getWorld().realWorld()) && getEngine().contains(e.getBlock().getLocation())) { 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 e025f23ac..e80c2ab53 100644 --- a/src/main/java/com/volmit/iris/engine/framework/EngineWorldManager.java +++ b/src/main/java/com/volmit/iris/engine/framework/EngineWorldManager.java @@ -43,4 +43,6 @@ public interface EngineWorldManager { void onBlockPlace(BlockPlaceEvent e); void onChunkLoad(Chunk e, boolean generated); + + void chargeEnergy(); } diff --git a/src/main/java/com/volmit/iris/engine/object/basic/IrisRate.java b/src/main/java/com/volmit/iris/engine/object/basic/IrisRate.java index bedd1b312..d7c8f93d1 100644 --- a/src/main/java/com/volmit/iris/engine/object/basic/IrisRate.java +++ b/src/main/java/com/volmit/iris/engine/object/basic/IrisRate.java @@ -48,4 +48,8 @@ public class IrisRate { public ChronoLatch toChronoLatch() { return new ChronoLatch(getInterval()); } + + public boolean isInfinite() { + return per.toMilliseconds() == 0; + } } diff --git a/src/main/java/com/volmit/iris/engine/object/engine/IrisEngineChunkData.java b/src/main/java/com/volmit/iris/engine/object/engine/IrisEngineChunkData.java new file mode 100644 index 000000000..d16ad785f --- /dev/null +++ b/src/main/java/com/volmit/iris/engine/object/engine/IrisEngineChunkData.java @@ -0,0 +1,47 @@ +/* + * 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.engine; + +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.object.spawners.IrisSpawner; +import com.volmit.iris.util.collection.KList; +import lombok.Data; + +@Data +public class IrisEngineChunkData { + private long chunk; + private KList cooldowns = new KList<>(); + + public void cleanup(Engine engine) + { + for(IrisEngineSpawnerCooldown i : getCooldowns().copy()) + { + IrisSpawner sp = engine.getData().getSpawnerLoader().load(i.getSpawner()); + + if(sp == null || i.canSpawn(sp.getMaximumRate())) + { + getCooldowns().remove(i); + } + } + } + + public boolean isEmpty() { + return cooldowns.isEmpty(); + } +} diff --git a/src/main/java/com/volmit/iris/engine/object/engine/IrisEngineData.java b/src/main/java/com/volmit/iris/engine/object/engine/IrisEngineData.java index f85efe3e4..0252346e1 100644 --- a/src/main/java/com/volmit/iris/engine/object/engine/IrisEngineData.java +++ b/src/main/java/com/volmit/iris/engine/object/engine/IrisEngineData.java @@ -18,6 +18,10 @@ package com.volmit.iris.engine.object.engine; +import com.volmit.iris.engine.data.cache.Cache; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.object.meta.IrisEnchantment; +import com.volmit.iris.engine.object.spawners.IrisSpawner; import com.volmit.iris.util.collection.KList; import lombok.Data; @@ -25,4 +29,51 @@ import lombok.Data; public class IrisEngineData { private IrisEngineStatistics statistics = new IrisEngineStatistics(); private KList spawnerCooldowns = new KList<>(); + private KList chunks = new KList<>(); + + public void removeChunk(int x, int z) + { + long k = Cache.key(x, z); + chunks.removeWhere((i) -> i.getChunk() == k); + } + + public IrisEngineChunkData getChunk(int x, int z) + { + long k = Cache.key(x, z); + + for(IrisEngineChunkData i : chunks) + { + if(i.getChunk() == k) + { + return i; + } + } + + IrisEngineChunkData c = new IrisEngineChunkData(); + c.setChunk(k); + chunks.add(c); + return c; + } + + public void cleanup(Engine engine) { + for(IrisEngineSpawnerCooldown i : getSpawnerCooldowns().copy()) + { + IrisSpawner sp = engine.getData().getSpawnerLoader().load(i.getSpawner()); + + if(sp == null || i.canSpawn(sp.getMaximumRate())) + { + getSpawnerCooldowns().remove(i); + } + } + + for(IrisEngineChunkData i : chunks.copy()) + { + i.cleanup(engine); + + if(i.isEmpty()) + { + getChunks().remove(i); + } + } + } } diff --git a/src/main/java/com/volmit/iris/engine/object/engine/IrisEngineSpawnerCooldown.java b/src/main/java/com/volmit/iris/engine/object/engine/IrisEngineSpawnerCooldown.java index 5fa28dbef..12de56329 100644 --- a/src/main/java/com/volmit/iris/engine/object/engine/IrisEngineSpawnerCooldown.java +++ b/src/main/java/com/volmit/iris/engine/object/engine/IrisEngineSpawnerCooldown.java @@ -25,7 +25,7 @@ import lombok.Data; @Data public class IrisEngineSpawnerCooldown { - private long lastSpawn; + private long lastSpawn = 0; private String spawner; public void spawn(Engine engine) { diff --git a/src/main/java/com/volmit/iris/engine/object/spawners/IrisSpawner.java b/src/main/java/com/volmit/iris/engine/object/spawners/IrisSpawner.java index 762fa32f9..116f2afdb 100644 --- a/src/main/java/com/volmit/iris/engine/object/spawners/IrisSpawner.java +++ b/src/main/java/com/volmit/iris/engine/object/spawners/IrisSpawner.java @@ -48,6 +48,9 @@ public class IrisSpawner extends IrisRegistrant { @Desc("The energy multiplier when calculating spawn energy usage") private double energyMultiplier = 1; + @Desc("This spawner will not spawn in a given chunk if that chunk has more than the defined amount of living entities.") + private int maxEntitiesPerChunk = 1; + @Desc("The block of 24 hour time to contain this spawn in.") private IrisTimeBlock timeBlock = new IrisTimeBlock(); @@ -57,6 +60,9 @@ public class IrisSpawner extends IrisRegistrant { @Desc("The maximum rate this spawner can fire") private IrisRate maximumRate = new IrisRate(); + @Desc("The maximum rate this spawner can fire on a specific chunk") + private IrisRate maximumRatePerChunk = new IrisRate(); + @Desc("Where should these spawns be placed") private IrisSpawnGroup group = IrisSpawnGroup.NORMAL; diff --git a/src/main/java/com/volmit/iris/util/plugin/MortarCommand.java b/src/main/java/com/volmit/iris/util/plugin/MortarCommand.java index ccb29caa7..8c6302c3d 100644 --- a/src/main/java/com/volmit/iris/util/plugin/MortarCommand.java +++ b/src/main/java/com/volmit/iris/util/plugin/MortarCommand.java @@ -91,7 +91,7 @@ public abstract class MortarCommand implements ICommand { b = true; - sender.sendMessage("" + C.GREEN + i.getNode() + " " + C.WHITE + "" + i.getArgsUsage() + C.GRAY + " - " + i.getDescription()); + sender.sendMessage("" + C.GREEN + i.getNode() + " " + "" + (getArgsUsage().trim().isEmpty() ? "" : (C.WHITE + i.getArgsUsage())) + C.GRAY + " - " + i.getDescription()); } if (!b) { diff --git a/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java b/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java index 735734f73..62f26e546 100644 --- a/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java +++ b/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java @@ -188,6 +188,12 @@ public class VolmitSender implements CommandSender { @Override public void sendMessage(String message) { + if(message.contains("")) + { + s.sendMessage(message.replaceAll("\\Q\\E", "")); + return; + } + try { String t = C.translateAlternateColorCodes('&', getTag() + message); @@ -198,6 +204,10 @@ public class VolmitSender implements CommandSender { catch(Throwable e) { + String t = C.translateAlternateColorCodes('&', getTag() + message); + String a = C.aura(t, IrisSettings.get().getGeneral().getSpinh(), IrisSettings.get().getGeneral().getSpins(), IrisSettings.get().getGeneral().getSpinb()); + + Iris.debug("Failure to parse " + a); s.sendMessage(C.translateAlternateColorCodes('&', getTag() + message)); } }