Skip to content
Aorux01 edited this page Jan 31, 2026 · 4 revisions

Plugin System

Neodyme features a powerful plugin system that allows you to extend server functionality without modifying the core codebase.

Plugin Structure

Plugins are loaded from the plugins/ directory and must follow this structure:

class MyPlugin {
    // Required properties
    name = "MyPlugin";
    version = "1.0.0";
    description = "A custom plugin for Neodyme";

    // Optional: Plugin dependencies
    dependencies = [];

    /**
     * Initialization method - REQUIRED
     * @param {PluginManager} pluginManager - The plugin manager instance
     * @returns {boolean} - Return true if initialization succeeded
     */
    async init(pluginManager) {
        try {
            // Your initialization code here
            LoggerService.log('info', `Plugin ${this.name} initialized successfully`);
            return true;
        } catch (error) {
            LoggerService.log('error', `Failed to initialize ${this.name}: ${error.message}`);
            return false;
        }
    }

    /**
     * Cleanup method - OPTIONAL but recommended
     * Called when plugin is unloaded or server shuts down
     */
    async shutdown() {
        // Clean up resources, close connections, etc.
        LoggerService.log('info', `Plugin ${this.name} shut down`);
    }
}

module.exports = MyPlugin;

Plugin Manager API

The PluginManager class provides these static methods:

Loading Plugins

// Load all plugins from plugins/ directory
await PluginManager.load();

// Load a specific plugin by filename (without .js extension)
await PluginManager.loadPlugin("MyCustomPlugin");

// Get list of loaded plugins
const loadedPlugins = PluginManager.getPlugins();

Management Operations

// Reload a specific plugin
await PluginManager.reloadPlugin("MyPlugin");

// Reload all plugins
await PluginManager.reload();

// Unload all plugins (usually called on server shutdown)
await PluginManager.unloadAll();

Creating Your First Plugin

1. Basic Example: Welcome Message Plugin

class WelcomePlugin {
    name = "WelcomePlugin";
    version = "1.0.0";
    description = "Sends welcome messages to players";

    async init(pluginManager) {
        // Store reference to plugin manager for later use
        this.pluginManager = pluginManager;
        
        // Register event handlers or modify server behavior here
        LoggerService.log('success', 'WelcomePlugin loaded - ready to greet players!');
        return true;
    }

    // Example method that could be called from other parts of your code
    sendWelcomeMessage(playerId) {
        // Your custom logic here
        LoggerService.log('info', `Sending welcome to player ${playerId}`);
    }

    async shutdown() {
        LoggerService.log('info', 'WelcomePlugin unloaded');
    }
}

module.exports = WelcomePlugin;

2. Advanced Example: Discord Integration Plugin

class DiscordIntegration {
    name = "DiscordIntegration";
    version = "2.1.0";
    description = "Integrates Discord with Neodyme server";
    dependencies = [];

    async init(pluginManager) {
        this.pluginManager = pluginManager;
        
        // Check if Discord bot is enabled in config
        if (ConfigManager.get('discordBot')) {
            await this.initializeDiscordBot();
        }
        
        if (ConfigManager.get('discordWebhook')) {
            await this.initializeWebhooks();
        }

        LoggerService.log('success', 'DiscordIntegration plugin loaded');
        return true;
    }

    async initializeDiscordBot() {
        // Discord bot initialization logic
        LoggerService.log('info', 'Discord bot integration enabled');
    }

    async initializeWebhooks() {
        // Webhook initialization logic
        LoggerService.log('info', 'Discord webhook integration enabled');
    }

    async shutdown() {
        // Clean up Discord connections
        LoggerService.log('info', 'DiscordIntegration plugin unloaded');
    }
}

module.exports = DiscordIntegration;

Plugin Configuration

Accessing Server Configuration

Plugins can access the server configuration:

const ConfigManager = require('./managers/ConfigManager');

class ConfigurablePlugin {
    // ... plugin properties

    async init(pluginManager) {
        // Read server configuration
        const debugMode = ConfigManager.get('debug');
        const serverPort = ConfigManager.get('port');
        
        if (debugMode) {
            LoggerService.log('info', `Server running on port ${serverPort}`);
        }
        
        return true;
    }
}

Using Logger Service

LoggerService.log('info', 'Informational message');
LoggerService.log('success', 'Success message');
LoggerService.log('warn', 'Warning message');
LoggerService.log('error', 'Error message');

Best Practices

1. Error Handling

async init(pluginManager) {
    try {
        // Your initialization code
        if (!someRequiredCondition) {
            throw new Error('Required condition not met');
        }
        return true;
    } catch (error) {
        LoggerService.log('error', `Plugin ${this.name} failed: ${error.message}`);
        return false;
    }
}

2. Resource Management

class ResourceIntensivePlugin {
    constructor() {
        this.intervals = [];
        this.timeouts = [];
    }

    async init(pluginManager) {
        // Store intervals/timeouts for cleanup
        this.intervals.push(setInterval(() => {
            this.periodicTask();
        }, 60000));
        
        return true;
    }

    async shutdown() {
        // Clean up all intervals and timeouts
        this.intervals.forEach(clearInterval);
        this.timeouts.forEach(clearTimeout);
        LoggerService.log('info', 'Cleaned up all timers');
    }
}

3. Plugin Dependencies

class DependentPlugin {
    name = "DependentPlugin";
    version = "1.0.0";
    dependencies = ["DatabasePlugin", "AuthPlugin"];

    async init(pluginManager) {
        const plugins = PluginManager.getPlugins();
        const hasDependencies = this.dependencies.every(dep => 
            plugins.some(plugin => plugin.name === dep)
        );
        
        if (!hasDependencies) {
            LoggerService.log('error', `Missing dependencies: ${this.dependencies.join(', ')}`);
            return false;
        }
        
        return true;
    }
}

Hot-Reloading Plugins

Plugins support hot-reloading during runtime:

// Reload a plugin without restarting the server
const success = await PluginManager.reloadPlugin("WelcomePlugin");
if (success) {
    LoggerService.log('success', 'Plugin reloaded successfully');
} else {
    LoggerService.log('error', 'Failed to reload plugin');
}

Plugin Lifecycle

  1. Discovery: PluginManager scans plugins/ directory for .js files
  2. Validation: Checks for required name and init method
  3. Initialization: Calls init() method with PluginManager instance
  4. Runtime: Plugin operates until server shutdown or reload
  5. Cleanup: shutdown() method is called when plugin is unloaded

Common Issues & Solutions

Plugin Not Loading

  • Issue: Plugin file has syntax errors
  • Solution: Check JavaScript syntax and console for error messages

Missing Dependencies

  • Issue: Plugin requires other plugins that aren't loaded
  • Solution: Ensure dependency plugins are loaded first or use dependencies array

Memory Leaks

  • Issue: Plugin doesn't clean up intervals/timeouts
  • Solution: Always implement shutdown() method to clean resources

Your plugins will automatically load when the server starts if they're placed in the plugins/ directory and follow the required structure.

Clone this wiki locally