Quantum Wake 0.1.0 - #1
Merged
Merged
Conversation
Research (docs/): analysed seven existing SC log tools and established two constraints empirically over 403 MB / 144 log backups: - SC 4.9 emits no combat events. Zero <Actor Death> / <Vehicle Destruction> despite 22 incapacitations across 12 sessions, so a killboard is not buildable from current logs. - No live player position is logged, so the minimap must be a topology map driven by an inferred location state machine, not a positional radar. Phase 1 (src/): .NET 10 solution with envelope parsing, 13 event types, install discovery, and a backfill/verification CLI. 46 tests over real log fixtures. Backfill reports zero unmatched tags and cross-checks exactly against independent greps. Three format quirks found and handled, all invisible to grepping: - entries span multiple lines and continuations carry their own timestamp (1,274 lost notifications, 15%) - <Calculate Route> has a second origin-less form (652 lost routes, 49%) - <RequestLocationInventory> has an expected "no inventory" failure variant
- LocationResolver turns structured log ids into mappable places (Stanton4b_RayariHydro_Cantwell -> Rayari Cantwell, Clio). Unknown ids survive as unmapped nodes carrying their raw id so new CIG content shows up as a gap rather than vanishing. - LocationStateMachine infers position from discrete signals and exposes a confidence level, since the logs carry no player position. - SessionBuilder aggregates a log file into a SessionSummary: ships with time in seat, locations, quantum jumps, contracts, and a timeline. - Playtime is split by gamerules so SC_Frontend hangar idling no longer counts as play - roughly 70% of logged activity in the sample set. - ContractNameParser decomposes ids like Covalex_Stanton_VeryHard_RecoverCargo into issuer, system, difficulty and type. Fixes an acronym bug in camel-case splitting that rendered FTL as "F T L". 108 tests passing.
- LogTailer follows the live Game.log with rotation handling and carries partial multi-line entries across polls. - SessionStore (SQLite) caches parsed sessions, keyed on a length plus write-time fingerprint, turning a 30s cold backfill into an instant warm start. LogLibrary rolls sessions up into library-wide totals. - ASP.NET Core server on 127.0.0.1:31337 serving REST plus a Server-Sent Events feed. The SignalR hub stays mapped as the Phase 6 multi-client seam, but the UI uses SSE so the page needs no bundled client and makes no outbound requests. - Dashboard: Now, Map, Sessions, Ships, Places, Contracts. One web UI, loaded by the browser today and by the overlay WebView2 next. - Map is a topology view - bodies on fixed rings with locations clustered around them - because the logs carry no player position. Unmapped ids are drawn rather than dropped. Ship metric corrected: SC 4.9 emits no seat-entry event (497 of 497 vehicle events are ClearDriver), so time in seat was always zero. Flights are now the headline metric and time aboard is an estimate from the last known stop, capped at two hours and labelled as approximate throughout. Verified against the real install: 145 sessions, 6d 5h in game, 22 ships, 73 places, 112 contract archetypes. 111 tests passing.
- SCCompanion.Overlay: transparent always-on-top WPF window hosting WebView2, loading the same web UI with ?overlay=1. Uses documented Win32 styles only (WS_EX_TRANSPARENT | TOOLWINDOW | NOACTIVATE | LAYERED) plus RegisterHotKey for Ctrl+Alt+O. No injection, no DirectX or WinAPI hooking, so nothing here should interest Easy Anti-Cheat. Starts the server itself if one is not already listening, so the user launches one thing. - Phase 5: <Actor Death> and <Vehicle Destruction> implemented from the archived format with NPC heuristics and kill classification. Matches nothing on 4.9 by design; the UI explains the zero rather than showing a bare count. - start.ps1 builds and launches dashboard plus overlay. - README and docs/phases-2-5.md. Verified end to end: 145 sessions, 6d 5h in game vs 8h 12m in menus, all endpoints 200, overlay launches and spawns the server successfully. 127 tests passing.
- Site-token classification gives facilities a real kind instead of Unknown (ASD Delve -> Outpost, Shubin -> Mine, Monorail/TransportHub -> Station, IndyFarm -> Outpost). - Handles ids carrying the system anywhere but the start, such as TheCollectorAsteroid_Stanton4 and Outpost_OLP_Stanton1b_Vivere. - Adds places known only by name: Levski, GrimHEX, Port Tressler, Seraphim Station, Everus Harbor, Baijini Point. - INVALID_LOCATION_ID is a sentinel, not a place, and is now discarded before it reaches the map or the stats. Coverage went from 68 of 73 ids mapped with 24 classified Unknown, to 72 of 72 mapped with none Unknown, across eight meaningful kinds. 136 tests passing.
SCCompanion.LogSim generates a fake install so the app can be exercised without playing - and so the dormant combat parser can be tested at all, since real 4.9 logs contain no combat events. The generator deliberately reproduces the format's ugly parts, because every hard case in the parser is a quirk: multi-line entries whose continuations carry their own timestamp, notifications firing four times with differing Action values, [SPAM] duplicates, both <Calculate Route> forms, the INVALID_LOCATION_ID variant, untagged lines, and heavy background noise. Verified: 12 generated sessions parse with zero unmatched tags and yield 79 actor deaths plus 25 vehicle destructions, the first end-to-end proof that the dormant combat path works. Pointed at that install the dashboard reports 59 kills, where the real install reports 0. Styling: the web UI and the overlay splash now follow Star Citizen's HUD language - chamfered panels with corner brackets, thin glowing cyan rules, wide-tracked uppercase labels, scanline overlay, and a starmap-style map with reticle ticks and glow. Fonts are Windows built-ins (Bahnschrift) so no webfont is fetched and the no-network guarantee holds. Fixes a real bug the simulator exposed: the session cache was global, so pointing the app at another install merged its sessions into the LIVE totals (157 instead of 145). The database is now keyed by a hash of the install root. Also corrects the CLI combat readout, which looked for a "combat.kill" event kind that never existed. 136 tests passing.
The overlay could not be resized, moved or even closed without Task Manager. WebView2 fills the client area and swallows the mouse, so WPF never saw its own resize borders. - WebView2 is inset by an 8px gutter and WM_NCHITTEST claims that gutter, handing the edges back to the system resize loop. - Interactive mode now shows a header bar (drag to move, close button) and a corner grip, with a lit cyan border so the mode is obvious. Pass-through mode stays a clean readout. - Position and size persist to overlay.json, with an on-screen check so a remembered position on an unplugged monitor cannot hide the window. docs/untapped-signals.md surveys what else the logs hold. The two best finds: - Purchases are fully logged - shop, item, price and a Success response - which gives a real spend tracker. Prices seen from 265 to 475,200 aUEC. - <ObjectiveUpserted> carries MISSION_OBJECTIVE_STATE_COMPLETED and joins on the missionId we already capture, closing the contract-completion gap that phases-2-5.md listed as unresolved. Also documented: loadout by attachment port, fleet size from VehicleListQuery (11 to 17 ships over time), and hangar/ship-elevator activity. 136 tests passing.
…ogos Authorship set to nekron across assembly metadata, README and UI. New parsing, all verified against the real install: - Purchases. SendShopBuyRequest paired with RmShopFlowResponse, counted only when the server answers Success. 216 confirmed purchases, 27,972,265 aUEC. - Contract outcomes. ObjectiveUpserted carries MISSION_OBJECTIVE_STATE_* and joins on the missionId we already had, closing the completion gap: 222 contracts seen, 139 completed, 2 abandoned. - Loadout. AttachmentReceived, deduplicated by port and item class since it refires on every spawn. 57 slots. - Fleet size. VehicleListQuery reports owned vehicles; 20 at peak. Ship names are not logged, only the count, so the roster shows what was actually flown. - Stash. Location inventory scope keys are opaque, but the query follows the named location request, so items can be attributed to a place. 4 locations, 44 item types at microTech LEO. Fixes a real bug nekron spotted: ObjectContainer_RestStop is a generic id used for every rest stop, so counting it merged unrelated destinations into one bucket. Generic destinations are now rewritten to the place actually reached - a trip logged as Area18 to "Rest Stop" really ended at microTech LEO. Generic "Rest Stop" fell from 79 to 24, the remainder being trips with no arrival signal, which stay honestly labelled rather than guessed at. Manufacturer logos extracted from the official Fankit and mapped to the ship prefixes in the logs, with trademark attribution in the footer. The fankit fonts are Banu and Xi'an alien scripts, so they are no use for UI text. 139 tests passing.
Clicking anything inside the overlay did nothing, while dragging the WPF header worked. Two causes, both real: - WS_EX_NOACTIVATE was applied permanently and only WS_EX_TRANSPARENT was cleared on unlock. A window that cannot activate never takes focus, and WebView2 will not route mouse input without it. Both flags now toggle together and the window claims focus for the browser. - AllowsTransparency is not supported with WebView2. In that mode WPF renders a layered surface and the OS hit-tests it from the alpha WPF painted; the browser draws itself through child HWNDs, so the region behind it stays alpha 0, reads as "no window here", and drops clicks before the browser sees them. The window is now opaque with a uniform layered alpha on the HWND, which keeps hit-testing intact. Also adds view navigation, which the widget had no way to do at all - it was stuck on the Now view: - Ctrl+Alt+Left / Ctrl+Alt+Right page through all nine views. These are global hotkeys driven from the shell into the page via ExecuteScriptAsync, so they work while click-through is on and the browser receives no input. - A slim scrolling tab strip is kept in overlay mode. 139 tests passing.
Neither registered, and both had real causes in the log rather than the app.
Deaths: <Actor Death> is gone and an Incapacitated notification is not always
raised - a session with three confirmed deaths logged zero of them. What the
game does still emit is a burst of corpse item-recovery lines, one per carried
item, as it records what was being held:
<Adding non kept item [CSCActorCorpseUtils::PopulateItemPortForItemRecovery...]>
Three deaths produced bursts of 40, 38 and 19 lines, minutes apart, so they are
grouped by a 30 second gap rather than counted directly. Deaths now populate on
current game versions; kills stay zero, since no event identifies a killer.
Ship swaps: SC 4.9 logs no boarding event, so a ship was only recorded when the
player got out of it. Retrieval is logged, but carries a bare entity id:
<CEntityComponentShipListProvider::SetVehicleSpawnedInformations>
VehicleEntityId: [771478242932], LandingArea: nekron's
The model name appears separately, embedded in navigation chatter as
DRAK_Corsair_771478242932[771478242932]. Those incidental sightings are now
harvested into an id-to-name registry, gated on a substring test so the
backfill does not pay for a regex on every line. Retrievals whose name is not
yet known are parked and resolved when it arrives.
Verified against the live session: 3 deaths, 2 ship retrievals, current ship
reads DRAK Corsair, zero unmatched tags.
139 tests passing.
Deaths were counted but never displayed - the card showed only incapacitations and kills. Adds a Deaths row and rewrites the note to say plainly that deaths are inferred from corpse item-recovery bursts, that an Incapacitated notification is not always raised, and that kills cannot be counted at all because no surviving event names a killer. Sanity-checked the inference across 30 backups: 21 corpse bursts against 10 raw incapacitation notifications, at 1-9 per session. That rules out the event firing for every nearby NPC corpse, and it is an item *recovery entitlement*, which is personal. The line names no player, though, so this is strong evidence rather than proof - hence the wording on the card.
The tool had no concept of income at all - only spend. Commodity kiosks log
every trade with shop, amount, quantity and transaction mode:
<CEntityComponentCommodityUIProvider::SendCommoditySellRequest>
shopName[SCShop_Admin_lt_base_g] amount[1058400.000000] quantity[288]
transactionMode[ResourceContainer] Cargo Box Data: [boxSize[16] | unitAmount[18]]
Individual sales run over a million aUEC, which dwarfs everything else the
economy view was showing. Across the library: 7,301,081 aUEC earned from
19 trades against 27,972,265 spent on items, for a net of -20,671,184 -
2,211 SCU sold through Admin lt base g alone.
Unlike item purchases there is no server response to pair with, so trades are
recorded as requested rather than settled, and the Spending page says so.
Also swept the current session for anything else unparsed. The remainder is
engine noise - particle limits, loading platform chatter, terrain
invalidation. Docking tube states only ever read eES_Unready, and the
FreightElevator volume is loading-platform logging rather than cargo
manifests, so neither is worth parsing.
139 tests passing.
Both pages were flat walls of engine identifiers: 57 ports like wep_stocked_3, helmethook_attach and Eyedetail_ItemPort, and 44 item codes per stash location with no ordering beyond the alphabet. Loadout slots now bucket into Weapons, Weapon attachments, Throwables, Armour, Medical, Utility, Carried and Appearance, with cosmetic character ports pushed last where they belong. Port names are also humanised - weapon_attach_hand_right reads as "Weapon hand right". Stash items bucket by item class into Weapons, Ammo, Attachments, Throwables, Armour, Medical, Tools, Food & drink and Containers. Classification lives in the data layer rather than the view, so it is shared by any host and can be tested. Matching is by keyword with a deliberate order - magazines and barrels are checked before weapons, or every _mag would read as a rifle - so ports and items added in future patches still land somewhere sensible instead of breaking the page. Verified against the real library: microTech LEO Rest Stop resolves to 23 armour, 11 weapons, 4 ammo, 2 medical, 2 tools. 139 tests passing.
Fleet, Loadout and Stash had grown past the point where scanning them by eye works - 22 ships, 57 equipment slots, 44 item types in one stash. - Fleet gains a last-flown dropdown (any time / 7 / 30 / 90 days / 6 months) and a name search. Ships now carry FirstFlown and LastFlown, and each card shows "last flown 3 days ago" rather than nothing. 8 of 22 ships were flown in the last 30 days. - Loadout search matches either a slot name or the items inside it, narrowing a slot to just its matching items instead of hiding the whole slot. - Stash search matches a place name or an item, so "where is my sniper" answers in one glance across every location. Filtering is client side over data already fetched, so it is instant and needs no round trip. Input is debounced at 120ms. 139 tests passing.
"and N more" was a dead end - it told you something was hidden with no way to reach it. Overflow rows now stay in the DOM behind a "show N more" toggle, so expanding costs no re-render, and truncation is skipped entirely while a search is active since hiding matches the user just searched for would be perverse. The sessions table was rendering all 146 rows at once. It now pages 25 at a time with controls at the bottom showing the range and page count. Applies to loadout slots (6 shown) and stash groups (8 shown).
The widget was the full page at a smaller width, which wastes space that matters when it sits over the game. Overlay mode is now genuinely condensed while the browser keeps everything: - Base type drops to 11.5px, card padding and gaps roughly halve. - Session figures sit in one row of compact stacked pairs rather than three full-width statlines, and the Now grid goes two-up with the location spanning the top. - Prose is page-only: captions, explanatory notes, the map legend, filter controls, the footer and the sessions pager are all hidden in the widget. - The live feed keeps a 12-entry tail and drops the secondary detail column; the full feed stays on the page. - Tables, bars, ship cards and summary tiles all get compact variants. - Default window shrinks from 420x560 to 330x440. Same markup and one stylesheet throughout - the widget is a CSS mode, not a second UI, so nothing has to be built twice.
…lter Adds an All time / 7 / 30 / 90 days / 6 months / year dropdown and a search over ship and location. The summary tiles now recompute from the filtered set rather than always restating lifetime figures, so they answer "how much did I play this month": 12 sessions and 11.5h in the last week, 37 and 39.5h in the last month, against 146 and 150.7h all time. Tiles also switch to metrics that are meaningful per period - sessions, in game, in menus, quantum jumps, contracts, deaths - and the table gains a Deaths column, which meant exposing Deaths on the sessions endpoint.
Every list was showing engine identifiers - behr_rifle_ballistic_01_white02, ANVL_Hornet_F7CM_Mk2 - because that is all the logs contain. The game ships the mapping to real names inside Data.p4k, and it turns out to be reachable with pure managed code. Data.p4k is a 150 GB ZIP64 archive of 1.36 million entries whose central directory is entirely standard; what defeats normal ZIP readers is the payload codec, ZStd method 100. So P4kArchive walks the directory by hand and hands the compressed bytes to a managed ZStd decoder. unp4k is not involved, nothing is unpacked to disk, and the file is opened shared and read-only so it is safe while the game runs. Data\Localization\english\global.ini is unencrypted: 10 MB, ~90,000 strings, yielding 9,549 item names and 663 vehicle names. Results: behr_rifle_ballistic_01_white02 -> P4-AR "Boneyard" Rifle klwe_pistol_energy_01 -> Arclight Pistol crlf_consumable_healing_01 -> MedPen (Hemozal) ANVL_Hornet_F7CM_Mk2 -> Anvil F7C-M Super Hornet Mk II Because the game patches, the extracted subset is cached to local app data stamped with Data.p4k's write time and rebuilds itself when that changes. POST /api/names/refresh forces it, and /api/install reports how many names are loaded. Classification still runs on the raw class, deliberately: the engine name carries the type information, while "P4-AR Boneyard Rifle" does not reliably contain the word rifle. Variant suffixes fall back to their base class, and every lookup falls back to the raw id, so a missing or updated archive degrades the display and never the app. 139 tests passing.
Keys occur as both item_Namexyz and item_Name_xyz. Only the first form was handled, which silently hid everything using the other - most armour among them. Trimming the separator lifts item name coverage on the real library from 56% to 73%: rsi_odyssey_undersuit_01_01_01 now reads "Beacon Undersuit White", and cds armour resolves to "Arden-SL Helmet Balefire", "Geist Armor Arms Rogue". The remaining raw ids are cosmetics (hair, brows, body meshes), commodity carryables and engine internals, none of which have a localization entry at all.
global.ini carries location names alongside item and vehicle ones, and they are things no rule could derive: RR_P5_L2 is "Gaslight", RR_MIC_L1 is "MIC-L1 Shallow Frontier Station", Pyro2_Outpost_col_m_scrp_indy_001 is "Sunset Mesa". The hand-written resolver was rendering those as "Pyro V L2 Rest Stop" and "Outpost on Monox". Location keys carry no functional prefix, so they are recognised by the id itself, with description and address suffixes excluded so a station's blurb never becomes its name. Grammatical ",P" variants are trimmed. The resolver now prefers an official name when one exists but still takes system, body and kind from the id, since the name alone does not carry them. It reaches the resolver through an ambient hook because the resolver is static and called from deep inside parsing; the cache is cleared when names load so nothing resolved earlier goes stale. Shop inventories remain out of reach - those entries are encrypted rather than merely ZStd-compressed, and reading them needs a decryption key. Parked for now.
Adds a period dropdown (any time / 7 / 30 / 90 days / 6 months) and shows the age against each item - "A03 Sniper Rifle, last seen 2026-08-06". This needed per-item timestamps rather than one per location: a location's most recent visit says nothing about when a particular item was last seen in it. The stash aggregate now keeps the newest sighting per item, and item counts follow the filter. Of 94 stored items, 26 were seen in the last week. The period filter always applies per item, while a search matching a place name still keeps that whole location.
nekron spotted that "Crusader LEO Rest Stop" is really Seraphim Station. The same rule was mislabelling the single most visited location in the library: RR_MIC_LEO showed as "microTech LEO Rest Stop" when it is Port Tressler, with 142 visits. There is no RR_*_LEO key in the localisation table - the game files these under Stanton1_Transfer, Stanton2_Transfer_Seraphim and so on - so the derived-name fallback was inventing a plausible but wrong label. LEO stations are now mapped explicitly and typed as Station rather than RestStop: RR_HUR_LEO -> Everus Harbor RR_ARC_LEO -> Baijini Point RR_CRU_LEO -> Seraphim Station RR_MIC_LEO -> Port Tressler Four tests asserted the old names; they were encoding the bug and have been corrected. Separately, loadHistory called each view's render in sequence, so a throw in an early one silently blanked every later one - and boot()'s retry loop swallowed the error, leaving no clue why a page was empty. Renders are now isolated and failures surface in a banner on the page instead of vanishing into the console. 141 tests passing.
nekron pointed out the page was a story of weapons moved and removed rather than a loadout, and that was exactly right: attachment events fire on every spawn and inventory refresh, so each slot accumulated everything ever put in it. The right hand slot listed 88 items, Fizzz Cola among them, ranked by frequency - which describes handling habits, not equipment. Slots now keep both ends of the sighting window and lead with the most recent occupant, which is what is actually equipped. Reading the real library it now resolves to a coherent kit: Arclight Pistol sidearm, P4-AR "Boneyard" Rifle, Custodian "Desert Shadow" SMG, Neutrino Racing helmet and flight suit, ORC-mkX arms. Everything else the slot has held moves under "previously", collapsed, with how long ago each was last seen. Slots order by most recently used, and search still matches the slot name, its current occupant, or anything in its history. Hand slots remain churn-heavy by nature - 87 items behind the current one - because holding something is not the same as equipping it. That is now visible as history rather than presented as a loadout. 141 tests passing.
The page was an all-time union of everything ever seen at a location, which meant items taken away years ago still appeared. Port Tressler listed 44 items that way; its actual contents on the last visit are 14. Inventory listings follow a query per scope, so listings are now scoped to the visit that produced them and only the newest visit per location survives. One wrinkle worth recording: a query does not list the whole inventory. The lines are tagged "End Page" - it lists the page on screen - so taking a single listing dropped Port Tressler to 2 items. Listings are therefore unioned within a session and only merged across sessions is avoided. The result is "contents as of your last visit", which is the honest ceiling here: removals are never logged, and only browsed pages are listed. Adds a "Latest place only" toggle. The same item often sits in several stashes - a MedPen appeared in three - so this keeps each item where it was most recently seen, giving "where is my X" a single answer. 141 tests passing.
Loadout took the newest sighting per slot across the whole library, which spliced a helmet from March onto a rifle from August - a combination nobody ever wore. It now shows the kit from the most recent session that recorded any, so it reads as one coherent outfit, with earlier sessions demoted to the per-slot history. Period filtering extends to Spending, Contracts and Places. These aggregate server-side, so /api/stats takes a days parameter rather than shipping per-session detail to the browser and filtering there. Places gains a search box too. The six near-identical selects are now one component: markup carries an empty select.period and the options come from a single PERIODS list, so adding a window is one edit. Views that word it differently (Fleet "Any time", Stash "Seen any time") override just that option. Adds 24 hour and 3 day windows - the last 24 hours covers 1 session and 2h40m in game, against 146 sessions all time. 141 tests passing.
Still unreadable at 31 rows, for two reasons neither of which was about which session to read. Eleven rows were the character model - teeth, eyelashes, eyebrows, scalp, head, body mesh - and several more were fixtures with exactly one possible occupant: the three mobiGlas ports, the default radar lens, the built-in visor, the necksocks. None of that is equipment, so it is excluded. The rest were numbered siblings. A character has nine magazine ports, four grenade ports and four medpen ports, and each was getting its own near-identical row. Families now collapse to one row carrying counts, so nine magazine rows become "Magazine, 9 slots: Custodian SMG Magazine x4, P4-AR Magazine x2, A03 Sniper Magazine x2, Arclight Battery". Also reverts the previous single-session approach. It read tidily but silently lost gear: the newest session recorded no arms, legs or core, so three armour slots disappeared. Last-equipped per slot across the library is both more complete and closer to what was asked for. 39 rows of noise down to 23 that describe an actual kit. 141 tests passing.
Hands hold things transiently - a tool, a drink, a helmet part-way off - which is handling rather than equipment, and they churned harder than any other slot at 88 distinct items in the right hand alone. Both are excluded. The "previously" block is gone too, and the history is no longer computed or sent rather than merely hidden. Everything a slot has ever held is a record of churn; showing it beside the current occupant was the reason the page read as a story of moving things around. 23 rows down to 21, all of which describe equipment. 141 tests passing.
A cold backfill reads 400 MB across 145 files and took about half a minute with no indication anything was happening - the page just sat empty while boot() retried in silence, which is indistinguishable from broken. The library already reported progress and nothing consumed it; the server now tracks it and the page shows a bar with file counts and elapsed time. Ledger lists every money movement newest first with a running net: 235 across the library. Amounts confirmed by a server response are shown plainly, cargo trades are marked with ~ because the kiosk never confirms them. Cargo breaks the trading down - 19 sales, revenue and volume by location, and unit price per SCU, which turns out to be the interesting column: the same Admin lt base g runs from 457 to 5,307 aUEC per SCU depending on the load. What the cargo page cannot say is what was in the boxes. The log names the commodity only by resourceGUID and that mapping lives in the DataCore, so the page reports volume, price and place and stays quiet about the rest. Both pages take the shared period selector. 141 tests passing.
…places client_price is the order total, not a unit price: a line reading client_price[52520] quantity[101] is 101 magazines for 52,520 aUEC altogether. Multiplying by quantity turned that one purchase into 5.3 million and inflated lifetime spend accordingly. Confirmed against a known price - 2,390 for 10 MedPens is 239 each. The ledger also reported "Admin lt base g" as the place for every cargo sale, because every commodity terminal in the game shares that kiosk id. Shops name a vendor, not a location, so the place is now back-tracked from the last arrival or quantum jump before the transaction. Vendors keep their own column, resolved through the game shop_name_* table where it publishes a brand. Also fixes rs_ext_cru-leo1 rendering as "Crusader LEO1 Rest Stop" - it is Seraphim Station, the same place RR_CRU_LEO already resolved to. The name cache now carries a schema version, so adding a table rebuilds it instead of waiting for the next game patch.
The map only ever drew places already visited, which is a map of nowhere - 72 dots with no context and no sense of what is left. The atlas now takes the ~1,300 locations the game names in its own localisation table, runs each back through the resolver for a system, body and kind, and draws the unvisited ones as hollow rings beside the solid ones. A Visited only toggle filters down to where the player has actually been; search always overrides it, since looking for somewhere you have never been should find it. Interiors are excluded - Pyro1_L2_03_Entrance and its 800-odd siblings are elevator landings inside a single building, and they buried the 238 places that are somewhere you fly to. Wheel zooms about the cursor, drag pans, and labels appear on every node once the view is close enough to have room for them. The player marker follows the live feed, with Centre on me to find it. Also documents why a cargo sale cannot be named: all four resourceGUIDs traded across the backups were searched through the whole 330 MB of Game2.dcb, as text and as bytes in both guid orderings, and none appears. The DataCore holds the commodity catalogue but not these ids, so the mapping is almost certainly in the encrypted shop inventory tables.
Nyx was one dot. The resolver only knew Levski, because Nyx shares none of the id grammar Stanton and Pyro use - no numbered bodies, no RR_ rest stops - so everything else fell through unresolved and the atlas dropped it. A rule of its own picks up the social stations, the twenty QV Breaker rock crackers, Moraine Base, the belts and the gateway stations, which is 55 places. UI strings and the bodies themselves share the same prefix and are deliberately excluded, with tests pinning both halves. The map now sizes each system from what it holds rather than using one fixed orbit. With every location drawn instead of only the visited handful, microTech's cluster ran straight over Calliope's next door; bodies are now spaced so neighbouring clusters clear each other with room for labels, which makes Stanton's disc noticeably larger than Nyx's. The three systems sit as a triangle with a jump lane on each edge, matching the real topology. Labels no longer clump when zoomed. They are sized in map units against the current zoom so they hold a constant size on screen, and each one is pushed radially away from its body so a cluster fans its names outwards instead of stacking them. Sites are placed by golden angle rather than in rings of twelve, which was putting every twelfth node on the same spoke. Spending showed raw class ids - POWR_JUST_S02_Genoa_SCItem rather than Genoa - because it was the one page that never passed items through the name table. Grouping by display name also merges colourways of the same weapon into one line. Cargo sales are grouped by where they happened rather than by kiosk, for the same reason the ledger was.
The README named seven prior-art projects in one sentence at the bottom and left it there. That undersold what was actually borrowed: the archived combat line formats, the kill-classification tree and the NPC-name marker list in this repo are StarLogs' event_parser.py logic re-typed in C#, not independent work. docs/credits.md now says so plainly and names what came from each project, plus the Fankit artwork, the packages, and the p4k format knowledge that came out of the scdatatools lineage rather than from us. The code carries the same links at the three places the borrowed logic lives, so it is visible while reading it and not only in a doc nobody opens. The dashboard footer credits the community tooling alongside the existing trademark notice - the people whose research made the parser possible should be named where users actually look, not only in the repository. Corrects a stale claim while in there: architecture.md said node data was seeded from api.star-citizen.wiki and starcitizen-api.com and committed as a local JSON file. There is no such file and never was. Names come from the game's own localisation table in Data.p4k and everything else from rules over the id grammar; those two APIs were a research cross-check only, which is what the doc now says. 154 tests passing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
SC Companion had to go. It was not a legal problem - a fan tool named after the game is low risk and the phrase is close to generic - but a discoverability one. Searching the name returns SC-Bridge/sc-companion first, a native Windows app for Star Citizen game log ingestion: same name, same platform, same premise. Behind it are a Microsoft Store app called SC Companion, a paid Android app of the same name, and sccompanion.com and .org, both live and both held by other people's tools. Every obvious channel for the name was already occupied. Verselog was picked after checking eight candidates against GitHub, the Store, the community and the domain registries. Dead Reckoning fit the concept best and died on an existing RSI org of that name - colliding inside the community is worse than outside it. Driftlog, Starfix, Starwake, Voidmark, Astrolabe and Wayfix are all live products. Ephemeris and Sextant are both clear in the Star Citizen space and both better metaphors, but a dozen astronomy libraries own the first and a 573-star Rails tool owns the second. Verselog is used by nothing at all, and says plainly what the app is: a log of your time in the 'verse, which is all this app has ever been derived from. docs/naming.md records the evidence, including the rejected names, so this is not re-litigated later. The rename covers namespaces, the six project directories, the solution, the launcher, the UI header, the overlay splash and every document. Verified beyond compiling: server starts, rescans all 146 logs in 4 s, resolves 9,527 items and 1,343 places, and serves the dashboard. One consequence worth knowing: the cache moved to %LOCALAPPDATA%\Verselog, so the first run rescans instead of starting warm. No migration code - the cache is derived from the logs and rebuilds in seconds, and carrying the dead name forever to save one rescan is a bad trade. The old directory can be deleted. 154 tests passing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The April research said six of seven tools are built on kill events and so all show an empty dashboard. That is still true of those seven and no longer true of the space. A second generation now builds on everything else Game.log records, which is precisely where this app lives, so docs/landscape.md replaces the stale picture with what is actually out there. The uncomfortable finding is Stelliverse: Tauri app, 8,312+ downloads, on the Microsoft Store, whose flight-log module covers locations and systems visited across Stanton, Pyro and Nyx with a map and hours per system, quantum jumps, ships flown, sessions, cargo trading and shop spending - and which describes itself as passive, local and zero ban risk, three positions this project reached independently. It is broader than us and far better known. Named plainly rather than talked around. Also close: SCLogReader has a running-balance ledger, missions, ships and loadout on the same stack we chose; AssetMemory tracks inventory by location with nested containers, which is our Stash but deeper. Both resolve names from UEX or the wiki, so both need the network for the thing we read straight out of Data.p4k. Two consequences worth acting on later. Phase 6 is contested ground, not open frontier - Picologs already shares org activity live, and SC Bridge does it with cloud sync we have promised never to build - so it should drop down the order. And Stelliverse advertises kills, deaths and K/D, which contradicts findings.md; an independent tool claiming the opposite of our evidence is worth a re-check before that doc is quoted as settled. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nekron's read is right: what this app produces is a pilot's logbook - flights, places, hours, spend, written down after the fact. That is a better description of the product than "your log of the 'verse", so it becomes the tagline in the README and the assembly description. Not the name, though. SCLogBook puts back the SC prefix the rename existed to escape, and lands one word away from SCLogReader - the tool nearest to us in features - so two similar apps would carry near-identical names. "Star Citizen Logbook" is also taken twice already, by citizen-logbook.com (active since 2019) and scl.hypertesto.me, and unqualified "logbook" belongs to aviation software. Recorded in docs/naming.md with the rest, so the question stays answered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Verselog lasted a day. nekron's objection killed it and was correct: "verse" does no Star Citizen work at all - it is a Bible verse, a song verse, the metaverse - and Epic ships a language called Verse, so the name sat in the path of whatever that ecosystem produces next. The first round optimised for "nothing else uses this" and got a name that said nothing. Uniqueness was the wrong thing to measure alone. Quantum Wake says the game without saying it. Quantum travel is Star Citizen's own idiom - Elite has frame shift, Star Wars has hyperspace - so a player reads "quantum" and knows what this is, while CIG's actual marks stay untouched, which they must. And the wake is precisely what this app has to work with: no position is ever logged, so what survives a flight is the trail it left in the log file. Nothing else uses the name - no repository, no product - and the .com has sat parked and empty since 2020. Display name is two words, identifier is one: Quantum Wake in the README, the UI header, the overlay splash and the assembly Product; Quantumwake.* for namespaces, directories and the solution, the way Visual Studio is VisualStudio in code. The tagline now names the game outright - a pilot's logbook for Star Citizen - since that was the job "verse" was failing to do. docs/naming.md carries the whole record, Verselog included, with the candidates rejected on the way: Jumplog (a skydiving logbook owns it), Spoolup (good SC signal, names the departure not the record), Portolan and Binnacle (sea, not space), Chiplog, Rutter, Lodestar and Astrogator (all taken elsewhere). Verified: builds clean, 154 tests pass, server rescans 146 logs in 3 s and serves the dashboard. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two vector marks drawn to the app's own palette, replacing the rotated-diamond placeholder. web/assets/mark.svg is a wake and the point that left it - two shapes, no ring, no text - because a browser tab renders it at 16px and the ring text in the full emblem is illegible below about 128. It is now the favicon, the topbar mark and, as XAML paths, the overlay splash, all from one geometry so they cannot drift apart. web/assets/logo.svg is the full emblem for the README. The emblem deliberately carries no Cloud Imperium trademark. A logo reading "STAR CITIZEN COMPANION" inside the ring reads as a badge of endorsement, which is the one thing fan projects are asked not to imply; "for Star Citizen" belongs in a tagline beside the mark, where it already is. The lower arc says what the app is instead. Licence is Apache 2.0, chosen over MIT for section 6: it grants no trademark rights, which matters now there is a name and a mark worth protecting. The carve-outs are the real work, and they are in NOTICE: - The Fankit artwork is Cloud Imperium's and cannot be sublicensed by us. The Fankit terms bind a forker directly and forbid commercial use. Noted at the root and again next to the images, with the advice to delete the directory - the Fleet view already degrades to a text badge. - No game data is in this repository and none may be added; names are read from the user's own Data.p4k at runtime. - StarLogs is MIT, so the re-implemented combat parser is clean, with its notice reproduced. Provisional pending nekron's call between Apache and GPL-3.0; the carve-outs are needed either way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nekron ran the launcher and it sat on "Starting server…" for minutes. The cause
is a missing verb, present since the launcher was first written: the arguments
were assembled as
dotnet --project src\...Server -c Release --no-build
with no `run`, so dotnet took --project as a top-level option, printed an error
into a hidden window and exited immediately. The health loop then polled a dead
port 60 times at up to 2.5 s each, which is why it hung for two and a half
minutes before admitting failure rather than failing at once.
It went unnoticed because the path that was actually tested is the overlay's:
the overlay spawns Quantumwake.Server.exe directly and always has. Anyone
launching the documented way got a hang.
Now the script launches that same executable instead of going back through the
SDK - one code path for both, and app arguments pass straight through with no
`--` separator to get wrong. It gives up the moment the child process exits
rather than polling a port nobody is listening on, and prints the child's
captured stdout/stderr instead of a hidden window swallowing the reason.
Verified by running the launcher's exact sequence: server answers in 0.4 s.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
It read as a working document: the views table still listed Ships and stopped at Contracts, missing Spending, Ledger, Cargo, Loadout and Stash; the map was described as Stanton and Pyro when it draws three systems and every place in them; the test count said 127 against 154 passing. The opener now says what the app is to someone who has never seen it - the game writes everything to Game.log and then rotates it away, and this reads it back - followed by badges, the eleven views, and a "why another one" section that links the landscape survey and names the three things the neighbours do not do. Better to answer that question honestly on the front page than to let a visitor from a crowded niche assume there is no answer. Also adds the LogSim project to the architecture table, where it was missing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Brings the project's full history - parser, server, dashboard, map, overlay and every rename - onto GitHub's initial commit rather than squashing four days of work into one import. Merged with unrelated histories, so the first commit here stays the one GitHub created. Two files existed on both sides. LICENSE keeps ours, which is the same Apache 2.0 text with the copyright line filled in rather than left as [yyyy] [name of copyright owner]. .gitignore keeps GitHub's .NET template, which is more thorough than what the project carried, with the project's own entries appended: the SQLite cache, IDE droppings and OS files. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two small UI changes that exist because the README needed pictures and the dashboard could not be photographed. The active view now lives in the URL fragment, so #map is a link that can be sent to someone and a page that survives a refresh. replaceState rather than assignment: cycling views with Ctrl+Alt+arrow should not leave thirty entries in the back button. That collided with the map immediately. The SVG was id="map", so the browser anchor-scrolled to it after load and left the header stranded mid-screen. It is id="starmap" now - with fragments naming views, no element may share a view's name - and switching view scrolls to the top, which is right anyway. ?snapshot=1 loads the data once and then leaves the page still. The event stream never closes by design, so a headless browser waits on it forever and never reaches the load event; every attempt to capture the dashboard timed out until this existed. It changes nothing for a normal visitor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CI builds and tests on every push and pull request. Windows only, and not by preference: the overlay targets net10.0-windows for WPF, so the solution cannot restore on a Linux runner. The other four projects are plain net10.0 and would build anywhere, which is worth remembering if a Linux-hosted server mode lands. Releases are cut by pushing a v* tag. The three executables publish into one folder deliberately - the overlay starts the server by looking for Quantumwake.Server.exe beside itself, so separate archives would break launching the overlay on its own. Tests run before publishing: this app is a log reader, so a red parser test means a release that shows empty views, which is worse than no release. Framework-dependent rather than self-contained keeps the download in megabytes rather than hundreds of them, at the cost of naming the .NET 10 Desktop Runtime as a prerequisite in the release notes. The release step uses gh, already on the runner, rather than a third-party action - the same reasoning that keeps the dashboard free of a CDN. Dependabot runs monthly, not weekly. Five direct dependencies and no service to keep patched; weekly would be noise. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nine captures of the real dashboard, taken headlessly against this install's own 145 logs, with the star map as the hero image and Fleet, Ledger, Sessions and Stash in a grid. A UI-heavy tool with no pictures asks a visitor to take its word for everything. The map screenshot corrected a claim I had written twice: the atlas draws 292 places, not 1,343. That larger number is how many the localisation table names, which is not the same thing as how many the resolver can place on a map. Fixed in the README and in the landscape survey. Version is 0.1.0 rather than 1.0.0. Everything works and 154 tests pass, but server mode is unbuilt, the parser-health panel is not surfaced, and no one has run this but its author - that is a 0.1.0. Repository URLs are in the assembly metadata now, and the README carries the CI badge. Note for the tag: the screenshots contain real gameplay data - spend totals, places, the ship roster. That is deliberate for a first release, and LogSim can regenerate the whole set from a fake install if it should not be public. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
The whole project, plus release preparation.
What is here
Game.logand every backup: map, sessions, fleet, places, contracts, spending, ledger, cargo, loadout, stash.Data.p4kwith our own ZIP64 + ZStd reader, so no lookup service is involved and no outbound request ever leaves the machine.Release preparation
v*tag; dependabot monthly.NOTICEfor the Fankit artwork (Cloud Imperium's, not ours to sublicense) and for the name and logo.Verification
154 tests pass. The server rescans 145 logs in about three seconds and serves the dashboard.
start.ps1is fixed here too — it had never actually started the server, missing therunverb since the day it was written, so anyone launching the documented way got a two-and-a-half minute hang.Note
The screenshots are real gameplay data: spend totals, ship roster, places visited.
LogSimcan regenerate the whole set from a fake install if that should not be public.Merge with a merge commit rather than a squash — the
v0.1.0tag points at the head of this branch, and squashing would leave it dangling.