Minestom/src/main/java/net/minestom/server/thread/TickThread.java

99 lines
2.8 KiB
Java

package net.minestom.server.thread;
import net.minestom.server.MinecraftServer;
import net.minestom.server.Tickable;
import net.minestom.server.entity.Entity;
import net.minestom.server.instance.Chunk;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Phaser;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
/**
* Thread responsible for ticking {@link Chunk chunks} and {@link Entity entities}.
* <p>
* Created in {@link ThreadDispatcher}, and awaken every tick with a task to execute.
*/
@ApiStatus.Internal
public final class TickThread extends MinestomThread {
private final ReentrantLock lock = new ReentrantLock();
private final Phaser phaser;
private volatile boolean stop;
private long tickTime;
private final List<ThreadDispatcher.Partition> entries = new ArrayList<>();
public TickThread(Phaser phaser, int number) {
super(MinecraftServer.THREAD_NAME_TICK + "-" + number);
this.phaser = phaser;
}
@Override
public void run() {
LockSupport.park(this);
while (!stop) {
this.lock.lock();
try {
tick();
} catch (Exception e) {
MinecraftServer.getExceptionManager().handleException(e);
}
this.lock.unlock();
// #acquire() callbacks
this.phaser.arriveAndDeregister();
LockSupport.park(this);
}
}
private void tick() {
for (ThreadDispatcher.Partition entry : entries) {
final List<Tickable> elements = entry.elements();
if (elements.isEmpty()) continue;
for (Tickable element : elements) {
if (lock.hasQueuedThreads()) {
this.lock.unlock();
// #acquire() callbacks should be called here
this.lock.lock();
}
try {
element.tick(tickTime);
} catch (Throwable e) {
MinecraftServer.getExceptionManager().handleException(e);
}
}
}
}
void startTick(long tickTime) {
if (entries.isEmpty())
return; // Nothing to tick
this.phaser.register();
this.tickTime = tickTime;
this.stop = false;
LockSupport.unpark(this);
}
public Collection<ThreadDispatcher.Partition> entries() {
return entries;
}
/**
* Gets the lock used to ensure the safety of entity acquisition.
*
* @return the thread lock
*/
public @NotNull ReentrantLock lock() {
return lock;
}
void shutdown() {
this.stop = true;
LockSupport.unpark(this);
}
}