196 Commits
Author SHA1 Message Date
vii d982cd9506 Merge pull request #2 from CoderDayton/release/0.3.1
Release 0.3.1: packaging, input and shutdown fixes
v0.3.1
2026-09-20 12:53:44 -05:00
vii 65adb3bddc fix(packaging): fail the release when a package glob matches nothing
An unmatched glob reached sha256sum and gh as literal text. The publish job
now collects the assets into an array and stops if a package is missing.
2026-09-20 12:33:26 -05:00
vii 47e23df2e0 docs(changelog): release 0.3.1 2026-09-20 12:31:39 -05:00
vii c0ff1842ee docs(changelog): record the packaging, input and shutdown fixes 2026-09-20 12:30:00 -05:00
vii e073947b91 fix(window): keep the pointer capture owner alive across shutdown
Cross-thread callers take a strong reference under a mutex, so a shutdown
racing SetGameSessionActive no longer frees the owner mid-call.
2026-09-20 12:26:39 -05:00
vii 66de662e5b fix(input): decide pointer capture from state, not coordinates
The router inferred relative mode from SDL reporting zero absolute
coordinates. X11 does; Wayland reports a position that accumulates the
deltas and leaves the window, so every camera-drag event took the
absolute branch and walked Roblox's cursor to the viewport edge.

Motion, button and wheel events now carry the window's relative mouse
mode, and the RMB camera-drag fallback only captures inside an
experience so the app surface keeps a free cursor.
2026-09-20 12:05:48 -05:00
vii 6c3631058c chore(docs): ignore the working plans directory 2026-09-20 12:05:47 -05:00
vii 6829fd00ed perf(graphics): decode ETC2 uploads off the submitting thread
Uploads decode on a background dispatcher and the submit carries a
timeline semaphore wait, so the GPU waits for the texture rather than
the render thread. The gather of the application's compressed bytes
moves there too when they are already mapped; unmapping or freeing that
memory drains the decodes still reading it.

Staged copies gain an explicit host-write barrier. A queue submission
only makes host writes from before it visible to the device, and these
writes land after the submit.

Devices without timelineSemaphore, and submits whose pNext already sizes
arrays by their semaphore counts, decode inline as before.

Blade Ball, median of three: worst vkQueueSubmit 140ms -> 1ms, p99
4.9ms -> 0.05ms, total 2534ms -> 309ms. Frame interval unchanged; its
tail is the engine's own main-thread step.
2026-09-19 18:02:16 -05:00
vii 8be3618cd5 feat(packaging): ship DEB, RPM and pacman packages with each release
The release workflow now builds the three native packages beside the
AppImage and attaches them to the GitHub release with a checksum each.
Nothing is pushed to a distribution repository.

Packages are named nightcap and take their version from the release tag
instead of upstream's project version, so they no longer claim to be
Mocktail 1.0.4. Each variant conflicts with the others because they all own
/usr/bin/mocktail.

