use std::collections::HashMap; use serde::Deserialize; pub const SPIGOT_PLUGIN_CONFIG: &str = "plugin.yml"; /// Represents when a plugin should be loaded #[derive(Debug, Deserialize, Default, Clone, PartialEq)] #[serde(rename_all = "UPPERCASE")] pub enum LoadOrder { Startup, #[default] Postworld, } /// Represents the default permission value #[derive(Debug, Deserialize, Clone, PartialEq)] #[serde(rename_all = "lowercase")] pub enum DefaultPermission { Op, #[serde(alias = "notop")] NotOp, True, False, } impl Default for DefaultPermission { fn default() -> Self { DefaultPermission::Op } } /// Represents a permission node definition #[derive(Debug, Deserialize, Clone)] pub struct Permission { #[serde(default)] pub description: Option, #[serde(default)] pub default: Option, #[serde(default)] pub children: Option>, } /// Represents a command definition #[derive(Debug, Deserialize, Clone)] pub struct Command { #[serde(default)] pub description: Option, #[serde(default)] pub usage: Option, #[serde(default)] pub aliases: Option, #[serde(default)] pub permission: Option, #[serde(rename = "permission-message")] #[serde(default)] pub permission_message: Option, } /// Helper type to handle fields that can be either a single string or a list of strings #[derive(Debug, Deserialize, Clone)] #[serde(untagged)] pub enum StringOrList { Single(String), Multiple(Vec), } impl StringOrList { /// Convert to a Vec regardless of the variant pub fn to_vec(&self) -> Vec { match self { StringOrList::Single(s) => vec![s.clone()], StringOrList::Multiple(v) => v.clone(), } } } /// The main plugin.yml configuration structure #[derive(Debug, Deserialize, Clone)] pub struct SpigotPluginYml { // Required fields /// The name of your plugin pub name: String, /// The current version of the plugin pub version: String, /// The main class of your plugin (extends JavaPlugin) pub main: String, // Optional metadata fields /// A short description of your plugin #[serde(default)] pub description: Option, /// The author(s) of the plugin (can be single or list) #[serde(default)] pub author: Option, /// List of authors (alternative to single author) #[serde(default)] pub authors: Option>, /// Contributors to the plugin #[serde(default)] pub contributors: Option>, /// The website of the plugin #[serde(default)] pub website: Option, // API and loading configuration /// The version of the Paper API (e.g., "1.21") #[serde(rename = "api-version")] #[serde(default)] pub api_version: Option, /// When to load the plugin (STARTUP or POSTWORLD) #[serde(default)] pub load: Option, /// The prefix for log messages #[serde(default)] pub prefix: Option, // Dependencies /// Plugins that must be present for this plugin to load #[serde(default)] pub depend: Option>, /// Plugins that enhance functionality if present #[serde(default)] pub softdepend: Option>, /// Plugins that this plugin should load before #[serde(default)] pub loadbefore: Option>, /// Other plugins this plugin can substitute for #[serde(default)] pub provides: Option>, // Libraries /// Maven dependencies to download #[serde(default)] pub libraries: Option>, // Commands and permissions /// Command definitions #[serde(default)] pub commands: Option>, /// Permission definitions #[serde(default)] pub permissions: Option>, /// Default permission value for unspecified permissions #[serde(rename = "default-permission")] #[serde(default)] pub default_permission: Option, // Paper-specific fields /// Paper plugin loader class #[serde(rename = "paper-plugin-loader")] #[serde(default)] pub paper_plugin_loader: Option, /// Skip library resolution (delegate to loader) #[serde(rename = "paper-skip-libraries")] #[serde(default)] pub paper_skip_libraries: Option, } impl SpigotPluginYml { /// Parse a plugin.yml from a YAML string pub fn from_str(yaml: &str) -> Result { serde_saphyr::from_str(yaml) } /// Get all authors (combines author and authors fields) pub fn get_all_authors(&self) -> Vec { let mut result = Vec::new(); if let Some(ref author) = self.author { result.push(author.clone()); } if let Some(ref authors) = self.authors { result.extend(authors.clone()); } result } /// Check if this plugin depends on another plugin pub fn depends_on(&self, plugin_name: &str) -> bool { if let Some(ref deps) = self.depend { return deps.iter().any(|d| d == plugin_name); } false } /// Check if this plugin soft-depends on another plugin pub fn soft_depends_on(&self, plugin_name: &str) -> bool { if let Some(ref deps) = self.softdepend { return deps.iter().any(|d| d == plugin_name); } false } }