Creating your first Runelite Plugin:

Clone the Runelite example plugin

To get started with your first runelite plugin, ensure you have:

Build Runelite first in Intellij: How to Build Runelite in IntelliJ IDEA: A Comprehensive Step-by-Step Guide

Click on this link, this is runelite’s offical example plugin that can be used as a base for our plugin: https://github.com/runelite/example-plugin/

Using a template for creating external plugins can offer several advantages:

  1. Structural Guidance: Templates provide a predefined structure and organization for your plugin. This structure often includes essential files, directories, and code snippets that are commonly used, saving you time and effort in setting up the basics.
  2. Best Practices: Templates often incorporate best practices and conventions established by experienced developers. They might include coding standards, naming conventions, and design patterns that can improve the quality and readability of your code.
  3. Consistency: Using a template ensures a level of consistency across different plugins. This consistency can make it easier for other developers to understand your code if they’re familiar with the template’s structure.
  4. Faster Development: By eliminating the need to set up the initial structure from scratch, templates can significantly speed up the development process. This allows you to focus more on implementing the specific functionalities of your plugin.
  5. Community Support: If the template is widely used within the RuneLite plugin development community, it might come with associated forums, documentation, or community support. This can be valuable when seeking help or troubleshooting issues.

However, while templates offer these benefits, it’s crucial to review and understand the code within the template. Always ensure that the template aligns with your project requirements and security standards before using it for plugin development.

Click on the code button and select download zip.

Add New Plugin to Runelite

Once downloaded unzip the file and move the folder and contents into your runelite project, this ensures the project can reference the files.

The destination to move the folder is under:

runelite-client [client] > src > main > java > net.runelite.client > plugins

Easiest way is to open the project and drag the folder into the plugins directory and press the Refactor button.

Rename new plugin directory in Intellij

  • Right-click on the new plugins directory, select Refactor and Rename.
  • Name your plugin, e.g. MyAwesomePlugin.

Set Up Plugin Configuration

  • Inside your new plugin module, modify the settings.gradle file to configure the plugin.

Both the settings.gradle and build.gradle files are crucial steps in setting up the Java project using Gradle, especially when developing a RuneLite plugin or any Java-based project. Here’s why it’s important:

Dependency Management:

  • Dependencies: The build.gradle file allows you to specify external dependencies required for your project. In the case of RuneLite plugin development, it includes dependencies such as the runelite-api and runelite-client. These dependencies are managed and fetched by Gradle when building your project.

Build Automation:

  • Building and Compiling: Gradle uses the build.gradle file to define tasks for building and compiling your project. This includes compiling your Java code, packaging it into a JAR file, and preparing it for execution.

Configuration and Customization:

  • Plugin Configuration: In the context of RuneLite plugins, the build.gradle file helps configure your plugin’s settings, such as specifying the project name, version, and dependencies.

The build.gradle is prebuilt ready from the example plugin the settings.gradle can be changed. In single quotes, replace ‘example’ with the name of the plugin.

Configuring Runelite plugin properties

Inside your new plugin module, modify the runelite-plugin.properties file to update key information about your plugin.

there are 5 key description elements in the properties file.

Purpose of Plugin Descriptor Attributes:

1. displayName:

  • Identification: The name attribute represents the name of your plugin.
  • Visibility: It’s the primary identifier users see when browsing available plugins.
  • Clarity: A clear, concise name helps users understand what your plugin does.

2. Description:

  • Explanation: The description attribute provides a brief summary of what your plugin does.
  • Informative: It helps users understand the purpose and functionality of your plugin at a glance.
  • Clarity and Engagement: A well-written description can attract users to try your plugin.

3. Tags:

  • Categorization: Tags, specified via the tags attribute, help categorize your plugin.
  • Discoverability: They enable users to find plugins related to specific functionalities or areas of interest.
  • Filtering: Tags assist users in filtering and finding plugins that align with their preferences or gameplay style.