The AUR workflow no longer clones or pushes aur.archlinux.org; it refreshes
nightcap-git metadata on demand and uploads it as an artifact. The recipes
move to packaging/aur/nightcap{,-bin,-git}, point at this repository, and
version from the newest release tag.
2026-09-19 01:12:12 -05:00
vii 265b476440 docs(packaging): list Nightcap releases in the AppStream metadata
The releases block carried upstream's 1.0.x history, so a software centre
read the app as newer than every Nightcap tag and would never offer 0.3.x as
an update. Describe the 0.x line instead, and name Nightcap in the project
description.
2026-09-19 01:11:16 -05:00
vii ff905fe5b7 test(input): pin the caret position before a trailing space
SDL_ttf marks only the zero-length substring past the end of the text with
TTF_SUBSTRING_TEXT_END, so a caret left of a trailing space keeps the cluster
position. Cover both carets so the end-of-text branch cannot swallow the one
beside it.
2026-09-19 01:10:54 -05:00
vii 02108a9bb1 perf(input): reuse the TextBox overlay fonts across rasters
Every keystroke re-ran TTF_Init, a fontconfig sort, six TTF_OpenFont calls
and TTF_Quit on the render thread. Hold the opened fonts on the overlay and
reopen them only when the Roblox font or the point size changes, keeping the
current set when a reopen fails. Measured over 100 rasters, 1.59 ms to
0.12 ms per keystroke.
2026-09-19 00:32:31 -05:00
vii 7dd32335ca fix(input): advance the TextBox caret past trailing whitespace
The final cluster rect SDL_ttf reports stops at the last inked glyph, so a
caret at the end of a single-line field did not move when a trailing space
was typed. Use the laid-out width there; wrapped layouts keep the clamp
because their width is the widest line rather than the last one.
2026-09-19 00:32:31 -05:00
vii 5ed6ed5e84 chore(packaging): declare the libpng dependency
Texture overrides decode PNG through libpng, which stubs/CMakeLists.txt
already requires. Lists it in the Arch, AUR, and Nix packages, the thin
dependency installer, and the README build instructions.
2026-09-18 19:30:58 -05:00
vii cef1b3ec4a Merge upstream komaruworld/mocktail into main 2026-09-18 19:29:24 -05:00
vii 8bde1a1c0d Merge pull request #1 from CoderDayton/release/0.3.0
Release 0.3.0
v0.3.0
2026-09-18 19:19:48 -05:00
vii 60e9c5c3ef docs(changelog): release 0.3.0 2026-09-18 19:06:08 -05:00
vii d76e1b6f54 docs(roadmap): move profiling and Discord presence to shipped, add first-load stutter 2026-09-18 19:06:02 -05:00
vii 33c06c063e docs(changelog): note the Sober-style Discord card defaults 2026-09-18 18:54:57 -05:00
vii 9e8afb233a feat(discord-rpc): show the Roblox badge as the default small image
Defaults images.small to the roblox_small asset on the bundled Discord
application, with "Roblox" as its hover text.
2026-09-18 18:54:12 -05:00
vii 7fda1eb239 feat(discord-rpc): show the experience creator and title the card Roblox
Default title is Roblox, details "Playing {place_name}", and state
"by {creator_name}". The creator comes from the games API response
already fetched for the place name. A text field that expands an
empty placeholder is left out, so the state never shows a bare "by".
2026-09-18 18:45:11 -05:00
vii f128e28b83 docs(perf): describe the main-thread pump rest modes and GameMode's governor permission 2026-09-18 18:26:32 -05:00
vii 718e67f9e1 perf(runtime): rest the engine pump between polls instead of spinning
The main thread polls nativeCallMessagesFromMainThread 146k times a second
with nothing to do. Between polls it now rests 100 us: nanosleep when the
governor is performance, TPAUSE (C0.2) when the CPU has WAITPKG, a spin
otherwise. Sleeping under a power-saving governor lets the render thread's
core clock down and drops frames, which is why TPAUSE is the default there.
MOCKTAIL_ENGINE_PUMP_REST=sleep|tpause|spin overrides. The profile trace
gains a slice for pumps that ran a message.
2026-09-18 15:36:54 -05:00
vii c6c354fdb1 perf(graphics): emit ETC2 uploads on the decode pool and stop the trace writer after a failed write
EmitPass reuses the decoder's persistent workers through RunOnDecodeWorkers
instead of creating and joining threads per batch. A failed trace write stops
the writer thread rather than leaving it ticking every 250 ms.
2026-09-18 12:42:36 -05:00
vii 25930d14ff fix(graphics, runtime): honor ETC2 source stride and cut main-loop overhead
ETC2 uploads read bufferRowLength/bufferImageHeight instead of assuming
packed rows. MakeFileObject retains the path field. The main-thread pump
caches its JNI attach, but not the GetJNIEnv fallback, so a VM swap retries.
An idle launch-broker drain skips both locks.
2026-09-18 12:21:29 -05:00
komaruworld 854969457f Fix textures and device info from Nightcap
Ported from CoderDayton/nightcap
2026-09-18 16:55:29 +03:00
vii 65030d8df1 fix(input): hold the pointer position during relative mouse capture
Relative-mode motion carries zero absolute coordinates. The router used
to accumulate the deltas into its pointer position, so a long camera turn
parked the reported position at the viewport edge and Roblox drew its
cursor there when the capture ended. The position now stays where it was
captured while deltas pass through. Zero-coordinate wheel and button
events keep it too, and an unknown position defaults to the viewport
center.
2026-09-18 02:51:03 -05:00
vii 0be5e808c5 fix(runtime): restore the affinity of every thread, not just the caller
sched_setaffinity binds one thread, so the fallback that undid a GameMode pin
only freed the thread that called Start(); the worker threads the fix exists to
protect stayed on the daemon's cores. Walk /proc/self/task instead, and treat a
readdir failure partway through as a failed restore rather than a finished one.

