mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-03 23:17:48 +01:00
Merge pull request #18 from R0bbyYT/feature/scheduler
Feature/scheduler - Optimization of the scheduler system
This commit is contained in:
commit
2c58253d95
@ -10,10 +10,12 @@ import net.minestom.server.instance.block.BlockManager;
|
||||
import net.minestom.server.instance.block.rule.vanilla.RedstonePlacementRule;
|
||||
import net.minestom.server.storage.StorageManager;
|
||||
import net.minestom.server.storage.systems.FileStorageSystem;
|
||||
import net.minestom.server.timer.TaskRunnable;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
import net.minestom.server.utils.time.UpdateOption;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
public class Main {
|
||||
|
||||
@ -34,6 +36,7 @@ public class Main {
|
||||
commandManager.register(new SimpleCommand());
|
||||
commandManager.register(new GamemodeCommand());
|
||||
commandManager.register(new DimensionCommand());
|
||||
commandManager.register(new ShutdownCommand());
|
||||
|
||||
/*RecipeManager recipeManager = MinecraftServer.getRecipeManager();
|
||||
ShapelessRecipe shapelessRecipe = new ShapelessRecipe("test", "groupname") {
|
||||
@ -53,12 +56,13 @@ public class Main {
|
||||
|
||||
MinecraftServer.getBenchmarkManager().enable(new UpdateOption(10 * 1000, TimeUnit.MILLISECOND));
|
||||
|
||||
MinecraftServer.getSchedulerManager().addShutdownTask(new TaskRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("Good night");
|
||||
}
|
||||
});
|
||||
MinecraftServer.getSchedulerManager().buildTask(() -> {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
|
||||
System.out.println(simpleDateFormat.format(new Date()));
|
||||
}).repeat(1, TimeUnit.SECOND).buildTask();
|
||||
|
||||
|
||||
MinecraftServer.getSchedulerManager().buildShutdownTask(() -> System.out.println("Good night")).buildTask();
|
||||
|
||||
PlayerInit.init();
|
||||
|
||||
|
@ -28,7 +28,6 @@ import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.network.ConnectionManager;
|
||||
import net.minestom.server.ping.ResponseDataConsumer;
|
||||
import net.minestom.server.timer.TaskRunnable;
|
||||
import net.minestom.server.utils.MathUtils;
|
||||
import net.minestom.server.utils.Position;
|
||||
import net.minestom.server.utils.Vector;
|
||||
@ -86,32 +85,29 @@ public class PlayerInit {
|
||||
ConnectionManager connectionManager = MinecraftServer.getConnectionManager();
|
||||
BenchmarkManager benchmarkManager = MinecraftServer.getBenchmarkManager();
|
||||
|
||||
MinecraftServer.getSchedulerManager().addRepeatingTask(new TaskRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
long ramUsage = benchmarkManager.getUsedMemory();
|
||||
ramUsage /= 1e6; // bytes to MB
|
||||
MinecraftServer.getSchedulerManager().buildTask(() -> {
|
||||
long ramUsage = benchmarkManager.getUsedMemory();
|
||||
ramUsage /= 1e6; // bytes to MB
|
||||
|
||||
String benchmarkMessage = "";
|
||||
for (Map.Entry<String, ThreadResult> resultEntry : benchmarkManager.getResultMap().entrySet()) {
|
||||
String name = resultEntry.getKey();
|
||||
ThreadResult result = resultEntry.getValue();
|
||||
benchmarkMessage += ChatColor.GRAY + name;
|
||||
benchmarkMessage += ": ";
|
||||
benchmarkMessage += ChatColor.YELLOW.toString() + MathUtils.round(result.getCpuPercentage(), 2) + "% CPU ";
|
||||
benchmarkMessage += ChatColor.RED.toString() + MathUtils.round(result.getUserPercentage(), 2) + "% USER ";
|
||||
benchmarkMessage += ChatColor.PINK.toString() + MathUtils.round(result.getBlockedPercentage(), 2) + "% BLOCKED ";
|
||||
benchmarkMessage += ChatColor.BRIGHT_GREEN.toString() + MathUtils.round(result.getWaitedPercentage(), 2) + "% WAITED ";
|
||||
benchmarkMessage += "\n";
|
||||
}
|
||||
|
||||
for (Player player : connectionManager.getOnlinePlayers()) {
|
||||
ColoredText header = ColoredText.of("RAM USAGE: " + ramUsage + " MB");
|
||||
ColoredText footer = ColoredText.of(benchmarkMessage);
|
||||
player.sendHeaderFooter(header, footer);
|
||||
}
|
||||
String benchmarkMessage = "";
|
||||
for (Map.Entry<String, ThreadResult> resultEntry : benchmarkManager.getResultMap().entrySet()) {
|
||||
String name = resultEntry.getKey();
|
||||
ThreadResult result = resultEntry.getValue();
|
||||
benchmarkMessage += ChatColor.GRAY + name;
|
||||
benchmarkMessage += ": ";
|
||||
benchmarkMessage += ChatColor.YELLOW.toString() + MathUtils.round(result.getCpuPercentage(), 2) + "% CPU ";
|
||||
benchmarkMessage += ChatColor.RED.toString() + MathUtils.round(result.getUserPercentage(), 2) + "% USER ";
|
||||
benchmarkMessage += ChatColor.PINK.toString() + MathUtils.round(result.getBlockedPercentage(), 2) + "% BLOCKED ";
|
||||
benchmarkMessage += ChatColor.BRIGHT_GREEN.toString() + MathUtils.round(result.getWaitedPercentage(), 2) + "% WAITED ";
|
||||
benchmarkMessage += "\n";
|
||||
}
|
||||
}, new UpdateOption(10, TimeUnit.TICK));
|
||||
|
||||
for (Player player : connectionManager.getOnlinePlayers()) {
|
||||
ColoredText header = ColoredText.of("RAM USAGE: " + ramUsage + " MB");
|
||||
ColoredText footer = ColoredText.of(benchmarkMessage);
|
||||
player.sendHeaderFooter(header, footer);
|
||||
}
|
||||
}).repeat(10, TimeUnit.TICK).buildTask();
|
||||
|
||||
connectionManager.addPacketConsumer((player, packetController, packet) -> {
|
||||
// Listen to all received packet
|
||||
|
33
src/main/java/fr/themode/demo/commands/ShutdownCommand.java
Normal file
33
src/main/java/fr/themode/demo/commands/ShutdownCommand.java
Normal file
@ -0,0 +1,33 @@
|
||||
package fr.themode.demo.commands;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.CommandProcessor;
|
||||
import net.minestom.server.command.CommandSender;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
/**
|
||||
* A simple shutdown command
|
||||
*/
|
||||
public class ShutdownCommand implements CommandProcessor {
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return "shutdown";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getAliases() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(CommandSender sender, String command, String[] args) {
|
||||
MinecraftServer.stopCleanly();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAccess(Player player) {
|
||||
return player.getPermissionLevel() >= 4;
|
||||
}
|
||||
}
|
@ -39,7 +39,6 @@ public final class UpdateManager {
|
||||
final ConnectionManager connectionManager = MinecraftServer.getConnectionManager();
|
||||
final EntityManager entityManager = MinecraftServer.getEntityManager();
|
||||
final InstanceManager instanceManager = MinecraftServer.getInstanceManager();
|
||||
final SchedulerManager schedulerManager = MinecraftServer.getSchedulerManager();
|
||||
|
||||
final long tickDistance = MinecraftServer.TICK_MS * 1000000;
|
||||
long currentTime;
|
||||
@ -58,9 +57,6 @@ public final class UpdateManager {
|
||||
// Waiting players update
|
||||
entityManager.updateWaitingPlayers();
|
||||
|
||||
// Scheduler
|
||||
schedulerManager.update();
|
||||
|
||||
// Keep Alive Handling
|
||||
final long time = System.currentTimeMillis();
|
||||
final KeepAlivePacket keepAlivePacket = new KeepAlivePacket(time);
|
||||
|
@ -5,7 +5,6 @@ import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.player.PlayerLoginEvent;
|
||||
import net.minestom.server.network.player.FakePlayerConnection;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.timer.TaskRunnable;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
import net.minestom.server.utils.time.UpdateOption;
|
||||
|
||||
@ -43,12 +42,7 @@ public class FakePlayer extends Player {
|
||||
final FakePlayer fakePlayer = new FakePlayer(uuid, username, option);
|
||||
|
||||
fakePlayer.addEventCallback(PlayerLoginEvent.class, event -> {
|
||||
MinecraftServer.getSchedulerManager().addDelayedTask(new TaskRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scheduledCallback.accept(fakePlayer);
|
||||
}
|
||||
}, new UpdateOption(1, TimeUnit.TICK));
|
||||
MinecraftServer.getSchedulerManager().buildTask(() -> scheduledCallback.accept(fakePlayer)).delay(1, TimeUnit.TICK).buildTask();
|
||||
});
|
||||
}
|
||||
|
||||
@ -83,12 +77,7 @@ public class FakePlayer extends Player {
|
||||
super.showPlayer(connection);
|
||||
if (!option.isInTabList()) {
|
||||
// Remove from tab-list
|
||||
MinecraftServer.getSchedulerManager().addDelayedTask(new TaskRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
connection.sendPacket(getRemovePlayerToList());
|
||||
}
|
||||
}, new UpdateOption(20, TimeUnit.TICK));
|
||||
MinecraftServer.getSchedulerManager().buildTask(() -> connection.sendPacket(getRemovePlayerToList())).delay(20, TimeUnit.TICK).buildTask();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ import net.minestom.server.network.packet.server.play.UpdateLightPacket;
|
||||
import net.minestom.server.particle.Particle;
|
||||
import net.minestom.server.particle.ParticleCreator;
|
||||
import net.minestom.server.storage.StorageFolder;
|
||||
import net.minestom.server.timer.TaskRunnable;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
import net.minestom.server.utils.Position;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
@ -572,18 +571,16 @@ public class InstanceContainer extends Instance {
|
||||
if (toUpdate == null) {
|
||||
return;
|
||||
}
|
||||
MinecraftServer.getSchedulerManager().addDelayedTask(new TaskRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final CustomBlock currentBlock = instance.getCustomBlock(position);
|
||||
if (currentBlock == null)
|
||||
return;
|
||||
if (currentBlock.getCustomBlockId() != toUpdate.getCustomBlockId()) { // block changed
|
||||
return;
|
||||
}
|
||||
currentBlock.scheduledUpdate(instance, position, getBlockData(position));
|
||||
|
||||
MinecraftServer.getSchedulerManager().buildTask(() -> {
|
||||
final CustomBlock currentBlock = instance.getCustomBlock(position);
|
||||
if (currentBlock == null)
|
||||
return;
|
||||
if (currentBlock.getCustomBlockId() != toUpdate.getCustomBlockId()) { // block changed
|
||||
return;
|
||||
}
|
||||
}, new UpdateOption(time, unit));
|
||||
currentBlock.scheduledUpdate(instance, position, getBlockData(position));
|
||||
}).delay(time, unit).buildTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,90 +2,91 @@ package net.minestom.server.timer;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.utils.thread.MinestomThread;
|
||||
import net.minestom.server.utils.time.CooldownUtils;
|
||||
import net.minestom.server.utils.time.UpdateOption;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* An object which manages all the {@link Task}'s
|
||||
*/
|
||||
public class SchedulerManager {
|
||||
|
||||
private static final AtomicInteger COUNTER = new AtomicInteger();
|
||||
private static final AtomicInteger SHUTDOWN_COUNTER = new AtomicInteger();
|
||||
private static ExecutorService batchesPool = new MinestomThread(MinecraftServer.THREAD_COUNT_SCHEDULER, MinecraftServer.THREAD_NAME_SCHEDULER);
|
||||
private List<Task> tasks = new CopyOnWriteArrayList<>();
|
||||
private List<Task> shutdownTasks = new CopyOnWriteArrayList<>();
|
||||
// A counter for all normal tasks
|
||||
private final AtomicInteger counter;
|
||||
// A counter for all shutdown tasks
|
||||
private final AtomicInteger shutdownCounter;
|
||||
//A threaded execution
|
||||
private final ExecutorService batchesPool;
|
||||
// A single threaded scheduled execution
|
||||
private final ScheduledExecutorService timerExecutionService;
|
||||
// A list with all normal registered tasks
|
||||
private final List<Task> tasks;
|
||||
// A list with all registered shutdown tasks
|
||||
private final List<Task> shutdownTasks;
|
||||
|
||||
/**
|
||||
* Add a task with a custom update option and a precise call count
|
||||
*
|
||||
* @param runnable the task to execute
|
||||
* @param updateOption the update option of the task
|
||||
* @param maxCallCount the number of time this task should be executed
|
||||
* @return the task id
|
||||
* Default constructor
|
||||
*/
|
||||
public int addTask(TaskRunnable runnable, UpdateOption updateOption, int maxCallCount) {
|
||||
final int id = COUNTER.incrementAndGet();
|
||||
runnable.setId(id);
|
||||
public SchedulerManager() {
|
||||
this.counter = new AtomicInteger();
|
||||
this.shutdownCounter = new AtomicInteger();
|
||||
|
||||
final Task task = new Task(runnable, updateOption, maxCallCount);
|
||||
task.refreshLastUpdateTime(System.currentTimeMillis());
|
||||
this.tasks.add(task);
|
||||
|
||||
return id;
|
||||
this.batchesPool = new MinestomThread(MinecraftServer.THREAD_COUNT_SCHEDULER, MinecraftServer.THREAD_NAME_SCHEDULER);
|
||||
this.timerExecutionService = Executors.newSingleThreadScheduledExecutor();
|
||||
this.tasks = new CopyOnWriteArrayList<>();
|
||||
this.shutdownTasks = new CopyOnWriteArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a task which will be repeated without interruption
|
||||
* Initializes a new {@link TaskBuilder} for creating a task.
|
||||
*
|
||||
* @param runnable the task to execute
|
||||
* @param updateOption the update option of the task
|
||||
* @return the task id
|
||||
* @param runnable The task to run when scheduled
|
||||
* @return the task builder
|
||||
*/
|
||||
public int addRepeatingTask(TaskRunnable runnable, UpdateOption updateOption) {
|
||||
return addTask(runnable, updateOption, 0);
|
||||
public TaskBuilder buildTask(Runnable runnable) {
|
||||
return new TaskBuilder(this, runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a task which will be executed only once
|
||||
* Initializes a new {@link TaskBuilder} for creating a shutdown task
|
||||
*
|
||||
* @param runnable the task to execute
|
||||
* @param updateOption the update option of the task
|
||||
* @return the task id
|
||||
* @param runnable The shutdown task to run when scheduled
|
||||
* @return the task builder
|
||||
*/
|
||||
public int addDelayedTask(TaskRunnable runnable, UpdateOption updateOption) {
|
||||
return addTask(runnable, updateOption, 1);
|
||||
public TaskBuilder buildShutdownTask(Runnable runnable) {
|
||||
return new TaskBuilder(this, runnable, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a task to run when the server shutdowns
|
||||
* Removes/Forces the end of a task
|
||||
*
|
||||
* @param runnable the task to perform
|
||||
* @return the task id
|
||||
* @param task The task to remove
|
||||
*/
|
||||
public int addShutdownTask(TaskRunnable runnable) {
|
||||
final int id = SHUTDOWN_COUNTER.incrementAndGet();
|
||||
runnable.setId(id);
|
||||
|
||||
final Task task = new Task(runnable, null, 1);
|
||||
this.shutdownTasks.add(task);
|
||||
|
||||
return id;
|
||||
public void removeTask(Task task) {
|
||||
this.tasks.removeIf(toRemove -> toRemove.equals(task));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown all the tasks and call tasks added from {@link #addShutdownTask(TaskRunnable)}
|
||||
* Removes/Forces the end of a task
|
||||
*
|
||||
* @param task The task to remove
|
||||
*/
|
||||
public void removeShutdownTask(Task task) {
|
||||
this.tasks.removeIf(toRemove -> toRemove.equals(task));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdowns all normal tasks and call the registered shutdown tasks
|
||||
*/
|
||||
public void shutdown() {
|
||||
batchesPool.execute(() -> {
|
||||
for (Task task : shutdownTasks) {
|
||||
task.getRunnable().run();
|
||||
}
|
||||
});
|
||||
batchesPool.shutdown();
|
||||
MinecraftServer.getLOGGER().info("Executing all shutdown tasks..");
|
||||
for (Task task : this.getShutdownTasks()) {
|
||||
task.schedule();
|
||||
}
|
||||
MinecraftServer.getLOGGER().info("Shutting down the scheduled execution service and batches pool.");
|
||||
this.timerExecutionService.shutdown();
|
||||
this.batchesPool.shutdown();
|
||||
try {
|
||||
batchesPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
@ -93,37 +94,56 @@ public class SchedulerManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the end of a task
|
||||
* Increments the current counter value.
|
||||
*
|
||||
* @param taskId the id of the task to remove
|
||||
* @return the updated counter value
|
||||
*/
|
||||
public void removeTask(int taskId) {
|
||||
this.tasks.removeIf(task -> task.getId() == taskId);
|
||||
public int getCounterIdentifier() {
|
||||
return this.counter.incrementAndGet();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
final long time = System.currentTimeMillis();
|
||||
batchesPool.execute(() -> {
|
||||
for (Task task : tasks) {
|
||||
final UpdateOption updateOption = task.getUpdateOption();
|
||||
final long lastUpdate = task.getLastUpdateTime();
|
||||
final boolean hasCooldown = CooldownUtils.hasCooldown(time, lastUpdate, updateOption.getTimeUnit(), updateOption.getValue());
|
||||
if (!hasCooldown) {
|
||||
final TaskRunnable runnable = task.getRunnable();
|
||||
final int maxCallCount = task.getMaxCallCount();
|
||||
final int callCount = runnable.getCallCount() + 1;
|
||||
runnable.setCallCount(callCount);
|
||||
|
||||
runnable.run();
|
||||
|
||||
task.refreshLastUpdateTime(time);
|
||||
|
||||
if (callCount == maxCallCount) {
|
||||
tasks.remove(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
/**
|
||||
* Increments the current shutdown counter value
|
||||
*
|
||||
* @return the updated shutdown counter value
|
||||
*/
|
||||
public int getShutdownCounterIdentifier() {
|
||||
return this.shutdownCounter.incrementAndGet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link List} with all registered tasks
|
||||
*
|
||||
* @return a {@link List} with all registered tasks
|
||||
*/
|
||||
public List<Task> getTasks() {
|
||||
return tasks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link List} with all registered shutdown tasks
|
||||
*
|
||||
* @return a {@link List} with all registered shutdown tasks
|
||||
*/
|
||||
public List<Task> getShutdownTasks() {
|
||||
return shutdownTasks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the execution service for all registered tasks
|
||||
*
|
||||
* @return the execution service for all registered tasks
|
||||
*/
|
||||
public ExecutorService getBatchesPool() {
|
||||
return batchesPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scheduled execution service for all registered tasks
|
||||
*
|
||||
* @return the scheduled execution service for all registered tasks
|
||||
*/
|
||||
public ScheduledExecutorService getTimerExecutionService() {
|
||||
return timerExecutionService;
|
||||
}
|
||||
}
|
||||
|
@ -1,47 +1,131 @@
|
||||
package net.minestom.server.timer;
|
||||
|
||||
import net.minestom.server.utils.time.UpdateOption;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Task {
|
||||
/**
|
||||
* An Object that represents a task that is scheduled for execution on the application.
|
||||
*/
|
||||
public class Task implements Runnable {
|
||||
|
||||
private int id;
|
||||
|
||||
private TaskRunnable runnable;
|
||||
private UpdateOption updateOption;
|
||||
|
||||
private int maxCallCount;
|
||||
|
||||
private long lastUpdateTime;
|
||||
|
||||
public Task(TaskRunnable runnable, UpdateOption updateOption, int maxCallCount) {
|
||||
this.id = runnable.getId();
|
||||
// Manages all tasks
|
||||
private final SchedulerManager schedulerManager;
|
||||
// The task logic
|
||||
private final Runnable runnable;
|
||||
// Task identifier
|
||||
private final int id;
|
||||
// True if the task planned for the application shutdown
|
||||
private final boolean shutdown;
|
||||
// Delay value for the task execution
|
||||
private final long delay;
|
||||
// Repeat value for the task execution
|
||||
private final long repeat;
|
||||
// Task completion/execution
|
||||
private ScheduledFuture<?> future;
|
||||
// The thread of the task
|
||||
private volatile Thread currentThreadTask;
|
||||
|
||||
/**
|
||||
* Creates a task
|
||||
*
|
||||
* @param schedulerManager The manager for the task
|
||||
* @param runnable The task to run when scheduled
|
||||
* @param shutdown Defines whether the task is a shutdown task
|
||||
* @param delay The time to delay
|
||||
* @param repeat The time until the repetition
|
||||
*/
|
||||
public Task(SchedulerManager schedulerManager, Runnable runnable, boolean shutdown, long delay, long repeat) {
|
||||
this.schedulerManager = schedulerManager;
|
||||
this.runnable = runnable;
|
||||
this.updateOption = updateOption;
|
||||
this.maxCallCount = maxCallCount;
|
||||
this.shutdown = shutdown;
|
||||
this.id = shutdown ? this.schedulerManager.getShutdownCounterIdentifier() : this.schedulerManager.getCounterIdentifier();
|
||||
this.delay = delay;
|
||||
this.repeat = repeat;
|
||||
}
|
||||
|
||||
protected void refreshLastUpdateTime(long lastUpdateTime) {
|
||||
this.lastUpdateTime = lastUpdateTime;
|
||||
/**
|
||||
* Executes the task
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
this.schedulerManager.getBatchesPool().execute(() -> {
|
||||
this.currentThreadTask = Thread.currentThread();
|
||||
try {
|
||||
this.runnable.run();
|
||||
} catch (Exception e) {
|
||||
System.err.println(
|
||||
String.format(
|
||||
"An exception in %s task %s is occurred! (%s)",
|
||||
this.shutdown ? "shutdown" : "",
|
||||
this.id,
|
||||
e.getMessage()
|
||||
)
|
||||
);
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (this.repeat == 0) this.finish();
|
||||
this.currentThreadTask = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected long getLastUpdateTime() {
|
||||
return lastUpdateTime;
|
||||
/**
|
||||
* Sets up the task for correct execution
|
||||
*/
|
||||
public void schedule() {
|
||||
this.future = this.repeat == 0L ?
|
||||
this.schedulerManager.getTimerExecutionService().schedule(this, this.delay, TimeUnit.MILLISECONDS) :
|
||||
this.schedulerManager.getTimerExecutionService().scheduleAtFixedRate(this, this.delay, this.repeat, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
/**
|
||||
* Gets the current status of the task
|
||||
*
|
||||
* @return the current stats of the task
|
||||
*/
|
||||
public TaskStatus getStatus() {
|
||||
if (this.future == null) return TaskStatus.SCHEDULED;
|
||||
if (this.future.isCancelled()) return TaskStatus.CANCELLED;
|
||||
if (this.future.isDone()) return TaskStatus.FINISHED;
|
||||
return TaskStatus.SCHEDULED;
|
||||
}
|
||||
|
||||
public TaskRunnable getRunnable() {
|
||||
return runnable;
|
||||
/**
|
||||
* Cancels this task. If the task is already running, the thread in which it is running is interrupted.
|
||||
* If the task is not currently running, Minestom will safely terminate it.
|
||||
*/
|
||||
public void cancel() {
|
||||
if (this.future != null) {
|
||||
this.future.cancel(false);
|
||||
|
||||
Thread current = this.currentThreadTask;
|
||||
if (current != null) current.interrupt();
|
||||
|
||||
this.finish();
|
||||
}
|
||||
}
|
||||
|
||||
public UpdateOption getUpdateOption() {
|
||||
return updateOption;
|
||||
/**
|
||||
* Removes the task
|
||||
*/
|
||||
private void finish() {
|
||||
if (this.shutdown)
|
||||
this.schedulerManager.removeShutdownTask(this);
|
||||
else
|
||||
this.schedulerManager.removeTask(this);
|
||||
}
|
||||
|
||||
public int getMaxCallCount() {
|
||||
return maxCallCount;
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) return true;
|
||||
if (object == null || getClass() != object.getClass()) return false;
|
||||
Task task = (Task) object;
|
||||
return id == task.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
}
|
||||
|
110
src/main/java/net/minestom/server/timer/TaskBuilder.java
Normal file
110
src/main/java/net/minestom/server/timer/TaskBuilder.java
Normal file
@ -0,0 +1,110 @@
|
||||
package net.minestom.server.timer;
|
||||
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
|
||||
/**
|
||||
* A builder which represents a fluent Object to schedule tasks
|
||||
*/
|
||||
public class TaskBuilder {
|
||||
|
||||
// Manager for the tasks
|
||||
private final SchedulerManager schedulerManager;
|
||||
// The logic behind every task
|
||||
private final Runnable runnable;
|
||||
// True if the task planned for the application shutdown
|
||||
private final boolean shutdown;
|
||||
// Delay value for the task execution
|
||||
private long delay;
|
||||
// Repeat value for the task execution
|
||||
private long repeat;
|
||||
|
||||
/**
|
||||
* Creates a task builder
|
||||
* <br>
|
||||
* <b>Note:</b> The task builder creates a normal task
|
||||
*
|
||||
* @param schedulerManager The manager for the tasks
|
||||
* @param runnable The task to run when scheduled
|
||||
*/
|
||||
public TaskBuilder(SchedulerManager schedulerManager, Runnable runnable) {
|
||||
this(schedulerManager, runnable, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates task builder
|
||||
*
|
||||
* @param schedulerManager The manager for the tasks
|
||||
* @param runnable The task to run when scheduled
|
||||
* @param shutdown Defines whether the task is a shutdown task
|
||||
*/
|
||||
public TaskBuilder(SchedulerManager schedulerManager, Runnable runnable, boolean shutdown) {
|
||||
this.schedulerManager = schedulerManager;
|
||||
this.runnable = runnable;
|
||||
this.shutdown = shutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that the task should delay its execution by the specified amount of time.
|
||||
*
|
||||
* @param time The time to delay
|
||||
* @param unit The unit of time for {@code time}
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public TaskBuilder delay(long time, TimeUnit unit) {
|
||||
this.delay = unit.toMilliseconds(time);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that the task should continue to run after waiting for the specified value until it is terminated.
|
||||
*
|
||||
* @param time The time until the repetition
|
||||
* @param unit The unit of time for {@code time}
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public TaskBuilder repeat(long time, TimeUnit unit) {
|
||||
this.repeat = unit.toMilliseconds(time);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the delay interval of the task
|
||||
*
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public TaskBuilder clearDelay() {
|
||||
this.delay = 0L;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the repeat interval of the task
|
||||
*
|
||||
* @return this builder, for chaining
|
||||
*/
|
||||
public TaskBuilder clearRepeat() {
|
||||
this.repeat = 0L;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds this task for execution
|
||||
*
|
||||
* @return the built task
|
||||
*/
|
||||
public Task buildTask() {
|
||||
Task task = new Task(
|
||||
this.schedulerManager,
|
||||
this.runnable,
|
||||
this.shutdown,
|
||||
this.delay,
|
||||
this.repeat);
|
||||
if (this.shutdown) {
|
||||
this.schedulerManager.getShutdownTasks().add(task);
|
||||
} else {
|
||||
this.schedulerManager.getTasks().add(task);
|
||||
task.schedule();
|
||||
}
|
||||
return task;
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package net.minestom.server.timer;
|
||||
|
||||
public abstract class TaskRunnable {
|
||||
|
||||
private int id;
|
||||
private int callCount;
|
||||
|
||||
public abstract void run();
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getCallCount() {
|
||||
return callCount;
|
||||
}
|
||||
|
||||
protected void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
protected void setCallCount(int callCount) {
|
||||
this.callCount = callCount;
|
||||
}
|
||||
}
|
21
src/main/java/net/minestom/server/timer/TaskStatus.java
Normal file
21
src/main/java/net/minestom/server/timer/TaskStatus.java
Normal file
@ -0,0 +1,21 @@
|
||||
package net.minestom.server.timer;
|
||||
|
||||
/**
|
||||
* An enumeration that representing all available statuses for a task
|
||||
*/
|
||||
public enum TaskStatus {
|
||||
|
||||
/**
|
||||
* The task is execution and is currently running
|
||||
*/
|
||||
SCHEDULED,
|
||||
/**
|
||||
* The task was cancelled with {@link Task#cancel()}
|
||||
*/
|
||||
CANCELLED,
|
||||
/**
|
||||
* The task has been completed. This only applies to tasks without repetition
|
||||
*/
|
||||
FINISHED,
|
||||
|
||||
}
|
@ -1,9 +1,5 @@
|
||||
package net.minestom.server.utils.thread;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.timer.SchedulerManager;
|
||||
import net.minestom.server.timer.TaskRunnable;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
Loading…
Reference in New Issue
Block a user