Why Use Name, Description, and Tags:

  • User Engagement: Clear, descriptive names and informative descriptions attract users and encourage them to try your plugin.
  • Discoverability: Well-defined tags improve the discoverability of your plugin within the RuneLite client, making it easier for users to find plugins that suit their needs.
  • Understanding and Context: These attributes provide context about your plugin’s purpose and functionality, helping users decide if it fits their gameplay requirements.
  • Community Interaction: A compelling name, comprehensive description, and relevant tags can also spark interest and engagement within the RuneLite community, leading to feedback and potential improvements for your plugin.

Author attribute within the plugin descriptor offers additional context and recognition for the creator of the RuneLite plugin.

Benefits of Adding the Author Attribute:

1. Attribution and Recognition:

  • Credit: The author attribute allows you to showcase the creator or team behind the plugin.
  • Recognition: It acknowledges the efforts of the plugin developer(s), fostering a sense of ownership and recognition within the RuneLite community.

2. Support and Feedback:

  • Contact Point: Users may wish to provide feedback, report issues, or seek assistance related to the plugin.

In summary, utilizing the name, description, and tags attributes in the plugin descriptor enhances the visibility, understanding, and discoverability of your RuneLite plugin, ultimately contributing to a better user experience and increased adoption among players.

Simply update the green values.

Plugins descriptor:

The plugins attribute within the plugin descriptor in RuneLite serves as a way to specify additional plugins that your plugin relies on or interacts with. It facilitates inter-plugin communication or dependencies between different plugins.

The naming convention is com. <plugin name>. <name of plugin class>

Name of plugin class will be mentioned below and represents the core collection of your java file a “blueprint” for creating objects.

Purpose of the plugins Attribute:

1. Inter-Plugin Communication:

  • Dependency Declaration: If your plugin relies on functionalities provided by another plugin, you can declare this dependency using the plugins attribute.
  • Communication: It allows your plugin to interact with or utilize functionalities provided by other specified plugins.

For this guide my plugin will be called ‘awesome’. Noting i renamed the plugin folder and both the settings.gradle and runelite-plugin.properties file values.

Create Your Plugin Classes

Move the Java class files that implements net.runelite.client.plugins.Plugin. These are located in src to the root folder. The src directory is not the structure we need for this runelite build so it can be removed.

Simply selecting both files, drag and drop on the root plugin folder, then refactor will work.

Rename ExampleConfig to <your plugin Name>Config e.g AwesomeConfig. Also rename ExamplePlugin to <your plugin Name>Plugin e.g AwesomePlugin.

Right click on the file, select Refactor then select Rename.

Config Plugin Class

  1. Configuration Management: A config class allows users to customize plugin behavior without altering the code. It lets users tweak settings through the RuneLite client’s GUI, providing a more user-friendly experience.
  2. Persistent Settings: Configurations can be saved persistently, meaning the settings will be retained even after the user logs out or restarts the game. This ensures that the plugin behaves consistently according to the user’s preferences.
  3. Ease of Maintenance: Separating configuration settings from the main plugin code makes it easier to manage and update. If you need to add or modify settings, you can do so without altering the core functionality of the plugin.

Here’s an example of how you might implement a config class in your RuneLite plugin:

package net.runelite.client.plugins.awesome;

import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;

@ConfigGroup("awesome")
public interface AwesomeConfig extends Config
{
	@ConfigItem(
		keyName = "awesome",
		name = "Says Awesome things",
		description = "The message to show to the user when they login"
	)
	default String greeting()
	{
		return "You are Awesome!";
	}
}

Notice the package is now called net.runelite.client.plugins.awesome this is because we refactored the name to our runelite project.

In this example, AwesomeConfig defines a configuration group for your plugin. It includes a string setting greeting that can be accessed and modified through the RuneLite client’s settings interface.

Later we can use this config within your plugin.

The Core Plugin Class

