Files
gitea-docker/desktop/UPDATE.md
2026-03-30 21:51:50 -07:00

21 KiB

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

    # 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

    cd /home/noti/dev/tickstales/desktop
    git checkout -b upgrade/libgdx-1.14.1
    
  • Verify current build works

    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
    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):

    ;; 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):

    ;; BEFORE
    [org.clojure/clojure "1.6.0"]
    
    ;; AFTER
    [org.clojure/clojure "1.11.3"]
    
  • Update Java target version in :javac-options:

    ;; BEFORE
    :javac-options ["-target" "1.8" "-source" "1.8" "-Xlint:-options"]
    
    ;; AFTER
    :javac-options ["-target" "11" "-source" "11" "-Xlint:-options"]
    
  • Commit this change:

    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):

// InputProcessor interface
boolean scrolled(int amount);

After (1.9.12+):

// 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:

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):
    ;; 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:

    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:

// 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:

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):
    (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:

;; 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:
    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:

    ;; 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):

    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:

    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:

    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:
    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):

    ;; 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):

    ;; BEFORE
    [org.clojure/clojure "1.8.0"]
    
    ;; AFTER
    [org.clojure/clojure "1.11.3"]
    
  • Update core.async version (approximately line 27):

    ;; 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):

    ;; BEFORE
    :javac-options ["-target" "1.7" "-source" "1.7" "-Xlint:-options"]
    
    ;; AFTER
    :javac-options ["-target" "11" "-source" "11" "-Xlint:-options"]
    
  • Commit this change:

    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):

Pixmap pm = ScreenUtils.getFrameBufferPixmap(x, y, width, height);

New API:

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:

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:

    ;; BEFORE
    pm (ScreenUtils/getFrameBufferPixmap x y w h)
    
    ;; AFTER
    pm (Pixmap/createFromFrameBuffer x y w h)
    
  • Commit this change:

    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:

    lein clean
    
  • Compile and check for errors:

    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

    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:

    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:

    LEIN_SNAPSHOTS_IN_RELEASE=true lein with-profile steam do clean, compile, uberjar
    
  • Verify jar was created:

    ls -la target/advent-standalone.jar
    
  • Test the uberjar:

    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:

4.2 Test packr Build

  • Build Linux package:

    java -jar packr.jar build-linux-64.json
    
  • Test the built executable:

    ./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/getFrameBufferPixmapPixmap/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:

# 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:

    git add -A
    git commit -m "Complete libGDX 1.14.1 upgrade"
    
  • Push branches (when ready):

    # 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

Release Notes

Issue Trackers