mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-12-19 23:19:21 +00:00
Mob spawning fixes (#1169)
* fix cooldown being 0 in most cases * fix max entity count for spawners
This commit is contained in:
@@ -62,6 +62,7 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@@ -299,28 +300,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
energy += 1.2;
|
energy += 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//@builder
|
|
||||||
IrisBiome biome = IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()
|
|
||||||
? getEngine().getSurfaceBiome(c) : null;
|
|
||||||
IrisEntitySpawn v = IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()
|
|
||||||
? spawnRandomly(Stream.concat(getData().getSpawnerLoader()
|
|
||||||
.loadAll(getDimension().getEntitySpawners())
|
|
||||||
.shuffleCopy(RNG.r).stream()
|
|
||||||
.filter(this::canSpawn)
|
|
||||||
.filter((i) -> i.isValid(biome))
|
|
||||||
.flatMap((i) -> stream(i, initial)),
|
|
||||||
Stream.concat(getData().getSpawnerLoader()
|
|
||||||
.loadAll(getEngine().getRegion(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
|
|
||||||
.shuffleCopy(RNG.r).stream().filter(this::canSpawn)
|
|
||||||
.flatMap((i) -> stream(i, initial)),
|
|
||||||
getData().getSpawnerLoader()
|
|
||||||
.loadAll(getEngine().getSurfaceBiome(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
|
|
||||||
.shuffleCopy(RNG.r).stream().filter(this::canSpawn)
|
|
||||||
.flatMap((i) -> stream(i, initial))))
|
|
||||||
.collect(Collectors.toList()))
|
|
||||||
.popRandom(RNG.r) : null;
|
|
||||||
//@done
|
|
||||||
|
|
||||||
if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) {
|
if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) {
|
||||||
getSpawnersFromMarkers(c).forEach((blockf, spawners) -> {
|
getSpawnersFromMarkers(c).forEach((blockf, spawners) -> {
|
||||||
if (spawners.isEmpty()) {
|
if (spawners.isEmpty()) {
|
||||||
@@ -335,94 +314,67 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v != null && v.getReferenceSpawner() != null) {
|
if (!IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()) {
|
||||||
int maxEntCount = v.getReferenceSpawner().getMaxEntitiesPerChunk();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (Entity i : c.getEntities()) {
|
//@builder
|
||||||
if (i instanceof LivingEntity) {
|
Predicate<IrisSpawner> filter = i -> i.canSpawn(getEngine(), c.getX(), c.getZ());
|
||||||
if (-maxEntCount <= 0) {
|
ChunkCounter counter = new ChunkCounter(c.getEntities());
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
IrisBiome biome = getEngine().getSurfaceBiome(c);
|
||||||
spawn(c, v);
|
IrisEntitySpawn v = spawnRandomly(Stream.concat(getData().getSpawnerLoader()
|
||||||
} catch (Throwable e) {
|
.loadAll(getDimension().getEntitySpawners())
|
||||||
J.s(() -> spawn(c, v));
|
.shuffleCopy(RNG.r)
|
||||||
}
|
.stream()
|
||||||
|
.filter(filter)
|
||||||
|
.filter((i) -> i.isValid(biome)),
|
||||||
|
Stream.concat(getData()
|
||||||
|
.getSpawnerLoader()
|
||||||
|
.loadAll(getEngine().getRegion(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
|
||||||
|
.shuffleCopy(RNG.r)
|
||||||
|
.stream()
|
||||||
|
.filter(filter),
|
||||||
|
getData().getSpawnerLoader()
|
||||||
|
.loadAll(getEngine().getSurfaceBiome(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
|
||||||
|
.shuffleCopy(RNG.r)
|
||||||
|
.stream()
|
||||||
|
.filter(filter)))
|
||||||
|
.filter(counter)
|
||||||
|
.flatMap((i) -> stream(i, initial))
|
||||||
|
.collect(Collectors.toList()))
|
||||||
|
.getRandom();
|
||||||
|
//@done
|
||||||
|
if (v == null || v.getReferenceSpawner() == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
spawn(c, v);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
J.s(() -> spawn(c, v));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void spawn(Chunk c, IrisEntitySpawn i) {
|
private void spawn(Chunk c, IrisEntitySpawn i) {
|
||||||
boolean allow = true;
|
IrisSpawner ref = i.getReferenceSpawner();
|
||||||
|
int s = i.spawn(getEngine(), c, RNG.r);
|
||||||
if (!i.getReferenceSpawner().getMaximumRatePerChunk().isInfinite()) {
|
actuallySpawned += s;
|
||||||
allow = false;
|
if (s > 0) {
|
||||||
IrisEngineChunkData cd = getEngine().getEngineData().getChunk(c.getX(), c.getZ());
|
ref.spawn(getEngine(), c.getX(), c.getZ());
|
||||||
IrisEngineSpawnerCooldown sc = null;
|
energy -= s * ((i.getEnergyMultiplier() * ref.getEnergyMultiplier() * 1));
|
||||||
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 void spawn(IrisPosition c, IrisEntitySpawn i) {
|
private void spawn(IrisPosition pos, IrisEntitySpawn i) {
|
||||||
boolean allow = true;
|
IrisSpawner ref = i.getReferenceSpawner();
|
||||||
|
if (!ref.canSpawn(getEngine(), pos.getX() >> 4, pos.getZ()))
|
||||||
|
return;
|
||||||
|
|
||||||
if (!i.getReferenceSpawner().getMaximumRatePerChunk().isInfinite()) {
|
int s = i.spawn(getEngine(), pos, RNG.r);
|
||||||
allow = false;
|
actuallySpawned += s;
|
||||||
IrisEngineChunkData cd = getEngine().getEngineData().getChunk(c.getX() >> 4, c.getZ() >> 4);
|
if (s > 0) {
|
||||||
IrisEngineSpawnerCooldown sc = null;
|
ref.spawn(getEngine(), pos.getX() >> 4, pos.getZ() >> 4);
|
||||||
for (IrisEngineSpawnerCooldown j : cd.getCooldowns()) {
|
energy -= s * ((i.getEnergyMultiplier() * ref.getEnergyMultiplier() * 1));
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,31 +402,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
return rarityTypes;
|
return rarityTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canSpawn(IrisSpawner i) {
|
|
||||||
return i.isValid(getEngine().getWorld().realWorld())
|
|
||||||
&& getCooldown(i).canSpawn(i.getMaximumRate());
|
|
||||||
}
|
|
||||||
|
|
||||||
private IrisEngineSpawnerCooldown getCooldown(IrisSpawner i) {
|
|
||||||
IrisEngineData ed = getEngine().getEngineData();
|
|
||||||
IrisEngineSpawnerCooldown cd = null;
|
|
||||||
|
|
||||||
for (IrisEngineSpawnerCooldown j : ed.getSpawnerCooldowns().copy()) {
|
|
||||||
if (j.getSpawner().equals(i.getLoadKey())) {
|
|
||||||
cd = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cd == null) {
|
|
||||||
cd = new IrisEngineSpawnerCooldown();
|
|
||||||
cd.setSpawner(i.getLoadKey());
|
|
||||||
cd.setLastSpawn(M.ms() - i.getMaximumRate().getInterval());
|
|
||||||
ed.getSpawnerCooldowns().add(cd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cd;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTick() {
|
public void onTick() {
|
||||||
|
|
||||||
@@ -708,4 +635,27 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
|
|
||||||
return (double) entityCount / (getEngine().getWorld().realWorld().getLoadedChunks().length + 1) * 1.28;
|
return (double) entityCount / (getEngine().getWorld().realWorld().getLoadedChunks().length + 1) * 1.28;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
private static class ChunkCounter implements Predicate<IrisSpawner> {
|
||||||
|
private final Entity[] entities;
|
||||||
|
private transient int index = 0;
|
||||||
|
private transient int count = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(IrisSpawner spawner) {
|
||||||
|
int max = spawner.getMaxEntitiesPerChunk();
|
||||||
|
if (max <= count)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (index < entities.length) {
|
||||||
|
if (entities[index++] instanceof LivingEntity) {
|
||||||
|
if (++count >= max)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
|
||||||
* Copyright (c) 2022 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.volmit.iris.engine.object;
|
|
||||||
|
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
|
||||||
import com.volmit.iris.util.collection.KList;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class IrisEngineChunkData {
|
|
||||||
private long chunk;
|
|
||||||
private KList<IrisEngineSpawnerCooldown> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,51 +20,31 @@ package com.volmit.iris.engine.object;
|
|||||||
|
|
||||||
import com.volmit.iris.engine.data.cache.Cache;
|
import com.volmit.iris.engine.data.cache.Cache;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class IrisEngineData {
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class IrisEngineData extends IrisSpawnerCooldowns {
|
||||||
private IrisEngineStatistics statistics = new IrisEngineStatistics();
|
private IrisEngineStatistics statistics = new IrisEngineStatistics();
|
||||||
private KList<IrisEngineSpawnerCooldown> spawnerCooldowns = new KList<>();
|
private KMap<Long, IrisSpawnerCooldowns> chunks = new KMap<>();
|
||||||
private KList<IrisEngineChunkData> chunks = new KList<>();
|
|
||||||
private Long seed = null;
|
private Long seed = null;
|
||||||
|
|
||||||
public void removeChunk(int x, int z) {
|
public void removeChunk(int x, int z) {
|
||||||
long k = Cache.key(x, z);
|
chunks.remove(Cache.key(x, z));
|
||||||
chunks.removeWhere((i) -> i.getChunk() == k);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IrisEngineChunkData getChunk(int x, int z) {
|
public IrisSpawnerCooldowns getChunk(int x, int z) {
|
||||||
long k = Cache.key(x, z);
|
return chunks.computeIfAbsent(Cache.key(x, z), k -> new IrisSpawnerCooldowns());
|
||||||
|
|
||||||
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) {
|
public void cleanup(Engine engine) {
|
||||||
for (IrisEngineSpawnerCooldown i : getSpawnerCooldowns().copy()) {
|
super.cleanup(engine);
|
||||||
IrisSpawner sp = engine.getData().getSpawnerLoader().load(i.getSpawner());
|
|
||||||
|
|
||||||
if (sp == null || i.canSpawn(sp.getMaximumRate())) {
|
chunks.values().removeIf(chunk -> {
|
||||||
getSpawnerCooldowns().remove(i);
|
chunk.cleanup(engine);
|
||||||
}
|
return chunk.isEmpty();
|
||||||
}
|
});
|
||||||
|
|
||||||
for (IrisEngineChunkData i : chunks.copy()) {
|
|
||||||
i.cleanup(engine);
|
|
||||||
|
|
||||||
if (i.isEmpty()) {
|
|
||||||
getChunks().remove(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class IrisRate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getInterval() {
|
public long getInterval() {
|
||||||
long t = per.getMilliseconds() / (amount == 0 ? 1 : amount);
|
long t = per.toMilliseconds() / (amount == 0 ? 1 : amount);
|
||||||
return Math.abs(t <= 0 ? 1 : t);
|
return Math.abs(t <= 0 ? 1 : t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
package com.volmit.iris.engine.object;
|
package com.volmit.iris.engine.object;
|
||||||
|
|
||||||
import com.volmit.iris.core.loader.IrisRegistrant;
|
import com.volmit.iris.core.loader.IrisRegistrant;
|
||||||
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.engine.object.annotations.ArrayType;
|
import com.volmit.iris.engine.object.annotations.ArrayType;
|
||||||
import com.volmit.iris.engine.object.annotations.Desc;
|
import com.volmit.iris.engine.object.annotations.Desc;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
@@ -95,6 +96,37 @@ public class IrisSpawner extends IrisRegistrant {
|
|||||||
return timeBlock.isWithin(world) && weather.is(world);
|
return timeBlock.isWithin(world) && weather.is(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canSpawn(Engine engine) {
|
||||||
|
if (!isValid(engine.getWorld().realWorld()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var rate = getMaximumRate();
|
||||||
|
return rate.isInfinite() || engine.getEngineData().getCooldown(this).canSpawn(rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canSpawn(Engine engine, int x, int z) {
|
||||||
|
if (!canSpawn(engine))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var rate = getMaximumRatePerChunk();
|
||||||
|
return rate.isInfinite() || engine.getEngineData().getChunk(x, z).getCooldown(this).canSpawn(rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawn(Engine engine) {
|
||||||
|
if (getMaximumRate().isInfinite())
|
||||||
|
return;
|
||||||
|
|
||||||
|
engine.getEngineData().getCooldown(this).spawn(engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawn(Engine engine, int x, int z) {
|
||||||
|
spawn(engine);
|
||||||
|
if (getMaximumRatePerChunk().isInfinite())
|
||||||
|
return;
|
||||||
|
|
||||||
|
engine.getEngineData().getChunk(x, z).getCooldown(this).spawn(engine);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFolderName() {
|
public String getFolderName() {
|
||||||
return "spawners";
|
return "spawners";
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.volmit.iris.engine.object;
|
||||||
|
|
||||||
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
|
import com.volmit.iris.util.collection.KMap;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public class IrisSpawnerCooldowns {
|
||||||
|
private final KMap<String, IrisEngineSpawnerCooldown> cooldowns = new KMap<>();
|
||||||
|
|
||||||
|
public IrisEngineSpawnerCooldown getCooldown(@NonNull IrisSpawner spawner) {
|
||||||
|
return getCooldown(spawner.getLoadKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IrisEngineSpawnerCooldown getCooldown(@NonNull String loadKey) {
|
||||||
|
return cooldowns.computeIfAbsent(loadKey, k -> {
|
||||||
|
IrisEngineSpawnerCooldown cd = new IrisEngineSpawnerCooldown();
|
||||||
|
cd.setSpawner(loadKey);
|
||||||
|
return cd;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup(Engine engine) {
|
||||||
|
cooldowns.values().removeIf(cd -> {
|
||||||
|
IrisSpawner sp = engine.getData().getSpawnerLoader().load(cd.getSpawner());
|
||||||
|
return sp == null || cd.canSpawn(sp.getMaximumRate());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return cooldowns.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user