This is a MODIFIED version of FreeJ2ME-Plus, not the upstream release.

Modified by: NSO Classic
Modified on: 2026-09-29
Base:        FreeJ2ME-Plus 1.52, https://github.com/TASEmulators/freej2me-plus
Released as: freej2me-plus 1.52-nso.29
Source:      https://cdn.nsoclassic.com/tools/freej2me-plus/1.52-nso.29/freej2me-plus-1.52-nso.29-source.tar.gz

             The URL is pinned to this release on purpose. GPLv3 section 6
             wants the source that corresponds to the binary you received, and
             a link to the current download page stops being that the moment a
             newer build becomes current. Pinning costs a commit before every
             republish; the alternative silently expires the source offer.

Changes against upstream 1.52 (Changes in 1.52-nso.10):

Changes in 1.52-nso.29 (bundled client 1.8.15):

  * The bundled game client moves from 1.8.14 to 1.8.15, pinned by digest
    2afdd08820142b5232f647d1e252de108d951deebf49fbe126ac2e866ab3ddbd. The digest was taken
    from the client's own SHA256SUMS asset and re-checked against the bytes the CDN serves
    before the pin moved.

    1.8.15 carries the rebuilt automation (daily quest, tà thú, cave and attendance as scheduled
    jobs, story quest 1-20), per-character auto settings, and the Tier130 skills whose resources
    the client installs over HTTPS on first launch.

  * The emulator's MIDP HTTP and HTTPS connector now performs real startup resource downloads
    with finite connect/read timeouts. HTTPS keeps the JVM's default certificate and hostname
    verification; clients using the startup installer must be paired with an emulator build
    containing this adapter. Legacy advertisement URLs retain their local placeholder behavior.

    This adapter landed after 1.52-nso.28 was published and first ships in this build; 1.8.15
    is the first bundled client that needs it.

Changes in 1.52-nso.28 (bundled client 1.8.14):

  * The bundled game client moves from 1.8.12 to 1.8.14, pinned by digest
    8f1e3200f4cb1916ae215cb547e83b1491a22553227113d525c16ea7f197e0e7. The digest was taken
    from the client's own SHA256SUMS asset and re-checked against the bytes the CDN serves
    before the pin moved.

    1.8.14 carries the automation work that had been sitting unreleased on the client's main
    branch: the tick-driven hunt core that removes the 5 s lockout behind both the stand-still
    and its recurrence, and the runner taking ownership of its own loop, which restores the
    player settings that were being dropped and finishes group massacre. Desktop players were
    still receiving 1.8.12 until this build.

    There is no 1.8.13 to skip past: that version's jar reached R2 but its publish run died on
    a CDN race before the release existed, and the client build is not byte-reproducible, so
    the version was abandoned rather than rebuilt into different bytes.

