com.badlogic.gdx.backends.headless.HeadlessApplication Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.badlogic.gdx.backends.headless;
import com.badlogic.gdx.Application;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.ApplicationLogger;
import com.badlogic.gdx.Audio;
import com.badlogic.gdx.Files;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Graphics;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.LifecycleListener;
import com.badlogic.gdx.Net;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.backends.headless.mock.audio.MockAudio;
import com.badlogic.gdx.backends.headless.mock.graphics.MockGraphics;
import com.badlogic.gdx.backends.headless.mock.input.MockInput;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Clipboard;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.TimeUtils;
/** a headless implementation of a GDX Application primarily intended to be used in servers
* @author Jon Renner */
public class HeadlessApplication implements Application {
protected final ApplicationListener listener;
protected Thread mainLoopThread;
protected final HeadlessFiles files;
protected final HeadlessNet net;
protected final MockAudio audio;
protected final MockInput input;
protected final MockGraphics graphics;
protected boolean running = true;
protected final Array runnables = new Array();
protected final Array executedRunnables = new Array();
protected final Array lifecycleListeners = new Array();
protected int logLevel = LOG_INFO;
protected ApplicationLogger applicationLogger;
private String preferencesdir;
public HeadlessApplication (ApplicationListener listener) {
this(listener, null);
}
public HeadlessApplication (ApplicationListener listener, HeadlessApplicationConfiguration config) {
if (config == null) config = new HeadlessApplicationConfiguration();
HeadlessNativesLoader.load();
setApplicationLogger(new HeadlessApplicationLogger());
this.listener = listener;
this.files = new HeadlessFiles();
this.net = new HeadlessNet(config);
// the following elements are not applicable for headless applications
// they are only implemented as mock objects
this.graphics = new MockGraphics();
this.graphics.setForegroundFPS(config.updatesPerSecond);
this.audio = new MockAudio();
this.input = new MockInput();
this.preferencesdir = config.preferencesDirectory;
Gdx.app = this;
Gdx.files = files;
Gdx.net = net;
Gdx.audio = audio;
Gdx.graphics = graphics;
Gdx.input = input;
initialize();
}
private void initialize () {
mainLoopThread = new Thread("HeadlessApplication") {
@Override
public void run () {
try {
HeadlessApplication.this.mainLoop();
} catch (Throwable t) {
if (t instanceof RuntimeException)
throw (RuntimeException)t;
else
throw new GdxRuntimeException(t);
}
}
};
mainLoopThread.start();
}
protected void mainLoop () {
Array lifecycleListeners = this.lifecycleListeners;
listener.create();
// unlike LwjglApplication, a headless application will eat up CPU in this while loop
// it is up to the implementation to call Thread.sleep as necessary
long t = TimeUtils.nanoTime() + graphics.getTargetRenderInterval();
if (graphics.getTargetRenderInterval() >= 0f) {
while (running) {
final long n = TimeUtils.nanoTime();
if (t > n) {
try {
long sleep = t - n;
Thread.sleep(sleep / 1000000, (int)(sleep % 1000000));
} catch (InterruptedException e) {
}
t = t + graphics.getTargetRenderInterval();
} else
t = n + graphics.getTargetRenderInterval();
executeRunnables();
graphics.incrementFrameId();
listener.render();
graphics.updateTime();
// If one of the runnables set running to false, for example after an exit().
if (!running) break;
}
}
synchronized (lifecycleListeners) {
for (LifecycleListener listener : lifecycleListeners) {
listener.pause();
listener.dispose();
}
}
listener.pause();
listener.dispose();
}
public boolean executeRunnables () {
synchronized (runnables) {
for (int i = runnables.size - 1; i >= 0; i--)
executedRunnables.add(runnables.get(i));
runnables.clear();
}
if (executedRunnables.size == 0) return false;
for (int i = executedRunnables.size - 1; i >= 0; i--)
executedRunnables.removeIndex(i).run();
return true;
}
@Override
public ApplicationListener getApplicationListener () {
return listener;
}
@Override
public Graphics getGraphics () {
return graphics;
}
@Override
public Audio getAudio () {
return audio;
}
@Override
public Input getInput () {
return input;
}
@Override
public Files getFiles () {
return files;
}
@Override
public Net getNet () {
return net;
}
@Override
public ApplicationType getType () {
return ApplicationType.HeadlessDesktop;
}
@Override
public int getVersion () {
return 0;
}
@Override
public long getJavaHeap () {
return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
}
@Override
public long getNativeHeap () {
return getJavaHeap();
}
ObjectMap preferences = new ObjectMap();
@Override
public Preferences getPreferences (String name) {
if (preferences.containsKey(name)) {
return preferences.get(name);
} else {
Preferences prefs = new HeadlessPreferences(name, this.preferencesdir);
preferences.put(name, prefs);
return prefs;
}
}
@Override
public Clipboard getClipboard () {
// no clipboards for headless apps
return null;
}
@Override
public void postRunnable (Runnable runnable) {
synchronized (runnables) {
runnables.add(runnable);
}
}
@Override
public void debug (String tag, String message) {
if (logLevel >= LOG_DEBUG) getApplicationLogger().debug(tag, message);
}
@Override
public void debug (String tag, String message, Throwable exception) {
if (logLevel >= LOG_DEBUG) getApplicationLogger().debug(tag, message, exception);
}
@Override
public void log (String tag, String message) {
if (logLevel >= LOG_INFO) getApplicationLogger().log(tag, message);
}
@Override
public void log (String tag, String message, Throwable exception) {
if (logLevel >= LOG_INFO) getApplicationLogger().log(tag, message, exception);
}
@Override
public void error (String tag, String message) {
if (logLevel >= LOG_ERROR) getApplicationLogger().error(tag, message);
}
@Override
public void error (String tag, String message, Throwable exception) {
if (logLevel >= LOG_ERROR) getApplicationLogger().error(tag, message, exception);
}
@Override
public void setLogLevel (int logLevel) {
this.logLevel = logLevel;
}
@Override
public int getLogLevel () {
return logLevel;
}
@Override
public void setApplicationLogger (ApplicationLogger applicationLogger) {
this.applicationLogger = applicationLogger;
}
@Override
public ApplicationLogger getApplicationLogger () {
return applicationLogger;
}
@Override
public void exit () {
postRunnable(new Runnable() {
@Override
public void run () {
running = false;
}
});
}
@Override
public void addLifecycleListener (LifecycleListener listener) {
synchronized (lifecycleListeners) {
lifecycleListeners.add(listener);
}
}
@Override
public void removeLifecycleListener (LifecycleListener listener) {
synchronized (lifecycleListeners) {
lifecycleListeners.removeValue(listener, true);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy