horizon-plugin-api 0.2.1

API utils and shared types for Horizon plugins
Documentation
I'll explain how to implement and use the Horizon Plugin API in a project. The plugin API you've shared is a framework for building modular functionality for the Horizon game server.

## Understanding the Plugin API

The Horizon Plugin API provides a way to extend the Horizon game server with custom functionality through plugins. Here's how it works:

1. Each plugin is a separate Rust crate that implements specific traits
2. The main server loads plugins dynamically at runtime
3. Plugins can interact with each other and the core server

## Implementing a Plugin

Let's create a simple plugin that adds chat functionality to the Horizon server.

### Step 1: Create the plugin crate structure

First, create a new directory in the `plugins` folder:

```bash
mkdir -p plugins/chat_plugin/src
cd plugins/chat_plugin
```

### Step 2: Create the Cargo.toml file

```toml
[package]
name = "chat_plugin"
version = "0.1.0"
edition = "2021"

[dependencies]
horizon-plugin-api = "0.2.0"
horizon_data_types = "0.4.0"
socketioxide = "0.15.1"
parking_lot = "0.12.3"
serde = "1.0.216"
serde_json = "1.0.134"
```

### Step 3: Implement the plugin

Create `src/lib.rs` with the following code:

```rust
use horizon_data_types::Player;
use socketioxide::extract::SocketRef;
pub use horizon_plugin_api::{Plugin, Pluginstate, LoadedPlugin};
use parking_lot::RwLock;
use std::sync::Arc;
use std::collections::HashMap;
use serde_json::{json, Value};

// Define the plugin API trait
pub trait PluginAPI {
    fn player_joined(&self, socket: SocketRef, player: Arc<RwLock<horizon_data_types::Player>>);
}

// Define the plugin constructor trait
pub trait PluginConstruct {
    fn new(plugins: HashMap<String, (Pluginstate, Plugin)>) -> Plugin;
    fn get_structs(&self) -> Vec<&str>;
}

// Implement the constructor for the Plugin type
impl PluginConstruct for Plugin {
    fn new(_plugins: HashMap<String, (Pluginstate, Plugin)>) -> Plugin {
        println!("Chat plugin initialized!");
        Plugin {}
    }

    fn get_structs(&self) -> Vec<&str> {
        vec!["ChatMessage"]
    }
}

// Implement the API for the Plugin type
impl PluginAPI for Plugin {
    fn player_joined(&self, socket: SocketRef, player: Arc<RwLock<horizon_data_types::Player>>) {
        println!("Player joined chat system");
        setup_chat_listeners(socket, player);
    }
}

// Setup chat event listeners
fn setup_chat_listeners(socket: SocketRef, player: Arc<RwLock<Player>>) {
    // Handle incoming chat messages
    socket.on("chat_message", move |data: socketioxide::extract::Data<Value>, socket: SocketRef| {
        let message = data.0;
        
        // Get player name
        let player_name = player.read().get_name().unwrap_or("Unknown".to_string());
        
        // Create the message payload with sender info
        let payload = json!({
            "sender": player_name,
            "message": message["text"],
            "timestamp": chrono::Utc::now().timestamp()
        });
        
        // Broadcast the message to all clients
        socket.broadcast().emit("chat_broadcast", payload).ok();
        
        // Echo back to sender with confirmation
        socket.emit("chat_sent", json!({"success": true})).ok();
        
        println!("Chat message processed from {}", player_name);
    });
}
```

## Using the Plugin in the Horizon Server

The plugin system automatically loads plugins from the `plugins` directory. Here's how the server interacts with the plugins:

1. The server's `PluginManager` scans the plugins directory during startup
2. It loads each plugin based on the Cargo.toml information
3. Plugins are initialized with the `new()` method
4. The server calls plugin methods like `player_joined` when appropriate

## Testing the Plugin

To test our chat plugin:

1. Build the plugin:
```bash
cd plugins/chat_plugin
cargo build
```

2. Start the Horizon server, which will automatically load our plugin:
```bash
cd ../..
cargo run
```

3. Connect clients to the server and test the chat functionality.

## Advanced Plugin Interactions

Plugins can interact with each other through dependencies. For example, our chat plugin could depend on a permission plugin to check if users are allowed to send messages.

### Implementing Inter-Plugin Communication:

```rust
// In chat_plugin/src/lib.rs:
impl PluginConstruct for Plugin {
    fn new(plugins: HashMap<String, (Pluginstate, Plugin)>) -> Plugin {
        // Get reference to permission plugin
        if let Some((_, permission_plugin)) = plugins.get("permission_plugin") {
            // Cast to the permission plugin's API type
            let permission_api = permission_plugin as &dyn permission_plugin::PluginAPI;
            
            // Use the permission plugin's functionality
            println!("Permission plugin is available: {}", 
                     permission_api.get_version());
        }
        
        Plugin {}
    }
    
    // Rest of implementation...
}
```

## Best Practices for Plugin Development

1. **Keep plugins focused**: Each plugin should do one thing well
2. **Minimize dependencies**: Only depend on other plugins when necessary
3. **Handle errors gracefully**: Don't crash the server if something goes wrong
4. **Document your API**: Make it clear how other plugins can interact with yours
5. **Follow the event-driven model**: Use the event system for most interactions
6. **Keep state minimal**: Don't store large amounts of data in the plugin itself

## Complete Project Structure

A complete Horizon project with plugins would look like:

```
horizon-project/
├── backend_api/         # Backend API implementation
├── plugin_api/          # Plugin API implementation
├── plugins/
│   ├── chat_plugin/     # Our chat plugin
│   ├── permission_plugin/
│   └── other_plugins/
├── server/              # Main server implementation
└── Cargo.toml           # Workspace configuration
```

The plugin system provides a clean, modular architecture that makes it easy to extend the Horizon server with new functionality without modifying the core server code.