/*
* This file is part of the Illarion project.
*
* Copyright © 2015 - Illarion e.V.
*
* Illarion is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Illarion is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
package illarion.client.util;
import org.illarion.engine.GameContainer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* This class stores a list of tasks that are supposed to be executed during the next update cycle of the game.
*
* @author Martin Karing <nitram@illarion.org>
*/
public final class UpdateTaskManager {
/**
* The task queue.
*/
@Nonnull
private final Queue<UpdateTask> taskQueue;
/**
* This value is set {@code true} while the updates are executed.
*/
private boolean isInUpdateCall;
/**
* This is the container the current update run is executed for.
*/
@Nullable
private GameContainer currentContainer;
/**
* The delta value of the current update run.
*/
private int currentDelta;
/**
* The thread that is tasked to execute the updates.
*/
@Nullable
private Thread currentThread;
/**
* The default constructor that prepares the internal structures.
*/
public UpdateTaskManager() {
taskQueue = new ConcurrentLinkedQueue<>();
}
/**
* This function is triggered during the update loop of the game and triggers the update tasks.
*
* @param container the game container
* @param delta the time since the last update
*/
public void onUpdateGame(@Nonnull GameContainer container, int delta) {
currentContainer = container;
currentDelta = delta;
currentThread = Thread.currentThread();
isInUpdateCall = true;
try {
while (true) {
@Nullable UpdateTask task = taskQueue.poll();
if (task == null) {
return;
}
task.onUpdateGame(container, delta);
}
} finally {
isInUpdateCall = false;
currentContainer = null;
}
}
/**
* Add a task to the list of tasks executed during the update loop. In case the update loop is currently
* executed from the calling thread, the task is executed instantly.
*
* @param task the task to execute
*/
public void addTask(@Nonnull UpdateTask task) {
if (isInUpdateCall && Objects.equals(currentThread, Thread.currentThread()) && (currentContainer != null)) {
task.onUpdateGame(currentContainer, currentDelta);
} else {
taskQueue.offer(task);
}
}
/**
* Add a task to the list of tasks executed during the next update.
*
* @param task the task to execute
*/
public void addTaskForLater(@Nonnull UpdateTask task) {
taskQueue.offer(task);
}
}