/*
* Copyright (c) 2015 NOVA, All rights reserved.
* This library is free software, licensed under GNU Lesser General Public License version 3
*
* This file is part of NOVA.
*
* NOVA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NOVA 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.
*
* You should have received a copy of the GNU General Public License
* along with NOVA. If not, see <http://www.gnu.org/licenses/>.
*/
package nova.internal.core.tick;
import nova.core.component.Updater;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.stream.Stream;
/**
* The update ticker is responsible for ticking Update objects.
* @author Calclavia
*/
public class UpdateTicker {
/**
* A set of Updater that will be ticked.
*/
private final Set<Updater> updaters = Collections.newSetFromMap(new WeakHashMap<>());
private final List<Runnable> preEvents = new ArrayList<>();
/**
* The last update time.
*/
private long last;
private double deltaTime;
public UpdateTicker() {
last = System.currentTimeMillis();
}
public void add(Updater ticker) {
synchronized (updaters) {
updaters.add(ticker);
}
}
public void remove(Updater ticker) {
synchronized (updaters) {
updaters.remove(ticker);
}
}
/**
* Queues an event to be executed.
* @param func Event to be executed.
*/
public void preQueue(Runnable func) {
synchronized (preEvents) {
preEvents.add(func);
}
}
public void update() {
synchronized (preEvents) {
preEvents.forEach(Runnable::run);
preEvents.clear();
}
long current = System.currentTimeMillis();
//The time in milliseconds between the last update and this one.
deltaTime = (current - last) / 1000d;
synchronized (updaters) {
//TODO: Check the threshold
Stream<Updater> stream = updaters.size() > 1000 ? updaters.parallelStream() : updaters.stream();
stream.forEach(t -> t.update(deltaTime));
}
last = current;
}
public double getDeltaTime() {
return deltaTime;
}
/**
* A synchronized ticker ticks using the game's update loop.
*/
public static class SynchronizedTicker extends UpdateTicker {
}
/**
* A thread ticker ticks using the NOVA's update loop.
*/
public static class ThreadTicker extends UpdateTicker {
}
/**
* A thread ticker ticks independent on the game's update loop.
*/
public static class TickingThread extends Thread {
public final UpdateTicker ticker;
public final int tps;
public final long sleepMillis;
public boolean pause = false;
public TickingThread(UpdateTicker ticker, int tps) {
setName("Nova Thread");
setPriority(Thread.MIN_PRIORITY);
this.ticker = ticker;
this.tps = tps;
this.sleepMillis = 1 / tps * 1000;
}
@Override
public void run() {
try {
//noinspection InfiniteLoopStatement
while (true) {
if (!pause) {
ticker.update();
}
Thread.sleep(sleepMillis);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}