mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-03 16:36:00 +00:00
fix engines not closing on server stop
This commit is contained in:
parent
97ddfd309b
commit
e42317139d
@ -572,12 +572,17 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
|
Bukkit.getWorlds()
|
||||||
|
.parallelStream()
|
||||||
|
.map(IrisToolbelt::access)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.forEach(PlatformChunkGenerator::close);
|
||||||
services.values().forEach(IrisService::onDisable);
|
services.values().forEach(IrisService::onDisable);
|
||||||
Bukkit.getScheduler().cancelTasks(this);
|
Bukkit.getScheduler().cancelTasks(this);
|
||||||
HandlerList.unregisterAll((Plugin) this);
|
HandlerList.unregisterAll((Plugin) this);
|
||||||
postShutdown.forEach(Runnable::run);
|
postShutdown.forEach(Runnable::run);
|
||||||
services.clear();
|
|
||||||
MultiBurst.burst.close();
|
MultiBurst.burst.close();
|
||||||
|
services.clear();
|
||||||
super.onDisable();
|
super.onDisable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,76 +288,79 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var chunk = mantle.getChunk(c);
|
var chunk = mantle.getChunk(c).use();
|
||||||
if (chunk.isFlagged(MantleFlag.ETCHED)) return;
|
try {
|
||||||
chunk.flag(MantleFlag.ETCHED, true);
|
Semaphore semaphore = new Semaphore(3);
|
||||||
|
chunk.raiseFlag(MantleFlag.ETCHED, () -> {
|
||||||
|
chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> J.s(() -> {
|
||||||
|
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(() -> {
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
})));
|
||||||
|
|
||||||
Semaphore semaphore = new Semaphore(3);
|
chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> J.s(() -> {
|
||||||
chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> J.s(() -> {
|
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||||
mantle.iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> {
|
KMap<Long, Integer> updates = new KMap<>();
|
||||||
int betterY = y + getWorld().minHeight();
|
RNG r = new RNG(Cache.key(c.getX(), c.getZ()));
|
||||||
if (!TileData.setTileState(c.getBlock(x, betterY, z), v.getData()))
|
mantle.iterateChunk(c.getX(), c.getZ(), MatterCavern.class, (x, yf, z, v) -> {
|
||||||
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());
|
int y = yf + getWorld().minHeight();
|
||||||
});
|
if (!B.isFluid(c.getBlock(x & 15, y, z & 15).getBlockData())) {
|
||||||
})));
|
return;
|
||||||
chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> J.s(() -> {
|
}
|
||||||
mantle.iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> {
|
boolean u = false;
|
||||||
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
|
if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.DOWN).getBlockData())) {
|
||||||
});
|
u = true;
|
||||||
})));
|
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.WEST).getBlockData())) {
|
||||||
|
u = true;
|
||||||
chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> J.s(() -> {
|
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.EAST).getBlockData())) {
|
||||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
u = true;
|
||||||
KMap<Long, Integer> updates = new KMap<>();
|
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.SOUTH).getBlockData())) {
|
||||||
RNG r = new RNG(Cache.key(c.getX(), c.getZ()));
|
u = true;
|
||||||
mantle.iterateChunk(c.getX(), c.getZ(), MatterCavern.class, (x, yf, z, v) -> {
|
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.NORTH).getBlockData())) {
|
||||||
int y = yf + getWorld().minHeight();
|
u = true;
|
||||||
if (!B.isFluid(c.getBlock(x & 15, y, z & 15).getBlockData())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
boolean u = false;
|
|
||||||
if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.DOWN).getBlockData())) {
|
|
||||||
u = true;
|
|
||||||
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.WEST).getBlockData())) {
|
|
||||||
u = true;
|
|
||||||
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.EAST).getBlockData())) {
|
|
||||||
u = true;
|
|
||||||
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.SOUTH).getBlockData())) {
|
|
||||||
u = true;
|
|
||||||
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.NORTH).getBlockData())) {
|
|
||||||
u = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (u) {
|
|
||||||
updates.compute(Cache.key(x & 15, z & 15), (k, vv) -> {
|
|
||||||
if (vv != null) {
|
|
||||||
return Math.max(vv, y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return y;
|
if (u) {
|
||||||
|
updates.compute(Cache.key(x & 15, z & 15), (k, vv) -> {
|
||||||
|
if (vv != null) {
|
||||||
|
return Math.max(vv, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
return y;
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
updates.forEach((k, v) -> update(Cache.keyX(k), v, Cache.keyZ(k), c, r));
|
||||||
|
mantle.iterateChunk(c.getX(), c.getZ(), MatterUpdate.class, (x, yf, z, v) -> {
|
||||||
|
int y = yf + getWorld().minHeight();
|
||||||
|
if (v != null && v.isUpdate()) {
|
||||||
|
int vx = x & 15;
|
||||||
|
int vz = z & 15;
|
||||||
|
update(x, y, z, c, new RNG(Cache.key(c.getX(), c.getZ())));
|
||||||
|
if (vx > 0 && vx < 15 && vz > 0 && vz < 15) {
|
||||||
|
updateLighting(x, y, z, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mantle.deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class);
|
||||||
|
getMetrics().getUpdates().put(p.getMilliseconds());
|
||||||
|
}, RNG.r.i(0, 20))));
|
||||||
});
|
});
|
||||||
|
|
||||||
updates.forEach((k, v) -> update(Cache.keyX(k), v, Cache.keyZ(k), c, r));
|
try {
|
||||||
mantle.iterateChunk(c.getX(), c.getZ(), MatterUpdate.class, (x, yf, z, v) -> {
|
semaphore.acquire(3);
|
||||||
int y = yf + getWorld().minHeight();
|
} catch (InterruptedException ignored) {}
|
||||||
if (v != null && v.isUpdate()) {
|
} finally {
|
||||||
int vx = x & 15;
|
chunk.release();
|
||||||
int vz = z & 15;
|
}
|
||||||
update(x, y, z, c, new RNG(Cache.key(c.getX(), c.getZ())));
|
|
||||||
if (vx > 0 && vx < 15 && vz > 0 && vz < 15) {
|
|
||||||
updateLighting(x, y, z, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mantle.deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class);
|
|
||||||
getMetrics().getUpdates().put(p.getMilliseconds());
|
|
||||||
}, RNG.r.i(0, 20))));
|
|
||||||
|
|
||||||
try {
|
|
||||||
semaphore.acquire(3);
|
|
||||||
} catch (InterruptedException ignored) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Runnable run(Semaphore semaphore, Runnable runnable) {
|
private static Runnable run(Semaphore semaphore, Runnable runnable) {
|
||||||
|
@ -359,16 +359,18 @@ public class Mantle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
closed.set(true);
|
closed.set(true);
|
||||||
BurstExecutor b = ioBurst.burst(loadedRegions.size());
|
hyperLock.disable();
|
||||||
for (Long i : loadedRegions.keySet()) {
|
BurstExecutor b = ioBurst.burst(toUnload.size());
|
||||||
b.queue(() -> {
|
loadedRegions.forEach((i, plate) -> b.queue(() -> {
|
||||||
try {
|
try {
|
||||||
loadedRegions.get(i).write(fileForRegion(dataFolder, i));
|
plate.close();
|
||||||
} catch (IOException e) {
|
plate.write(fileForRegion(dataFolder, i));
|
||||||
e.printStackTrace();
|
} catch (Throwable e) {
|
||||||
}
|
Iris.error("Failed to write Tectonic Plate " + C.DARK_GREEN + Cache.keyX(i) + " " + Cache.keyZ(i));
|
||||||
});
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
}));
|
||||||
|
loadedRegions.clear();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
b.complete();
|
b.complete();
|
||||||
@ -376,7 +378,6 @@ public class Mantle {
|
|||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadedRegions.clear();
|
|
||||||
Iris.debug("The Mantle has Closed " + C.DARK_AQUA + dataFolder.getAbsolutePath());
|
Iris.debug("The Mantle has Closed " + C.DARK_AQUA + dataFolder.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,8 @@ import lombok.Getter;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.Semaphore;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicIntegerArray;
|
import java.util.concurrent.atomic.AtomicIntegerArray;
|
||||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||||
|
|
||||||
@ -45,7 +46,8 @@ public class MantleChunk {
|
|||||||
private final int z;
|
private final int z;
|
||||||
private final AtomicIntegerArray flags;
|
private final AtomicIntegerArray flags;
|
||||||
private final AtomicReferenceArray<Matter> sections;
|
private final AtomicReferenceArray<Matter> sections;
|
||||||
private final AtomicInteger ref = new AtomicInteger();
|
private final Semaphore ref = new Semaphore(Integer.MAX_VALUE, true);
|
||||||
|
private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a mantle chunk
|
* Create a mantle chunk
|
||||||
@ -103,20 +105,27 @@ public class MantleChunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void close() throws InterruptedException {
|
||||||
|
closed.set(true);
|
||||||
|
ref.acquire(Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean inUse() {
|
public boolean inUse() {
|
||||||
return ref.get() > 0;
|
return ref.availablePermits() < Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MantleChunk use() {
|
public MantleChunk use() {
|
||||||
ref.incrementAndGet();
|
if (closed.get()) throw new IllegalStateException("Chunk is closed!");
|
||||||
|
ref.acquireUninterruptibly();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void release() {
|
public void release() {
|
||||||
ref.decrementAndGet();
|
ref.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flag(MantleFlag flag, boolean f) {
|
public void flag(MantleFlag flag, boolean f) {
|
||||||
|
if (closed.get()) throw new IllegalStateException("Chunk is closed!");
|
||||||
flags.set(flag.ordinal(), f ? 1 : 0);
|
flags.set(flag.ordinal(), f ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,6 +136,15 @@ public class TectonicPlate {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void close() throws InterruptedException {
|
||||||
|
for (int i = 0; i < chunks.length(); i++) {
|
||||||
|
MantleChunk chunk = chunks.get(i);
|
||||||
|
if (chunk != null) {
|
||||||
|
chunk.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a chunk exists in this plate or not (same as get(x, z) != null)
|
* Check if a chunk exists in this plate or not (same as get(x, z) != null)
|
||||||
*
|
*
|
||||||
|
@ -143,5 +143,6 @@ public class HyperLock {
|
|||||||
|
|
||||||
public void disable() {
|
public void disable() {
|
||||||
enabled = false;
|
enabled = false;
|
||||||
|
locks.values().forEach(ReentrantLock::lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import java.util.concurrent.*;
|
|||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
public class MultiBurst implements ExecutorService {
|
public class MultiBurst implements ExecutorService {
|
||||||
|
private static final long TIMEOUT = Long.getLong("iris.burst.timeout", 15000);
|
||||||
public static final MultiBurst burst = new MultiBurst();
|
public static final MultiBurst burst = new MultiBurst();
|
||||||
private final AtomicLong last;
|
private final AtomicLong last;
|
||||||
private final String name;
|
private final String name;
|
||||||
@ -231,7 +232,7 @@ public class MultiBurst implements ExecutorService {
|
|||||||
try {
|
try {
|
||||||
while (!service.awaitTermination(1, TimeUnit.SECONDS)) {
|
while (!service.awaitTermination(1, TimeUnit.SECONDS)) {
|
||||||
Iris.info("Still waiting to shutdown burster...");
|
Iris.info("Still waiting to shutdown burster...");
|
||||||
if (p.getMilliseconds() > 7000) {
|
if (p.getMilliseconds() > TIMEOUT) {
|
||||||
Iris.warn("Forcing Shutdown...");
|
Iris.warn("Forcing Shutdown...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user