3.0.9 - #15
Merged
Merged
3.0.9#15
Conversation
Changed all Webclient instances in the updater to HttpClient. Cleaned up code quality slightly
Make the updater use HttpClient instead of WebClient
Hid FriendTab, Added Update checker on startup, Included needed .NET components in build, Fixed crashing issues at startup.
Added specific numbers option to TTS, "18.67" instead of just "18.6", Fixed issue causing spark black screen using oculus dash, Added echo combat dashboard, Updated overlays (they are still broken a bit), Fixed issue causing settings to reset for spark, Updated loading screen tips option, Fixed 60hz option in replay and updated replay accuracy.
Added spectator option to player pings Fixed TTS
Added so workflow builds correctly
Added FRIENDS_BOT_URL constant for future use.
changed a lot, unsure if it all works, tested it and found 0 issues but you never know.
… the 'Are you sure?' prompt on closes.
Full UI overhaul, Media controller bug fixed not detecting clicks, Clips Controller bug fixed not detecting clips, Performance boost by updating event logger, Updated update function, Removed useless code and update systems, Improved theme controller, Added session logger, Tracking all time spark usage when echo is open (minutes)
added pvu blue as a colour theme
MainLoop runs on the thread pool via Task.Run. Thread.Sleep held that worker for the whole inter-frame delay instead of releasing it
MatchPlayer converted between sample counts and seconds using StatsIntervalMs, which is the rate the fetch loop targets, not the one it gets. Windows wakes on 16 ms ticks, so 60hz is more like 40hz
PingIPList was async void, so an exception had no Task to surface on and went straight to the runtime. It pings every address on the subnet, where failures are the normal case
Spark already banked lifetime playtime locally in SparkSettings.totalPlaytimeSeconds but never did anything with it beyond the All-Time figure on the Session card. This contributes it to a shared pool and shows the community total alongside the personal one. Clients report their running total rather than a delta, which makes the call idempotent: it rides the existing 60s CCU heartbeat, whose response nobody checks, so a dropped reply, a retry or a duplicate has to cost nothing. An install that was closed for a week just catches up on its next report. The reported identifier is SHA-256 of the MAC rather than Logger.DeviceId itself, which is the raw MAC. The pool needs to tell installs apart to de-duplicate and rate-limit them; it does not need to know whose they are. Gated behind the new shareGlobalPlaytime setting, on by default, with a toggle in Settings > General. Also splits playtime accrual out of UpdateSessionCard into BankPlaytime and moves it ahead of the window-visibility gate. Playing with Spark minimised to the tray is the normal case, and while accrual sat with the rest of the Session card that time was credited to neither the local nor the global total. Requires the matching /playtime endpoints on the Railway backend; until those deploy the card shows "--" and reports are swallowed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reports a display name alongside the playtime total so the pool can be ranked, not just summed. Prefers the Discord identity because it is the one of the two a user cannot casually retype -- client_name is free text in Settings, so it makes a weak claim to an identity. Reads global_name ahead of the username handle, matching what the rest of the app shows, and guards on discordUserData rather than IsLoggedIn alone: the latter only checks for a token, and the profile fetch that fills it can still have failed. An install with neither name still contributes to the community total, it just gets no row on the board. The settings tooltip previously promised "no username", which adding a name makes false, so it now states exactly which name is sent and when. Version to 3.1.8 across the csproj and the MSIX manifest; the MSI picks it up on its own via GetAssemblyIdentity against the built assembly. Requires the matching /playtime/leaderboard endpoint on the backend. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Quest Spectator could only find people by scanning the public match API, which lists neither private matches nor social lobbies — so it could never follow anyone into one. Friends presence has no such limit: a player's own Spark knows the session id it is in and publishes it, whatever kind of session that is. - Rename the feature to Simple Spectate Mode and present it as "spectate anyone": the public API still covers non-friends in public matches, and presence extends that to private matches and lobbies for friends. - Add self-follow, so two PCs on one Discord account can spectate each other. Both share a presence row, so the spectating copy suppresses its own pushes or it overwrites the session it is reading. - Read lobby session ids out of the client's r14 log. The /session API answers -6 with no id in a lobby, so this is the only way a friend in a lobby is joinable. Matches keep the API's id. - Heartbeat presence every 30s. It was only pushed on connection-state change, so anyone in one match past the bot's 120s staleness window went silently offline to their friends. - Register with the bot before the first push. Presence is an UPDATE, and registration only happened when the Friends tab was opened — a tab that is off by default and whose content WPF never instantiates while hidden, so most users were pushing into nowhere. - Theme the Friends tab: colours now come from the theme via DynamicResource and enum-driven triggers rather than hardcoded hex, so it repaints live. - Friends tab on by default, with a settings migration so existing users get it. Changing a default only reaches fresh installs otherwise, since Save() writes every key. - Fix LogRow(LogType.File, ...) calls that passed no file name and so logged nothing, including two pre-existing ones in the auto-follow path. Version 3.1.9. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The "[NSLOBBY] requesting N player session in game session {guid}" line is
only written when the client actively matchmakes a session — not when it is
placed in one or rejoins. Measured across 62 real r14 logs, the room the
client was actually in came from "lobbyid" in the Oculus room data-store
update, and NSLOBBY was:
- absent entirely in 34 of those logs, so the reader would have reported
no session at all for the majority of lobbies
- stale in 1 more, naming a room the client had already left
and there was no log where NSLOBBY knew something lobbyid did not.
So lobbyid is now the sole authority: most recent wins, and the all-zero
guid the client writes on leaving clears it. Two things this has to avoid,
both confirmed against the logs and covered by tests:
- "lobby_id" (underscore) in ovr_RichPresence_Set lines is often the
all-zero guid *while* in a room, so the key match is strict.
- the session teardown markers arrive *after* the next room's lobbyid
during a lobby-to-match move, so honouring them would clear a room we
had just correctly picked up. They are no longer consulted.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
In a social lobby the game API answers error -6 with no session id, so both join-link boxes sat on their placeholder and a lobby could not be shared or copied. EchoLogSessionReader already knows the room from the client's own log, so use that whenever the connection state is InLobby and the frame's session id otherwise. Both boxes now go through one writer rather than being set from lastFrame in three places — the previous sites were all inside a `lastFrame != null` check, which is never true in a lobby, which is precisely when the log is the only source. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The join link reads CurrentSessionId from the UI tick, and the getter used to do the file work inline — rate-limited to once a second, but still disk I/O on the UI thread. A watcher refreshes it off-thread instead and the getter just returns what it last found. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The log line was written before the request went out and the response was never checked, so a rejected push — expired Discord token, bot down — read exactly like a successful one. That is worse than no line at all when the question being asked is "why can't my friend see me". Successes still only log when what we advertise changes, since the heartbeat repeats every 30s. Failures always log, and clear the dedupe so the next success is visible rather than being swallowed as unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Added replay analyser as a tab, merged from separate repo, Fixed combat dashboard kill feed not updating, Added name converting for combat gun names and stuff, Added more TTS speed options, Added private match only option to Ping Spike TTS, Added option to fix broken .butter files to convert to echoreplay files, Updated how butter files record to hopefully avoid future corruption.
Updated installation link and .NET version in README.
Added sections for Idle Dash and Combat Dash with images.
Fix three async/timing bugs in the fetch loop and quest scanner
Added a new image for Arena Dash in the README.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changelog for everything are in commits. Ignore secretkeys, will always fail unless .bak gets removed