# LibGDX 1.9.6 → 1.14.1 Upgrade Plan ## Overview This plan upgrades Tick's Tales from libGDX 1.9.6 to 1.14.1, along with updating Clojure, core.async, and Java target version. **Risk Level:** Medium - Breaking changes are well-defined and limited to specific methods. **Estimated Effort:** 2-4 hours including testing --- ## Background & Research Sources Before executing this plan, the implementor should understand the scope of changes between libGDX 1.9.6 and 1.14.1. ### Primary Research Sources | Source | URL | Purpose | |--------|-----|---------| | libGDX CHANGES file | https://github.com/libgdx/libgdx/raw/master/CHANGES | Official changelog - read versions 1.9.7 through 1.14.1 | | libGDX Releases | https://github.com/libgdx/libgdx/releases | Release notes with upgrade guidance | | libGDX Wiki | https://libgdx.com/wiki/ | General documentation | | LWJGL 3 Changelog | https://www.lwjgl.org/changelog | LWJGL changes bundled with libGDX | | Clojure Changelog | https://github.com/clojure/clojure/blob/master/Changes.md | Clojure version changes | | core.async Changelog | https://github.com/clojure/core.async/blob/master/CHANGES.md | core.async version changes | ### How to Research Issues If you encounter unexpected errors during this upgrade: 1. **Check the libGDX CHANGES file** for your specific error message or class name ```bash # Search for a specific class or method curl -s https://raw.githubusercontent.com/libgdx/libgdx/master/CHANGES | grep -i "YourClassName" ``` 2. **Search libGDX issues**: https://github.com/libgdx/libgdx/issues - Search for error messages - Search for class names that fail 3. **Check LWJGL issues**: https://github.com/LWJGL/lwjgl3/issues - LWJGL3 is bundled with libGDX; native library issues may originate here 4. **Check play-clj keyword translation**: - The macro `key->method` in `play-clj/src/play_clj/utils.clj:80-83` converts keywords to Java method calls - `:set-fullscreen-mode` becomes `.setFullscreenMode()` - If a method was renamed, search for the new name using the keyword pattern --- ## Why This Upgrade? ### 1. Bug Fixes LibGDX 1.9.6 was released in 2017. The 1.14.1 release includes fixes for: - Audio device switching issues (automatic in 1.12.1+) - Borderless fullscreen bugs - Various native crashes on LWJGL 3 - Memory leaks in frame buffer handling ### 2. LWJGL 3 Updates The bundled LWJGL version updates from 3.1.0 to 3.3.3: - Better hardware compatibility - Fixed various native crashes - Improved Wayland support (Linux) ### 3. Java Compatibility LibGDX 1.13.0+ is built with Java 17: - Targeting Java 11 ensures compatibility with modern JVMs - Your current JDK 25 will work without issues ### 4. Clojure Updates Clojure 1.8.0 → 1.11.3 brings: - Better error messages - Performance improvements - `parse-double`, `parse-long`, `parse-boolean` utilities - `update-keys`, `update-vals` functions --- ## Prerequisites - [ ] **Create a branch for this upgrade work** ```bash cd /home/noti/dev/tickstales/desktop git checkout -b upgrade/libgdx-1.14.1 ``` - [ ] **Verify current build works** ```bash lein check ``` Note any warnings or errors for comparison later. --- ## Part 1: Update play-clj Library The play-clj library (symlinked at `/home/noti/dev/tickstales/play-clj` → `/home/noti/dev/play-clj`) requires modifications before the game can be updated. ### 1.1 Create Branch in play-clj - [ ] Navigate to play-clj and create a branch ```bash cd /home/noti/dev/play-clj git checkout -b upgrade/libgdx-1.14.1 ``` ### 1.2 Update play-clj Dependencies **File:** `/home/noti/dev/play-clj/project.clj` **Why this change:** - LibGDX must be updated to match the game's version - Clojure 1.6.0 is ancient (2014); 1.11.3 is the current stable release - Java 11 target is required for libGDX 1.13.0+ which is built with Java 17 **Research if blocked:** - Check Maven Central for available versions: https://central.sonatype.com/search?q=g:com.badlogicgames.gdx - Clojure versions: https://clojure.org/releases/downloads - [ ] Update libGDX dependencies (approximately lines 6-8): ```clojure ;; BEFORE [com.badlogicgames.gdx/gdx "1.9.5"] [com.badlogicgames.gdx/gdx-box2d "1.9.5"] [com.badlogicgames.gdx/gdx-bullet "1.9.5"] ;; AFTER [com.badlogicgames.gdx/gdx "1.14.1"] [com.badlogicgames.gdx/gdx-box2d "1.14.1"] [com.badlogicgames.gdx/gdx-bullet "1.14.1"] ``` - [ ] Update Clojure version (approximately line 9): ```clojure ;; BEFORE [org.clojure/clojure "1.6.0"] ;; AFTER [org.clojure/clojure "1.11.3"] ``` - [ ] Update Java target version in `:javac-options`: ```clojure ;; BEFORE :javac-options ["-target" "1.8" "-source" "1.8" "-Xlint:-options"] ;; AFTER :javac-options ["-target" "11" "-source" "11" "-Xlint:-options"] ``` - [ ] **Commit this change:** ```bash git add project.clj git commit -m "Update libGDX to 1.14.1 and Clojure to 1.11.3" ``` ### 1.3 Fix InputProcessor.scrolled() Signature Change **File:** `/home/noti/dev/play-clj/src/play_clj/core_listeners.clj` **Why this change:** In libGDX 1.9.12, the `InputProcessor.scrolled()` method signature changed to support: 1. **Horizontal scrolling** (trackpads, some mice) 2. **Fractional scroll amounts** (high-precision devices) **Before (1.9.6 - 1.9.11):** ```java // InputProcessor interface boolean scrolled(int amount); ``` **After (1.9.12+):** ```java // InputProcessor interface boolean scrolled(float amountX, float amountY); ``` **What happens if you don't fix this:** - `AbstractMethodError` at runtime when any scroll event occurs - The game will crash when the mouse wheel is used **Research if blocked:** - libGDX CHANGES: Search for "scrolled" or "InputProcessor" - libGDX PR #6154: https://github.com/libgdx/libgdx/pull/6154 - InputProcessor javadoc: https://libgdx.com/wiki/input/input-handling **Location in code:** The `input-processor` function creates a `reify` of the `InputProcessor` interface. Line 22-23 defines the `scrolled` method. - [ ] Update the `scrolled` method in the `input-processor` function (lines 22-23): ```clojure ;; BEFORE (scrolled [this a] (execute-fn! on-scrolled {:amount a}) ;; AFTER (scrolled [this amountX amountY] (execute-fn! on-scrolled {:amount-x amountX :amount-y amountY}) ``` **Impact on game code:** - Your game's `:on-scrolled` handler in `scene.clj:1445` is commented out, so this won't immediately affect gameplay - If you use scrolling in the future, access scroll amounts via `:amount-x` and `:amount-y` instead of `:amount` - [ ] **Commit this change:** ```bash git add src/play_clj/core_listeners.clj git commit -m "Fix scrolled() signature for libGDX 1.9.12+ compatibility" ``` ### 1.4 Add InputProcessor.touchCancelled() Method **File:** `/home/noti/dev/play-clj/src/play_clj/core_listeners.clj` **Why this change:** In libGDX 1.12.0, a new method was added to the `InputProcessor` interface: ```java // Added in libGDX 1.12.0 boolean touchCancelled(int screenX, int screenY, int pointer, int button); ``` **Purpose:** This method is called when a touch event is cancelled by the system (e.g., when a dialog appears during a touch, or on mobile when a call comes in). Previously, these situations could leave the game in an inconsistent state. **What happens if you don't fix this:** - `AbstractMethodError` at runtime when the game first processes any input - The reify will not implement all interface methods, causing immediate crash on startup **Research if blocked:** - libGDX CHANGES: Search for "touchCancelled" - libGDX issue #6871: https://github.com/libgdx/libgdx/issues/6871 - libGDX 1.12.0 release notes: https://github.com/libgdx/libgdx/releases/tag/1.12.0 **Location in code:** Add this method inside the `reify InputProcessor` block, after the `touchUp` method. - [ ] Add the `touchCancelled` method to the `input-processor` function (after the `touchUp` method, around line 33): ```clojure (touchUp [this sx sy p b] (execute-fn! on-touch-up {:input-x sx :input-y sy :pointer p :button b}) false) ;; ADD THIS METHOD: (touchCancelled [this sx sy p b] false) ``` **Optional enhancement:** If you want to handle touch cancellation events: ```clojure ;; You could add an :on-touch-cancelled handler similar to other input handlers: (touchCancelled [this sx sy p b] (execute-fn! on-touch-cancelled {:input-x sx :input-y sy :pointer p :button b}) false) ``` - [ ] **Commit this change:** ```bash git add src/play_clj/core_listeners.clj git commit -m "Add touchCancelled() method for libGDX 1.12.0+ compatibility" ``` ### 1.5 Update Documentation (Optional) **File:** `/home/noti/dev/play-clj/src/play_clj/core.clj` **Why this change:** The docstring example for `:on-scrolled` shows the old `:amount` key. Updating it prevents confusion for future developers. - [ ] Update the `:on-scrolled` docstring (lines 206-210) to reflect new keys: ```clojure ;; BEFORE ; the mouse wheel was scrolled :on-scrolled (fn [screen entities] (println (:amount screen)) ; the amount scrolled entities) ;; AFTER ; the mouse wheel was scrolled :on-scrolled (fn [screen entities] (println (:amount-x screen)) ; the horizontal scroll amount (println (:amount-y screen)) ; the vertical scroll amount entities) ``` - [ ] **Commit this change (if made):** ```bash git add src/play_clj/core.clj git commit -m "Update :on-scrolled documentation for new scroll API" ``` ### 1.6 Install Updated play-clj - [ ] Install the updated play-clj library: ```bash cd /home/noti/dev/play-clj lein install ``` - [ ] Verify installation succeeded (should see "Created jar" message) **If installation fails:** - Check that all dependencies resolve: `lein deps` - Check for Clojure syntax errors: `lein check` - Verify Maven local repository: `ls ~/.m2/repository/play-clj/play-clj/` - [ ] **Commit any generated files:** ```bash git status # If pom.xml or other files were modified: git add -A git commit -m "Update generated files after lein install" ``` --- ## Part 2: Update Game Project ### 2.1 Return to Game Directory - [ ] Navigate back to the game: ```bash cd /home/noti/dev/tickstales/desktop ``` ### 2.2 Update Game Dependencies **File:** `/home/noti/dev/tickstales/desktop/project.clj` **Why this change:** - libGDX must match the version installed in play-clj - Clojure 1.11.3 is compatible with 1.8.0 code; no source changes required - core.async 1.6.681 includes bug fixes and performance improvements - Java 11 target is required for libGDX 1.13.0+ **Research if blocked:** - Clojure compatibility: https://clojure.org/reference/compatibility - core.async releases: https://github.com/clojure/core.async/releases - [ ] Update libGDX dependencies (approximately lines 19-21): ```clojure ;; BEFORE [com.badlogicgames.gdx/gdx "1.9.6"] [com.badlogicgames.gdx/gdx-backend-lwjgl3 "1.9.6"] [com.badlogicgames.gdx/gdx-platform "1.9.6" :classifier "natives-desktop"] ;; AFTER [com.badlogicgames.gdx/gdx "1.14.1"] [com.badlogicgames.gdx/gdx-backend-lwjgl3 "1.14.1"] [com.badlogicgames.gdx/gdx-platform "1.14.1" :classifier "natives-desktop"] ``` - [ ] Update Clojure version (approximately line 22): ```clojure ;; BEFORE [org.clojure/clojure "1.8.0"] ;; AFTER [org.clojure/clojure "1.11.3"] ``` - [ ] Update core.async version (approximately line 27): ```clojure ;; BEFORE [org.clojure/core.async "0.2.385"] ;; AFTER [org.clojure/core.async "1.6.681"] ``` - [ ] Update Java target version in `:javac-options` (approximately line 30): ```clojure ;; BEFORE :javac-options ["-target" "1.7" "-source" "1.7" "-Xlint:-options"] ;; AFTER :javac-options ["-target" "11" "-source" "11" "-Xlint:-options"] ``` - [ ] **Commit this change:** ```bash git add project.clj git commit -m "Update libGDX to 1.14.1, Clojure to 1.11.3, core.async to 1.6.681" ``` ### 2.3 Fix ScreenUtils.getFrameBufferPixmap() Deprecation **File:** `/home/noti/dev/tickstales/desktop/src-common/advent/utils.clj` **Why this change:** In libGDX 1.9.14, `ScreenUtils.getFrameBufferPixmap()` was deprecated and replaced with `Pixmap.createFromFrameBuffer()`. **Old API (deprecated):** ```java Pixmap pm = ScreenUtils.getFrameBufferPixmap(x, y, width, height); ``` **New API:** ```java Pixmap pm = Pixmap.createFromFrameBuffer(x, y, width, height); ``` **What happens if you don't fix this:** - The code will still compile (deprecation warning, not error) - May fail at runtime in future versions when the method is removed - The new method is more efficient **Research if blocked:** - libGDX CHANGES: Search for "ScreenUtils" or "getFrameBufferPixmap" - Pixmap javadoc: https://libgdx.com/wiki/graphics/2d/pixmaps **Location in code:** Line 258 in `src-common/advent/utils.clj`, inside the function that captures screenshots for save files. - [ ] Find line 258 and update the deprecated call: ```clojure ;; BEFORE pm (ScreenUtils/getFrameBufferPixmap x y w h) ;; AFTER pm (Pixmap/createFromFrameBuffer x y w h) ``` - [ ] **Commit this change:** ```bash git add src-common/advent/utils.clj git commit -m "Replace deprecated ScreenUtils/getFrameBufferPixmap with Pixmap/createFromFrameBuffer" ``` --- ## Part 3: Build and Test ### 3.1 Clean and Compile - [ ] Clean previous build artifacts: ```bash lein clean ``` - [ ] Compile and check for errors: ```bash lein check ``` Expected: Compilation should succeed. Some reflection warnings are acceptable. **If compilation fails:** 1. **"Could not locate play_clj__init.class"** - play-clj wasn't installed ```bash cd /home/noti/dev/play-clj && lein install && cd /home/noti/dev/tickstales/desktop ``` 2. **"AbstractMethodError"** - Interface method not implemented - Check that `touchCancelled` was added to `core_listeners.clj` - Check that `scrolled` has the correct signature 3. **"ClassNotFoundException"** for libGDX classes - Run `lein deps` to download dependencies - Check Maven Central for correct artifact names 4. **Java version errors** - Verify you're running JDK 11+: `java -version` - Update `:javac-options` if needed - [ ] If compilation fails, fix errors and commit fixes before proceeding. ### 3.2 Run Development Build - [ ] Start the game: ```bash lein run ``` - [ ] **Test Checklist:** - [ ] Game launches without errors - [ ] Main menu displays correctly - [ ] Mouse cursor changes work - [ ] Click interactions work (left-click on objects) - [ ] Dialogue system works - [ ] Inventory system works - [ ] Save/Load works - [ ] Music plays - [ ] Sound effects play - [ ] Fullscreen/windowed toggle works - [ ] Game exits cleanly **If runtime errors occur:** 1. **"UnsatisfiedLinkError"** - Native library issue - Check that `gdx-platform` with `:classifier "natives-desktop"` is in dependencies - LWJGL natives should auto-extract 2. **"NoClassDefFoundError"** - Missing class at runtime - Check for deprecated/removed classes in libGDX CHANGES - Ensure all dependencies have matching versions 3. **Audio issues** - LWJGL 3.3.x has improved audio device handling - Check system audio configuration - [ ] If any tests fail, fix issues and commit fixes before proceeding. ### 3.3 Build Release Uberjar - [ ] Build the standalone jar: ```bash LEIN_SNAPSHOTS_IN_RELEASE=true lein with-profile steam do clean, compile, uberjar ``` - [ ] Verify jar was created: ```bash ls -la target/advent-standalone.jar ``` - [ ] Test the uberjar: ```bash java -jar target/advent-standalone.jar ``` - [ ] **Test Checklist (uberjar):** - [ ] Game launches from uberjar - [ ] Basic gameplay works - [ ] Steam integration works (if applicable) --- ## Part 4: Packaging (Optional) If you need to create distributable packages: ### 4.1 Update packr Configuration (If Needed) The packr configuration files reference JDK 8 JREs in the `jvms/` directory. These should continue to work since the bytecode targets Java 11. **Why Java 8 JREs still work:** - We compile with `-target 11 -source 11` - Java bytecode is backwards compatible within major versions - No Java 11+ specific APIs are used **Research if updating JREs:** - Azul Zulu JREs: https://azul.com/downloads/?package=jre - packr documentation: https://github.com/libgdx/packr - [ ] If updating to Java 17+ runtime for distribution: - Download Azul Zulu JDK 17+ JREs - Place in `jvms/` directory - Update `build-*.json` files to reference new JRE paths ### 4.2 Test packr Build - [ ] Build Linux package: ```bash java -jar packr.jar build-linux-64.json ``` - [ ] Test the built executable: ```bash ./target/linux/amd64/"Tick's Tales" ``` --- ## Summary of Changes ### play-clj Changes (3 files) | File | Change | Reason | |------|--------|--------| | `project.clj` | libGDX 1.9.5 → 1.14.1 | Match game version, get bug fixes | | `project.clj` | Clojure 1.6.0 → 1.11.3 | Modern version, better error messages | | `project.clj` | Java target 1.8 → 11 | Required for libGDX 1.13.0+ | | `src/play_clj/core_listeners.clj` | Fix `scrolled` signature | API changed in 1.9.12 | | `src/play_clj/core_listeners.clj` | Add `touchCancelled` method | New method in 1.12.0 | | `src/play_clj/core.clj` | Update `:on-scrolled` docstring | Reflect new API | ### Game Changes (2 files) | File | Change | Reason | |------|--------|--------| | `project.clj` | libGDX 1.9.6 → 1.14.1 | Match play-clj version | | `project.clj` | Clojure 1.8.0 → 1.11.3 | Match play-clj version | | `project.clj` | core.async 0.2.385 → 1.6.681 | Bug fixes, performance | | `project.clj` | Java target 1.7 → 11 | Required for libGDX 1.13.0+ | | `src-common/advent/utils.clj` | `ScreenUtils/getFrameBufferPixmap` → `Pixmap/createFromFrameBuffer` | Deprecated in 1.9.14 | --- ## What Does NOT Need Changes Based on analysis, the following do NOT require modifications: ### Keyword-Based Method Calls (All Compatible) All keyword-based method calls in both play-clj and the game remain compatible. The play-clj macro system translates keywords to Java method calls at compile time: ``` :set-fullscreen-mode → .setFullscreenMode() :get-key-frame-index → .getKeyFrameIndex() ``` None of the methods used by your game were renamed between 1.9.6 and 1.14.1. **Verified compatible keywords:** - `(graphics! :set-cursor ...)` ✓ - `(music! ... :set-volume ...)` ✓ - `(sound! ... :set-volume ...)` ✓ - `(slider! ... :get-value)` ✓ - `(label! ... :set-text ...)` ✓ - `(texture! ... :get-region-width)` ✓ - `(animation! ... :get-key-frame-index ...)` ✓ - `(pixmap! ... :set-filter ...)` ✓ - `(particle-effect! ... :reset/:start)` ✓ ### Features Not Used by Game These libGDX features changed but your game doesn't use them: - Box2D physics (API changes) - Bullet 3D physics (API changes) - TiledMap loading (new loaders) - Pools/ReflectionPool (deprecated) - 3D rendering (ModelBatch changes) - JsonValue parsing (case sensitivity) - `Scaling` enum (became object) --- ## Rollback Plan If issues arise that cannot be resolved: ```bash # Rollback play-clj cd /home/noti/dev/play-clj git checkout . lein install # Rollback game cd /home/noti/dev/tickstales/desktop git checkout . lein clean ``` --- ## Completion - [ ] **Final commit with all changes:** ```bash git add -A git commit -m "Complete libGDX 1.14.1 upgrade" ``` - [ ] **Push branches (when ready):** ```bash # play-clj cd /home/noti/dev/play-clj git push origin upgrade/libgdx-1.14.1 # game cd /home/noti/dev/tickstales/desktop git push origin upgrade/libgdx-1.14.1 ``` --- ## References ### Official Documentation - [libGDX CHANGES](https://github.com/libgdx/libgdx/blob/master/CHANGES) - Complete changelog - [libGDX Wiki](https://libgdx.com/wiki/) - General documentation - [LWJGL 3 Documentation](https://www.lwjgl.org/guide) - LWJGL3 guide ### Release Notes - [libGDX 1.14.1 Release](https://github.com/libgdx/libgdx/releases/tag/1.14.1) - [libGDX 1.14.0 Release](https://github.com/libgdx/libgdx/releases/tag/1.14.0) - Major changes - [libGDX 1.13.0 Release](https://github.com/libgdx/libgdx/releases/tag/1.13.0) - Java 17 build - [libGDX 1.12.0 Release](https://github.com/libgdx/libgdx/releases/tag/1.12.0) - `touchCancelled` added - [libGDX 1.9.12 Release](https://github.com/libgdx/libgdx/releases/tag/1.9.12) - `scrolled` signature changed - [libGDX 1.9.14 Release](https://github.com/libgdx/libgdx/releases/tag/1.9.14) - `ScreenUtils.getFrameBufferPixmap` deprecated ### Related Projects - [Clojure Changelog](https://github.com/clojure/clojure/blob/master/Changes.md) - [core.async Changelog](https://github.com/clojure/core.async/blob/master/CHANGES.md) - [packr](https://github.com/libgdx/packr) - JRE bundling tool ### Issue Trackers - [libGDX Issues](https://github.com/libgdx/libgdx/issues) - [LWJGL Issues](https://github.com/LWJGL/lwjgl3/issues)