Skip to content

fix: match Game Settings pilots by the options file's identity - #3

Merged
Rmkrs merged 1 commit into
Rmkrs:mainfrom
dan51588:fix/game-settings-pilot-identity
Oct 29, 2026
Merged

Rmkrs merged 1 commit into
Rmkrs:mainfrom
dan51588:fix/game-settings-pilot-identity

Conversation

@dan51588

Copy link
Copy Markdown
Contributor

Problem

Game Settings lists every pilot as offline, even with several pilots in game. As a result:

  • Save's guard ("the pilot came online before the change could be saved") never fires, so it lets you edit the options of a pilot who is in game, which the client overwrites at logout.
  • Rows fall back to "Unknown pilot · <id>" even for pilots the pilot archive and shortcut.ini know by name.

Cause

The client uses two forms of a character's id, and Game Settings compared one with the other:

Where Id Client code
player<id>_options.ini file name Character_ID % 1000000000 OptionClass::Load (0x7F84F0)
the session ticket, read by the manager as ShortcutIdentity full 64-bit Character_ID TicketClass at SClient +0x12D8, Character_ID at ticket +0x10 = SClient +0x12E8
shortcut.ini sections ([<id>_PDA_EQUIP], [<id>_Skills], …) full Character_ID

OptionClass::Load is called from the game task with ticket->Character_ID, and starts as follows (from a reconstruction of the client's source from the binary):

void OptionClass::Load(__int64 character_id, SClient *client)
{
	Set_Defaults(client);
	CharacterID = character_id % 1000000000;
	char filename[64];
	_snprintf(filename, 64, "player%d_%s", CharacterID, "options.ini");
	...

GamePilotSettingsCatalog.ResolveOnlineIdentities added the full ShortcutIdentity, or in its fallback the byte-swapped local player object id, which is the same value. Load matched the file ids against the pilot archive's and shortcut.ini's names, which were also keyed by the full id. So any pilot whose id is 1,000,000,000 or more never matches its own file.

Observed on a real install

  • 35 player*_options.ini files, and shortcut.ini with 18 pilots whose ids range from 1,784,938,560 to 4,031,841,088.
  • 0 of the 18 full ids match an options file name; all 18 match once reduced modulo 1,000,000,000.

Fix

GamePilotSettingsCatalog.ToOptionsFileIdentity(id) = (uint)(id % 1_000_000_000), applied to the online ids (both branches), the pilot archive's ids and shortcut.ini's section ids, which are now parsed as ulong. Everything that consumes these (the online flags, Save's guard, the names) compares against the file's id, so nothing else changes.

Testing

  • dotnet build Net7ClientManager.slnx: 0 errors, no new analyzer warnings.
  • Live:
    • in-game pilots show as online and go offline at logout;
    • rows show the pilots' names;
    • Save refuses to write an online pilot's options and saves an offline pilot's.
  • Rows for options files of characters that neither the archive nor shortcut.ini knows (old or deleted characters) still read "Unknown pilot · <id>", as before.

🤖 Generated with Claude Code

The client names a pilot's options file player<id>_options.ini after its
character id modulo 1,000,000,000 (OptionClass::Load, 0x7F84F0), while
the session ticket and shortcut.ini hold the full 64-bit id. Game
Settings compared the full id with the file's, so every pilot whose id
is 1,000,000,000 or more (all Net-7 pilots seen) showed offline. That
also disabled Save's refusal to write an online pilot's options, and the
pilot archive and shortcut.ini names never matched their files.

Reduce the observed id, the archive's id and shortcut.ini's section ids
the same way before matching.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dan51588
dan51588 marked this pull request as ready for review October 29, 2026 07:01
@Rmkrs
Rmkrs merged commit 3a86d2e into Rmkrs:main Oct 29, 2026
1 check passed
@dan51588
dan51588 deleted the fix/game-settings-pilot-identity branch October 30, 2026 22:22
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