mirror of
https://github.com/Minestom/Minestom.git
synced 2024-09-28 06:27:27 +02:00
Improve tick scheduling
This commit is contained in:
parent
997e35459e
commit
2e8b3477bf
@ -108,16 +108,8 @@ public final class UpdateManager {
|
||||
// Tick all instances
|
||||
MinecraftServer.getInstanceManager().getInstances().forEach(instance ->
|
||||
instance.tick(tickStart));
|
||||
|
||||
// Tick all chunks (and entities inside)
|
||||
final CountDownLatch countDownLatch = threadProvider.update(tickStart);
|
||||
|
||||
// Wait tick end
|
||||
try {
|
||||
countDownLatch.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.threadProvider.updateAndAwait(tickStart);
|
||||
|
||||
// Clear removed entities & update threads
|
||||
long tickTime = System.currentTimeMillis() - tickStart;
|
||||
|
@ -20,6 +20,8 @@ public interface Acquirable<T> {
|
||||
* Gets all the {@link Entity entities} being ticked in the current thread.
|
||||
* <p>
|
||||
* Useful when you want to ensure that no acquisition is ever done.
|
||||
* <p>
|
||||
* Be aware that the entity stream is only updated at the beginning of the thread tick.
|
||||
*
|
||||
* @return the entities ticked in the current thread
|
||||
*/
|
||||
|
@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Phaser;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
@ -30,6 +30,8 @@ public abstract class ThreadProvider {
|
||||
private final Set<Entity> updatableEntities = ConcurrentHashMap.newKeySet();
|
||||
private final Set<Entity> removedEntities = ConcurrentHashMap.newKeySet();
|
||||
|
||||
private final Phaser phaser = new Phaser(1);
|
||||
|
||||
public ThreadProvider(int threadCount) {
|
||||
this.threads = new ArrayList<>(threadCount);
|
||||
|
||||
@ -112,24 +114,23 @@ public abstract class ThreadProvider {
|
||||
*
|
||||
* @param time the tick time in milliseconds
|
||||
*/
|
||||
public synchronized @NotNull CountDownLatch update(long time) {
|
||||
CountDownLatch countDownLatch = new CountDownLatch(threads.size());
|
||||
for (TickThread thread : threads) {
|
||||
public void updateAndAwait(long time) {
|
||||
for (var entry : threadChunkMap.entrySet()) {
|
||||
final TickThread thread = entry.getKey();
|
||||
final var chunkEntries = entry.getValue();
|
||||
if (chunkEntries == null || chunkEntries.isEmpty()) {
|
||||
// Nothing to tick
|
||||
continue;
|
||||
}
|
||||
// Execute tick
|
||||
thread.runnable.startTick(countDownLatch, () -> {
|
||||
final var chunkEntries = threadChunkMap.get(thread);
|
||||
if (chunkEntries == null || chunkEntries.isEmpty()) {
|
||||
// Nothing to tick
|
||||
Acquirable.refreshEntries(Collections.emptySet());
|
||||
return;
|
||||
}
|
||||
|
||||
this.phaser.register();
|
||||
thread.runnable.startTick(phaser, () -> {
|
||||
Acquirable.refreshEntries(chunkEntries);
|
||||
|
||||
final ReentrantLock lock = thread.getLock();
|
||||
lock.lock();
|
||||
chunkEntries.forEach(chunkEntry -> {
|
||||
Chunk chunk = chunkEntry.chunk;
|
||||
final Chunk chunk = chunkEntry.chunk;
|
||||
if (!ChunkUtils.isLoaded(chunk))
|
||||
return;
|
||||
chunk.tick(time);
|
||||
@ -138,18 +139,18 @@ public abstract class ThreadProvider {
|
||||
for (Entity entity : entities) {
|
||||
if (lock.hasQueuedThreads()) {
|
||||
lock.unlock();
|
||||
// #acquire callbacks should be called here
|
||||
// #acquire() callbacks should be called here
|
||||
lock.lock();
|
||||
}
|
||||
entity.tick(time);
|
||||
}
|
||||
}
|
||||
});
|
||||
Acquirable.refreshEntries(Collections.emptySet());
|
||||
lock.unlock();
|
||||
// #acquire() callbacks
|
||||
});
|
||||
}
|
||||
return countDownLatch;
|
||||
this.phaser.arriveAndAwaitAdvance();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,7 +4,7 @@ import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Phaser;
|
||||
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@ -60,16 +60,16 @@ public class TickThread extends Thread {
|
||||
// The context is necessary to control the tick rates
|
||||
if (localContext != null) {
|
||||
// Execute tick
|
||||
localContext.runnable.run();
|
||||
localContext.countDownLatch.countDown();
|
||||
CONTEXT_UPDATER.compareAndSet(this, localContext, null);
|
||||
localContext.runnable.run();
|
||||
localContext.phaser.arriveAndDeregister();
|
||||
}
|
||||
LockSupport.park(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected void startTick(@NotNull CountDownLatch countDownLatch, @NotNull Runnable runnable) {
|
||||
this.tickContext = new TickContext(countDownLatch, runnable);
|
||||
protected void startTick(@NotNull Phaser phaser, @NotNull Runnable runnable) {
|
||||
this.tickContext = new TickContext(phaser, runnable);
|
||||
LockSupport.unpark(tickThread);
|
||||
}
|
||||
|
||||
@ -79,11 +79,11 @@ public class TickThread extends Thread {
|
||||
}
|
||||
|
||||
private static class TickContext {
|
||||
private final CountDownLatch countDownLatch;
|
||||
private final Phaser phaser;
|
||||
private final Runnable runnable;
|
||||
|
||||
private TickContext(@NotNull CountDownLatch countDownLatch, @NotNull Runnable runnable) {
|
||||
this.countDownLatch = countDownLatch;
|
||||
private TickContext(@NotNull Phaser phaser, @NotNull Runnable runnable) {
|
||||
this.phaser = phaser;
|
||||
this.runnable = runnable;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user