Also stop chrome_trace_writer emitting a valueless "ts" on to_chars failure, or
a bare inf/nan, either of which costs the whole trace instead of one field.
2026-09-18 02:00:58 -05:00
vii 1b030a57eb perf(runtime, graphics): release core-pinning gamemode and parallelize texture uploads
Release the GameMode request when the daemon narrows the CPU mask; the pin
concentrates Roblox's worker pool and is re-applied every few seconds, so
ending the request is the only thing that lifts it. `gamemode: on` keeps it.

Emit texture uploads on worker threads instead of serially inside
vkQueueSubmit, in two passes so mip 0 lands before the levels scaled from it.

Decode ETC2 through a persistent pool and lower the parallel floor to one
128x128 image, so small batches stop running single-threaded.

Document all three in docs/PERFORMANCE.md.
2026-09-18 00:47:57 -05:00
vii 2f5527b8b5 perf(libc_shim): cut path translation cost per file call
Mappings are kept sorted longest prefix first, unmapped paths skip allocation, and the path trace switch is read once.
2026-09-16 21:22:31 -05:00
vii 579cedbf1d perf(textures): pool ETC2 staging buffers and speed up resampling
Staging buffers stay mapped and are reused instead of allocated per upload. Box resampling precomputes column spans and copies repeated rows, with identical output.
2026-09-16 21:22:31 -05:00
vii a7b90e5919 fix(jnivm): stop leaking JNI handles until the table fills
FindClass and GetObjectClass reuse one handle per class, detached threads release their local refs, and local ref deletes and singleton checks no longer scan. A full table logs the classes holding handles. Stale handles above slot 4096 no longer read as C strings.
2026-09-16 21:22:31 -05:00
vii 3bba795ea3 feat(profile): add --profile Chrome trace of Vulkan adapter work
Records presents, GPU waits, submits, ETC2 decode, and pipeline and shader creation for ui.perfetto.dev. Adds a benchmark guide and a trace summary script.
2026-09-16 21:22:30 -05:00
vii 5ce4487d4f feat(discord): add custom presence title, state, and icons
text.title sets the activity name, images.* set the large and small icons and hover text, and text.state may be empty to hide it. Text and image fields expand {place_name} and {place_icon}; fields that render empty are omitted. show_place_name: false now also hides the place thumbnail.
2026-09-16 11:45:30 -05:00
vii c544389dd0 fix(textures): make the crosshair arms symmetric
Move the right and bottom arms out 1px so every arm reaches 12px from the center pixel with a 4px gap.
2026-09-16 11:11:06 -05:00
vii bdb84142d7 docs(textures): ship a crosshair override people can copy in
Adds textures/ with the crosshair PNG named by its ETC2 hash and a README
covering install, naming and how to dump hashes for other textures. Nothing
installs or loads it; copying into ~/.config/mocktail/textures is opt-in.
2026-09-16 04:53:53 -05:00
vii 40698efb7d docs(changelog): release 0.2.0 v0.2.0 2026-09-16 03:25:39 -05:00
vii 3d2a2b3d98 docs(changelog): record the input, storage, and packaging changes 2026-09-16 02:56:11 -05:00
vii 78a314b761 ci(packages): reduce to a branded nightly AppImage
The workflow built DEB, RPM and pacman packages on every push to main and
every pull request, then published them as "Mocktail continuous" with
assets named Mocktail-* and a continuous tag pushed as komaruworld.

Nightcap ships the AppImage and the Flatpak, so the three native package
jobs are removed along with the APT and RPM repository step, which could
not work here regardless: it downloads .deb and .rpm from this repository's
latest release, and the release workflow publishes neither.

