using Minecraft.Server.FourKit.Plugin; using System; using System.Collections.Generic; using System.Text; namespace Minecraft.Server.FourKit.Scheduler { public class FourKitScheduler { private Dictionary _taskInstanceMap = new Dictionary(); private Dictionary _taskActionMap = new Dictionary(); //temp task based on about intmax / 3, leaves 715m (715827882) ids for real tasks and 1.4b(1431655765) for temp tasks //this is done to avoid needing to cleanup existing task ids, could be handled private int _nextTempTaskId = 715827882; private int _nextTaskId = 0; private int _lastTick = -1; /// /// Removes all tasks from the scheduler. /// public void cancelAllTasks() { foreach (var task in _taskInstanceMap.Values) { NativeBridge.RemoveScheduler?.Invoke(task.getTaskId()); } _taskInstanceMap.Clear(); _taskActionMap.Clear(); _nextTempTaskId = 715827882; _nextTaskId = 0; } /// /// Removes task from scheduler. /// /// Id number of task to be removed. public void cancelTask(int taskId) { if (_taskInstanceMap.ContainsKey(taskId)) { NativeBridge.RemoveScheduler?.Invoke(taskId); _taskInstanceMap.Remove(taskId); _taskActionMap.Remove(taskId); } } /// /// Removes all tasks associated with a particular plugin from the scheduler. /// /// Owner of tasks to be removed. public void cancelTasks(ServerPlugin plugin) { List tasksToRemove = new List(); foreach (var task in _taskInstanceMap.Values) { if (task.getOwner() == plugin) { NativeBridge.RemoveScheduler?.Invoke(task.getTaskId()); tasksToRemove.Add(task.getTaskId()); } } foreach (var taskId in tasksToRemove) { _taskInstanceMap.Remove(taskId); _taskActionMap.Remove(taskId); } } /// /// Returns a list of all pending tasks. The ordering of the tasks is not related to their order of execution. /// /// Active workers. public List getPendingTasks() { return new List(_taskInstanceMap.Values); } /// /// Check if the task currently running. /// /// A repeating task might not be running currently, but will be running in the future. /// A task that has finished, and does not repeat, will not be running ever again. /// /// Explicitly, a task is running if there exists a thread for it, and that thread is alive. /// /// The task to check. /// If the task is currently running. public bool isCurrentlyRunning(int taskId) { if (_taskInstanceMap.ContainsKey(taskId)) { return _taskInstanceMap[taskId].startedRunning; } return false; } /// /// Check if the task queued to be run later. /// /// If a repeating task is currently running, it might not be queued now but could be in the future. /// A task that is not queued, and not running, will not be queued again. /// /// The task to check. /// If the task is queued to be run. public bool isQueued(int taskId) { if (_taskInstanceMap.ContainsKey(taskId)) { return !_taskInstanceMap[taskId].startedRunning; } return false; } /// /// Returns a task that will run on the next server tick. /// /// The reference to the plugin scheduling task. /// The task to be run. /// A task that contains the id number. /// If plugin is null. /// If task is null. public FourKitTask runTask(ServerPlugin plugin, Action task) { FourKitTask fourKitTask = new FourKitTask(plugin, _nextTempTaskId++, 0, -1); startTask(fourKitTask, task); return fourKitTask; } /// /// Returns a task that will run after the specified number of server ticks. /// /// The reference to the plugin scheduling task. /// The task to be run. /// The ticks to wait before running the task. /// A task that contains the id number. /// If plugin is null. /// If task is null. public FourKitTask runTaskLater(ServerPlugin plugin, Action task, int delay) { FourKitTask fourKitTask = new FourKitTask(plugin, _nextTempTaskId++, delay, -1); startTask(fourKitTask, task); return fourKitTask; } /// /// Returns a task that will repeatedly run until cancelled, starting after the specified number of server ticks. /// /// The reference to the plugin scheduling task. /// The task to be run. /// The ticks to wait before running the task. /// The ticks to wait between runs. /// A task that contains the id number. /// If plugin is null. /// If task is null. public FourKitTask runTaskTimer(ServerPlugin plugin, Action task, int delay, int period) { FourKitTask fourKitTask = new FourKitTask(plugin, _nextTempTaskId++, delay, period); startTask(fourKitTask, task); return fourKitTask; } /// /// Starts tracking a task instance and registers it with the native scheduler bridge. /// /// The task instance to schedule. /// The callback action executed when the task runs. internal void startTask(FourKitTask task, Action action) { task.startedRunning = true; _taskInstanceMap[task.getTaskId()] = task; _taskActionMap[task.getTaskId()] = action; NativeBridge.AddScheduler?.Invoke(task.getTaskId(), task.startDelay, task.runCooldown); } /// /// Updates scheduled tasks for the current server tick and runs due task callbacks. /// /// The current server tick. internal void update(int currentTick) { if (_lastTick == -1) _lastTick = currentTick; List tasksToRemove = new List(); foreach (var task in _taskInstanceMap.Values) { if (!task.shouldRun) { tasksToRemove.Add(task.getTaskId()); continue; } if (task.startDelay > 0) { task.startDelay -= (currentTick - _lastTick); if (task.startDelay <= 0) { task.startDelay = 0; _taskActionMap[task.getTaskId()]?.Invoke(); } continue; } if (task.runCooldown == -1) { task.lastRunTick = currentTick; _taskActionMap[task.getTaskId()]?.Invoke(); tasksToRemove.Add(task.getTaskId()); } else { int lastTaskTick = task.lastRunTick; if (lastTaskTick == -1 || (lastTaskTick + task.runCooldown) <= currentTick) { task.lastRunTick = currentTick; _taskActionMap[task.getTaskId()]?.Invoke(); } } } foreach (var taskId in tasksToRemove) { _taskInstanceMap.Remove(taskId); _taskActionMap.Remove(taskId); } } } }