Skip to main content

Overview

Command packets allow direct control of aircraft parameters, chat communication, and weapon loadout configuration. These are essential for creating interactive features and game modifications.

FSNETCMD_AIRCMD

Packet ID: 30 | Direction: Bidirectional (Server ↔ Client) Used to send commands to aircraft, such as changing fuel, payload, engine settings, and flight characteristics.

Location

lib/PacketManager/packets/FSNETCMD_AIRCMD.py

Fields

aircraft_id
int
Target aircraft identifier
message
str
Command string (e.g., “INITFUEL 5000kg” or “*43 1000”)
command
tuple | None
Parsed command tuple (command_name, value) if message starts with *

Methods

decode
method
Decodes the AIRCMD packet and parses command if presentExample:
from lib.PacketManager.packets import FSNETCMD_AIRCMD

packet = FSNETCMD_AIRCMD(data, should_decode=True)
print(f"Aircraft ID: {packet.aircraft_id}")
print(f"Message: {packet.message}")
if packet.command:
    cmd, value = packet.command
    print(f"Command: {cmd} = {value}")
get_command_from_message
method
Parses engine commands (messages starting with *)Parameters:
  • message (str): Command message like “*43 1000”
Returns: tuple | None - (command_name, value) or None if invalidExample:
# Message: "*43 1000"
# Returns: ("WEIGFUEL", "1000")
command, value = packet.get_command_from_message("*43 1000")
encode
static method
Creates an AIRCMD packetParameters:
  • aircraft_id (int): Target aircraft
  • message (str): Command string
  • with_size (bool): Include size header
Returns: bytes - Encoded packetExample:
packet = FSNETCMD_AIRCMD.encode(
    aircraft_id=1,
    message="INITFUEL 5000kg",
    with_size=True
)
set_payload
static method
Sets aircraft payload (cargo/passenger weight)Parameters:
  • aircraft_id (int): Target aircraft
  • payload (int): Payload weight
  • units (str): Weight units (“kg” or “lb”), default “kg”
  • with_size (bool): Include size header
Example:
# Load 2000kg cargo
packet = FSNETCMD_AIRCMD.set_payload(
    aircraft_id=1,
    payload=2000,
    units="kg",
    with_size=True
)
message_to_client.append(packet)
set_command
static method
Sets any aircraft parameter using AIRCMD keywordsParameters:
  • aircraft_id (int): Target aircraft
  • command (str): Command name from AIRCMD_KEYWORDS
  • value (str | int): Command value
  • with_size (bool): Include size header
Example:
# Set fuel to 3750kg
packet = FSNETCMD_AIRCMD.set_command(
    aircraft_id=1,
    command="INITFUEL",
    value="3750kg",
    with_size=True
)
set_afterburner
static method
Enables or disables afterburnerParameters:
  • aircraft_id (int): Target aircraft
  • enabled (int | bool): 1/True for on, 0/False for off
  • with_size (bool): Include size header
Example:
# Turn on afterburner
packet = FSNETCMD_AIRCMD.set_afterburner(
    aircraft_id=1,
    enabled=True,
    with_size=True
)
player.writer.write(packet)

AIRCMD Keywords

Commands are defined in constants.py as AIRCMD_KEYWORDS. Common commands include:
  • INITFUEL - Set fuel amount (e.g., “3750kg”)
  • INITLOAD - Set payload weight (e.g., “2000kg”)
  • AFTBURNR - Afterburner on/off (“TRUE”/“FALSE”)
  • WEIGHCLN - Clean weight of aircraft
  • WEIGFUEL - Maximum fuel weight
  • WEIGLOAD - Maximum payload weight
  • MAXSPEED - Maximum airspeed
  • INITAAM - Initial AAM count
  • INITAGM - Initial AGM count
  • INITBOMB - Initial bomb count
  • POSITION - Set position (“X Y Z [M]”)
  • ATTITUDE - Set attitude (“H P B [DEG]”)
  • INITSPED - Set initial speed
See constants.py:165-472 for the complete list of 100+ commands.

Usage Examples

Refueling System

# From refuel.py plugin
from lib.PacketManager.packets import FSNETCMD_AIRCMD, FSNETCMD_AIRPLANESTATE

def refuel_aircraft(player, data):
    decode = FSNETCMD_AIRPLANESTATE(data)
    
    # Check if near refuel point
    if is_at_refuel_point(decode.position):
        # Add fuel
        new_fuel = decode.fuel + FUEL_RATE
        refuel_packet = FSNETCMD_AIRCMD.set_command(
            player.aircraft.id,
            "INITFUEL",
            f"{new_fuel}kg",
            with_size=True
        )
        player.writer.write(refuel_packet)

Damage-Based Afterburner Control

# From smoke_on_damage plugin
from lib.PacketManager.packets import FSNETCMD_AIRCMD

def on_damage(player, damage_amount):
    if damage_amount > HEAVY_DAMAGE_THRESHOLD:
        # Disable afterburner on heavily damaged aircraft
        disable_ab = FSNETCMD_AIRCMD.set_afterburner(
            player.aircraft.id,
            False,
            with_size=True
        )
        player.message_to_client.append(disable_ab)
    else:
        # Re-enable afterburner when repaired
        enable_ab = FSNETCMD_AIRCMD.set_afterburner(
            player.aircraft.id,
            True,
            with_size=True
        )
        player.message_to_client.append(enable_ab)

Dynamic Aircraft Modification

# Modify aircraft on spawn
def on_join(player):
    commands = [
        FSNETCMD_AIRCMD.set_command(player.aircraft.id, "INITFUEL", "5000kg", True),
        FSNETCMD_AIRCMD.set_command(player.aircraft.id, "INITAAM", "4", True),
        FSNETCMD_AIRCMD.set_command(player.aircraft.id, "INITAGM", "2", True),
        FSNETCMD_AIRCMD.set_payload(player.aircraft.id, 1000, "kg", True)
    ]
    for cmd in commands:
        player.message_to_client.append(cmd)

FSNETCMD_TEXTMESSAGE

Packet ID: 32 | Direction: Bidirectional (Server ↔ Client) Handles in-game chat messages between players.

Location

lib/PacketManager/packets/FSNETCMD_TEXTMESSAGE.py

Fields

raw_message
str
Full message including username in format: “(Username)message text”
user
str
Username of the sender (parsed from raw_message)
message
str
Message text without username prefix

Methods

decode
method
Decodes the text message packet and extracts user/messageExample:
from lib.PacketManager.packets import FSNETCMD_TEXTMESSAGE

msg = FSNETCMD_TEXTMESSAGE(data, should_decode=True)
print(f"{msg.user}: {msg.message}")
# Output: "Pilot123: Hello everyone!"
encode
static method
Creates a text message packetParameters:
  • message (str): Message text (can include username in parentheses)
  • with_size (bool): Include size header
Returns: bytes - Encoded packetExample:
# Server announcement
msg = FSNETCMD_TEXTMESSAGE.encode(
    "Welcome to the server!",
    with_size=True
)
message_to_client.append(msg)

# Message from specific user
msg = FSNETCMD_TEXTMESSAGE.encode(
    "(Admin)Server will restart in 5 minutes",
    with_size=True
)

Usage Examples

Chat Filter Plugin

# From chat_filter.py
from lib.PacketManager.packets import FSNETCMD_TEXTMESSAGE

BAD_WORDS = ["spam", "hack", "cheat"]

def filter_chat(data, player):
    decode = FSNETCMD_TEXTMESSAGE(data)
    
    # Check for bad words
    censored_text = decode.message
    for word in BAD_WORDS:
        if word.lower() in censored_text.lower():
            censored_text = censored_text.replace(word, "***")
    
    # Re-encode with censored text
    if censored_text != decode.message:
        message = FSNETCMD_TEXTMESSAGE.encode(
            f"({decode.user}){censored_text}",
            with_size=True
        )
        return message
    
    return data  # No changes

Chat Commands

# From chat_weather_setter.py
from lib.PacketManager.packets import FSNETCMD_TEXTMESSAGE

def process_commands(data, player):
    msg = FSNETCMD_TEXTMESSAGE(data)
    
    if msg.message.startswith("/fog"):
        # Parse: /fog r,g,b
        try:
            colors = msg.message.split()[1].split(",")
            r, g, b = map(int, colors)
            set_fog_color(r, g, b)
        except:
            error_msg = FSNETCMD_TEXTMESSAGE.encode(
                "Invalid fog argument, usage /fog r,g,b",
                with_size=True
            )
            player.message_to_client.append(error_msg)
    
    elif msg.message.startswith("/time"):
        time = msg.message.split()[1]
        if time == "day":
            set_time_of_day("day")
        elif time == "night":
            set_time_of_day("night")

Discord Integration

# From discordSync.py
from lib.PacketManager.packets import FSNETCMD_TEXTMESSAGE

def relay_to_discord(data):
    msg = FSNETCMD_TEXTMESSAGE(data)
    discord_channel.send(f"**{msg.user}**: {msg.message}")

def discord_to_game(username, message):
    packet = FSNETCMD_TEXTMESSAGE.encode(
        f"({username}){message}",
        with_size=True
    )
    # Broadcast to all players
    for player in CONNECTED_PLAYERS:
        player.message_to_client.append(packet)

Custom Chat Helper

# From YSchat.py
from lib.PacketManager.packets import FSNETCMD_TEXTMESSAGE

def send_chat(username, message):
    """Helper function to send chat messages"""
    msg = f"({username}){message}"
    return FSNETCMD_TEXTMESSAGE.encode(msg, True)

# Usage
welcome_msg = send_chat("Server", "Welcome to Sakuya AC!")
message_to_client.append(welcome_msg)

FSNETCMD_WEAPONCONFIG

Packet ID: 36 | Direction: Bidirectional (Server ↔ Client) Configures aircraft weapon loadouts and smoke colors.

Location

lib/PacketManager/packets/FSNETCMD_WEAPONCONFIG.py

Fields

aircraft_id
int
Target aircraft identifier
number
int
Number of weapon entries (multiplied by 2)
weapon_config
dict
Dictionary mapping weapon types to counts/configurations
  • Key: Weapon name (e.g., “FSWEAPON_AIM9”, “FSWEAPON_BOMB”)
  • Value: Count (int) or RGB color list for smoke

Methods

decode
method
Decodes weapon configuration packetExample:
from lib.PacketManager.packets import FSNETCMD_WEAPONCONFIG

config = FSNETCMD_WEAPONCONFIG(data, should_decode=True)
print(f"Aircraft {config.aircraft_id} weapons:")
for weapon, count in config.weapon_config.items():
    if "SMOKE" in weapon:
        print(f"  {weapon}: RGB{count}")
    else:
        print(f"  {weapon}: {count}")
encode
static method
Creates a weapon configuration packetParameters:
  • aircraft_id (int): Target aircraft
  • weapon_config (dict): Weapon type → count mapping
  • with_size (bool): Include size header
Returns: bytes - Encoded packetExample:
config = {
    "FSWEAPON_AIM9": 4,
    "FSWEAPON_AIM120": 2,
    "FSWEAPON_BOMB": 4,
    "FSWEAPON_GUN": 500
}

packet = FSNETCMD_WEAPONCONFIG.encode(
    aircraft_id=1,
    weapon_config=config,
    with_size=True
)
addSmoke
static method
Adds smoke generators to an aircraft with default gray colorParameters:
  • aircraft_id (int): Target aircraft
Returns: bytes - Encoded packet with size headerExample:
# Add smoke to aircraft
smoke_packet = FSNETCMD_WEAPONCONFIG.addSmoke(player.aircraft.id)
player.message_to_client.append(smoke_packet)

Weapon Types

Defined in constants.py:101-154 as FSWEAPON_DICT:
  • FSWEAPON_GUN (0) - Machine gun
  • FSWEAPON_AIM9 (1) - Short-range AAM
  • FSWEAPON_AGM65 (2) - Air-to-ground missile
  • FSWEAPON_BOMB (3) - Standard bomb
  • FSWEAPON_ROCKET (4) - Unguided rockets
  • FSWEAPON_FLARE (5) - Countermeasure flares
  • FSWEAPON_AIM120 (6) - Medium-range AAM
  • FSWEAPON_BOMB250 (7) - 250lb bomb
  • FSWEAPON_SMOKE (8) - Smoke generator
  • FSWEAPON_BOMB500HD (9) - 500lb high-drag bomb
  • FSWEAPON_AIM9X (10) - Advanced short-range AAM
  • FSWEAPON_SMOKE0-7 (32-39) - Individual smoke colors

Usage Examples

Custom Loadouts

from lib.PacketManager.packets import FSNETCMD_WEAPONCONFIG

def set_air_superiority_loadout(aircraft_id):
    loadout = {
        "FSWEAPON_AIM9": 2,
        "FSWEAPON_AIM120": 4,
        "FSWEAPON_GUN": 500,
        "FSWEAPON_FLARE": 30
    }
    return FSNETCMD_WEAPONCONFIG.encode(aircraft_id, loadout, True)

def set_ground_attack_loadout(aircraft_id):
    loadout = {
        "FSWEAPON_AGM65": 4,
        "FSWEAPON_BOMB": 6,
        "FSWEAPON_ROCKET": 38,
        "FSWEAPON_GUN": 500
    }
    return FSNETCMD_WEAPONCONFIG.encode(aircraft_id, loadout, True)

Smoke Color Configuration

# Custom smoke colors
smoke_config = {
    32: [255, 0, 0],    # Red smoke
    33: [0, 255, 0],    # Green smoke
    34: [0, 0, 255]     # Blue smoke
}

packet = FSNETCMD_WEAPONCONFIG.encode(
    aircraft_id=1,
    weapon_config=smoke_config,
    with_size=True
)

Mission-Based Loadouts

def on_mission_start(player, mission_type):
    if mission_type == "CAP":  # Combat Air Patrol
        loadout = set_air_superiority_loadout(player.aircraft.id)
    elif mission_type == "CAS":  # Close Air Support
        loadout = set_ground_attack_loadout(player.aircraft.id)
    elif mission_type == "TRAINING":
        loadout = FSNETCMD_WEAPONCONFIG.addSmoke(player.aircraft.id)
    
    player.message_to_client.append(loadout)

FSNETCMD_MISSILELAUNCH

Packet ID: 20 | Direction: Bidirectional (Server ↔ Client) Sent when a missile or weapon is launched.

Location

lib/PacketManager/packets/FSNETCMD_MISSILELAUNCH.py

Key Fields

  • weapon_type (int/str) - Weapon identifier
  • position [x, y, z] - Launch position
  • atti [h, p, b] - Launch attitude
  • velocity (float) - Initial velocity
  • fired_by_aircraft (int) - Launching aircraft ID
  • fired_by (int) - Player ID
  • fired_at (int) - Target ID (for guided weapons)

FSNETCMD_GETDAMAGE

Packet ID: 22 | Direction: Bidirectional (Server ↔ Client) Sent when an aircraft or ground target takes damage.

Location

lib/PacketManager/packets/FSNETCMD_GETDAMAGE.py

Key Fields

  • victim_id (int) - ID of damaged object
  • victim_type (int) - Object type (aircraft/ground)
  • attacker_id (int) - ID of attacker
  • attacker_type (int) - Attacker type
  • damage (int) - Damage amount
  • weapon_type (str) - Weapon that caused damage

FSNETCMD_LOCKON

Packet ID: 18 | Direction: Bidirectional (Server ↔ Client) Sent when a player locks onto a target.

Location

lib/PacketManager/packets/FSNETCMD_LOCKON.py

Key Fields

  • locker_id (int) - ID of locking aircraft
  • locker_is_air (bool) - Is locker an aircraft?
  • lockee_id (int) - ID of locked target
  • lockee_is_air (bool) - Is target an aircraft?

Performance Tips

  1. Cache encoded packets that are sent repeatedly
  2. Use with_size=True for network transmission
  3. Batch weapon configs instead of sending multiple packets
  4. Filter chat messages on server side to reduce bandwidth

Build docs developers (and LLMs) love