Skip to main content

Overview

Connection packets handle the initial handshake between clients and servers, including authentication, join requests, and disconnect notifications.

FSNETCMD_LOGON

Packet ID: 1 | Direction: Client → Server (Server → Client for acknowledgment) Sent by clients to log into a server. The server replies with an empty LOGON packet to acknowledge successful login.

Location

lib/PacketManager/packets/FSNETCMD_LOGON.py

Fields

username
str
Player’s username (max 16 characters in short form)
version
int
YSFlight version identifier for compatibility checking
alias
str
Full username if longer than 16 characters, otherwise same as username

Methods

decode
method
Decodes the LOGON packet into readable fieldsExample:
from lib.PacketManager.packets import FSNETCMD_LOGON

packet = FSNETCMD_LOGON(data, should_decode=True)
print(f"User: {packet.username}")
print(f"Alias: {packet.alias}")
print(f"Version: {packet.version}")
encode
static method
Creates a LOGON packetParameters:
  • username (str): Player username
  • version (int): YSFlight version number
  • with_size (bool): Include size header
Returns: bytes - Encoded packetExample:
packet = FSNETCMD_LOGON.encode(
    username="Pilot123",
    version=20180930,
    with_size=True
)
alter_version
static method
Modifies the version number in an existing LOGON packetParameters:
  • buffer (bytes): Original packet data
  • new_version (int): New version number
Returns: bytes - Modified packetExample:
# Change client version for compatibility
modified = FSNETCMD_LOGON.alter_version(data, 20180930)

Usage Example

# In proxy.py - handling client login
if packet_type == "FSNETCMD_LOGON":
    decode = FSNETCMD_LOGON(packet)
    player.login(decode)
    info(f"{decode.alias} logged in (version: {decode.version})")
    
    # Check version compatibility
    if decode.version < 20180930:
        warning(f"Old client version: {decode.version}")

FSNETCMD_LOGOFF

Packet ID: 2 | Direction: Client → Server Sent when a client logs off from the server. Appears to be unused by YSFlight in practice.

Location

lib/PacketManager/packets/FSNETCMD_LOGOFF.py

Fields

No payload - empty packet.

Methods

encode
static method
Creates a LOGOFF packetExample:
packet = FSNETCMD_LOGOFF.encode(with_size=True)

FSNETCMD_JOINREQUEST

Packet ID: 8 | Direction: Client → Server (Server → Client for readback) Sent by clients to request joining the simulation with a specific aircraft and starting position.

Location

lib/PacketManager/packets/FSNETCMD_JOINREQUEST.py

Fields

iff
int
IFF (Identification Friend or Foe) team identifier. Note: The value sent is 1 less than the player’s selected IFF.
aircraft
str
Aircraft identifier/name (max 32 characters)
start_pos
str
Starting position identifier (STP name, max 32 characters)
fuel
int
Initial fuel amount
smoke
int
Initial smoke configuration

Methods

decode
method
Decodes the join request packetExample:
from lib.PacketManager.packets import FSNETCMD_JOINREQUEST

packet = FSNETCMD_JOINREQUEST(data, should_decode=True)
print(f"Aircraft: {packet.aircraft}")
print(f"Start: {packet.start_pos}")
print(f"IFF: {packet.iff}")
print(f"Fuel: {packet.fuel}")
encode
static method
Creates a JOINREQUEST packetParameters:
  • iff (int): Team identifier
  • aircraft (str): Aircraft name
  • start_pos (str): Starting position
  • fuel (int): Initial fuel
  • smoke (int): Smoke configuration
  • with_size (bool): Include size header
Example:
packet = FSNETCMD_JOINREQUEST.encode(
    iff=0,
    aircraft="F-16C",
    start_pos="CARRIER",
    fuel=5000,
    smoke=0,
    with_size=True
)

Usage Example

# In proxy.py - handling join request
if packet_type == "FSNETCMD_JOINREQUEST":
    decode = FSNETCMD_JOINREQUEST(packet)
    info(f"{player.username} requesting {decode.aircraft}")
    info(f"Start position: {decode.start_pos}")
    info(f"IFF: {decode.iff}, Fuel: {decode.fuel}")
    
    # Modify aircraft before forwarding
    if decode.aircraft in RESTRICTED_AIRCRAFT:
        decode.aircraft = "F-15C"  # Force different aircraft

Aircraft Replacement Plugin Example

# From aircraft_replacer plugin
from lib.PacketManager.packets import FSNETCMD_JOINREQUEST

def replace_aircraft(data, player):
    packet = FSNETCMD_JOINREQUEST(data)
    
    # Replace old aircraft with new ones
    if packet.aircraft == "F-4E":
        packet.aircraft = "F-15C"
    
    # Re-encode and forward
    new_packet = FSNETCMD_JOINREQUEST.encode(
        iff=packet.iff,
        aircraft=packet.aircraft,
        start_pos=packet.start_pos,
        fuel=packet.fuel,
        smoke=packet.smoke,
        with_size=True
    )
    return new_packet

FSNETCMD_JOINAPPROVAL

Packet ID: 9 | Direction: Server → Client Sent by the server after receiving the readback from the client’s ADDOBJECT packet. Signals that the client is approved to join.

Location

lib/PacketManager/packets/FSNETCMD_JOINAPPROVAL.py

Fields

No payload - empty packet.

Methods

encode
static method
Creates a JOINAPPROVAL packetExample:
packet = FSNETCMD_JOINAPPROVAL.encode(with_size=True)

Join Sequence

The complete join sequence is:
  1. Client sends JOINREQUEST to server
  2. Server sends ADDOBJECT to client (add your aircraft)
  3. Client sends READBACK acknowledging ADDOBJECT
  4. Server sends JOINAPPROVAL ← This packet
  5. Client officially enters the simulation

FSNETCMD_REJECTJOINREQ

Packet ID: 10 | Direction: Server → Client Sent by the server to reject a join request.

Location

lib/PacketManager/packets/FSNETCMD_REJECTJOINREQ.py

Usage

from lib.PacketManager.packets import FSNETCMD_REJECTJOINREQ

# Reject a player's join request
reject_packet = FSNETCMD_REJECTJOINREQ.encode(with_size=True)
message_to_client.append(reject_packet)

Connection Flow Diagram

Client                          Proxy                          Server
  |                               |                               |
  |--- LOGON ------------------->|--- LOGON ------------------->|
  |                               |                               |
  |<-- LOGON (ack) --------------|<-- LOGON (ack) --------------|
  |                               |                               |
  |--- JOINREQUEST ------------->|--- JOINREQUEST ------------->|
  |                               |                               |
  |<-- ADDOBJECT ----------------|<-- ADDOBJECT ----------------|
  |                               |                               |
  |--- READBACK ---------------->|--- READBACK ---------------->|
  |                               |                               |
  |<-- JOINAPPROVAL -------------|<-- JOINAPPROVAL -------------|
  |                               |                               |
  |<-- AIRPLANESTATE (stream)    |<-- AIRPLANESTATE (stream)    |
  |                               |                               |

Version Compatibility

YSFlight uses version numbers to ensure client-server compatibility:
  • 20180930: YSFlight 2018 / YSCE
  • 20191124: YSFlight 20191124
  • Older versions: May not be compatible
The proxy can modify version numbers using FSNETCMD_LOGON.alter_version() to maintain compatibility.

Error Handling

try:
    packet = FSNETCMD_LOGON(data)
except Exception as e:
    warning(f"Failed to decode LOGON packet: {e}")
    # Send rejection or error packet

Build docs developers (and LLMs) love