Skip to content

Integrate approved UI and plugin changes with image dependency replacement - #216

Merged
eriknihlen merged 19 commits into
mainfrom
codex/ci-approved-prs
Oct 8, 2026
Merged

eriknihlen merged 19 commits into
mainfrom
codex/ci-approved-prs

Conversation

@eriknihlen

Copy link
Copy Markdown
Owner

Combine the approved changes so CI tests their interactions in one branch before merging to main. Contributor commits are preserved unchanged.

Includes David Smith's PRs #205, #206, #207, #208, #209, #210, #212 and #213: cross-platform peer tests, mouse-press position, inventory frame sizing, hotkey focus, overlay sizing, plugin themes, experience data and tab icons. Includes #215's replacement of ImageSharp/Chorizite.Core and the CI fixes discovered during validation (native-command failure reporting, deterministic tests and the Intel macOS file-status ABI).

Excludes #204: its focus-loss callback reentrancy bug remains unresolved. #211 is an issue, not a PR.

Validation: combined Release solution build passed with zero warnings/errors. #215 already passed Windows, Linux and both macOS CI jobs. This PR runs the full configured suite on the combined tree. Private build failures on unchanged main and the opt-in live-release test's outdated launcher version remain documented limitations outside this PR's portable CI gate.

Merge with a merge commit to preserve contributor history. No release tag or publication is requested.

davidc-smith and others added 19 commits October 5, 2026 16:41
ParityPeerHub started the in-process hub on the thread pool and went
straight on to subscribe the arm and connect ParityPeerClient. When a
client's first connect beat the hub's bind, the transport asked for a hub
to be started; the parity client's startHub throws by design, so the
transport stopped for good and the scenario timed out after 5 s waiting
for a handshake that could never happen. On macOS this lost the race for
most of the ten Peer* scenarios.

The hub now probes its own endpoint until it accepts a connection (or
fails, or 5 s pass) before anything subscribes.

Claude-Session: https://claude.ai/code/session_014hCYK7XAeS88JWnMdEqgyb
macOS limits a Unix socket path to 104 characters, and its temp folder
(/var/folders/.../T/) already takes about 50. The parity arms' data
folder (acdream-parity/<arm>-<32 hex>/plugin-peers/hub.sock) and the
launcher control tests' pipe names (CoreFxPipe_launcher-test-<32 hex>)
went past it, so UnixDomainSocketEndPoint threw before any test logic ran.
Both now use 12 hex characters and a short prefix. The real paths are
unaffected: the peer hub lives under the cache folder and the launcher's
pipe name is the caller's.

Claude-Session: https://claude.ai/code/session_014hCYK7XAeS88JWnMdEqgyb
The retained UI placed each press and release at IMouse.Position, which
asks the window where the pointer is now. By the time the press is
handled the pointer can be a cell further on, so dragging straight away
lifted the neighbouring item. The press now lands where the last move
event left the pointer; those events arrive in order with the buttons.

Claude-Session: https://claude.ai/code/session_019dvJ5gakBkq3uJyr1PAC3u
The client mounts the inventory inside a resizable window frame, but the
longer pack column resized the inventory contents and re-measured their
anchors instead. When the pack capacity arrived after a taller saved
height, the contents stopped following the frame and left an empty band
below the backpack grid; when it was known at mount, the contents ran
past the bottom of the frame. The column now grows the frame and raises
its minimum height, and the contents keep stretching with it.

Claude-Session: https://claude.ai/code/session_019dvJ5gakBkq3uJyr1PAC3u
No production code pushes an input-dispatcher scope, so the Chat and
Dialog checks never fired and a plain letter hotkey went off while the
player typed in chat. The registry now reads the retained interface's
keyboard focus and modal through the capture slot GameWindow owns.

Claude-Session: https://claude.ai/code/session_01EtugJHhFMqGXY2V6Lz2ZFB
Entering the world restores the window layout, which sizes the interface
root and records the screen size without telling the overlay host. The
next draw then saw no change and never resized the overlay layers, so
they stayed at the pre-game 800x600 and a plugin canvas was clipped
outside that rectangle. It only came right when a world overlay with
something to draw pushed its camera viewport into the shared rectangle,
or the window was resized again.

The host now follows its interface root: the runtime calls FollowRoot
every frame, and the world overlays no longer write the shared
rectangle. They still size their own elements from the camera.

Claude-Session: https://claude.ai/code/session_01SY57mHJLZ6djpWZ5nP37Tw
A canvas paints its own pixels, so it was never told which plugin theme
the player picked under Plugin appearance and could only draw one fixed
look. IUiRegistry now carries the selected theme (kind, picker name and
palette as PluginColors) and raises ThemeChanged on the plugin callback
thread when the player picks another.

The graphical host follows PluginUiThemeSettings through
BufferedUiRegistry.FollowTheme, so plugins read the saved theme from the
moment the interface comes up. The scoped registry both hosts share
forwards the theme and drops a plugin's handlers with the plugin. The
windowless host answers Classic and never raises a change.

Additive with inert defaults: a host that predates this answers Classic.

Claude-Session: https://claude.ai/code/session_01SY57mHJLZ6djpWZ5nP37Tw
ICharacterInfo gains HasExperience, TotalExperience, UnassignedExperience,
ExperienceToNextLevel, AvailableLuminance, MaximumLuminance and an
ExperienceChanged event, all defaulted so older plugins and hosts keep
working. The runtime surface reads them from the local player's own
property bundle (PlayerDescription plus the private Int64 updates), which
both hosts share, and raises ExperienceChanged only when what a plugin
would read actually differs. A logoff resets the values until the next
character's description arrives.

The level maths the character sheet used moves to LevelProgress in Core
and the experience-table loader to ExperienceTableReader in Content, so
the sheet and the plugin surface share one copy. The scoped plugin host
wraps Character so a plugin's ExperienceChanged handlers come off with it.

Claude-Session: https://claude.ai/code/session_01SY57mHJLZ6djpWZ5nP37Tw
<tab> takes the same icon and iconkind attributes as <button>. The tab
already draws an icon through UiSimpleButton, so the parser now reads the
pair through one shared helper for both controls.

Claude-Session: https://claude.ai/code/session_01SY57mHJLZ6djpWZ5nP37Tw
A tab's caption already mutes when the tab is not selected; its icon now
recedes with it. UiSimpleButton draws its icon through an IconTint the tab
overrides, so buttons keep drawing their icons as authored.

Claude-Session: https://claude.ai/code/session_01SY57mHJLZ6djpWZ5nP37Tw
@eriknihlen
eriknihlen merged commit 1ee5a08 into main Oct 8, 2026
7 checks passed
@eriknihlen
eriknihlen deleted the codex/ci-approved-prs branch October 8, 2026 18:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants