Skip to main content
This guide walks you through creating your first plugin for Sakuya AC. We’ll build a simple plugin that adds a custom command and monitors flight data.

Prerequisites

Before creating plugins, you should understand:
  • Basic Python programming
  • How the YSFlight network protocol works (see Packet System)
  • The packet types available in lib/PacketManager/packets

Creating Your First Plugin

1

Create the Plugin File

Create a new Python file in the plugins/ directory:
touch plugins/my_first_plugin.py
The filename will be used as the plugin name when loaded.
2

Add the ENABLED Flag

Every plugin must have an ENABLED flag. This allows you to disable plugins without deleting them:
"""
My First Plugin - A simple example plugin
"""

ENABLED = True  # Set to False to disable this plugin
The PluginManager will only load plugins where ENABLED = True
3

Create the Plugin Class

Every plugin needs a Plugin class with an __init__() and register() method:
class Plugin:
    def __init__(self):
        self.plugin_manager = None
    
    def register(self, plugin_manager):
        """Called by PluginManager during plugin loading"""
        self.plugin_manager = plugin_manager
        # Register hooks and commands here
The register() method is where you hook into events and register commands.
4

Register a Command

Let’s add a simple command that responds to /hello:
from lib import YSchat

ENABLED = True

class Plugin:
    def __init__(self):
        self.plugin_manager = None
    
    def register(self, plugin_manager):
        self.plugin_manager = plugin_manager
        # Register the /hello command
        self.plugin_manager.register_command(
            'hello',
            self.hello_command,
            help_text="Sends a greeting message"
        )
    
    def hello_command(self, full_message, player, message_to_client, message_to_server):
        """Handle the /hello command"""
        # Send a message back to the player
        response = YSchat.message(f"Hello {player.username}! Welcome to the server.")
        message_to_client.append(response)
        return True
The help_text parameter automatically adds your command to the /help menu
5

Test Your Plugin

  1. Start the Sakuya AC server
  2. Check the logs for: Loaded plugin my_first_plugin
  3. Connect with YSFlight client
  4. Type /help to see your command listed
  5. Type /hello to test it
[INFO] Loaded plugin my_first_plugin

Adding a Hook

Let’s extend the plugin to monitor when players send chat messages:
from lib import YSchat
from lib.PacketManager.packets import FSNETCMD_TEXTMESSAGE

ENABLED = True

class Plugin:
    def __init__(self):
        self.plugin_manager = None
    
    def register(self, plugin_manager):
        self.plugin_manager = plugin_manager
        
        # Register command
        self.plugin_manager.register_command(
            'hello',
            self.hello_command,
            help_text="Sends a greeting message"
        )
        
        # Register hook for chat messages
        self.plugin_manager.register_hook('on_chat', self.on_chat)
    
    def hello_command(self, full_message, player, message_to_client, message_to_server):
        response = YSchat.message(f"Hello {player.username}! Welcome to the server.")
        message_to_client.append(response)
        return True
    
    def on_chat(self, data, player, message_to_client, message_to_server):
        """Called whenever a chat message is sent"""
        decode = FSNETCMD_TEXTMESSAGE(data)
        message = decode.raw_message
        
        # Log the message
        print(f"[CHAT] {player.username}: {message}")
        
        # Return True to allow message to continue normally
        # Return False to block the message
        return True

Understanding Hook Return Values

def on_chat(self, data, player, message_to_client, message_to_server):
    # Process the data but let it continue
    print("Message received")
    return True  # Message proceeds normally

Complete Example Plugin

Here’s a complete working plugin that counts chat messages:
"""
Message Counter Plugin - Counts messages sent by each player
"""
from lib import YSchat
from lib.PacketManager.packets import FSNETCMD_TEXTMESSAGE

ENABLED = True

class Plugin:
    def __init__(self):
        self.plugin_manager = None
        self.message_counts = {}  # Store message counts per player
    
    def register(self, plugin_manager):
        self.plugin_manager = plugin_manager
        self.plugin_manager.register_hook('on_chat', self.on_chat)
        self.plugin_manager.register_hook('on_unjoin', self.on_unjoin)
        self.plugin_manager.register_command(
            'msgcount',
            self.msgcount_command,
            help_text="Shows how many messages you've sent"
        )
    
    def on_chat(self, data, player, message_to_client, message_to_server):
        """Count messages from each player"""
        username = player.username
        if username not in self.message_counts:
            self.message_counts[username] = 0
        self.message_counts[username] += 1
        return True
    
    def on_unjoin(self, data, player, message_to_client, message_to_server):
        """Clean up when player leaves"""
        if player.username in self.message_counts:
            del self.message_counts[player.username]
        return True
    
    def msgcount_command(self, full_message, player, message_to_client, message_to_server):
        """Show message count to player"""
        username = player.username
        count = self.message_counts.get(username, 0)
        response = YSchat.message(f"You have sent {count} messages this session.")
        message_to_client.append(response)
        return True

Next Steps

Plugin Structure

Learn about plugin file structure and best practices

Real Examples

Study complete plugins like radar and chat filter

Build docs developers (and LLMs) love