Changes in 1.52-nso.27 (bundled client 1.8.12; macOS installer, slimmer runtime):

  * The bundled game client moves from 1.8.10 to 1.8.12, pinned by digest
    680bd2fe4d37486a77c9553a537064fb39f791bc727f837f05194004b5e1aee5. That digest was
    verified byte-identical across the GitHub release asset, its SHA256SUMS and the CDN
    object before the pin moved.

  * macOS desktop builds now ship an unsigned .pkg installer that puts NSO Classic.app into
    /Applications, alongside the ZIP. The package is not Developer ID signed or notarized,
    so Gatekeeper still asks the player to confirm the first launch, and a Mac under a policy
    that forbids unidentified software refuses both.

  * The bundled macOS runtime is now a jlink image linked from the pinned Temurin JDK rather
    than the full JRE, and it carries the notices of every module it contains, including
    jdk.crypto.ec so the TLS providers the emulator can reach over HTTPS stay present. The
    Windows build is unchanged and still carries the pinned JRE.

  * The macOS launcher refuses to start while another emulator is already working in the same
    support directory: a kernel-held lock plus a scan for an emulator JVM whose working
    directory is that directory covers a second launch, a legacy ZIP copy and the replacement
    JVM the emulator's Close/Restart action leaves behind. A legacy copy started first is
    still outside the launcher's control.

  * The macOS bundle carries the NSO Classic app icon, and the GPLv3 notice names this
    release's exact corresponding-source archive and digest.

  * Multi-OS Desktop Packaging:
    - Added native macOS App Bundle (NSO Classic.app) scaffolding and packaging scripts.
      Routes application state/RMS directly to ~/Library/Application Support/NSO Classic.
    - Added Win32 native wWinMain C stub launcher (nso-classic.exe) hiding console window
      and routing state to %LOCALAPPDATA%\NSO Classic with Unicode path handling.
    - Bundled Eclipse Temurin OpenJDK 17.0.14+7 JRE into portable zip releases.
    - Added automatic canvas focus (lcd.requestFocusInWindow) upon window creation.


  * The AWT runner advertises a physical keyboard through the private property
    `freej2me.keyboard=qwerty` instead of overwriting `microedition.platform`,
    which is the emulator's identity and is read by MIDlets for capability
    decisions. Without this, a typed `2` reached the MIDlet as multi-tap `a`.

  * `Display.postInputEvent` no longer spawns a thread per event. Input events
    go through the serial queue, so back-to-back keyTyped/keyPressed pairs can
    no longer be delivered out of order.

  * `MobilePlatform.keyPressed` routes the CLR keycode to a focused lcdui text
    editor as backspace, so Backspace reaches an lcdui text field.

  * `Connector.open("socket://host:port")` returns a real TCP socket. Upstream
    fell through to its HTTP implementation, so a MIDlet that cast the result
    to `SocketConnection` -- the only thing the CLDC contract allows -- died
    with a ClassCastException before sending a byte. No online game could
    connect. `openInputStream`/`openDataInputStream` on a `socket://` URL now
    own the connection, as CLDC requires: closing that stream closes the
    socket.

  * Each keystroke is delivered to the screen that was current when it
    arrived. `MobilePlatform` held the receiver in one shared static field
    that every later input event overwrote, while the queued event only read
    it when the event thread ran, so a character typed just before a screen
    change landed on the replacement screen -- on the game's login and
    registration forms that meant a password fragment, and a Backspace,
    reaching the wrong screen.

  * The editable field row is drawn once, by a shared painter. `TextBox` (a
    Screen) and `TextField` (an Item) each carried their own byte-identical
    copy of it, so every rule about what an editor may show had to be written
    twice and kept in step. It was not: a `PASSWORD` field drew the credential
    in clear text for as long as the screen was up, and the keypad character
    picker's candidate was drawn at the caret before the picker had been used,
    so a typed character was displayed with an extra one after it.

  * Enter commits an editor instead of inserting a character, on both editor
    paths. The AWT runner maps Enter to FIRE, and FIRE means "insert the
    picked keypad candidate"; on a PC keyboard there is no candidate to
    insert, so the key did nothing and the field could not be left without the
    mouse. FIRE now inserts only while the picker is actually in use. On a
    `TextBox` it otherwise runs the screen's first command; on a `TextField`,
    which is the editor the game's login form is built from, it runs the
    field's own command, or the screen's first command if the field has none.
    1.52-nso.6 carried this for `TextBox` only, so the login form it shipped
    with still appended a character on Enter.

  * A press on the command bar the native screens draw runs the command under
    the pointer. The bar was drawn but never hit-tested, so on a touch build
    the visible OK and Cancel did nothing. A focused item's own command is
    drawn centred between them and is hit-tested there; 1.52-nso.6 read that
    press as the screen command whose half it fell in.

  * A `Form` item's default command runs at all. `Displayable.render` drew the
    label and `Form.getItemCommand` returned the command, but nothing ever
    called its listener, so on the game's login form the drawn command was
    decoration on every input path.

  * The native screen chrome is a two-tone monochrome sheet - paper, ink, one
    rule - with the caret, the keypad candidate and the charset hint each
    given their own colour, so what the field is doing is legible instead of
    inferred from position.

Distributed under the GPLv3, as upstream is. See LICENSE.

This notice is required by GPLv3 section 5(a) and ships in both the binary
archive and the corresponding source tarball.
