fix updater and mob spawning instantly failing

This commit is contained in:
Julian Krings 2025-06-14 19:35:28 +02:00
parent 35b879f0df
commit e461c1e199
No known key found for this signature in database
GPG Key ID: 208C6E08C3B718D2
6 changed files with 150 additions and 176 deletions

View File

@ -188,9 +188,11 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
for (Player i : getEngine().getWorld().realWorld().getPlayers()) {
int r = 1;
int cX = i.getLocation().getBlockX() >> 4;
int cZ = i.getLocation().getBlockZ() >> 4;
for (int x = -r; x <= r; x++) {
for (int z = -r; z <= r; z++) {
mantle.getChunk(i.getLocation().getChunk()).flag(MantleFlag.DISCOVERED, true);
mantle.getChunk(cX + x, cZ + z).flag(MantleFlag.DISCOVERED, true);
}
}
}
@ -200,20 +202,22 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
for (Player i : getEngine().getWorld().realWorld().getPlayers()) {
int r = 1;
Chunk c = i.getLocation().getChunk();
for (int x = -r; x <= r; x++) {
for (int z = -r; z <= r; z++) {
if (c.getWorld().isChunkLoaded(c.getX() + x, c.getZ() + z) && Chunks.isSafe(getEngine().getWorld().realWorld(), c.getX() + x, c.getZ() + z)) {
Iris.scheduler.entity(i).run(() -> {
Chunk c = i.getLocation().getChunk();
for (int x = -r; x <= r; x++) {
for (int z = -r; z <= r; z++) {
int cX = c.getX() + x;
int cZ = c.getZ() + z;
if (!c.getWorld().isChunkLoaded(cX, cZ) || !Chunks.isSafe(getEngine().getWorld().realWorld(), cX, cZ))
continue;
if (IrisSettings.get().getWorld().isPostLoadBlockUpdates()) {
getEngine().updateChunk(c.getWorld().getChunkAt(c.getX() + x, c.getZ() + z));
getEngine().updateChunk(c.getWorld().getChunkAt(cX, cZ));
}
if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) {
Chunk cx = getEngine().getWorld().realWorld().getChunkAt(c.getX() + x, c.getZ() + z);
int finalX = c.getX() + x;
int finalZ = c.getZ() + z;
J.a(() -> getMantle().raiseFlag(finalX, finalZ, MantleFlag.INITIAL_SPAWNED_MARKER,
Chunk cx = getEngine().getWorld().realWorld().getChunkAt(cX, cZ);
J.a(() -> getMantle().raiseFlag(cX, cZ, MantleFlag.INITIAL_SPAWNED_MARKER,
() -> {
J.a(() -> spawnIn(cx, true), RNG.r.i(5, 200));
getSpawnersFromMarkers(cx).forEach((blockf, spawners) -> {
@ -229,7 +233,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
}
}
}
}
}, null);
}
}
@ -532,19 +536,17 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
IrisPosition pos = new IrisPosition((c.getX() << 4) + x, y, (c.getZ() << 4) + z);
if (mark.isEmptyAbove()) {
AtomicBoolean remove = new AtomicBoolean(false);
Boolean remove = Iris.scheduler.region()
.run(c.getWorld(), c.getX(), c.getZ(), () -> c.getBlock(x, y + 1, z).getType().isSolid() || c.getBlock(x, y + 2, z).getType().isSolid())
.result()
.exceptionally(e -> {
Iris.reportError(e);
e.printStackTrace();
return false;
})
.join();
try {
J.sfut(() -> {
if (c.getBlock(x, y + 1, z).getBlockData().getMaterial().isSolid() || c.getBlock(x, y + 2, z).getBlockData().getMaterial().isSolid()) {
remove.set(true);
}
}).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
if (remove.get()) {
if (remove == Boolean.TRUE) {
b.add(pos);
return;
}

View File

@ -293,20 +293,21 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
try {
Semaphore semaphore = new Semaphore(3);
chunk.raiseFlag(MantleFlag.ETCHED, () -> {
chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> J.s(() -> {
var region = Iris.scheduler.region();
chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> region.run(c.getWorld(), c.getX(), c.getZ(), () -> {
mantle.iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> {
int betterY = y + getWorld().minHeight();
if (!TileData.setTileState(c.getBlock(x, betterY, z), v.getData()))
Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), v.getData().getMaterial().name());
});
})));
chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> J.s(() -> {
chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> region.run(c.getWorld(), c.getX(), c.getZ(), () -> {
mantle.iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> {
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
});
})));
chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> J.s(() -> {
chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> region.runDelayed(c.getWorld(), c.getX(), c.getZ(), () -> {
PrecisionStopwatch p = PrecisionStopwatch.start();
KMap<Long, Integer> updates = new KMap<>();
RNG r = new RNG(Cache.key(c.getX(), c.getZ()));
@ -353,7 +354,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
});
mantle.deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class);
getMetrics().getUpdates().put(p.getMilliseconds());
}, RNG.r.i(0, 20))));
}, RNG.r.i(1, 20))));
});
try {

View File

@ -31,8 +31,6 @@ import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.plugin.Chunks;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -48,13 +46,11 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.loot.LootContext;
import org.bukkit.loot.LootTable;
import org.bukkit.loot.Lootable;
import org.bukkit.util.Vector;
import java.util.Collection;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import static com.volmit.iris.util.data.registry.Particles.ITEM;
@ -181,37 +177,33 @@ public class IrisEntity extends IrisRegistrant {
return spawn(gen, at, new RNG(at.hashCode()));
}
public Entity spawn(Engine gen, Location at, RNG rng) {
public Entity spawn(Engine gen, final Location at, RNG rng) {
if (!Iris.scheduler.isOwnedByCurrentRegion(at)) {
try {
final Location finalAt = at;
return Iris.scheduler.region().run(at, () -> spawn(gen, finalAt, rng))
.result()
.get(500, TimeUnit.MILLISECONDS);
} catch (Throwable e) {
return null;
}
}
if (!Chunks.isSafe(at)) {
return null;
}
if (isSpawnEffectRiseOutOfGround()) {
AtomicReference<Location> f = new AtomicReference<>(at);
try {
J.sfut(() -> {
if (Chunks.hasPlayersNearby(f.get())) {
Location b = f.get().clone();
Location start = new Location(b.getWorld(), b.getX(), b.getY() - 5, b.getZ());
f.set(start);
}
}).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
at = f.get();
if (isSpawnEffectRiseOutOfGround() && Chunks.hasPlayersNearby(at)) {
at.add(0, -5, 0);
}
Entity ee = doSpawn(at);
if (ee == null && !Chunks.isSafe(at)) {
if (ee == null) {
return null;
}
if (!spawnerScript.isEmpty() && ee == null) {
synchronized (this) {
gen.getExecution().getAPI().setLocation(at);
gen.getExecution().getAPI().setLocation(at.clone());
try {
ee = (Entity) gen.getExecution().evaluate(spawnerScript);
} catch (Throwable ex) {
@ -240,109 +232,96 @@ public class IrisEntity extends IrisRegistrant {
int gg = 0;
for (IrisEntity i : passengers) {
Entity passenger = i.spawn(gen, at, rng.nextParallelRNG(234858 + gg++));
if (!Bukkit.isPrimaryThread()) {
J.s(() -> e.addPassenger(passenger));
}
e.addPassenger(i.spawn(gen, at, rng.nextParallelRNG(234858 + gg++)));
}
if (e instanceof Attributable) {
Attributable a = (Attributable) e;
if (e instanceof Attributable attributable) {
for (IrisAttributeModifier i : getAttributes()) {
i.apply(rng, a);
i.apply(rng, attributable);
}
}
if (e instanceof Lootable) {
Lootable l = (Lootable) e;
if (e instanceof Lootable lootable && getLoot().getTables().isNotEmpty()) {
lootable.setLootTable(new LootTable() {
@Override
public NamespacedKey getKey() {
return new NamespacedKey(Iris.instance, "loot-" + IrisEntity.this.hashCode());
}
if (getLoot().getTables().isNotEmpty()) {
Location finalAt = at;
l.setLootTable(new LootTable() {
@Override
public NamespacedKey getKey() {
return new NamespacedKey(Iris.instance, "loot-" + IrisEntity.this.hashCode());
@Override
public Collection<ItemStack> populateLoot(Random random, LootContext context) {
KList<ItemStack> items = new KList<>();
for (String fi : getLoot().getTables()) {
IrisLootTable i = gen.getData().getLootLoader().load(fi);
items.addAll(i.getLoot(gen.isStudio(), rng.nextParallelRNG(345911), InventorySlotType.STORAGE, at.getWorld(), at.getBlockX(), at.getBlockY(), at.getBlockZ()));
}
@Override
public Collection<ItemStack> populateLoot(Random random, LootContext context) {
KList<ItemStack> items = new KList<>();
return items;
}
for (String fi : getLoot().getTables()) {
IrisLootTable i = gen.getData().getLootLoader().load(fi);
items.addAll(i.getLoot(gen.isStudio(), rng.nextParallelRNG(345911), InventorySlotType.STORAGE, finalAt.getWorld(), finalAt.getBlockX(), finalAt.getBlockY(), finalAt.getBlockZ()));
}
return items;
@Override
public void fillInventory(Inventory inventory, Random random, LootContext context) {
for (ItemStack i : populateLoot(random, context)) {
inventory.addItem(i);
}
@Override
public void fillInventory(Inventory inventory, Random random, LootContext context) {
for (ItemStack i : populateLoot(random, context)) {
inventory.addItem(i);
}
gen.scramble(inventory, rng);
}
});
}
gen.scramble(inventory, rng);
}
});
}
if (e instanceof LivingEntity) {
LivingEntity l = (LivingEntity) e;
l.setAI(isAi());
l.setCanPickupItems(isPickupItems());
if (e instanceof LivingEntity living) {
living.setAI(isAi());
living.setCanPickupItems(isPickupItems());
if (getLeashHolder() != null) {
l.setLeashHolder(getLeashHolder().spawn(gen, at, rng.nextParallelRNG(234548)));
living.setLeashHolder(getLeashHolder().spawn(gen, at, rng.nextParallelRNG(234548)));
}
l.setRemoveWhenFarAway(isRemovable());
living.setRemoveWhenFarAway(isRemovable());
if (getHelmet() != null && rng.i(1, getHelmet().getRarity()) == 1) {
l.getEquipment().setHelmet(getHelmet().get(gen.isStudio(), rng));
living.getEquipment().setHelmet(getHelmet().get(gen.isStudio(), rng));
}
if (getChestplate() != null && rng.i(1, getChestplate().getRarity()) == 1) {
l.getEquipment().setChestplate(getChestplate().get(gen.isStudio(), rng));
living.getEquipment().setChestplate(getChestplate().get(gen.isStudio(), rng));
}
if (getLeggings() != null && rng.i(1, getLeggings().getRarity()) == 1) {
l.getEquipment().setLeggings(getLeggings().get(gen.isStudio(), rng));
living.getEquipment().setLeggings(getLeggings().get(gen.isStudio(), rng));
}
if (getBoots() != null && rng.i(1, getBoots().getRarity()) == 1) {
l.getEquipment().setBoots(getBoots().get(gen.isStudio(), rng));
living.getEquipment().setBoots(getBoots().get(gen.isStudio(), rng));
}
if (getMainHand() != null && rng.i(1, getMainHand().getRarity()) == 1) {
l.getEquipment().setItemInMainHand(getMainHand().get(gen.isStudio(), rng));
living.getEquipment().setItemInMainHand(getMainHand().get(gen.isStudio(), rng));
}
if (getOffHand() != null && rng.i(1, getOffHand().getRarity()) == 1) {
l.getEquipment().setItemInOffHand(getOffHand().get(gen.isStudio(), rng));
living.getEquipment().setItemInOffHand(getOffHand().get(gen.isStudio(), rng));
}
}
if (e instanceof Ageable && isBaby()) {
((Ageable) e).setBaby();
if (e instanceof Ageable ageable && isBaby()) {
ageable.setBaby();
}
if (e instanceof Panda) {
((Panda) e).setMainGene(getPandaMainGene());
((Panda) e).setMainGene(getPandaHiddenGene());
if (e instanceof Panda panda) {
panda.setMainGene(getPandaMainGene());
panda.setMainGene(getPandaHiddenGene());
}
if (e instanceof Villager) {
Villager villager = (Villager) e;
if (e instanceof Villager villager) {
villager.setRemoveWhenFarAway(false);
Iris.scheduler.entity(villager).run(() -> villager.setPersistent(true), null);
villager.setPersistent(true);
}
if (e instanceof Mob) {
Mob m = (Mob) e;
m.setAware(isAware());
if (e instanceof Mob mob) {
mob.setAware(isAware());
}
if (spawnEffect != null) {
@ -365,40 +344,35 @@ public class IrisEntity extends IrisRegistrant {
rawCommands.forEach(r -> r.run(fat));
}
Location finalAt1 = at;
if (isSpawnEffectRiseOutOfGround() && e instanceof LivingEntity living && Chunks.hasPlayersNearby(at)) {
e.setInvulnerable(true);
living.setAI(false);
living.setCollidable(false);
living.setNoDamageTicks(100000);
AtomicInteger t = new AtomicInteger(0);
Iris.scheduler.region().runAtFixedRate(at, task -> {
if (t.get() > 100) {
task.cancel();
return;
}
J.s(() -> {
if (isSpawnEffectRiseOutOfGround() && e instanceof LivingEntity && Chunks.hasPlayersNearby(finalAt1)) {
Location start = finalAt1.clone();
e.setInvulnerable(true);
((LivingEntity) e).setAI(false);
((LivingEntity) e).setCollidable(false);
((LivingEntity) e).setNoDamageTicks(100000);
AtomicInteger t = new AtomicInteger(0);
Iris.scheduler.global().runAtFixedRate(task -> {
if (t.get() > 100) {
task.cancel();
return;
t.incrementAndGet();
if (e.getLocation().getBlock().getType().isSolid() || living.getEyeLocation().getBlock().getType().isSolid()) {
Iris.scheduler.teleportAsync(e, at.add(0, 0.1, 0));
ItemStack itemCrackData = new ItemStack(living.getEyeLocation().clone().subtract(0, 2, 0).getBlock().getBlockData().getMaterial());
e.getWorld().spawnParticle(ITEM, living.getEyeLocation(), 6, 0.2, 0.4, 0.2, 0.06f, itemCrackData);
if (M.r(0.2)) {
e.getWorld().playSound(e.getLocation(), Sound.BLOCK_CHORUS_FLOWER_GROW, 0.8f, 0.1f);
}
t.incrementAndGet();
if (e.getLocation().getBlock().getType().isSolid() || ((LivingEntity) e).getEyeLocation().getBlock().getType().isSolid()) {
e.teleport(start.add(new Vector(0, 0.1, 0)));
ItemStack itemCrackData = new ItemStack(((LivingEntity) e).getEyeLocation().clone().subtract(0, 2, 0).getBlock().getBlockData().getMaterial());
e.getWorld().spawnParticle(ITEM, ((LivingEntity) e).getEyeLocation(), 6, 0.2, 0.4, 0.2, 0.06f, itemCrackData);
if (M.r(0.2)) {
e.getWorld().playSound(e.getLocation(), Sound.BLOCK_CHORUS_FLOWER_GROW, 0.8f, 0.1f);
}
} else {
task.cancel();
((LivingEntity) e).setNoDamageTicks(0);
((LivingEntity) e).setCollidable(true);
((LivingEntity) e).setAI(true);
e.setInvulnerable(false);
}
}, 1, 1);
}
});
} else {
task.cancel();
living.setNoDamageTicks(0);
living.setCollidable(true);
living.setAI(true);
e.setInvulnerable(false);
}
}, 1, 1);
}
return e;
@ -428,29 +402,6 @@ public class IrisEntity extends IrisRegistrant {
return null;
}
if (!Bukkit.isPrimaryThread()) {
// Someone called spawn (worldedit maybe?) on a non server thread
// Due to the structure of iris, we will call it sync and busy wait until it's done.
AtomicReference<Entity> ae = new AtomicReference<>();
try {
J.s(() -> ae.set(doSpawn(at)));
} catch (Throwable e) {
return null;
}
PrecisionStopwatch p = PrecisionStopwatch.start();
while (ae.get() == null) {
J.sleep(25);
if (p.getMilliseconds() > 500) {
return null;
}
}
return ae.get();
}
if (isSpecialType()) {
if (specialType.toLowerCase().startsWith("mythicmobs:")) {
return Iris.linkMythicMobs.spawnMob(specialType.substring(11), at);

View File

@ -36,8 +36,14 @@ import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Entity;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.volmit.iris.Iris.scheduler;
@Snippet("entity-spawn")
@Accessors(chain = true)
@NoArgsConstructor
@ -164,8 +170,15 @@ public class IrisEntitySpawn implements IRare {
return null;
}
if (!ignoreSurfaces && !irisEntity.getSurface().matches(at.clone().subtract(0, 1, 0).getBlock())) {
return null;
if (!ignoreSurfaces) {
Location block = at.clone().subtract(0, 1, 0);
BlockData data = scheduler.region()
.run(block, () -> block.getBlock().getBlockData())
.result()
.join();
if (!irisEntity.getSurface().matches(data)) {
return null;
}
}
Vector3d boundingBox = INMS.get().getBoundingbox(irisEntity.getType());
@ -199,15 +212,22 @@ public class IrisEntitySpawn implements IRare {
int startZ = center.getBlockZ() - (int) (boundingBox.z / 2);
int endZ = center.getBlockZ() + (int) (boundingBox.z / 2);
var region = scheduler.region();
var lock = new Semaphore(Integer.MAX_VALUE, true);
var bool = new AtomicBoolean(true);
for (int x = startX; x <= endX; x++) {
for (int y = startY; y <= endY; y++) {
for (int z = startZ; z <= endZ; z++) {
if (world.getBlockAt(x, y, z).getType() != Material.AIR) {
return false;
}
Location l = new Location(world, x, y, z);
lock.acquireUninterruptibly();
region.run(l, () -> {
if (!bool.get()) return false;
return bool.compareAndSet(true, l.getBlock().getType() == Material.AIR);
}).result().exceptionally(f -> false).thenRun(lock::release);
}
}
}
return true;
lock.acquireUninterruptibly(Integer.MAX_VALUE);
return bool.get();
}
}

View File

@ -20,7 +20,7 @@ package com.volmit.iris.engine.object;
import com.volmit.iris.engine.object.annotations.Desc;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
@Desc("The type of surface entities should spawn on")
@ -47,8 +47,8 @@ public enum IrisSurface {
* @param state The blockstate
* @return True if it matches
*/
public boolean matches(Block state) {
Material type = state.getType();
public boolean matches(BlockData state) {
Material type = state.getMaterial();
if (type.isSolid()) {
return this == LAND || this == OVERWORLD || (this == ANIMAL
&& (type == Material.GRASS_BLOCK || type == Material.DIRT

View File

@ -1,10 +1,10 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.scheduling.J;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
@ -80,7 +80,7 @@ public class LegacyTileData extends TileData {
@Override
public void toBukkit(Block block) {
J.s(() -> handler.toBukkit(block));
Iris.scheduler.region().run(block.getLocation(), () -> handler.toBukkit(block));
}
@Override