Documentation
Findings
Reverse-engineering reference for Project A — engine internals, networking, assets, and the local server emulator.
Engine Offsets
RVAs recovered from the shipping client image. All values are relative to the module base unless noted as structure field offsets. Grouped by subsystem for SDK dumps, hooks, and runtime object traversal.
Static Find Object & Package Loading
Entry points for resolving UObject instances by path and loading
packages. static_load_object_candidate shares an address with
load_package — treat it as an internal load path until confirmed
as the public StaticLoadObject export.
| Symbol | Offset | Notes |
|---|---|---|
static_find_object | 0x1B92940 | Wide-path wrapper |
static_find_object_thunk | 0x1B92C40 | Thunk layer |
static_find_object_fast | 0x1BA2D30 | FName / object hash lookup |
static_find_object_hash | 0x1BA2DD0 | Object hash walk |
resolve_name | 0x1B8FB70 | Name resolution helper |
load_package | 0x1B89C80 | Package load |
load_package_wrapper | 0x1B89BB0 | Outer wrapper |
Viewport & Rendering
UGameViewportClient VMT hook for post-render overlays. Slot index
96 → byte offset 768
(0x300, index × 8 on x64). Confirmed by the indirect call through
the viewport vtable at +768 in
viewport_draw.
| Symbol | Image RVA | VMT Index | VMT Offset | Notes |
|---|---|---|---|---|
game_viewport_client_vtable | 0x42B6C08 | — | — | Primary vtable pointer |
viewport_vtable_postrender | — | 96 | 768 (0x300) | UGameViewportClient::PostRender |
viewport_draw | 0x2A5A830 | — | — | Caller — dispatches vtable slot 96 |
viewport_draw_vtable_entry | 0x42B6F68 | — | — | Resolved vtable entry |
viewport_draw_vtable_offset | — | 108 (0x6C) | 864 (0x360) | Separate draw slot |
game_viewport_client_vtable_alt | 0x3CA20F8 | — | — | Cooked duplicate |
viewport_draw_entry_alt | 0x3CA2458 | — | — | Cooked duplicate |
// Decompiler pattern from viewport_draw (0x2A5A830):
// v152 - 48 → UGameViewportClient* instance
// + 768LL → vtable index 96 (96 × 8)
(*(void (__fastcall **)(__int64, __int64))
(*(_QWORD *)(viewport - 48) + 768LL))(viewport - 48, canvas);
Skeleton & Bone Transforms
Bone query and component-space transform chain for mesh/skeleton inspection.
| Symbol | Offset | Notes |
|---|---|---|
exec_get_bone_transform_by_name | 0x30DBF90 | Blueprint exec stub |
get_bone_transform_by_name | 0x2941830 | Native bone lookup |
calc_component_space_transforms | 0x29405B0 | Component-space pass |
transform_to_matrix_world | 0x2946B20 | World matrix composition |
Global Object Array (GObjects)
Standard UE4 chunked object array layout. Each FUObjectItem is 0x18 bytes.
| Symbol | Offset | Notes |
|---|---|---|
gobjects_chunks | 0x5C4FA08 | Chunk pointer table |
gobjects_count | 0x5C4FA1C | Live object count |
fuobject_item_size | 0x18 | Struct size |
fuobject_item_object | 0x00 | Field: UObject* |
fuobject_item_flags | 0x08 | Field: flags |
fuobject_item_serial | 0x10 | Field: serial number |
Name System (GNames / FName)
gname_state is an indirect pointer — dereference before walking chunks.
Entry count lives at *(gname_state + 0x800). Chunks are
0x4000 entries wide.
| Symbol | Offset | Notes |
|---|---|---|
gname_state | 0x5C4B390 | Read pointer first |
fname_to_string | 0x19DB1D0 | FName → FString |
fname_ctor_ansi | 0x19CED40 | ANSI constructor |
fname_ctor_wide | 0x19CEDB0 | Wide constructor |
fname_entry_to_string | 0x19D37E0 | Entry decode |
fname_entry_ansi_decode | 0xEEF570 | ANSI entry path |
fname_entry_wide_decode | 0xEF0790 | Wide entry path |
name_chunk_size | 0x4000 | Entries per chunk |
name_state_count | 0x800 | Offset of count field |
UObject & FProperty Layout
Structure field offsets for manual serialization and property walking — not image RVAs.
| Field | Offset | Field | Offset |
|---|---|---|---|
UObject::Flags | 0x08 | UObject::InternalIndex | 0x0C |
UObject::Class | 0x10 | UObject::Name (FName) | 0x18 |
UObject::Outer | 0x28 | UStruct::PropertyLink | 0x70 |
FProperty::PropertyFlags | 0x30 | FProperty::ArrayDim | 0x38 |
FProperty::ElementSize | 0x3C | FProperty::Offset_Internal | 0x4C |
FProperty::PropertyLinkNext | 0x60 |
World State & Allocator
Minimum globals needed for encrypted world pointer resolution and heap allocation hooks.
| Symbol | Offset | Notes |
|---|---|---|
uworld_state | 0x5087140 | Encrypted UWorld state |
uworld_key | 0x5087178 | Decryption key material |
fmemory_malloc | 0x18FA960 | FMemory::Malloc |
gmalloc | 0x5B48F48 | Global allocator pointer |
ProcessEvent
Native Blueprint dispatch. process_event_wrapper is a derived
override layer on top of the core implementation. Vtable slot index
72 (0x48) → offset
0x240.
| Symbol | Offset / RVA | VMT Index | VMT Offset | Notes |
|---|---|---|---|---|
process_event | 0x1B8CB70 | — | — | Core implementation |
process_event_wrapper | 0x280BB30 | — | — | Override / wrapper |
uobject_vtable | 0x3EA11C8 | — | — | UObject vtable reference |
process_event_vtable_slot | — | 72 (0x48) | 0x240 | UObject::ProcessEvent — VMT hook slot |
ufunction_function_flags | 0xA0 | — | — | UFunction field |
ufunction_parms_size | 0xA6 | — | — | UFunction field |
ufunction_return_offset | 0xA8 | — | — | UFunction field |
ufunction_native_func | 0xC8 | — | — | Native function pointer |
// Image RVAs — Project A shipping build
namespace Offsets {
// SFO / package loading
inline constexpr uintptr_t StaticFindObject = 0x1B92940;
inline constexpr uintptr_t StaticFindObjectFast = 0x1BA2D30;
inline constexpr uintptr_t LoadPackage = 0x1B89C80;
// Globals
inline constexpr uintptr_t GObjectsChunks = 0x5C4FA08;
inline constexpr uintptr_t GObjectsCount = 0x5C4FA1C;
inline constexpr uintptr_t GNameState = 0x5C4B390;
inline constexpr uintptr_t UWorldState = 0x5087140;
inline constexpr uintptr_t UWorldKey = 0x5087178;
// Dispatch
inline constexpr uintptr_t ProcessEvent = 0x1B8CB70;
inline constexpr uintptr_t ProcessEventWrapper = 0x280BB30;
inline constexpr int ProcessEventVmtIndex = 72; // 0x48
inline constexpr uintptr_t ProcessEventVmtOffset = 0x240; // index * 8
// Viewport VMT — index 96, offset 768 (0x300)
inline constexpr int ViewportPostRenderIndex = 96;
inline constexpr uintptr_t ViewportPostRenderOffset = 768; // 0x300
}
Ares Packet Path
Ares is the custom transport layer sitting between the UE net driver and the socket. Packets carry a CRC32 + length header, pass through optional obfuscation transforms, and are handed off to a secondary transport interface for the actual send. These offsets map the full handler pipeline recovered from the shipping binary.
Wire Format
Every Ares frame on the wire follows a fixed 6-byte header. The CRC covers the header plus payload.
| Field | Offset | Type | Description |
|---|---|---|---|
| CRC32 | 0x0 | uint32 | Checksum over bytes 0…end |
| Length | 0x4 | uint16 | Payload byte count |
| Payload | 0x6 | bytes | Application data |
Handler Architecture
Two handler vtables exist — the primary Ares handler and a DDoS/tunnel variant. Incoming
traffic enters through vtable slot +0x18; outgoing through
+0x20.
| Symbol | Offset | Role |
|---|---|---|
ares_handler_vtable | 0x422E900 | Primary handler vtable |
ares_ddos_handler_vtable | 0x422E990 | DDoS / tunnel handler |
ares_incoming_entry | 0x2766190 | Incoming dispatch (vtable +0x18) |
ares_outgoing_entry | 0x2766A00 | Outgoing dispatch (vtable +0x20) |
ares_packet_verify | 0x2768E80 | CRC + length verifier |
ares_crc32 | 0x197EA90 | CRC32 implementation |
Incoming Pipeline
Receive path: preprocess → verify CRC/length → reset or advance bitstream on failure/success.
| Stage | Offset | Status |
|---|---|---|
| Preprocessor A | 0x2765970 | Body dump pending |
| Preprocessor B | 0x27652A0 | Body dump pending |
| Verifier entry | 0x2768E80 | Read CRC at +0, len at +4 |
| Verify fail / reset | 0x2768F9F / 0x276901E | Recovery path |
| Verify success | 0x27690A8 | Advance to payload |
Outgoing Pipeline
Send path builds the header, optionally obfuscates the payload, then hands off to the
transport layer. A per-handler packet counter at handler+0x70 is
copied into control frames and incremented.
| Stage | Offset | Notes |
|---|---|---|
| Header build | 0x2766A00 | Writes CRC + len, copies payload |
| Payload transform | 0x2766410 | Outgoing obfuscation |
| Transport handoff | 0x2765D50 | Boundary to socket layer |
| Bitstream transform | 0x2766CE0 | Updates stream crypto state at +0xB8 |
| Meta vfunc call | 0x2766000 | [transport_vtable+0x30] |
| Payload vfunc call | 0x2766033 | [secondary_vtable+0x38] |
Bitstream Layout
Offsets within the Ares bitstream object used by the transform layer.
| Field | Offset |
|---|---|
| Data buffer | 0x90 |
| Bit end | 0xA0 |
| Bit start | 0xA8 |
| Crypto state | 0xB8 |
Control Frames & Tunnel Wrapper
Outgoing control blobs carry a packet counter and a mode magic dword. The DDoS handler
prepends two byte-swapped IDs before the payload via the tunnel wrapper at
0x2764BE0.
struct AresControlBlob {
uint32_t packet_counter; // copied from handler+0x70, then incremented
uint32_t mode_magic; // 0x35D8FB3D (mode 0) or 0xE6508848 (mode 1)
};
// Transport resolution at runtime:
// transport = *(uintptr_t*)(handler + 0x28);
// meta_target = *(uintptr_t*)(*(uintptr_t*)transport + 0x30);
// secondary_iface = transport + 0x8;
// payload_target = *(uintptr_t*)(*(uintptr_t*)secondary_iface + 0x38);
Pak AES Key
The client ships encrypted .pak archives. This 256-bit AES key
decrypts them for asset extraction with tools like FModel or umodel. Without it, pak
index reads fail and content paths cannot be resolved.
Usage
Paste the key into your extractor's AES key field (FModel → Settings → AES). The key applies globally to all encrypted paks in the build — no per-pak variation was observed for this patchline.
0x4BE71AF2459CF83899EC9DC2CB60E22AC4B3047E0211034BBABE9D174C069DD6
Matchmaking (Client)
Client-side matchmaking surface recovered from string analysis and SDK dumps. The game talks to backend services over HTTP during queue, party, pregame, and core-game phases. For the reconstructed local server endpoints, see the Server → Matchmaking API section.
Key Classes
| Class | Role |
|---|---|
UMatchmakingManager | Top-level manager — owns queue state and delegates to the service layer |
UMatchmakingService | Service facade — bridges UI/party models to HTTP calls |
UPartyMatchmakingModel | Party-side model — tracks eligibility, queue ID, and member readiness |
MatchmakingMetadata | Struct carrying queue config, map pool, and provisioning flow hints |
Client Functions
Blueprint-exposed and native entry points identified from exported strings:
| Function | Purpose |
|---|---|
EnterMatchmakingQueue / LeaveMatchmakingQueue | Queue lifecycle |
JoinMatchmaking / LeaveMatchmaking | Party-level join/leave |
ConvertToMatchmakingParty | Promote a social party to matchmaking-ready |
IsMatchmaking / IsLeavingMatchmaking | State queries |
OnMatchmakingChanged | Delegate fired on queue state transitions |
OnMatchmakingMatchFoundChanged | Delegate fired when a match is found |
GetMatchmakingMatchFoundDurationSeconds | Timer helper for match-found UI |
HTTP Surface (Client)
Paths the client calls against the RNet control plane:
| Path | Purpose |
|---|---|
/matchmaking/v1/queues/configs | Fetch all queue definitions |
/matchmaking/v1/queues/{queueId} | Fetch a single queue (optionally version-suffixed) |
/parties/v1/parties/{id}/matchmaking/join/{queueId} | Join queue from party context |
/parties/v1/parties/{id}/matchmaking/leave | Leave queue |
Party States & Errors
| Symbol | Meaning |
|---|---|
EAresPartyState::MATCHMAKING | Party is actively searching |
EAresPartyState::STARTING_MATCHMAKING | Transition into queue |
EAresPartyState::LEAVING_MATCHMAKING | Transition out of queue |
ErrPartyStateCantEnterMatchmaking | Invalid party state for queue entry |
ErrPartyNotInMatchmaking | Leave called while not queued |
ErrMatchmakingError | Generic backend failure |
EProvisioningFlowID::Matchmaking | Provisioning flow tag for matchmade games |
Debug cvar matchmaking.testqueue.enabled and boolean flags
bMatchmaking, bLeavingMatchmaking,
bMatchmakingMatchFound appear on the manager for local testing.
Pak Mount
Entry point for mounting encrypted pak archives into the engine's file system. The export
at 0x1B93E30 forwards into
sub_278B3B0, which registers a pak file with the platform file
interface and handles chunked _P.pak naming.
Function Signature
// pak mount = 0x1B93E30 → calls into:
bool __fastcall MountPak(FPakPlatformFile* platform, const wchar_t* pak_path, int mount_order, const wchar_t* mount_point);
Behaviour Summary
| Step | What happens |
|---|---|
| 1. Resolve path | Looks up the pak file through the platform file interface vtable (+184) |
| 2. Create reader | Allocates a 480-byte pak reader via sub_277BBE0 and validates the header |
| 3. Chunk detection | If the path ends with _P.pak, parses the chunk index from the filename prefix (e.g. pakchunkN_P.pak → order 100 * N + mount_order) |
| 4. Mount point | Optional fourth argument overrides the mount point string on the reader object |
| 5. Register | On success, appends {order, reader} to the platform's mounted-pak array and returns true |
| 6. Failure path | On header validation failure, queues a deferred mount entry instead of registering immediately |
Chunk Naming Logic
The _P.pak branch strips the suffix, splits on underscores, and
parses the numeric chunk prefix to compute mount priority. This ensures patch chunks mount
in the correct order relative to the base pak.
if (path.ends_with(L"_P.pak")) {
// strip "_P.pak", parse leading chunk number from "pakchunkN_..."
int chunk_index = parse_chunk_prefix(path); // via wcstol on prefix segment
mount_order = 100 * chunk_index + original_mount_order;
}
// mount_order + reader pointer pushed to platform->mounted_paks[]
Game Mode State Machine
UGameModeStateMachineComponent drives the in-match state flow
(round start, buy phase, combat, round end) by transitioning between
UStateComponent children. Hooking
ScriptSetStartingState allows observing or overriding which state
the game mode enters on round init.
| Detail | Value |
|---|---|
| Module | ShooterGame |
| Parent | UStateMachineComponent |
| Size | 0x01E0 |
| Key method | ScriptSetStartingState(UStateComponent*) |
// Class ShooterGame.GameModeStateMachineComponent
// 0x0000 (0x01E0 - 0x01E0)
class UGameModeStateMachineComponent final : public UStateMachineComponent
{
public:
void ScriptSetStartingState(class UStateComponent* State);
public:
static class UClass* StaticClass()
{
STATIC_CLASS_IMPL("GameModeStateMachineComponent")
}
static const class FName& StaticName()
{
STATIC_NAME_IMPL(L"GameModeStateMachineComponent")
}
static class UGameModeStateMachineComponent* GetDefaultObj()
{
return GetDefaultObjImpl<UGameModeStateMachineComponent>();
}
};
Server Overview
Python control-plane reconstruction for the Project A client. HTTP/HTTPS RNet-compatible
endpoints on 127.0.0.1:39001 by default; UDP/TCP gameplay observer
on port 7777. Auth uses Basic riot:{account_key}.
Server/project_a_server.py entry point
Server/projecta/control_plane/
server.py CLI bootstrap (--port 39001, --game-port 7777)
routes/registry.py ordered route-family dispatch
routes/*.py per-domain HTTP handlers
payloads/*.py JSON response builders
Server/projecta/gameplay/
ares_server.py UDP game-port observer/responder
handshake.py Ares handshake state machine
Game state phases: menus → custom → pregame → core.
Setup & Launch
Zero-config local run via start_server.bat — creates a Python venv,
installs dependencies, and listens on 127.0.0.1:39001. Use
start_client.bat to patch client certificates and launch
ShooterClient.exe.
Ports & Protocols
| Port | Protocol | Purpose |
|---|---|---|
39001 | HTTP + HTTPS | Control plane (same socket — TLS detected via first-byte peek) |
39001 | WebSocket (WAMP) | Live backend-state push over RMS |
7777 | UDP | Gameplay — Ares / UE4 stateless connect handshake |
5432 | PostgreSQL | Optional durable account/state storage |
Authentication
HTTP requests use Authorization: Basic riot:{account_key}.
Access-token and entitlements-token endpoints also accept Bearer tokens issued locally.
Default account from launcher: Riot ID as GameName#TAG → normalized
account key GameName-TAG.
CLI Flags
| Flag | Default | Description |
|---|---|---|
--host | 127.0.0.1 | Control-plane bind address |
--port | 39001 | HTTP/HTTPS/WebSocket port |
--game-host | 127.0.0.1 | Host returned in ConnectionDetails |
--game-port | 7777 | UDP gameplay port |
--allow-memory-db | off | In-memory accounts — auto-enabled by start_server.bat when no DB URL |
--database-url | env | PostgreSQL URL for persistent storage |
--reset-state | off | Ignore persisted party/match state on boot |
--resume-state | off | Resume last persisted transient state |
--matchmaking-delay-ms | 0 | Delay before queue advances to pregame (0 = instant) |
--riot-name / --tag-line | DevPlayer / LOCAL | Default local account Riot ID |
Environment Variables
| Variable | Purpose |
|---|---|
PROJECTA_DATABASE_URL | PostgreSQL connection string |
PROJECT_A_RIOT_ID | Riot ID for client launcher (Name#TAG) |
PROJECT_A_CLIENT_EXE | Override path to ShooterClient.exe |
PROJECT_A_MATCHMAKING_DELAY_MS | Matchmaking delay override |
PROJECT_A_AUTO_ACCEPT_FRIEND_REQUESTS | Auto-accept friend requests (1) |
Certificates
On first boot the server generates a local TLS certificate
(reverse-logs/rnet_probe.crt). The client launcher patches
cacert.pem bundles inside the game folder so the client trusts
this CA. Existing bundles are backed up as *.bak-local-ca.
python Server\project_a_server.py --host 127.0.0.1 --port 39001 --allow-memory-db --reset-state
python Server\project_a_server.py --game-port 7777 --matchmaking-delay-ms 0
Bootstrap & Auth
Client startup sequence — process control, local account, tokens, and region config.
GET/process-control/v1/process
Health check — returns isRunning, pid.
GET/local/v1/account
Current local account — Subject, partyId, Riot ID fields.
POST/local/v1/accounts
Create additional local accounts. Body: account_key, game_name, tag_line.
GET/rso-auth/v1/authorization/access-token
RSO access token for authenticated requests.
GET/entitlements/v1/token
Entitlement token payload.
GET/v1/config/{region}
Collapsed client config (e.g. /v1/config/na).
GET/metadata/v1/
Patchline metadata — ClientVersion.
POST/riotclient/region-locale
Set region/locale. Body: {"region": "na", "locale": "en_US"}.
Matchmaking API
Queue configuration endpoints. Handled by routes/matchmaking.py.
GET/matchmaking/v1/queues/configs
All queue configs. Known queue IDs:
custom Local Custom (default, max party 10)
ShootingRange Shooting Range (solo)
v Local Test Queue
unrated Local Unrated
competitive Local Competitive (ranked)
spikerush Local Spike Rush
GET/matchmaking/v1/queues/{queueId}
Single queue config. Also accepts client-version suffix:
GET/matchmaking/v1/queues/unrated/release-0.45-shipping-13-404591
Each queue payload includes QueueID, Mode, Maps, TeamSize, ProvisioningFlow, and wait-time fields.
Party & Queue
Party management and matchmaking entry. Handled by routes/party.py.
GET/parties/v1/players/{subject}
Player party state — CurrentPartyID, eligibility.
GET/parties/v1/parties/{partyId}
Full party payload — members, State, EligibleQueues.
POST/parties/v1/parties/{partyId}/queue
Enter matchmaking. Body: {"QueueID": "unrated"}. Sets party state to MATCHMADE_GAME_STARTING and advances to pregame.
POST/parties/v1/parties/{partyId}/matchmaking/join/{queueId}
Alternate join path — queue ID in URL or body. Calls enter_matchmaking() with immediate_pregame=True.
POST/parties/v1/parties/{partyId}/matchmaking/leave
Leave matchmaking — resets party state to DEFAULT.
POST/parties/v1/parties/{partyId}/makecustomgame
Start custom game setup — optional map/mode in body.
POST/parties/v1/parties/{partyId}/startcustomgame
Launch custom game into pregame character select.
POST/parties/v1/parties/{partyId}/startsoloexperience
Solo experience — skips queue, goes directly to pregame with locked characters.
Pregame
Character select and match provisioning. Handled by routes/pregame.py.
GET/pregame/v1/players/{subject}
Player pregame state — MatchID, CharacterID, CharacterSelectionState.
GET/pregame/v1/matches/{matchId}
Match lobby — teams, PregameState, map/mode.
POST/pregame/v1/matches/{matchId}/select/{characterId}
Hover/select agent.
POST/pregame/v1/matches/{matchId}/lock/{characterId}
Lock agent. When all party members lock, auto-transitions to core phase.
POST/pregame/v1/matches/{matchId}/start
Force start — returns ConnectionDetails with game server host/port.
{
"ConnectionDetails": {
"GameServerHost": "127.0.0.1",
"GameServerPort": 7777,
"GamePodID": "...",
"PlayerKey": "..."
}
}
GET/pregame/v1/matches/{matchId}/chattoken
GET/pregame/v1/matches/{matchId}/voicetoken
Team chat/voice tokens for pregame lobby.
Core Game
In-match state and game server connection. Handled by routes/core_game.py.
GET/core-game/v1/players/{subject}
Active match player state — MatchID when phase is core.
GET/core-game/v1/matches/{matchId}
Match connection details, teams, provisioning state.
POST/core-game/v1/players/{subject}/fixsession
Recover session — forces phase to core, re-primes backend state.
POST/core-game/v1/players/{subject}/disassociate/{matchId}
Disconnect from match.
GET/core-game/v1/matches/{matchId}/allchatmuctoken
GET/core-game/v1/matches/{matchId}/teamchatmuctoken
GET/core-game/v1/matches/{matchId}/teamvoicetoken
In-match chat and voice tokens.
Typical flow tested in test_endpoint_matrix.py:
POST /parties/v1/parties/{partyId}/queue {"QueueID": "v"}
GET /pregame/v1/players/{subject} → MatchID
GET /pregame/v1/matches/{matchId}
POST /pregame/v1/matches/{matchId}/lock/{charId}
POST /pregame/v1/matches/{matchId}/start → ConnectionDetails (port 7777)
GET /core-game/v1/players/{subject}
GET /core-game/v1/matches/{matchId}
Session
Client heartbeat and session keepalive. Handled by routes/session.py.
POST/session/v1/sessions/{subject}/heartbeat
Client loop-state heartbeat. Body may include LoopState, LoopStateMetadata. Triggers presence broadcast.
GET/session/v1/sessions/{subject}
Current session payload for the authenticated player.
WebSocket & RMS
The control plane accepts WebSocket upgrades on the same port as HTTP/HTTPS
(runtime/http.py). After the WAMP handshake, the server pushes
party and match state changes through Riot Messaging Service (RMS)
notifications — the client does not need to poll every transition.
Connection
Client sends Upgrade: websocket to the control-plane port.
Server responds with WAMP session ID and registers the client in
ws_clients. TLS and plain HTTP share the same listener —
first byte 0x16 triggers SSL wrap.
Backend State Push
When party or match state changes (queue join, character lock, phase transition), routes
call broadcast_backend_state_update(). This builds RMS messages
via rms_party_messages() and
rms_match_messages() and sends them to all connected WebSocket
clients for the affected profile.
| Trigger | RMS source | When |
|---|---|---|
| Party change | rms_party_messages() | Invite, join, queue, custom game, accessibility |
| Match change | rms_match_messages() | Pregame select/lock, start, core transition |
| Presence | broadcast_presence_update() | Heartbeat, chat/v2/me update |
| Social | broadcast_social_roster_update() | Friend add/remove, alias change |
HTTP RMS Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /riot-messaging-service/v1/session | RMS session state |
| GET | /riot-messaging-service/v1/out-of-sync | Sync check — returns empty message list |
| GET | /riot-messaging-service/v1/message/{topic} | Fetch pending RMS messages (fallback poll) |
{
"Service": "ares",
"Resource": "/parties/v1/parties/{partyId}",
"EventType": "Update",
"Payload": "…JSON string of party/match state…"
}
Gameplay UDP
After pregame returns ConnectionDetails, the client connects to
the game port (default 7777) over UDP. The server implements a
minimal Ares/UE4 observer — not a full dedicated server. See also
Ares Packet Path for the client-side wire format.
Modules
| File | Role |
|---|---|
gameplay/ares_server.py | Standalone UDP server — challenge/ack handshake + JSONL logging |
gameplay/handshake.py | Stateful Ares handshake observer with UE control channel |
gameplay/ares.py | Frame build/parse, CRC32, bitstream transforms |
gameplay/ue_control_channel.py | UE4 control channel — Welcome, LoginComplete |
ue_game_server.py | Alternate UE-style gameplay responder entry point |
Stateless Connect Handshake
UE4.22 stateless connect flow implemented in AresUdpServer:
| Step | Direction | Action |
|---|---|---|
| 1 | Client → Server | Probe packet (timestamp = 0 or non-handshake) |
| 2 | Server → Client | Challenge — random 20-byte cookie + server timestamp |
| 3 | Client → Server | Response — echoes cookie with client timestamp |
| 4 | Server → Client | Ack — secret_id=true, confirms connection |
Wire Format
Packets use the Ares 6-byte header (CRC32 + u16 length + payload). Handshake payloads
are encoded as UE4 StatelessConnectHandlerComponent bitstreams
(~195 bits). Cookie size: 20 bytes.
python -m Server.projecta.gameplay.ares_server --host 0.0.0.0 --port 7777 --log reverse-logs/ares_udp_server.jsonl
Limitation: Gameplay simulation is incomplete. The UDP layer handles handshake and packet logging; in-match game state is not fully simulated.
Chat, Store & Content
Supporting services the client hits during bootstrap and between matches. All endpoints
are covered by test_full_api_surface.py.
Chat & Social
| Method | Path | Purpose |
|---|---|---|
| GET | /chat/v1/session | Chat session bootstrap |
| PUT | /chat/v2/me | Update own presence |
| GET | /chat/v3/friends | Friend list |
| GET/POST | /chat/v4/friendrequests | List / send friend requests |
| GET/PUT | /chat/v4/presences | Friend presence list / update |
| GET/POST | /chat/v5/conversations | List / join conversations (party MUC) |
| GET | /chat/v5/conversations/{cid}/messages | Conversation history |
| POST | /chat/v5/messages | Send message |
| POST | /chat/v5/conversations/read | Mark conversation read |
Voice
| Method | Path | Purpose |
|---|---|---|
| GET/POST/DELETE | /voice-chat/v2/sessions | Voice session lifecycle |
| GET | /voice-chat/v2/settings | Input mode, volume settings |
| GET | /voice-chat/v2/devices/capture | Capture devices |
| GET | /voice-chat/v2/devices/render | Render devices |
| PUT | /voice-chat/v1/push-to-talk | Push-to-talk toggle |
Store & Wallet
| Method | Path | Purpose |
|---|---|---|
| GET | /store/v1/offers/ | Storefront offers |
| GET | /store/v1/wallet/{subject} | Player wallet balances |
| GET | /cap/v1/wallets | CAP wallet alias |
| GET | /cap/v1/entitlements | All owned entitlements |
| POST | /cap/v1/orders | Purchase item — returns OrderID |
| POST | /payments/v1/initialize-purchase | Initialize purchase flow |
| GET | /entitlements/{typeId}/{subject} | Entitlements by item type |
Content, Contracts & Loadout
| Method | Path | Purpose |
|---|---|---|
| GET | /content-service/v2/content | Characters, maps, modes catalog |
| GET | /contract-definitions/v2/definitions | Contract templates |
| GET | /contracts/v1/contracts/{subject} | Player contract progress |
| POST | /contracts/v1/item-upgrades/{id}/{subject} | Item upgrade order |
| GET | /personalization/v1/players/{subject}/playerloadout | Weapon loadout |
| PUT | /ares-personalization/personalization/v1/players/{subject}/playerloadout | Save loadout |
| GET | /agg-stats/v1/stats/v/0 | Aggregate player stats |
| GET | /mmr/v1/players/{subject}/competitiveupdates | Competitive tier updates |
Account & Policy
| Method | Path | Purpose |
|---|---|---|
| GET/PUT | /player-account/aliases/v1/active | Current / update Riot ID |
| POST | /player-account/aliases/v1/validity | Check name availability |
| PUT | /name-service/v2/players | Resolve display names by subject |
| GET | /anti-addiction/v1/products/ares/policies/*/anti-addiction-state | Playtime / shutdown policies |
| GET | /eula/v1/agreement/content | EULA text |
| GET | /ares-match-details/match-details/v1/matches/{matchId} | Post-match details |
Route Families & Path Normalization
All HTTP handlers are registered in routes/registry.py and
dispatched in order. Before dispatch, routes/normalization.py
rewrites service-prefixed and legacy paths onto the local namespace.
Path Aliases
| Client path prefix | Normalized to |
|---|---|
/ares-core-game/… | /core-game/… |
/ares-personalization/… | /personalization/… |
/ares-parties/… | /parties/… |
/ares-pregame/… | /pregame/… |
/ares-contracts/… | /contracts/… |
/v1/parties/… | /parties/v1/parties/… |
/v1/players/… | /parties/v1/players/… |
Dispatch Order
client bootstrap, auth, config, RMS
chat chat sessions, friends, presences, messages
social friend requests, roster
account local accounts, aliases, validity
policy anti-addiction, EULA
voice voice-chat sessions, devices, push-to-talk
session heartbeats
party parties, invites, custom games, queue join
matchmaking queue configs
pregame character select, match lobby
core_game in-match state, connection details
personalization loadouts, entitlements
content content-service, contract definitions
contracts player contracts, item upgrades
store offers, wallet, CAP orders, payments
reporting player reports
name_service display name resolution
mmr competitive tier data
misc catch-all / auxiliary endpoints