fabric-synctask #1
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,6 +4,8 @@ build/
|
|||||||
!**/src/main/**/build/
|
!**/src/main/**/build/
|
||||||
!**/src/test/**/build/
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
Tasks/run
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
### IntelliJ IDEA ###
|
||||||
.idea
|
.idea
|
||||||
*.iws
|
*.iws
|
||||||
|
@ -1,18 +1,8 @@
|
|||||||
plugins {
|
|
||||||
id 'java'
|
|
||||||
id 'maven-publish'
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.postgresql:postgresql:42.5.0'
|
implementation 'org.postgresql:postgresql:42.5.0'
|
||||||
testImplementation 'com.google.code.gson:gson:2.10'
|
testImplementation 'com.google.code.gson:gson:2.10'
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-api:5.9.0"
|
testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junit_version}"
|
||||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.9.0"
|
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${project.junit_version}"
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
withSourcesJar()
|
|
||||||
withJavadocJar()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
|
@ -1,18 +1,44 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'fabric-loom' version '1.1-SNAPSHOT'
|
||||||
id 'maven-publish'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||||
|
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||||
|
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||||
|
|
||||||
|
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||||
|
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junit_version}"
|
testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junit_version}"
|
||||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${project.junit_version}"
|
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${project.junit_version}"
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
processResources {
|
||||||
withSourcesJar()
|
inputs.property "version", project.version
|
||||||
withJavadocJar()
|
|
||||||
|
filesMatching("fabric.mod.json") {
|
||||||
|
expand "version": project.version
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||||
|
// this fixes some edge cases with special characters not displaying correctly
|
||||||
|
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||||
|
// If Javadoc is generated, this must be specified in that task too.
|
||||||
|
it.options.encoding = "UTF-8"
|
||||||
|
|
||||||
|
// The Minecraft launcher currently installs Java 8 for users, so your mod probably wants to target Java 8 too
|
||||||
|
// JDK 9 introduced a new way of specifying this that will make sure no newer classes or methods are used.
|
||||||
|
// We'll use that if it's available, but otherwise we'll use the older option.
|
||||||
|
def targetVersion = 17
|
||||||
|
if (JavaVersion.current().isJava9Compatible()) {
|
||||||
|
it.options.release = targetVersion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
test {
|
test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package fr.altarik.toolbox.task;
|
||||||
|
|
||||||
|
public abstract class AltarikRunnable implements Runnable {
|
||||||
|
|
||||||
|
private boolean isCancelled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warning: Some task cannot be cancelled (mostly async tasks like {@link fr.altarik.toolbox.task.async.AsyncTasks})
|
||||||
|
* The result of this call is ignored in this case, you can still add a way to not execute its content (like if(isCancelled) return;)
|
||||||
|
*/
|
||||||
|
public void cancel() {
|
||||||
|
this.isCancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return isCancelled;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package fr.altarik.toolbox.task;
|
||||||
|
|
||||||
|
public interface PeriodicTaskI extends TaskI {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a task periodically
|
||||||
|
* @param function the function to execute
|
||||||
|
* @param delay delay before starting the task
|
||||||
|
* @param period time to wait between runs
|
||||||
|
* @throws InterruptedException When executed asynchronously, task may be interrupted
|
||||||
|
* @see fr.altarik.toolbox.task.sync.PeriodicSyncTask
|
||||||
|
*/
|
||||||
|
void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException;
|
||||||
|
}
|
40
Tasks/src/main/java/fr/altarik/toolbox/task/Scheduler.java
Normal file
40
Tasks/src/main/java/fr/altarik/toolbox/task/Scheduler.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package fr.altarik.toolbox.task;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Scheduler implements Runnable {
|
||||||
|
|
||||||
|
private final List<SchedulerTaskData> tasks;
|
||||||
|
private final SendTaskWorkerI worker;
|
||||||
|
|
||||||
|
public Scheduler(SendTaskWorkerI worker, List<SchedulerTaskData> tasks) {
|
||||||
|
this.worker = worker;
|
||||||
|
this.tasks = tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
List<SchedulerTaskData> removeList = new ArrayList<>(tasks.size());
|
||||||
|
for(SchedulerTaskData data : tasks) {
|
||||||
|
if(!data.getFunction().isCancelled()) {
|
||||||
|
long currentDelay = data.getCurrentDelay();
|
||||||
|
if(currentDelay != 0) {
|
||||||
|
data.setCurrentDelay(currentDelay - 1);
|
||||||
|
} else {
|
||||||
|
worker.sendTask(data.getFunction());
|
||||||
|
if(data.getPeriod() == -1) {
|
||||||
|
removeList.add(data);
|
||||||
|
} else {
|
||||||
|
data.setCurrentDelay(data.getPeriod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
removeList.add(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(SchedulerTaskData toRemove : removeList) {
|
||||||
|
tasks.remove(toRemove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package fr.altarik.toolbox.task;
|
||||||
|
|
||||||
|
public class SchedulerTaskData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delay before executing the function for the first time
|
||||||
|
* Correspond to tick in synchronous context and milliseconds in asynchronous context
|
||||||
|
*/
|
||||||
|
private final long delay;
|
||||||
|
/**
|
||||||
|
* Period of time before re-executing the function
|
||||||
|
* Correspond to tick in synchronous context and milliseconds in asynchronous context
|
||||||
|
*/
|
||||||
|
private final long period;
|
||||||
|
private final AltarikRunnable function;
|
||||||
|
|
||||||
|
private long currentDelay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Delay and Period times corresponds to tick in synchronous context and milliseconds in asynchronous context
|
||||||
|
*
|
||||||
|
* @param function instructions to execute
|
||||||
|
* @param delay Delay before executing the function for the first time
|
||||||
|
* @param period Period of time before re-executing the function
|
||||||
|
*/
|
||||||
|
public SchedulerTaskData(AltarikRunnable function, long delay, long period) {
|
||||||
|
this.function = function;
|
||||||
|
this.delay = delay;
|
||||||
|
this.period = period;
|
||||||
|
this.currentDelay = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AltarikRunnable getFunction() {
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCurrentDelay() {
|
||||||
|
return currentDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentDelay(long currentDelay) {
|
||||||
|
this.currentDelay = currentDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDelay() {
|
||||||
|
return delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPeriod() {
|
||||||
|
return period;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package fr.altarik.toolbox.task;
|
||||||
|
|
||||||
|
public interface SendTaskWorkerI {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal use for scheduler, do not use.
|
||||||
|
* Scheduler use this method to send the task to execute to worker
|
||||||
|
* @param task task to execute now
|
||||||
|
*/
|
||||||
|
void sendTask(AltarikRunnable task);
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package fr.altarik.toolbox.task;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
|
public class ServerTickListener {
|
||||||
|
|
||||||
|
private final Runnable task;
|
||||||
|
|
||||||
|
public ServerTickListener(Runnable syncTask) {
|
||||||
|
this.task = syncTask;
|
||||||
|
ServerTickEvents.START_SERVER_TICK.register(this::onServerTick);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onServerTick(MinecraftServer minecraftServer) {
|
||||||
|
task.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
53
Tasks/src/main/java/fr/altarik/toolbox/task/Task.java
Normal file
53
Tasks/src/main/java/fr/altarik/toolbox/task/Task.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package fr.altarik.toolbox.task;
|
||||||
|
|
||||||
|
import fr.altarik.toolbox.task.async.AsyncPeriodicTasks;
|
||||||
|
import fr.altarik.toolbox.task.async.AsyncTaskI;
|
||||||
|
import fr.altarik.toolbox.task.async.AsyncTasks;
|
||||||
|
import fr.altarik.toolbox.task.sync.PeriodicSyncTask;
|
||||||
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
|
||||||
|
public class Task implements ModInitializer {
|
||||||
|
|
||||||
|
public final TaskI asyncWorkers = AsyncTasks.initialize();
|
||||||
|
public final PeriodicTaskI periodicSyncTask = PeriodicSyncTask.initialize();
|
||||||
|
|
||||||
|
public final AsyncTaskI asyncTasks = AsyncTasks.initialize();
|
||||||
|
|
||||||
|
public final PeriodicTaskI periodicAsyncTask = AsyncPeriodicTasks.initialize();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitialize() {
|
||||||
|
/* try {
|
||||||
|
asyncWorkers.addTask(new AltarikRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.out.println("Hello world 1");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
periodicSyncTask.addTask(new AltarikRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.out.println("Hello world 2");
|
||||||
|
}
|
||||||
|
}, 40, 60);
|
||||||
|
asyncTasks.addTask(new AltarikRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.out.println("Hello world 3 : " + Thread.currentThread().getName());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
periodicAsyncTask.addTask(new AltarikRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
System.out.println("Hello world 4 : " + Thread.currentThread().getName());
|
||||||
|
}
|
||||||
|
}, 60, 80);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskI getAsyncWorkers() {
|
||||||
|
return asyncWorkers;
|
||||||
|
}
|
||||||
|
}
|
12
Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java
Normal file
12
Tasks/src/main/java/fr/altarik/toolbox/task/TaskI.java
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package fr.altarik.toolbox.task;
|
||||||
|
|
||||||
|
public interface TaskI {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send task to worker, execution depends on implementation
|
||||||
|
* @param function task you send to worker
|
||||||
|
* @throws InterruptedException used by asynchronous workers if threads has been interrupted or shutdown
|
||||||
|
*/
|
||||||
|
void addTask(AltarikRunnable function) throws InterruptedException;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
package fr.altarik.toolbox.task.async;
|
||||||
|
|
||||||
|
import fr.altarik.toolbox.task.*;
|
||||||
|
|
||||||
|
import java.util.Stack;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A task manager to execute periodic tasks asynchronously. A scheduler on the main/server thread will send the task to
|
||||||
|
* worker threads.
|
||||||
|
*/
|
||||||
|
public class AsyncPeriodicTasks implements PeriodicTaskI, AsyncTaskI, SendTaskWorkerI {
|
||||||
|
|
||||||
|
private final ExecutorService worker;
|
||||||
|
private final Stack<SchedulerTaskData> tasks;
|
||||||
|
protected final Scheduler scheduler;
|
||||||
|
private final ServerTickListener listener;
|
||||||
|
|
||||||
|
private AsyncPeriodicTasks(int numberOfWorker) {
|
||||||
|
if(numberOfWorker == 1) {
|
||||||
|
worker = Executors.newSingleThreadExecutor();
|
||||||
|
} else if (numberOfWorker <= 0) {
|
||||||
|
worker = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||||
|
} else {
|
||||||
|
worker = Executors.newFixedThreadPool(numberOfWorker);
|
||||||
|
}
|
||||||
|
tasks = new Stack<>();
|
||||||
|
this.scheduler = new Scheduler(this, tasks);
|
||||||
|
this.listener = new ServerTickListener(scheduler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this method at startup or before first use of {@link AsyncTasks#addTask(AltarikRunnable)}, cause without it, nothing will work
|
||||||
|
* This method declare worker thread and start it, without call it, by calling addTask(Runnable), it'll add your task to Queue, but tasks will never be consumed.
|
||||||
|
*
|
||||||
|
* @return an instance of AsyncTasks
|
||||||
|
*/
|
||||||
|
public static PeriodicTaskI initialize(int numberOfWorker) {
|
||||||
|
return new AsyncPeriodicTasks(numberOfWorker);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PeriodicTaskI initialize() {
|
||||||
|
return initialize(Runtime.getRuntime().availableProcessors());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the task to the scheduler, the task is executed at the next server tick and at every following tick
|
||||||
|
* @param function the function which will be executed
|
||||||
|
* @throws InterruptedException if worker has terminated or is shutting down
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addTask(AltarikRunnable function) throws InterruptedException {
|
||||||
|
this.addTask(function, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the task to the scheduler, executed depending on the parameters (delay and period)
|
||||||
|
* @param function the function to execute
|
||||||
|
* @param delay delay in tick before starting the task
|
||||||
|
* @param period time in tick to wait between runs
|
||||||
|
* @throws InterruptedException if worker has terminated or is shutting down
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addTask(AltarikRunnable function, long delay, long period) throws InterruptedException {
|
||||||
|
if(worker.isTerminated() || worker.isShutdown()) {
|
||||||
|
throw new InterruptedException("Worker has been terminated or shutdown, it's impossible to add new task");
|
||||||
|
}
|
||||||
|
tasks.add(new SchedulerTaskData(function, delay, period - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to execute task you already send in 10 seconds, otherwise workers are killed.
|
||||||
|
* @throws AsyncTasks.UnfinishedTasksException if workers has been shutdown before finishing every tasks
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void close() throws Exception {
|
||||||
|
worker.shutdown();
|
||||||
|
boolean result = worker.awaitTermination(10, TimeUnit.SECONDS);
|
||||||
|
if(!result) {
|
||||||
|
worker.shutdownNow();
|
||||||
|
throw new AsyncTasks.UnfinishedTasksException("Tasks take too many time to finish, shutdown has been enforce");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendTask(AltarikRunnable task) {
|
||||||
|
worker.submit(task);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package fr.altarik.toolbox.task.async;
|
||||||
|
|
||||||
|
import fr.altarik.toolbox.task.TaskI;
|
||||||
|
|
||||||
|
public interface AsyncTaskI extends TaskI, AutoCloseable {
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
package fr.altarik.toolbox.asynctasks;
|
package fr.altarik.toolbox.task.async;
|
||||||
|
|
||||||
|
import fr.altarik.toolbox.task.AltarikRunnable;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@ -7,7 +9,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
/**
|
/**
|
||||||
* A non-blocking small sized time-consuming tasks to executed asynchronously.
|
* A non-blocking small sized time-consuming tasks to executed asynchronously.
|
||||||
*/
|
*/
|
||||||
public class AsyncTasks implements AutoCloseable {
|
public class AsyncTasks implements AsyncTaskI {
|
||||||
|
|
||||||
private final ExecutorService worker;
|
private final ExecutorService worker;
|
||||||
|
|
||||||
@ -15,23 +17,23 @@ public class AsyncTasks implements AutoCloseable {
|
|||||||
if(numberOfWorker == 1) {
|
if(numberOfWorker == 1) {
|
||||||
worker = Executors.newSingleThreadExecutor();
|
worker = Executors.newSingleThreadExecutor();
|
||||||
} else if (numberOfWorker <= 0) {
|
} else if (numberOfWorker <= 0) {
|
||||||
worker = Executors.newCachedThreadPool();
|
worker = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||||
} else {
|
} else {
|
||||||
worker = Executors.newFixedThreadPool(numberOfWorker);
|
worker = Executors.newFixedThreadPool(numberOfWorker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this method at startup or before first use of {@link AsyncTasks#addTask(Runnable)}, cause without it, nothing will work
|
* Call this method at startup or before first use of {@link AsyncTasks#addTask(AltarikRunnable)}, cause without it, nothing will work
|
||||||
* This method declare worker thread and start it, without call it, by calling addTask(Runnable), it'll add your task to Queue, but tasks will never be consumed.
|
* This method declare worker thread and start it, without call it, by calling addTask(Runnable), it'll add your task to Queue, but tasks will never be consumed.
|
||||||
*
|
*
|
||||||
* @return an instance of AsyncTasks
|
* @return an instance of AsyncTasks
|
||||||
*/
|
*/
|
||||||
public static AsyncTasks initialize(int numberOfWorker) {
|
public static AsyncTaskI initialize(int numberOfWorker) {
|
||||||
return new AsyncTasks(numberOfWorker);
|
return new AsyncTasks(numberOfWorker);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncTasks initialize() {
|
public static AsyncTaskI initialize() {
|
||||||
return initialize(Runtime.getRuntime().availableProcessors());
|
return initialize(Runtime.getRuntime().availableProcessors());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +67,7 @@ public class AsyncTasks implements AutoCloseable {
|
|||||||
* @param function task to be executed
|
* @param function task to be executed
|
||||||
* @throws InterruptedException when worker thread or BlockQueue has been interrupted while waiting (which is anormal)
|
* @throws InterruptedException when worker thread or BlockQueue has been interrupted while waiting (which is anormal)
|
||||||
*/
|
*/
|
||||||
public void addTask(Runnable function) throws InterruptedException {
|
public void addTask(AltarikRunnable function) throws InterruptedException {
|
||||||
if(worker.isTerminated() || worker.isShutdown()) {
|
if(worker.isTerminated() || worker.isShutdown()) {
|
||||||
throw new InterruptedException("Worker has been terminated or shutdown, it's impossible to add new task");
|
throw new InterruptedException("Worker has been terminated or shutdown, it's impossible to add new task");
|
||||||
}
|
}
|
||||||
@ -75,9 +77,11 @@ public class AsyncTasks implements AutoCloseable {
|
|||||||
/**
|
/**
|
||||||
* This method is call when you want to close workers and wait for waiting tasks to finish
|
* This method is call when you want to close workers and wait for waiting tasks to finish
|
||||||
*
|
*
|
||||||
|
* @throws UnfinishedTasksException when all tasks cannot be terminated in 10 seconds
|
||||||
|
* @throws InterruptedException if interrupted while waiting for tasks to finish
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() throws Exception {
|
public void close() throws UnfinishedTasksException, InterruptedException {
|
||||||
worker.shutdown();
|
worker.shutdown();
|
||||||
boolean result = worker.awaitTermination(10, TimeUnit.SECONDS);
|
boolean result = worker.awaitTermination(10, TimeUnit.SECONDS);
|
||||||
if(!result) {
|
if(!result) {
|
@ -0,0 +1,39 @@
|
|||||||
|
package fr.altarik.toolbox.task.sync;
|
||||||
|
|
||||||
|
import fr.altarik.toolbox.task.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PeriodicSyncTask implements PeriodicTaskI, SendTaskWorkerI {
|
||||||
|
|
||||||
|
private final ServerTickListener listener;
|
||||||
|
private final List<SchedulerTaskData> tasks;
|
||||||
|
protected final Scheduler scheduler;
|
||||||
|
|
||||||
|
private PeriodicSyncTask() {
|
||||||
|
this.tasks = new ArrayList<>(2);
|
||||||
|
this.scheduler = new Scheduler(this, tasks);
|
||||||
|
this.listener = new ServerTickListener(scheduler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static PeriodicTaskI initialize() {
|
||||||
|
return new PeriodicSyncTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTask(AltarikRunnable function) {
|
||||||
|
addTask(function, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTask(AltarikRunnable function, long delay, long period) {
|
||||||
|
tasks.add(new SchedulerTaskData(function, delay, period - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendTask(AltarikRunnable task) {
|
||||||
|
task.run();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package fr.altarik.toolbox.task.sync;
|
||||||
|
|
||||||
|
import fr.altarik.toolbox.task.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SyncTask implements TaskI, SendTaskWorkerI {
|
||||||
|
|
||||||
|
private final ServerTickListener listener;
|
||||||
|
private final List<SchedulerTaskData> tasks;
|
||||||
|
protected final Scheduler scheduler;
|
||||||
|
|
||||||
|
private SyncTask() {
|
||||||
|
this.tasks = new ArrayList<>(2);
|
||||||
|
this.scheduler = new Scheduler(this, tasks);
|
||||||
|
this.listener = new ServerTickListener(scheduler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TaskI initialize() {
|
||||||
|
return new SyncTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTask(AltarikRunnable function) {
|
||||||
|
addTask(function, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTask(AltarikRunnable function, int delay) {
|
||||||
|
tasks.add(new SchedulerTaskData(function, delay, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendTask(AltarikRunnable task) {
|
||||||
|
task.run();
|
||||||
|
}
|
||||||
|
}
|
15
Tasks/src/main/resources/Task.mixins.json
Normal file
15
Tasks/src/main/resources/Task.mixins.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"minVersion": "0.8",
|
||||||
|
"package": "fr.altarik.toolbox.task.mixin",
|
||||||
|
"compatibilityLevel": "JAVA_17",
|
||||||
|
"mixins": [
|
||||||
|
],
|
||||||
|
"client": [
|
||||||
|
],
|
||||||
|
"verbose": false,
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
33
Tasks/src/main/resources/fabric.mod.json
Normal file
33
Tasks/src/main/resources/fabric.mod.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "task",
|
||||||
|
"version": "${version}",
|
||||||
|
"name": "Task",
|
||||||
|
"description": "A mod to use as a dependency for others to schedule tasks",
|
||||||
|
"authors": [
|
||||||
|
"Altarik"
|
||||||
|
],
|
||||||
|
"contributors": [
|
||||||
|
"Legot Quentin<legotquentin@gmail.com>"
|
||||||
|
],
|
||||||
|
"contact": {
|
||||||
|
"homepage": "https://altarik.fr"
|
||||||
|
},
|
||||||
|
"license": "Altarik @ All-Rights-Reserved ",
|
||||||
|
"icon": "assets/quests/icon.png",
|
||||||
|
"environment": "*",
|
||||||
|
"entrypoints": {
|
||||||
|
"main": [
|
||||||
|
"fr.altarik.toolbox.task.Task"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mixins": [
|
||||||
|
"Task.mixins.json"
|
||||||
|
],
|
||||||
|
"depends": {
|
||||||
|
"fabricloader": ">=0.14.12",
|
||||||
|
"fabric": "*",
|
||||||
|
"minecraft": "1.19.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
package fr.altarik.toolbox;
|
package fr.altarik.toolbox.task.async;
|
||||||
|
|
||||||
import fr.altarik.toolbox.asynctasks.AsyncTasks;
|
import fr.altarik.toolbox.task.AltarikRunnable;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -18,15 +18,18 @@ class AsyncTaskTest {
|
|||||||
@Test
|
@Test
|
||||||
void testAsyncOp() throws Exception {
|
void testAsyncOp() throws Exception {
|
||||||
int numberOfTasks = 10000;
|
int numberOfTasks = 10000;
|
||||||
System.out.println("Initializing async tasks worker");
|
// System.out.println("Initializing async tasks worker");
|
||||||
AsyncTasks worker = AsyncTasks.initialize(1); // only testing on a single worker, otherwise result have a high chance to not be in the order we want
|
AsyncTaskI worker = AsyncTasks.initialize(1); // only testing on a single worker, otherwise result have a high chance to not be in the order we want
|
||||||
Stack<Integer> results = new Stack<>();
|
Stack<Integer> results = new Stack<>();
|
||||||
for(int i = 0; i < numberOfTasks; i++) {
|
for(int i = 0; i < numberOfTasks; i++) {
|
||||||
System.out.println(log("sending task " + i));
|
// System.out.println(log("sending task " + i));
|
||||||
AtomicInteger atomicInteger = new AtomicInteger(i);
|
AtomicInteger atomicInteger = new AtomicInteger(i);
|
||||||
worker.addTask(() -> {
|
worker.addTask(new AltarikRunnable() {
|
||||||
System.out.println(log(" task " + atomicInteger.get()));
|
@Override
|
||||||
results.push(atomicInteger.get());
|
public void run() {
|
||||||
|
// System.out.println(log(" task " + atomicInteger.get()));
|
||||||
|
results.push(atomicInteger.get());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
worker.close(); // wait until all worker terminated
|
worker.close(); // wait until all worker terminated
|
||||||
@ -35,6 +38,5 @@ class AsyncTaskTest {
|
|||||||
expected[i] = i;
|
expected[i] = i;
|
||||||
}
|
}
|
||||||
assertArrayEquals(expected, results.toArray());
|
assertArrayEquals(expected, results.toArray());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package fr.altarik.toolbox.task.async;
|
||||||
|
|
||||||
|
import fr.altarik.toolbox.task.AltarikRunnable;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Stack;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class PeriodicAsyncTaskTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPeriodicASyncTask() throws Exception {
|
||||||
|
AsyncPeriodicTasks worker = (AsyncPeriodicTasks) AsyncPeriodicTasks.initialize(1);
|
||||||
|
Stack<AtomicInteger> results = new Stack<>();
|
||||||
|
AtomicInteger value1 = new AtomicInteger(1);
|
||||||
|
AtomicInteger value2 = new AtomicInteger(2);
|
||||||
|
AltarikRunnable runnable1 = new AltarikRunnable() {
|
||||||
|
private int i = 0;
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
results.add(value1);
|
||||||
|
i++;
|
||||||
|
if(i == 2)
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
AltarikRunnable runnable2 = new AltarikRunnable() {
|
||||||
|
private int i = 0;
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
results.add(value2);
|
||||||
|
i++;
|
||||||
|
if(i == 4)
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
worker.addTask(runnable1, 1, 4);
|
||||||
|
worker.addTask(runnable2, 0, 2);
|
||||||
|
for(int i = 0; i < 10; i++) {
|
||||||
|
worker.scheduler.run();
|
||||||
|
}
|
||||||
|
AtomicInteger[] expected = {
|
||||||
|
value2,
|
||||||
|
value1,
|
||||||
|
value2,
|
||||||
|
value2,
|
||||||
|
value1,
|
||||||
|
value2,
|
||||||
|
value2,
|
||||||
|
value1
|
||||||
|
};
|
||||||
|
worker.close();
|
||||||
|
Assertions.assertArrayEquals(expected, results.toArray());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package fr.altarik.toolbox.task.sync;
|
||||||
|
|
||||||
|
import fr.altarik.toolbox.task.AltarikRunnable;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
class PeriodicSyncTaskTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testPeriodicSyncTask() {
|
||||||
|
List<AtomicInteger> results = new ArrayList<>();
|
||||||
|
PeriodicSyncTask worker = (PeriodicSyncTask) PeriodicSyncTask.initialize();
|
||||||
|
AtomicInteger value1 = new AtomicInteger(1);
|
||||||
|
AtomicInteger value2 = new AtomicInteger(2);
|
||||||
|
worker.addTask(new AltarikRunnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
results.add(value1);
|
||||||
|
}
|
||||||
|
}, 1, 3);
|
||||||
|
worker.addTask(new AltarikRunnable() {
|
||||||
|
private int i = 0;
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
results.add(value2);
|
||||||
|
if(i++ == 5)
|
||||||
|
this.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for(int i = 0; i < 10; i++) {
|
||||||
|
worker.scheduler.run();
|
||||||
|
}
|
||||||
|
AtomicInteger[] expected = {
|
||||||
|
value2,
|
||||||
|
value1,
|
||||||
|
value2,
|
||||||
|
value2,
|
||||||
|
value2,
|
||||||
|
value1,
|
||||||
|
value2,
|
||||||
|
value2,
|
||||||
|
value1
|
||||||
|
};
|
||||||
|
Assertions.assertArrayEquals(expected, results.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package fr.altarik.toolbox.task.sync;
|
||||||
|
|
||||||
|
import fr.altarik.toolbox.task.AltarikRunnable;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
class SyncTaskTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testOneTimeTask() {
|
||||||
|
SyncTask worker = (SyncTask) SyncTask.initialize();
|
||||||
|
List<AtomicInteger> results = new ArrayList<>();
|
||||||
|
AtomicInteger value1 = new AtomicInteger(1);
|
||||||
|
AtomicInteger value2 = new AtomicInteger(2);
|
||||||
|
AltarikRunnable task1 = new AltarikRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
results.add(value1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
AltarikRunnable task2 = new AltarikRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
results.add(value2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
worker.addTask(task1);
|
||||||
|
worker.scheduler.run();
|
||||||
|
worker.scheduler.run();
|
||||||
|
worker.addTask(task2);
|
||||||
|
worker.addTask(task1);
|
||||||
|
worker.addTask(task2);
|
||||||
|
worker.scheduler.run();
|
||||||
|
worker.addTask(task1);
|
||||||
|
worker.scheduler.run();
|
||||||
|
AtomicInteger[] expected = {
|
||||||
|
value1,
|
||||||
|
value2,
|
||||||
|
value1,
|
||||||
|
value2,
|
||||||
|
value1
|
||||||
|
};
|
||||||
|
Assertions.assertArrayEquals(expected, results.toArray());
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,13 @@ subprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
java {
|
||||||
|
withSourcesJar()
|
||||||
|
withJavadocJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
name 'altarik-snapshots'
|
name 'altarik-snapshots'
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
|
org.gradle.jvmargs=-Xmx5G
|
||||||
|
|
||||||
|
|
||||||
junit_version=5.9.0
|
junit_version=5.9.0
|
||||||
|
minecraft_version=1.19.3
|
||||||
|
yarn_mappings=1.19.3+build.5
|
||||||
|
loader_version=0.14.12
|
||||||
|
fabric_version=0.70.0+1.19.3
|
||||||
|
|
||||||
maven_group=fr.altarik.toolbox
|
maven_group=fr.altarik.toolbox
|
||||||
maven_version=2.0.0-SNAPSHOT
|
maven_version=2.0.0-SNAPSHOT
|
||||||
repo_username=Altarik
|
repo_username=Altarik
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
@ -1,2 +1,13 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven {
|
||||||
|
name = 'Fabric'
|
||||||
|
url = 'https://maven.fabricmc.net/'
|
||||||
|
}
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rootProject.name = 'Toolbox'
|
rootProject.name = 'Toolbox'
|
||||||
include(':Tasks', ':Database')
|
include(':Tasks', ':Database')
|
||||||
|
Loading…
Reference in New Issue
Block a user