The plugin class in RuneLite serves as the foundation and structure for extending the RuneLite client’s functionality. There are several reasons why using a plugin class is beneficial:

  1. Modularity and Organization: The plugin class provides a structured way to organize your code. It separates different functionalities or features into distinct plugins, making the codebase modular and easier to manage
  2. Integration with RuneLite Framework: By extending the net.runelite.client.plugins.Plugin class, your plugin gains access to various hooks, interfaces, and methods provided by the RuneLite client. This inheritance enables your plugin to interact with the game client, listen to events, modify UI elements, and access game data.
  3. Event Handling: RuneLite’s EventBus system allows plugins to subscribe to specific game events. The plugin class, when appropriately annotated with @Subscribe, can listen to these events and execute custom logic when they occur, providing a way to respond dynamically to in-game changes.
  4. Lifecycle Management: The plugin class includes methods such as startUp() and shutDown() that allow you to initialize resources when the plugin is activated and clean up when it’s deactivated. This ensures proper resource management and prevents memory leaks.
  5. Configuration Handling: Plugin classes often integrate with configuration classes using dependency injection. This allows plugins to easily access and utilize user-configurable settings, enabling customization without altering the codebase.

Overall, the plugin class acts as a scaffold for your custom functionality within RuneLite, providing a standardized structure, access to the RuneLite framework, event handling capabilities, and lifecycle management. It encapsulates your plugin’s behavior and integrates it seamlessly into the RuneLite client.

The Code

package net.runelite.client.plugins.awesome;

import com.google.inject.Provides;
import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.events.GameStateChanged;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;

@Slf4j
@PluginDescriptor(
	name = "Awesome"
)
public class AwesomePlugin extends Plugin
{
	@Inject
	private Client client;

	@Inject
	private AwesomeConfig config;

	@Override
	protected void startUp() throws Exception
	{
		log.info("The Awesomeness has started!");
	}

	@Override
	protected void shutDown() throws Exception
	{
		log.info("Awesomeness has stopped!");
	}

	@Subscribe
	public void onGameStateChanged(GameStateChanged gameStateChanged)
	{
		if (gameStateChanged.getGameState() == GameState.LOGGED_IN)
		{
			client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "I think " + config.greeting(), null);
		}
	}

	@Provides
	AwesomeConfig provideConfig(ConfigManager configManager)
	{
		return configManager.getConfig(AwesomeConfig.class);
	}
}

extends in Java:

  • In Java, extends is a keyword used to create a subclass of another class. When a class extends another class, it inherits all the non-private fields and methods of that class. The subclass (or child class) can then add its own fields and methods, and it can override methods from the superclass to provide its own implementation. This forms the basis of inheritance in object-oriented programming, facilitating code reuse and hierarchy.
  • For instance, in the context of RuneLite plugin development, when you create a plugin class and extend it from net.runelite.client.plugins.Plugin, you’re inheriting functionalities and structures provided by the Plugin class. By extending it, your plugin class can override its methods like startUp(), shutDown(), and others to customize the behavior specific to your plugin.

@Inject:

  • The @Inject annotation is part of the Java Dependency Injection (DI) framework, commonly used in the context of frameworks like Google Guice or Dagger, but also in other DI frameworks or containers.
  • When used in a field, constructor, or method, @Inject informs the DI framework that an instance of that class or dependency needs to be provided (injected) by the framework itself. In RuneLite plugin development, @Inject is often used in combination with the Guice dependency injection framework, which RuneLite utilizes.
  • In the previous example, @Inject is used to request the Guice framework to provide an instance of MyAwesomePluginConfig to the plugin class. This enables RuneLite to manage the lifecycle and dependencies of the plugin and its associated configurations.

Overall, extends facilitates class inheritance, allowing classes to inherit features from other classes, while @Inject is used in dependency injection frameworks to request and manage the injection of dependencies into a class, simplifying the handling of dependencies and improving code modularity.

@Override:

  • In Java, the @Override annotation is used to indicate that a method in a subclass is overriding a method of its superclass. It’s a way to explicitly declare that the annotated method is intended to override a method from the parent class.
  • This annotation helps in preventing accidental errors when overriding methods, as it informs the compiler to check if the annotated method is actually overriding a superclass method. If the method signature doesn’t match a method in the superclass, the compiler will throw an error, alerting you to a potential mistake.
  • For RuneLite plugins, @Override is commonly used when implementing methods from the net.runelite.client.plugins.Plugin class or its related interfaces, ensuring that you correctly override the necessary methods for your plugin’s functionality.

