mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-12-19 15:09:18 +00:00
reintroduce native threads for the updater as a setting and cleanup
This commit is contained in:
@@ -58,6 +58,7 @@ import com.volmit.iris.util.parallel.MultiBurst;
|
|||||||
import com.volmit.iris.util.plugin.IrisService;
|
import com.volmit.iris.util.plugin.IrisService;
|
||||||
import com.volmit.iris.util.plugin.VolmitPlugin;
|
import com.volmit.iris.util.plugin.VolmitPlugin;
|
||||||
import com.volmit.iris.util.plugin.VolmitSender;
|
import com.volmit.iris.util.plugin.VolmitSender;
|
||||||
|
import com.volmit.iris.util.plugin.chunk.ChunkTickets;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import com.volmit.iris.util.scheduling.Queue;
|
import com.volmit.iris.util.scheduling.Queue;
|
||||||
import com.volmit.iris.util.scheduling.ShurikenQueue;
|
import com.volmit.iris.util.scheduling.ShurikenQueue;
|
||||||
@@ -95,6 +96,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
public static MultiverseCoreLink linkMultiverseCore;
|
public static MultiverseCoreLink linkMultiverseCore;
|
||||||
public static IrisCompat compat;
|
public static IrisCompat compat;
|
||||||
public static FileWatcher configWatcher;
|
public static FileWatcher configWatcher;
|
||||||
|
public static ChunkTickets tickets;
|
||||||
private static VolmitSender sender;
|
private static VolmitSender sender;
|
||||||
private static Thread shutdownHook;
|
private static Thread shutdownHook;
|
||||||
|
|
||||||
@@ -450,6 +452,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
IrisSafeguard.IrisSafeguardSystem();
|
IrisSafeguard.IrisSafeguardSystem();
|
||||||
getSender().setTag(getTag());
|
getSender().setTag(getTag());
|
||||||
IrisSafeguard.splash(true);
|
IrisSafeguard.splash(true);
|
||||||
|
tickets = new ChunkTickets();
|
||||||
linkMultiverseCore = new MultiverseCoreLink();
|
linkMultiverseCore = new MultiverseCoreLink();
|
||||||
configWatcher = new FileWatcher(getDataFile("settings.json"));
|
configWatcher = new FileWatcher(getDataFile("settings.json"));
|
||||||
services.values().forEach(IrisService::onEnable);
|
services.values().forEach(IrisService::onEnable);
|
||||||
|
|||||||
@@ -177,6 +177,9 @@ public class IrisSettings {
|
|||||||
@Data
|
@Data
|
||||||
public static class IrisSettingsUpdater {
|
public static class IrisSettingsUpdater {
|
||||||
public int maxConcurrency = 256;
|
public int maxConcurrency = 256;
|
||||||
|
public boolean nativeThreads = false;
|
||||||
|
public double threadMultiplier = 2;
|
||||||
|
|
||||||
public double chunkLoadSensitivity = 0.7;
|
public double chunkLoadSensitivity = 0.7;
|
||||||
public MsRange emptyMsRange = new MsRange(80, 100);
|
public MsRange emptyMsRange = new MsRange(80, 100);
|
||||||
public MsRange defaultMsRange = new MsRange(20, 40);
|
public MsRange defaultMsRange = new MsRange(20, 40);
|
||||||
@@ -185,6 +188,10 @@ public class IrisSettings {
|
|||||||
return Math.max(Math.abs(maxConcurrency), 1);
|
return Math.max(Math.abs(maxConcurrency), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getThreadMultiplier() {
|
||||||
|
return Math.min(Math.abs(threadMultiplier), 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
public double getChunkLoadSensitivity() {
|
public double getChunkLoadSensitivity() {
|
||||||
return Math.min(chunkLoadSensitivity, 0.9);
|
return Math.min(chunkLoadSensitivity, 0.9);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,16 +2,15 @@ package com.volmit.iris.core.pregenerator;
|
|||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.IrisSettings;
|
import com.volmit.iris.core.IrisSettings;
|
||||||
import com.volmit.iris.core.nms.container.Pair;
|
import com.volmit.iris.core.service.PreservationSVC;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
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.KMap;
|
|
||||||
import com.volmit.iris.util.format.Form;
|
import com.volmit.iris.util.format.Form;
|
||||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||||
import com.volmit.iris.util.math.M;
|
import com.volmit.iris.util.math.M;
|
||||||
import com.volmit.iris.util.math.Position2;
|
import com.volmit.iris.util.math.Position2;
|
||||||
import com.volmit.iris.util.math.RollingSequence;
|
import com.volmit.iris.util.math.RollingSequence;
|
||||||
|
import com.volmit.iris.util.plugin.chunk.TicketHolder;
|
||||||
import com.volmit.iris.util.profile.LoadBalancer;
|
import com.volmit.iris.util.profile.LoadBalancer;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import io.papermc.lib.PaperLib;
|
import io.papermc.lib.PaperLib;
|
||||||
@@ -21,7 +20,6 @@ import org.bukkit.World;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@@ -31,7 +29,7 @@ public class ChunkUpdater {
|
|||||||
private static final String REGION_PATH = "region" + File.separator + "r.";
|
private static final String REGION_PATH = "region" + File.separator + "r.";
|
||||||
private final AtomicBoolean paused = new AtomicBoolean();
|
private final AtomicBoolean paused = new AtomicBoolean();
|
||||||
private final AtomicBoolean cancelled = new AtomicBoolean();
|
private final AtomicBoolean cancelled = new AtomicBoolean();
|
||||||
private final KMap<Long, Pair<Long, AtomicInteger>> lastUse = new KMap<>();
|
private final TicketHolder holder;
|
||||||
private final RollingSequence chunksPerSecond = new RollingSequence(5);
|
private final RollingSequence chunksPerSecond = new RollingSequence(5);
|
||||||
private final AtomicInteger totalMaxChunks = new AtomicInteger();
|
private final AtomicInteger totalMaxChunks = new AtomicInteger();
|
||||||
private final AtomicInteger chunksProcessed = new AtomicInteger();
|
private final AtomicInteger chunksProcessed = new AtomicInteger();
|
||||||
@@ -40,13 +38,13 @@ public class ChunkUpdater {
|
|||||||
private final AtomicBoolean serverEmpty = new AtomicBoolean(true);
|
private final AtomicBoolean serverEmpty = new AtomicBoolean(true);
|
||||||
private final AtomicLong lastCpsTime = new AtomicLong(M.ms());
|
private final AtomicLong lastCpsTime = new AtomicLong(M.ms());
|
||||||
private final int maxConcurrency = IrisSettings.get().getUpdater().getMaxConcurrency();
|
private final int maxConcurrency = IrisSettings.get().getUpdater().getMaxConcurrency();
|
||||||
|
private final int coreLimit = (int) Math.max(Runtime.getRuntime().availableProcessors() * IrisSettings.get().getUpdater().getThreadMultiplier(), 1);
|
||||||
private final Semaphore semaphore = new Semaphore(maxConcurrency);
|
private final Semaphore semaphore = new Semaphore(maxConcurrency);
|
||||||
private final LoadBalancer loadBalancer = new LoadBalancer(semaphore, maxConcurrency, IrisSettings.get().getUpdater().emptyMsRange);
|
private final LoadBalancer loadBalancer = new LoadBalancer(semaphore, maxConcurrency, IrisSettings.get().getUpdater().emptyMsRange);
|
||||||
private final AtomicLong startTime = new AtomicLong();
|
private final AtomicLong startTime = new AtomicLong();
|
||||||
private final Dimensions dimensions;
|
private final Dimensions dimensions;
|
||||||
private final PregenTask task;
|
private final PregenTask task;
|
||||||
private final ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
|
private final ExecutorService chunkExecutor = IrisSettings.get().getUpdater().isNativeThreads() ? Executors.newFixedThreadPool(coreLimit) : Executors.newVirtualThreadPerTaskExecutor();
|
||||||
private final ExecutorService chunkExecutor = Executors.newVirtualThreadPerTaskExecutor();
|
|
||||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||||
private final CountDownLatch latch;
|
private final CountDownLatch latch;
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
@@ -55,6 +53,7 @@ public class ChunkUpdater {
|
|||||||
public ChunkUpdater(World world) {
|
public ChunkUpdater(World world) {
|
||||||
this.engine = IrisToolbelt.access(world).getEngine();
|
this.engine = IrisToolbelt.access(world).getEngine();
|
||||||
this.world = world;
|
this.world = world;
|
||||||
|
this.holder = Iris.tickets.getHolder(world);
|
||||||
this.dimensions = calculateWorldDimensions(new File(world.getWorldFolder(), "region"));
|
this.dimensions = calculateWorldDimensions(new File(world.getWorldFolder(), "region"));
|
||||||
this.task = dimensions.task();
|
this.task = dimensions.task();
|
||||||
this.totalMaxChunks.set(dimensions.count * 1024);
|
this.totalMaxChunks.set(dimensions.count * 1024);
|
||||||
@@ -113,7 +112,6 @@ public class ChunkUpdater {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}, 0, 3, TimeUnit.SECONDS);
|
}, 0, 3, TimeUnit.SECONDS);
|
||||||
scheduler.scheduleAtFixedRate(this::unloadChunks, 0, 1, TimeUnit.SECONDS);
|
|
||||||
scheduler.scheduleAtFixedRate(() -> {
|
scheduler.scheduleAtFixedRate(() -> {
|
||||||
boolean empty = Bukkit.getOnlinePlayers().isEmpty();
|
boolean empty = Bukkit.getOnlinePlayers().isEmpty();
|
||||||
if (serverEmpty.getAndSet(empty) == empty)
|
if (serverEmpty.getAndSet(empty) == empty)
|
||||||
@@ -128,6 +126,7 @@ public class ChunkUpdater {
|
|||||||
t.setPriority(Thread.MAX_PRIORITY);
|
t.setPriority(Thread.MAX_PRIORITY);
|
||||||
t.start();
|
t.start();
|
||||||
|
|
||||||
|
Iris.service(PreservationSVC.class).register(t);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -140,8 +139,6 @@ public class ChunkUpdater {
|
|||||||
|
|
||||||
chunkExecutor.shutdown();
|
chunkExecutor.shutdown();
|
||||||
chunkExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
chunkExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
executor.shutdown();
|
|
||||||
executor.awaitTermination(5, TimeUnit.SECONDS);
|
|
||||||
scheduler.shutdownNow();
|
scheduler.shutdownNow();
|
||||||
unloadAndSaveAllChunks();
|
unloadAndSaveAllChunks();
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
@@ -200,20 +197,16 @@ public class ChunkUpdater {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mc = engine.getMantle().getMantle().getChunk(x, z).use();
|
||||||
try {
|
try {
|
||||||
Chunk c = world.getChunkAt(x, z);
|
Chunk c = world.getChunkAt(x, z);
|
||||||
engine.getMantle().getMantle().getChunk(c);
|
|
||||||
engine.updateChunk(c);
|
engine.updateChunk(c);
|
||||||
|
|
||||||
for (int xx = -1; xx <= 1; xx++) {
|
removeTickets(x, z);
|
||||||
for (int zz = -1; zz <= 1; zz++) {
|
|
||||||
var counter = lastUse.get(Cache.key(x + xx, z + zz));
|
|
||||||
if (counter != null) counter.getB().decrementAndGet();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
chunksUpdated.incrementAndGet();
|
chunksUpdated.incrementAndGet();
|
||||||
chunksProcessed.getAndIncrement();
|
chunksProcessed.getAndIncrement();
|
||||||
|
mc.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,41 +228,16 @@ public class ChunkUpdater {
|
|||||||
for (int dz = -1; dz <= 1; dz++) {
|
for (int dz = -1; dz <= 1; dz++) {
|
||||||
int xx = x + dx;
|
int xx = x + dx;
|
||||||
int zz = z + dz;
|
int zz = z + dz;
|
||||||
executor.submit(() -> {
|
PaperLib.getChunkAtAsync(world, xx, zz, false, true)
|
||||||
try {
|
.thenAccept(chunk -> {
|
||||||
Chunk c;
|
if (chunk == null || !chunk.isGenerated()) {
|
||||||
try {
|
latch.countDown();
|
||||||
c = PaperLib.getChunkAtAsync(world, xx, zz, false, true)
|
generated.set(false);
|
||||||
.thenApply(chunk -> {
|
return;
|
||||||
if (chunk != null)
|
}
|
||||||
chunk.addPluginChunkTicket(Iris.instance);
|
holder.addTicket(chunk);
|
||||||
return chunk;
|
latch.countDown();
|
||||||
}).get();
|
});
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
|
||||||
generated.set(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == null) {
|
|
||||||
generated.set(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!c.isLoaded()) {
|
|
||||||
var future = J.sfut(() -> c.load(false));
|
|
||||||
if (future != null) future.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PaperLib.isChunkGenerated(c.getWorld(), xx, zz))
|
|
||||||
generated.set(false);
|
|
||||||
|
|
||||||
var pair = lastUse.computeIfAbsent(Cache.key(c), k -> new Pair<>(0L, new AtomicInteger(-1)));
|
|
||||||
pair.setA(M.ms());
|
|
||||||
pair.getB().updateAndGet(i -> i == -1 ? 1 : ++i);
|
|
||||||
} finally {
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,27 +246,16 @@ public class ChunkUpdater {
|
|||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Iris.info("Interrupted while waiting for chunks to load");
|
Iris.info("Interrupted while waiting for chunks to load");
|
||||||
}
|
}
|
||||||
return generated.get();
|
|
||||||
|
if (generated.get()) return true;
|
||||||
|
removeTickets(x, z);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void unloadChunks() {
|
private void removeTickets(int x, int z) {
|
||||||
for (var key : new ArrayList<>(lastUse.keySet())) {
|
for (int xx = -1; xx <= 1; xx++) {
|
||||||
if (key == null) continue;
|
for (int zz = -1; zz <= 1; zz++) {
|
||||||
var pair = lastUse.get(key);
|
holder.removeTicket(x + xx, z + zz);
|
||||||
if (pair == null) continue;
|
|
||||||
var lastUseTime = pair.getA();
|
|
||||||
var counter = pair.getB();
|
|
||||||
if (lastUseTime == null || counter == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (M.ms() - lastUseTime >= 5000 && counter.get() == 0) {
|
|
||||||
int x = Cache.keyX(key);
|
|
||||||
int z = Cache.keyZ(key);
|
|
||||||
J.s(() -> {
|
|
||||||
world.removePluginChunkTicket(x, z, Iris.instance);
|
|
||||||
world.unloadChunk(x, z);
|
|
||||||
lastUse.remove(key);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -311,7 +268,6 @@ public class ChunkUpdater {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unloadChunks();
|
|
||||||
world.save();
|
world.save();
|
||||||
}).get();
|
}).get();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
|||||||
@@ -136,12 +136,12 @@ public class IrisEngineSVC implements IrisService {
|
|||||||
@Override
|
@Override
|
||||||
protected long loop() {
|
protected long loop() {
|
||||||
try {
|
try {
|
||||||
queuedTectonicPlates.set(0);
|
int queuedPlates = 0;
|
||||||
tectonicPlates.set(0);
|
int totalPlates = 0;
|
||||||
loadedChunks.set(0);
|
long chunks = 0;
|
||||||
unloaderAlive.set(0);
|
int unloaders = 0;
|
||||||
trimmerAlive.set(0);
|
int trimmers = 0;
|
||||||
totalWorlds.set(0);
|
int iris = 0;
|
||||||
|
|
||||||
double maxDuration = Long.MIN_VALUE;
|
double maxDuration = Long.MIN_VALUE;
|
||||||
double minDuration = Long.MAX_VALUE;
|
double minDuration = Long.MAX_VALUE;
|
||||||
@@ -149,23 +149,30 @@ public class IrisEngineSVC implements IrisService {
|
|||||||
var registered = entry.getValue();
|
var registered = entry.getValue();
|
||||||
if (registered.closed) continue;
|
if (registered.closed) continue;
|
||||||
|
|
||||||
totalWorlds.incrementAndGet();
|
iris++;
|
||||||
unloaderAlive.addAndGet(registered.unloaderAlive() ? 1 : 0);
|
if (registered.unloaderAlive()) unloaders++;
|
||||||
trimmerAlive.addAndGet(registered.trimmerAlive() ? 1 : 0);
|
if (registered.trimmerAlive()) trimmers++;
|
||||||
|
|
||||||
var engine = registered.getEngine();
|
var engine = registered.getEngine();
|
||||||
if (engine == null) continue;
|
if (engine == null) continue;
|
||||||
|
|
||||||
queuedTectonicPlates.addAndGet((int) engine.getMantle().getUnloadRegionCount());
|
queuedPlates += engine.getMantle().getUnloadRegionCount();
|
||||||
tectonicPlates.addAndGet(engine.getMantle().getLoadedRegionCount());
|
totalPlates += engine.getMantle().getLoadedRegionCount();
|
||||||
loadedChunks.addAndGet(entry.getKey().getLoadedChunks().length);
|
chunks += entry.getKey().getLoadedChunks().length;
|
||||||
|
|
||||||
double duration = engine.getMantle().getAdjustedIdleDuration();
|
double duration = engine.getMantle().getAdjustedIdleDuration();
|
||||||
if (duration > maxDuration) maxDuration = duration;
|
if (duration > maxDuration) maxDuration = duration;
|
||||||
if (duration < minDuration) minDuration = duration;
|
if (duration < minDuration) minDuration = duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trimmerAlive.set(trimmers);
|
||||||
|
unloaderAlive.set(unloaders);
|
||||||
|
tectonicPlates.set(totalPlates);
|
||||||
|
queuedTectonicPlates.set(queuedPlates);
|
||||||
maxIdleDuration.set(maxDuration);
|
maxIdleDuration.set(maxDuration);
|
||||||
minIdleDuration.set(minDuration);
|
minIdleDuration.set(minDuration);
|
||||||
|
loadedChunks.set(chunks);
|
||||||
|
totalWorlds.set(iris);
|
||||||
|
|
||||||
worlds.values().forEach(Registered::update);
|
worlds.values().forEach(Registered::update);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ public class WandSVC implements IrisService {
|
|||||||
|
|
||||||
int total = c.getSizeX() * c.getSizeY() * c.getSizeZ();
|
int total = c.getSizeX() * c.getSizeY() * c.getSizeZ();
|
||||||
var latch = new CountDownLatch(1);
|
var latch = new CountDownLatch(1);
|
||||||
|
var holder = Iris.tickets.getHolder(p.getWorld());
|
||||||
new Job() {
|
new Job() {
|
||||||
private int i;
|
private int i;
|
||||||
private Chunk chunk;
|
private Chunk chunk;
|
||||||
@@ -108,7 +109,7 @@ public class WandSVC implements IrisService {
|
|||||||
while (time > M.ms()) {
|
while (time > M.ms()) {
|
||||||
if (!it.hasNext()) {
|
if (!it.hasNext()) {
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
chunk.removePluginChunkTicket(Iris.instance);
|
holder.removeTicket(chunk);
|
||||||
chunk = null;
|
chunk = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,9 +123,10 @@ public class WandSVC implements IrisService {
|
|||||||
var bChunk = b.getChunk();
|
var bChunk = b.getChunk();
|
||||||
if (chunk == null) {
|
if (chunk == null) {
|
||||||
chunk = bChunk;
|
chunk = bChunk;
|
||||||
chunk.addPluginChunkTicket(Iris.instance);
|
holder.addTicket(chunk);
|
||||||
} else if (chunk != bChunk) {
|
} else if (chunk != bChunk) {
|
||||||
chunk.removePluginChunkTicket(Iris.instance);
|
holder.removeTicket(chunk);
|
||||||
|
holder.addTicket(bChunk);
|
||||||
chunk = bChunk;
|
chunk = bChunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -440,7 +440,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
//INMS.get().injectBiomesFromMantle(e, getMantle());
|
//INMS.get().injectBiomesFromMantle(e, getMantle());
|
||||||
|
|
||||||
if (!IrisSettings.get().getGenerator().earlyCustomBlocks) return;
|
if (!IrisSettings.get().getGenerator().earlyCustomBlocks) return;
|
||||||
e.addPluginChunkTicket(Iris.instance);
|
Iris.tickets.addTicket(e);
|
||||||
J.s(() -> {
|
J.s(() -> {
|
||||||
var chunk = getMantle().getChunk(e).use();
|
var chunk = getMantle().getChunk(e).use();
|
||||||
int minY = getTarget().getWorld().minHeight();
|
int minY = getTarget().getWorld().minHeight();
|
||||||
@@ -452,7 +452,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
chunk.release();
|
chunk.release();
|
||||||
e.removePluginChunkTicket(Iris.instance);
|
Iris.tickets.removeTicket(e);
|
||||||
}
|
}
|
||||||
}, RNG.r.i(20, 60));
|
}, RNG.r.i(20, 60));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ public interface EngineMantle extends MatterGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default long getUnloadRegionCount() {
|
default int getUnloadRegionCount() {
|
||||||
return getMantle().getUnloadRegionCount();
|
return getMantle().getUnloadRegionCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
|
|
||||||
Chunk c = PaperLib.getChunkAtAsync(world, x, z)
|
Chunk c = PaperLib.getChunkAtAsync(world, x, z)
|
||||||
.thenApply(d -> {
|
.thenApply(d -> {
|
||||||
d.addPluginChunkTicket(Iris.instance);
|
Iris.tickets.addTicket(d);
|
||||||
|
|
||||||
for (Entity ee : d.getEntities()) {
|
for (Entity ee : d.getEntities()) {
|
||||||
if (ee instanceof Player) {
|
if (ee instanceof Player) {
|
||||||
@@ -217,7 +217,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
ee.remove();
|
ee.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.getWorldManager().onChunkLoad(d, false);
|
|
||||||
return d;
|
return d;
|
||||||
}).get();
|
}).get();
|
||||||
|
|
||||||
@@ -243,7 +242,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
|
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
||||||
.thenRunAsync(() -> {
|
.thenRunAsync(() -> {
|
||||||
c.removePluginChunkTicket(Iris.instance);
|
Iris.tickets.removeTicket(c);
|
||||||
engine.getWorldManager().onChunkLoad(c, true);
|
engine.getWorldManager().onChunkLoad(c, true);
|
||||||
}, syncExecutor)
|
}, syncExecutor)
|
||||||
.get();
|
.get();
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.volmit.iris.util.plugin.chunk;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.world.WorldLoadEvent;
|
||||||
|
import org.bukkit.event.world.WorldUnloadEvent;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ChunkTickets implements Listener {
|
||||||
|
private final Map<World, TicketHolder> holders = new HashMap<>();
|
||||||
|
|
||||||
|
public ChunkTickets() {
|
||||||
|
Iris.instance.registerListener(this);
|
||||||
|
Bukkit.getWorlds().forEach(w -> holders.put(w, new TicketHolder(w)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public TicketHolder getHolder(@NonNull World world) {
|
||||||
|
return holders.get(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTicket(@NonNull Chunk chunk) {
|
||||||
|
addTicket(chunk.getWorld(), chunk.getX(), chunk.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTicket(@NonNull World world, int x, int z) {
|
||||||
|
var holder = getHolder(world);
|
||||||
|
if (holder != null) holder.addTicket(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeTicket(@NonNull Chunk chunk) {
|
||||||
|
return removeTicket(chunk.getWorld(), chunk.getX(), chunk.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeTicket(@NonNull World world, int x, int z) {
|
||||||
|
var holder = getHolder(world);
|
||||||
|
if (holder != null) return holder.removeTicket(x, z);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
public void on(@NonNull WorldLoadEvent event) {
|
||||||
|
holders.put(event.getWorld(), new TicketHolder(event.getWorld()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
|
public void on(@NonNull WorldUnloadEvent event) {
|
||||||
|
holders.remove(event.getWorld());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.volmit.iris.util.plugin.chunk;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.engine.data.cache.Cache;
|
||||||
|
import com.volmit.iris.util.collection.KMap;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
public class TicketHolder {
|
||||||
|
private final World world;
|
||||||
|
private final KMap<Long, Long> tickets = new KMap<>();
|
||||||
|
|
||||||
|
public TicketHolder(@NonNull World world) {
|
||||||
|
this.world = world;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTicket(@NonNull Chunk chunk) {
|
||||||
|
if (chunk.getWorld() != world) return;
|
||||||
|
addTicket(chunk.getX(), chunk.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTicket(int x, int z) {
|
||||||
|
tickets.compute(Cache.key(x, z), ($, ref) -> {
|
||||||
|
if (ref == null) {
|
||||||
|
world.addPluginChunkTicket(x, z, Iris.instance);
|
||||||
|
return 1L;
|
||||||
|
}
|
||||||
|
return ++ref;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeTicket(@NonNull Chunk chunk) {
|
||||||
|
if (chunk.getWorld() != world) return false;
|
||||||
|
return removeTicket(chunk.getX(), chunk.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeTicket(int x, int z) {
|
||||||
|
return tickets.compute(Cache.key(x, z), ($, ref) -> {
|
||||||
|
if (ref == null) return null;
|
||||||
|
if (--ref <= 0) {
|
||||||
|
world.removePluginChunkTicket(x, z, Iris.instance);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return ref;
|
||||||
|
}) == null;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user