Overview
PRUDP packets may have optional payloads. These payloads may be anything, however typically DATA packets use RMC. RMC, presumably standing for “Remote Method Call”, is a standardized protocol for calling methods on remote services. RMC has been known to come in at least 3 different variations. The variation used is already know to both the server and client. These variations are:
- “Packed” - Information about the service and method is tightly packed, such as using integers for protocol/method IDs
- “Packed” extended - The exact same as the previous “packed” variation, except an additional uint16 is added as the “true” protocol ID. In this case the uint8 “protocol ID” is
0x7F - “Verbose” - Rather than tightly packing data, this variation opts to encode information about the remote service and method in a more verbose way, using strings in place of integer IDs. This variation also changes how Structures are encoded
All NEX titles use one of the “packed” variations. Many Rendez-Vous titles also seem to use the “packed” variations. However, some Rendez-Vous titles use the “verbose” variation
“Packed” variations
Request Format
| Type | Description |
|---|---|
| Uint32 | Size, excluding this field |
| Uint8 | Protocol id, ORed with 0x80 |
| Uint16 | Extended protocol id. Only present if using the “extended” variation (protocol id is 0x7F). |
| Uint32 | Call id, an incrementing number used to match a response to the right request |
| Uint32 | Method id |
| … | Method parameters |
Response Format
| Type | Description |
|---|---|
| Uint32 | Size, excluding this field |
| Uint8 | Protocol id |
| Uint16 | Extended protocol id. Only present if the protocol id is 0x7F. |
| Bool | “Is success” |
On success:
| Type | Description |
|---|---|
| Uint32 | Call id |
| Uint32 | Method id, ORed with 0x8000 |
| … | Response data |
On error:
| Type | Description |
|---|---|
| Uint32 | Error code, see errors.py |
| Uint32 | Call id |
“Verbose” variation
Request Format
| Type | Description |
|---|---|
| Uint32 | Size, excluding this field |
| String | Protocol name |
| Bool | “Is request” (true) |
| Uint32 | Call id, an incrementing number used to match a response to the right request |
| String | Method name, with the protocol name as a prefix |
| ClassVersionContainer | Information about the Structures used in the request |
| … | Method parameters |
Response Format
| Type | Description |
|---|---|
| Uint32 | Size, excluding this field |
| String | Protocol name |
| Bool | “Is request” (false) |
| Bool | “Is success” |
On success:
| Type | Description |
|---|---|
| Uint32 | Call id |
| String | Method name, with the protocol name as a prefix |
| … | Response data |
In all known cases, the method name string in responses ends with a *. Looking at the response handlers for some games, this seems to be related to a “return value pointer”, though it is not entirely clear at this time
On error:
| Type | Description |
|---|---|
| Uint32 | Error code, see errors.py |
| Uint32 | Call id |
ClassVersionContainer
The ClassVersionContainer is a List of ClassVersion types. Unlike in the “packed” variations, where structure version information is optionally stored as a header on the structure, a ClassVersion defines this version only once before the rest of the message is parsed. Presumably this is done to not re-encode the same version information multiple times, though the cases where this is beneficial are few. Every request in the “verbose” variation begins with a ClassVersionContainer, even if it has 0 elements. Responses do not use a ClassVersionContainer, nor do they encode the structure header
ClassVersion
| Type | Description |
|---|---|
| String | Structure name |
| Uint16 | Structure version |
Remarks
The following services never send an RMC response, even if an error occurred:
Other services always send an RMC response.