157 lines
5.6 KiB
Markdown
157 lines
5.6 KiB
Markdown
# Retail live-session lifecycle pseudocode
|
|
|
|
**Scope:** GameWindow Slice 3 character-list, character-entry, and transport-
|
|
disconnect conformance corrections.
|
|
|
|
## Named-retail oracle
|
|
|
|
- `CharacterIdentity::UnPack @ 0x004FE880`
|
|
- `CharacterSet::UnPack @ 0x004FE340`
|
|
- `CharacterSet::GetGreyedOutFor @ 0x004FDFA0`
|
|
- `gmCharacterManagementUI::EnterGame @ 0x004ED440`
|
|
- `gmCharGenMainUI::Update @ 0x004E8460`
|
|
- `CPlayerSystem::Handle_Login__CharacterSet @ 0x0055F6D0`
|
|
- `Proto_UI::SendEnterWorldRequest @ 0x00546A00`
|
|
- `CPlayerSystem::Handle_Character__EnterGame_ServerReady @ 0x0055E4F0`
|
|
- `Proto_UI::SendEnterWorld @ 0x00546BC0`
|
|
- `CPlayerSystem::LogOnCharacter @ 0x0055F890`
|
|
- `CPlayerSystem::UseTime @ 0x00563110`
|
|
- `Proto_UI::LogOffCharacter @ 0x00546A20`
|
|
- `CPlayerSystem::RequestLogOff @ 0x00562DD0`
|
|
- inbound F653 dispatch `@ 0x0055C963`
|
|
- `CPlayerSystem::ExecuteLogOff @ 0x0055D780`
|
|
- `ClientNet::ExitWorldDisconnect @ 0x00541E00`
|
|
- `ClientNet::LogOffServer @ 0x00543EF0`
|
|
- `SharedNet::SendOptionalHeader @ 0x00543160`
|
|
|
|
The verbatim layouts are `CharacterIdentity` and `CharacterSet` in
|
|
`docs/research/named-retail/acclient.h` (types 3206 and 3209).
|
|
|
|
## CharacterSet wire decode
|
|
|
|
```text
|
|
CharacterIdentity.UnPack(cursor):
|
|
identity.guid = read_u32(cursor)
|
|
identity.name = read_PString(cursor)
|
|
identity.secondsGreyedOut = read_u32(cursor)
|
|
align cursor to 4 bytes
|
|
|
|
CharacterSet.UnPack(cursor):
|
|
result.status = read_u32(cursor)
|
|
|
|
activeCount = read_u32(cursor)
|
|
result.active = empty
|
|
repeat activeCount times:
|
|
result.active.append(CharacterIdentity.UnPack(cursor))
|
|
|
|
deletedCount = read_u32(cursor)
|
|
result.deleted = empty
|
|
repeat deletedCount times:
|
|
result.deleted.append(CharacterIdentity.UnPack(cursor))
|
|
|
|
result.numAllowedCharacters = read_u32(cursor)
|
|
result.account = read_PString(cursor)
|
|
result.useTurbineChat = read_u32(cursor)
|
|
result.hasThroneOfDestiny = read_u32(cursor)
|
|
```
|
|
|
|
The two values previously described as "leading/trailing padding" are the
|
|
retail status and deleted-character count. ACE currently writes zero for both,
|
|
which hid the schema error in acdream and in Holtburger's current reader.
|
|
|
|
Cross-checks:
|
|
|
|
- ACE `GameMessageCharacterList` writes the same active identity records,
|
|
allowed-slot count, canonical `Session.Account`, and booleans, but currently
|
|
emits status/deleted-count as zero and no deleted records.
|
|
- Holtburger `CharacterListData` agrees on active records and the tail, but
|
|
likewise labels both zero values as padding. The named retail `CharacterSet`
|
|
layout and `UnPack` control flow win where the references differ.
|
|
|
|
## Retail selection and acdream unattended entry
|
|
|
|
```text
|
|
gmCharacterManagementUI.EnterGame():
|
|
playerSystem = GetPlayerSystem()
|
|
if playerSystem exists
|
|
and selectedGuid != 0
|
|
and CharacterSet.GetGreyedOutFor(
|
|
CharacterSet.GetSlot(selectedGuid)) <= 0:
|
|
show entering-world dialog
|
|
playerSystem.LogOnCharacter(selectedGuid)
|
|
```
|
|
|
|
Retail ordinarily requires an explicit selected active character. The only
|
|
automatic retail path found is `gmCharGenMainUI::Update`: after character
|
|
creation it walks the active list, skips entries greyed for a positive number
|
|
of seconds, matches the newly-created name case-insensitively, and logs that
|
|
GUID on.
|
|
|
|
acdream does not yet have the retained character-management screen. Its
|
|
unattended auto-entry is therefore an explicit adaptation with a narrow rule:
|
|
|
|
```text
|
|
for each identity in active wire order:
|
|
if identity.guid != 0 and identity.secondsGreyedOut == 0:
|
|
select this active-list index
|
|
stop
|
|
if none matched:
|
|
do not enter a character
|
|
```
|
|
|
|
Deleted entries are never candidates. This preserves the established "first
|
|
available character" behavior without treating a pending-deletion character
|
|
as available.
|
|
|
|
## Canonical account used by EnterWorld
|
|
|
|
```text
|
|
CPlayerSystem.LogOnCharacter(selectedGuid), when ready:
|
|
selectedGuid = persistentData.selectedCharacter
|
|
account = playerSystem.account // populated from CharacterSet.account
|
|
Proto_UI.SendEnterWorld(account, selectedGuid)
|
|
ClientNet.EnterWorld()
|
|
```
|
|
|
|
The account string in the final F657 message comes from the server-returned
|
|
`CharacterSet.account`, not from the spelling typed into the startup login
|
|
form. acdream must therefore make `WorldSession.EnterWorld` consume
|
|
`Characters.AccountName` internally.
|
|
|
|
## Logout and negotiated transport disconnect
|
|
|
|
```text
|
|
ClientNet.LogOffServer():
|
|
packet = make optional-header packet(flags = Disconnect)
|
|
for each negotiated ReceiverData:
|
|
SharedNet.SendOptionalHeader(packet, receiver.address, receiver)
|
|
logOffSent = true
|
|
logonReceiverId = 0
|
|
ExitWorldDisconnect()
|
|
```
|
|
|
|
The in-world character path remains:
|
|
|
|
```text
|
|
send F653 + active character GUID
|
|
wait for server's opcode-only F653
|
|
send negotiated transport Disconnect
|
|
release transport
|
|
```
|
|
|
|
ACE's `GameMessageCharacterLogOff` confirms the server form is exactly four
|
|
bytes. Its `NetworkSession` terminates a session when it receives a packet with
|
|
the transport Disconnect flag.
|
|
|
|
The transport Disconnect is connection-scoped, not character-state-scoped.
|
|
Once acdream has accepted ConnectRequest receiver id/iteration, disposal sends
|
|
it whether the session is still selecting a character, entering the world, in
|
|
world, or failed later. F653 remains restricted to an active in-world
|
|
character. A pre-negotiation failure has no receiver identity and only closes
|
|
the local socket.
|
|
|
|
## Deliberately unchanged registered gaps
|
|
|
|
- UN-6: the fixed 200 ms ConnectResponse delay remains registered.
|
|
- TS-28: LoginComplete readiness remains a later protocol slice.
|
|
- AD-44: closing exits rather than returning to a retained character screen.
|