@Subscribe:

  • In the context of RuneLite plugin development, @Subscribe is used to mark methods that should be subscribed to certain RuneLite events. This annotation comes from the EventBus system used by RuneLite, allowing your plugin to listen and react to specific events within the game.
  • For instance, if you want your plugin to respond to a chat message event or a player movement event, you can create a method within your plugin class and annotate it with @Subscribe. When that event occurs in the game, the method annotated with @Subscribe will be invoked automatically.

@Provides Annotation:

  • The @Provides annotation is typically used in the context of dependency injection frameworks like Google Guice. It’s used to indicate a method that provides an instance of a particular dependency.
  • When combined with Guice, the @Provides annotation is used in a module class to define methods that create and provide instances of classes or dependencies. Guice uses these methods to know how to create instances when they are needed as dependencies.
  • For RuneLite plugins, you might use @Provides in a Guice module to specify how to provide certain dependencies or instances required by your plugin.

In summary, @Override ensures method overriding, @Subscribe allows methods to listen to specific RuneLite events, and @Provides helps in defining how dependencies are provided in the context of a dependency injection framework like Guice. Each serves a specific purpose in RuneLite plugin development, aiding in proper method overriding, event handling, and dependency management.

Test Your Plugin

  • In the Runelite client click on settings and ensure to enable your plugin by setting the toggle to enabled.

Implement Plugin Functionality and Enhancements

Using the RuneLite API:

The RuneLite API provides a set of tools and interfaces to interact with the Old School RuneScape client. Here’s how you can leverage it in your plugin:

  1. Accessing Game Data:
    • The API allows you to retrieve game data such as player information, item details, NPC information, and more.
    • For instance, you can access the player’s current location, stats, inventory, or even the state of the game world.
  2. Modifying UI Elements:
    • You can manipulate the game’s user interface (UI) to display additional information or create custom overlays.
    • This might involve adding new components, changing existing UI elements, or displaying information in specific areas of the game screen.
  3. Creating Overlays:
    • Overlays are visual elements that provide information on top of the game screen.
    • You can create overlays to display data like timers, notifications, tooltips, or any information relevant to the game state.
  4. Listening for Events:
    • RuneLite’s EventBus system allows your plugin to subscribe to various in-game events.
    • Events can range from player actions, chat messages, item pickups, to changes in the game environment. Your plugin can listen to these events and react accordingly.

Testing Your Plugin:

Thorough testing is crucial to ensure your plugin functions correctly:

  1. Functional Testing:
    • Test all aspects of your plugin’s functionality to ensure it works as intended.
    • Check different scenarios, edge cases, and interactions with the game to validate behavior.
  2. User Experience Testing:
    • Consider how users will interact with your plugin. Test usability, responsiveness, and intuitiveness.

Debugging with Logging:

Logging plays a vital role in debugging and maintaining your plugin:

  1. Logging Levels:
    • Use different logging levels (e.g., log.info(), log.debug(), log.error()) to provide varying levels of detail in your logs.
    • Informational logs (log.info()) can provide essential updates or status information.
    • Debug logs (log.debug()) can be used for more detailed information useful for debugging but might be too verbose for regular use.
    • Error logs (log.error()) are crucial for capturing unexpected issues or errors.
  2. Debugging Process:
    • Implement logging strategically throughout your plugin to track the flow of execution and output relevant information during different stages or when specific conditions are met.
    • Utilize logs to trace variables, method calls, and potential issues encountered during runtime.

By effectively using the RuneLite API, thorough testing, and strategic logging practices, you can create robust and reliable plugins for the RuneLite client, enhancing the gaming experience for Old School RuneScape players.

Publish Your Plugin (Optional)

  • If you’re ready to share your plugin, consider hosting it on GitHub or the RuneLite Plugin Hub.

Remember to refer to the RuneLite API documentation and existing plugins for reference and guidance. Continuous testing and refining will help you create a robust and useful plugin for RuneLite!

Take you runelite plugin development journey further and learn how to make a pvp tool! Osrs Plugin Runelite Development: PvP Helper – Part 1

If you’re keen on honing your automation and script design skills, I found an article that walks through setting up a private RuneScape server. It’s an excellent platform for practicing. Here’s the link: Setting up a Private Runeserver – Great for practicing automation and script desgin

6 thoughts on “Creating your first Runelite Plugin:

Leave a Reply

Your email address will not be published. Required fields are marked *