diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000000..da87bd8a58 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,27 @@ +FROM registry.fedoraproject.org/fedora:43 + +RUN dnf -y update && \ + dnf -y install \ + git curl unzip which procps-ng psmisc findutils \ + java-21-openjdk-devel \ + # X + desktop + xorg-x11-server-Xvfb xterm dbus-x11 \ + xfce4-session xfce4-panel xfce4-settings xfce4-terminal thunar \ + xfwm4 \ + feh \ + # VNC + web VNC + x11vnc novnc python3-websockify \ + # OpenGL (Mesa) + GLVND + tools (glxinfo) + mesa-dri-drivers mesa-libGL mesa-libEGL mesa-libGLU \ + libglvnd-glx libglvnd-egl \ + glx-utils \ + && dnf clean all + + +RUN dnf -y install weston xorg-x11-server-Xwayland wayland-utils \ + && dnf clean all + + +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..d5d735f429 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,36 @@ +{ + "name": "jME env (SERVER)", + "build": { + "dockerfile": "Dockerfile" + }, + "forwardPorts": [6080], + "portsAttributes": { + "6080": { + "label": "jME Desktop", + "onAutoForward": "openPreview" + } + }, + "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" + } + + } + } +} \ 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..798f24fd1f --- /dev/null +++ b/.devcontainer/gpu-nvidia/devcontainer.json @@ -0,0 +1,25 @@ +{ + "name": "jME env (NVIDIA)", + "build": { + "dockerfile": "../Dockerfile", + "context": ".." + }, + "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": "" + }, + "postCreateCommand": "bash .devcontainer/scripts/setup.sh", + "customizations": { + "vscode": { + "settings": { + "workbench.colorTheme": "GitHub Dark Dimmed" + } + } + } +} \ 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..74154b90f9 --- /dev/null +++ b/.devcontainer/gup-soft/devcontainer.json @@ -0,0 +1,24 @@ +{ + "name": "jME env", + "build": { + "dockerfile": "../Dockerfile", + "context": ".." + }, + "runArgs": [ + "--device=/dev/dri", + "--group-add=video", + "--group-add=render" + ], + "containerEnv": { + "LIBGL_ALWAYS_SOFTWARE": "0", + "JME3_DIALOGS_FACTORY": "" + }, + "postCreateCommand": "bash .devcontainer/scripts/setup.sh", + "customizations": { + "vscode": { + "settings": { + "workbench.colorTheme": "GitHub Dark Dimmed" + } + } + } +} \ 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..90eabffd7f --- /dev/null +++ b/.devcontainer/scripts/start-desktop.sh @@ -0,0 +1,70 @@ +#!/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 + + + +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 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 >/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..e7e0525d52 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,6 +1,13 @@ { - "recommendations": [ - "vscjava.vscode-java-pack", - "slevesque.shader" - ] -} + "recommendations": [ + "vscjava.vscode-java-pack", + "slevesque.shader", + // "github.vscode-github-actions", + "Anthropic.claude-code", + "ms-vscode-remote.remote-containers", + // "GitHub.codespaces", + "GitHub.copilot-chat", + "ms-vscode.remote-server", + // "HarryHopkinson.vim-theme" + ] +} \ 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..a092e2bc52 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,15 +1,9 @@ { "java.configuration.updateBuildConfiguration": "automatic", "java.compile.nullAnalysis.mode": "automatic", - "java.refactor.renameFromFileExplorer": "prompt", "java.format.settings.url": "./.vscode/JME_style.xml", - "editor.formatOnPaste": true, + "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/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) {