What remains runs nightly and on demand rather than per commit, skips the
build when the continuous tag already points at HEAD, publishes
Nightcap-nightly-x86_64.AppImage with a checksum beside it, and tags as
github-actions[bot]. A manual run from another branch builds and
smoke-tests without touching the release.
2026-09-16 02:51:20 -05:00
vii 2d1dd3788b ci(release): pass GH_TOKEN to the AppImage dependency installer
install_anylinux_dependencies.sh now queries the GitHub API for the rolling
release's asset IDs and digests. Without a token it uses the unauthenticated
rate limit, which shared Actions runner IPs exhaust. packages.yml already
passes the token; the release workflow runs the same script in the same
container and did not.
2026-09-16 02:42:06 -05:00
vii 56d3160641 Merge upstream komaruworld/mocktail into main
Takes upstream's AnyLinux dependency rework: the checked-in digest list is
replaced by a name list, and the installer snapshots GitHub asset IDs and
SHA256 digests together at build time, verifying each archive before
installation. This removes the manual hash refresh a998754 had to do.

Keeps Nightcap's FAQ.md over the upstream copy; ours is the same document
with Nightcap paths, RPC on by default, and the Discord play time section.

Keeps TextureManager2 enabled rather than upstream's revert to TM1. Their
mip regression is described on the mobile MipPackStream path, and this fork
already reports real host memory and a PC device profile. Hours of play
show no texture problem, so the workaround is not adopted without evidence
it is needed here.
2026-09-16 02:37:08 -05:00
vii 5db99041bc docs: rewrite the input roadmap items and trim the donation list
Discord Rich Presence item 1 is custom presence fields; the private-server
join item is dropped. The profiling item names the Chrome trace format
instead of Perfetto.

Item 2 covered hot-plug and input release on disconnect, which already
work, so it is now only the button glyph gap. Raw mouse and the pointer
fix move to Shipped.

Drops the BCH donation address from the README.
2026-09-16 02:29:07 -05:00
vii 9ec56338c3 test: fix umask, dash, and scheduling assumptions in three suites
native_update_test wrote approval artifacts with the process umask, which
candidate_approval rejects when group writable. The helper now chmods 0600.

webview_helper_launcher_test drove its fake helper with `dd <&198` under
#!/bin/sh. dash rejects multi-digit file descriptors, so the script never
ran and the packet file stayed empty. It now reads the control socket in
python3, as the adjacent tests in the file already do.

audio_foundation_test asserted the poller thread had run before stopping
it, without waiting for it to be scheduled; it failed about one run in two.
It now waits for the first poll under a bounded deadline.
2026-09-16 02:28:09 -05:00
vii 894ebf8eb7 fix(services): create BrowserTracker storage directories private and usable
The service created its own credential directory with create_directories
and then refused it, because IsPrivateDirectory rejects a group-writable
path and mkdir masks its mode with the process umask. On a umask of 002
that failed every first run; a umask carrying owner bits left the
directory unwritable by its owner instead.

CreatePrivateDirectories creates each missing component and tightens it to
0700 through a descriptor opened O_DIRECTORY | O_NOFOLLOW. Components that
already exist keep their mode and are still judged by IsPrivateDirectory.
2026-09-16 02:28:02 -05:00
vii 6bec8a6c5c feat(input): add input.raw_mouse and keep the pointer inside the viewport
Relative-mode motion reports zero absolute coordinates, so the router
accumulates deltas. The accumulator was never clamped, only the copy sent
to the engine, so a long turn pushed it far outside the viewport and every
reversal was swallowed until the pointer travelled all the way back.

input.raw_mouse sends look deltas in host units instead of guest surface
units. Those differ only when the desktop display scale and the window's
pixel density disagree, as under fractional scaling. Default off.
2026-09-16 02:27:56 -05:00
vii b9e7bc761b docs(roadmap): swap RPC join items for custom presence fields
Name the Chrome trace format for --profile instead of Perfetto.
2026-09-15 22:53:19 -05:00
komaruworld b54c896498 ci hate me? 2026-09-15 19:52:24 +03:00
komaruworld 1cd7b7db8f Fuck ci 2026-09-15 19:42:56 +03:00
vii f87aaca2fb feat(discord): enable Rich Presence by default under Nightcap's own application
Adds Terms and Privacy pages to the site for the Discord application.
2026-09-15 10:34:50 -05:00
vii 901ba615ab fix(runtime): keep fflags.json values over the performance preset instead of failing launch 2026-09-15 10:34:50 -05:00