diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000000..0d994e8d37 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,38 @@ +FROM registry.fedoraproject.org/fedora:43 + +RUN dnf -y update && \ + dnf -y install \ + git curl unzip which procps-ng psmisc findutils \ + alsa-lib alsa-plugins-pulseaudio \ + pulseaudio-libs pulseaudio-utils \ + # X + desktop + xorg-x11-server-Xvfb xterm dbus-x11 \ + xfce-polkit \ + xfce4-session xfce4-panel xfce4-settings xfce4-terminal thunar \ + xfwm4 \ + feh \ + # VNC + web VNC + x11vnc novnc python3-websockify \ + # Xpra + dependencies (xpra-html5 not in Fedora repos; installed below from source) + xpra python3-gobject python3-paramiko \ + # OpenGL (Mesa) + GLVND + tools (glxinfo) + mesa-dri-drivers mesa-libGL mesa-libEGL mesa-libGLU \ + libglvnd-glx libglvnd-egl \ + glx-utils zip weston xorg-x11-server-Xwayland wayland-utils \ + && dnf clean all + + + +ENV SDKMAN_DIR=/root/.sdkman +RUN curl -s "https://get.sdkman.io" | bash \ + && source "$SDKMAN_DIR/bin/sdkman-init.sh" \ + && sdk install java 25-tem \ + && sdk default java 25-tem + +ENV JAVA_HOME=${SDKMAN_DIR}/candidates/java/current +ENV PATH=${JAVA_HOME}/bin:${PATH} + + +COPY assets/wallpaper.jpg /root/wallpaper.jpg +COPY assets/novnc-index.html /usr/share/novnc/index.html + \ No newline at end of file diff --git a/.devcontainer/assets/novnc-index.html b/.devcontainer/assets/novnc-index.html new file mode 100644 index 0000000000..1dd03f733b --- /dev/null +++ b/.devcontainer/assets/novnc-index.html @@ -0,0 +1,14 @@ + + + + + + + noVNC + + + + Warming up noVNC... + + + \ No newline at end of file diff --git a/.devcontainer/assets/wallpaper.jpg b/.devcontainer/assets/wallpaper.jpg new file mode 100644 index 0000000000..ddbd1cbb09 Binary files /dev/null and b/.devcontainer/assets/wallpaper.jpg differ diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..a3675f0535 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,43 @@ +{ + "name": "jME env (SERVER)", + "build": { + "dockerfile": "Dockerfile" + }, + + "forwardPorts": [6080], + "portsAttributes": { + "6080": { + "label": "jME Desktop (Xpra HTML5)", + "onAutoForward": "openBrowser" + }, + "5900": { + "label": "VNC", + "onAutoForward": "ignore" + } + }, + "containerEnv": { + "JME_DEV_ENVIRONMENT": "yesReally", + "LIBGL_ALWAYS_SOFTWARE": "1", + "MESA_LOADER_DRIVER_OVERRIDE": "llvmpipe", + "GALLIUM_DRIVER": "llvmpipe", + "WAYLAND_DISPLAY": "", + "WAYLAND_SOCKET": "", + "XDG_RUNTIME_DIR": "", + "GDK_BACKEND": "x11", + "SDL_BACKEND": "x11", + "GLFW_PLATFORM": "x11", + "DISPLAY": ":99" + + }, + "postCreateCommand": "bash .devcontainer/scripts/setup.sh", + "postStartCommand": "bash .devcontainer/scripts/start-desktop.sh", + "customizations": { + "vscode": { + "settings": { + "workbench.colorTheme": "GitHub Dark Dimmed", + "java.jdt.ls.java.home": "/root/.sdkman/candidates/java/25-tem/" + } + + } + } +} \ No newline at end of file diff --git a/.devcontainer/gpu-nvidia/devcontainer.json b/.devcontainer/gpu-nvidia/devcontainer.json new file mode 100644 index 0000000000..acafff8749 --- /dev/null +++ b/.devcontainer/gpu-nvidia/devcontainer.json @@ -0,0 +1,32 @@ +{ + "name": "jME env (NVIDIA)", + "build": { + "dockerfile": "../Dockerfile", + "context": ".." + }, + "mounts": [ + "source=${localEnv:XDG_RUNTIME_DIR}/pulse/native,target=/tmp/pulse/native,type=bind", + "source=${localEnv:HOME}/.config/pulse/cookie,target=/tmp/pulse/cookie,type=bind,readonly" + ], + "runArgs": [ + "--gpus=all" + ], + "containerEnv": { + "LIBGL_ALWAYS_SOFTWARE": "0", + "NVIDIA_VISIBLE_DEVICES": "all", + "NVIDIA_DRIVER_CAPABILITIES": "graphics,utility,compute", + "__GL_THREADED_OPTIMIZATIONS": "0", + "JME3_DIALOGS_FACTORY": "", + "PULSE_SERVER": "unix:/tmp/pulse/native", + "PULSE_COOKIE": "/tmp/pulse/cookie" + }, + "postCreateCommand": "bash .devcontainer/scripts/setup.sh", + "customizations": { + "vscode": { + "settings": { + "workbench.colorTheme": "GitHub Dark Dimmed", + "java.jdt.ls.java.home": "/root/.sdkman/candidates/java/25-tem/" + } + } + } +} \ No newline at end of file diff --git a/.devcontainer/gup-soft/devcontainer.json b/.devcontainer/gup-soft/devcontainer.json new file mode 100644 index 0000000000..769cef0f8c --- /dev/null +++ b/.devcontainer/gup-soft/devcontainer.json @@ -0,0 +1,31 @@ +{ + "name": "jME env", + "build": { + "dockerfile": "../Dockerfile", + "context": ".." + }, + "mounts": [ + "source=${localEnv:XDG_RUNTIME_DIR}/pulse/native,target=/tmp/pulse/native,type=bind", + "source=${localEnv:HOME}/.config/pulse/cookie,target=/tmp/pulse/cookie,type=bind,readonly" + ], + "runArgs": [ + "--device=/dev/dri", + "--group-add=video", + "--group-add=render" + ], + "containerEnv": { + "LIBGL_ALWAYS_SOFTWARE": "0", + "JME3_DIALOGS_FACTORY": "", + "PULSE_SERVER": "unix:/tmp/pulse/native", + "PULSE_COOKIE": "/tmp/pulse/cookie" + }, + "postCreateCommand": "bash .devcontainer/scripts/setup.sh", + "customizations": { + "vscode": { + "settings": { + "workbench.colorTheme": "GitHub Dark Dimmed", + "java.jdt.ls.java.home": "/root/.sdkman/candidates/java/25-tem/" + } + } + } +} \ No newline at end of file diff --git a/.devcontainer/scripts/setup.sh b/.devcontainer/scripts/setup.sh new file mode 100644 index 0000000000..68754c4b53 --- /dev/null +++ b/.devcontainer/scripts/setup.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail + + +# Optional: warm Gradle wrapper so first run is less painful +if [ -f ./gradlew ]; then + ./gradlew --version || true +fi \ No newline at end of file diff --git a/.devcontainer/scripts/start-desktop.sh b/.devcontainer/scripts/start-desktop.sh new file mode 100755 index 0000000000..def2cb50e6 --- /dev/null +++ b/.devcontainer/scripts/start-desktop.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +set -euo pipefail +if [ "$JME_DEV_ENVIRONMENT" != "yesReally" ]; +then + echo "Not running! This script is meant to be run in the jMonkeyEngine dev container environment, and may do unexpected things if run elsewhere." + exit 1 +fi + +export DISPLAY="${DISPLAY:-:99}" +unset WAYLAND_DISPLAY WAYLAND_SOCKET XDG_RUNTIME_DIR +export GDK_BACKEND=x11 +export SDL_VIDEODRIVER=x11 +export GLFW_PLATFORM=x11 + +# Fedora noVNC web root path +NOVNC_WEB="/usr/share/novnc" +if [ ! -d "$NOVNC_WEB" ]; then + echo "ERROR: noVNC web root not found at $NOVNC_WEB" + echo "Try checking where novnc installed files are:" + rpm -ql novnc | sed -n '1,120p' || true + exit 1 +fi + +# Start virtual X server +if ! pgrep -f "Xvfb ${DISPLAY}" >/dev/null 2>&1; then + nohup Xvfb "${DISPLAY}" -screen 0 1440x900x24 +extension GLX +render -noreset >/tmp/xvfb.log 2>&1 & +fi + +# Start a dbus session (XFCE wants it) +if ! pgrep -u "$(id -u)" -f "dbus-daemon.*--session" >/dev/null 2>&1; then + # shellcheck disable=SC2046 + eval "$(dbus-launch --sh-syntax)" +fi + +# Start a PolicyKit agent to avoid XFCE PolicyKitAgent errors (if available) +start_polkit_agent() { + if command -v polkit-gnome-authentication-agent-1 >/dev/null 2>&1; then + nohup polkit-gnome-authentication-agent-1 >/tmp/polkit-agent.log 2>&1 & + return + fi + if command -v xfce-polkit >/dev/null 2>&1; then + nohup xfce-polkit >/tmp/xfce-polkit.log 2>&1 & + return + fi + if [ -x "/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1" ]; then + nohup /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 >/tmp/polkit-agent.log 2>&1 & + return + fi + echo "No PolicyKit agent found; PolicyKit dialogs may show an error." +} + +start_polkit_agent + + + +if [ "$JME_DEV_ENVIRONMENT" != "yesReally" ]; +then + echo "Not running! This script is meant to be run in the jMonkeyEngine dev container environment, and may do unexpected things if run elsewhere." + exit 1 +fi + +# Init home +mkdir -p "$HOME/.config" "$HOME/.cache" "$HOME/.local/share" + + +# Start window manager +if ! pgrep -u "$(id -u)" -x xfwm4 >/dev/null 2>&1; then + nohup xfwm4 --compositor=off --daemon >/tmp/xfwm4.log 2>&1 & +fi + + +# Start XFCE session +if ! pgrep -u "$(id -u)" -x xfce4-session >/dev/null 2>&1; then + nohup xfce4-session >/tmp/xfce4-session.log 2>&1 & +fi + +# Set wallpaper +feh --no-fehbg --bg-fill "/root/wallpaper.jpg" + +# Start PulseAudio for app sound forwarding (used by Xpra speaker stream). +if command -v pulseaudio >/dev/null 2>&1; then + if ! pgrep -u "$(id -u)" -x pulseaudio >/dev/null 2>&1; then + nohup pulseaudio --start >/tmp/pulseaudio.log 2>&1 || true + fi +fi + +# Start VNC server (no password; fine for Codespaces) +if ! pgrep -f "x11vnc.*-rfbport 5900" >/dev/null 2>&1; then + nohup x11vnc -display "${DISPLAY}" -nopw -forever -shared -cursor arrow -rfbport 5900 \ + -nowf -noxdamage -xwarppointer -noxrecord -noxfixes >/tmp/x11vnc.log 2>&1 & +fi + +# Start noVNC (websockify) +if ! pgrep -f "websockify.*6080" >/dev/null 2>&1; then + python3 -m websockify --web="${NOVNC_WEB}" 6080 localhost:5900 +fi + diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml deleted file mode 100644 index 6ff2d099fa..0000000000 --- a/.github/workflows/format.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: auto-format -on: - push: - -jobs: - format: - runs-on: ubuntu-latest - if: ${{ false }} - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Prettify code - uses: creyD/prettier_action@v4.3 - with: - prettier_options: --tab-width 4 --print-width 110 --write **/**/*.java - prettier_version: "2.8.8" - only_changed: True - commit_message: "auto-format" - prettier_plugins: "prettier-plugin-java" diff --git a/.gitignore b/.gitignore index 121fd33ac3..acb22783d8 100644 --- a/.gitignore +++ b/.gitignore @@ -50,4 +50,5 @@ javadoc_deploy.pub !.vscode/settings.json !.vscode/JME_style.xml !.vscode/extensions.json +!.vscode/java.code-snippets joysticks-*.txt \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json index a1538208b3..cf20732ef1 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,6 +1,9 @@ { - "recommendations": [ - "vscjava.vscode-java-pack", - "slevesque.shader" - ] -} + "recommendations": [ + "vscjava.vscode-java-pack", + "slevesque.shader", + "ms-vscode-remote.remote-containers", + "GitHub.copilot-chat", + "ms-vscode.remote-server" + ] +} \ No newline at end of file diff --git a/.vscode/java.code-snippets b/.vscode/java.code-snippets new file mode 100644 index 0000000000..7c67647e00 --- /dev/null +++ b/.vscode/java.code-snippets @@ -0,0 +1,54 @@ +{ + + "logger":{ + "prefix":"logger", + "body": [ + "private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(${1:${TM_FILENAME_BASE}}.class.getName());" + ], + "description":"Add java.util Logger" + }, + "log":{ + "prefix": "log", + "body":[ + "if(logger.isLoggable(java.util.logging.Level.$1 )){\n\tlogger.log(java.util.logging.Level.$1, \"$2\");\n}" + ], + + }, + "logfinest":{ + "prefix": "logfinest", + "body":[ + "logger.finest($1);" + ] + }, + "logfiner":{ + "prefix": "logfiner", + "body":[ + "logger.finer($1);" + ] + }, + "logfine":{ + "prefix": "logfine", + "body":[ + "logger.fine($1);" + ] + }, + "loginfo":{ + "prefix": "loginfo", + "body":[ + "logger.info($1);" + ] + }, + "logwarning":{ + "prefix": "logwarning", + "body":[ + "logger.warning($1);" + ] + }, + "logsevere":{ + "prefix": "logsevere", + "body":[ + "logger.severe($1);" + ] + } + +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 89d691dd52..e6cc75a894 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,15 +1,8 @@ { - "java.configuration.updateBuildConfiguration": "automatic", "java.compile.nullAnalysis.mode": "automatic", - "java.refactor.renameFromFileExplorer": "prompt", - "java.format.settings.url": "./.vscode/JME_style.xml", - "editor.formatOnPaste": true, + "java.format.settings.url": "${workspaceFolder}/.vscode/JME_style.xml", + "editor.formatOnPaste": false, "editor.formatOnType": false, - "editor.formatOnSave": true, - "editor.formatOnSaveMode": "modifications" , - - "prettier.tabWidth": 4, - "prettier.printWidth": 110, - "prettier.enable": true, - "prettier.resolveGlobalModules": true + "editor.formatOnSave": false, + "editor.formatOnSaveMode": "modifications", } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3..8bdaf60c75 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4413138c9..2e1113280e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index b740cf1339..adff685a03 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -112,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -170,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -203,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 7101f8e467..e509b2dd8f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -68,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java b/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java index ec89b9df06..887f7348e6 100644 --- a/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java +++ b/jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java @@ -129,7 +129,7 @@ private void initOpenAL() { if (!alc.isCreated()) { alc.createALC(); } - } catch (UnsatisfiedLinkError ex) { + } catch (Exception ex) { logger.log(Level.SEVERE, "Failed to load audio library (OpenAL). Audio will be disabled.", ex); audioDisabled = true; return; diff --git a/jme3-core/src/main/java/com/jme3/system/AppSettings.java b/jme3-core/src/main/java/com/jme3/system/AppSettings.java index 92354ff91e..8c154b46ea 100644 --- a/jme3-core/src/main/java/com/jme3/system/AppSettings.java +++ b/jme3-core/src/main/java/com/jme3/system/AppSettings.java @@ -296,12 +296,12 @@ public final class AppSettings extends HashMap { static { defaults.put("Display", 0); defaults.put("CenterWindow", true); - defaults.put("Width", 640); - defaults.put("Height", 480); + defaults.put("Width", 1440); + defaults.put("Height", 900); defaults.put("WindowWidth", Integer.MIN_VALUE); defaults.put("WindowHeight", Integer.MIN_VALUE); defaults.put("BitsPerPixel", 24); - defaults.put("Frequency", 60); + defaults.put("Frequency", 0); defaults.put("DepthBits", 24); defaults.put("StencilBits", 0); defaults.put("Samples", 0); @@ -317,7 +317,7 @@ public final class AppSettings extends HashMap { defaults.put("MinHeight", 0); defaults.put("MinWidth", 0); defaults.put("GammaCorrection", true); - defaults.put("Resizable", false); + defaults.put("Resizable", true); defaults.put("SwapBuffers", true); defaults.put("OpenCL", false); defaults.put("OpenCLPlatformChooser", DefaultPlatformChooser.class.getName()); diff --git a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java index c9d8b79182..3f31c7adb6 100644 --- a/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java +++ b/jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java @@ -66,7 +66,13 @@ public abstract class JmeSystemDelegate { protected Consumer errorMessageHandler = (message) -> { JmeDialogsFactory dialogFactory = null; try { - dialogFactory = (JmeDialogsFactory)Class.forName("com.jme3.system.JmeDialogsFactoryImpl").getConstructor().newInstance(); + String dialogFactoryClass = System.getenv("JME3_DIALOGS_FACTORY"); + if(dialogFactoryClass == null) { + dialogFactoryClass = System.getProperty("jme3.dialogsFactory","com.jme3.system.JmeDialogsFactoryImpl"); + } + if(dialogFactoryClass != null && !dialogFactoryClass.trim().isEmpty()){ + dialogFactory = (JmeDialogsFactory)Class.forName(dialogFactoryClass).getConstructor().newInstance(); + } } catch(ClassNotFoundException e){ logger.warning("JmeDialogsFactory implementation not found."); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { @@ -79,7 +85,14 @@ public abstract class JmeSystemDelegate { protected BiFunction settingsHandler = (settings,loadFromRegistry) -> { JmeDialogsFactory dialogFactory = null; try { - dialogFactory = (JmeDialogsFactory)Class.forName("com.jme3.system.JmeDialogsFactoryImpl").getConstructor().newInstance(); + String dialogFactoryClass = System.getenv("JME3_DIALOGS_FACTORY"); + if(dialogFactoryClass == null) { + dialogFactoryClass = System.getProperty("jme3.dialogsFactory","com.jme3.system.JmeDialogsFactoryImpl"); + } + if(dialogFactoryClass != null && !dialogFactoryClass.trim().isEmpty()){ + dialogFactory = (JmeDialogsFactory)Class.forName(dialogFactoryClass).getConstructor().newInstance(); + } + dialogFactory = (JmeDialogsFactory)Class.forName(dialogFactoryClass).getConstructor().newInstance(); } catch(ClassNotFoundException e){ logger.warning("JmeDialogsFactory implementation not found."); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {