Extensions

Extensions allow one plugin to add data fields to another plugin's database entries without modifying the original entry class. This is how Spark maintains modularity while letting plugins work together.

When to Use Extensions

Use extensions when your plugin needs to store data on entries that belong to another plugin. Common examples:

  • Combat plugin storing stat values on item entries

  • Crafting plugin storing recipe unlock data on profession entries

  • Progression plugin storing experience rewards on quest entries

If you control both the entry and the data, just add fields directly to the entry. Extensions are for cross-plugin scenarios.

How Extensions Work

An extension consists of three parts:

  1. Extension Data: A ScriptableObject that holds the extra fields, linked to a target entry by ID.

  2. Extension Manifest: A configuration asset that tells the Spark Editor where and how to display the extension.

  3. Extension Logic (optional): Event handlers or other code that uses the extension data.

At runtime, extension data is loaded by SparkExtensionRegistry and accessed by combining the extension type and target entry ID.

Creating Extension Data

Inherit from SparkDatabaseExtensionData:

SparkDatabaseExtensionData inherits from ScriptableObject and has a targetId field that stores the ID of the database entry it extends. This is managed automatically by the Spark Editor.

Storage

Extension data files are stored alongside the plugin that creates them, in a Resources/ subfolder:

Accessing Extension Data at Runtime

Use SparkExtensionRegistry:

The registry uses a cache key format of {ExtensionType}|{TargetId} for O(1) lookups.

IPluginExtension Interface

To make your extension appear in the Spark Editor, implement IPluginExtension:

Properties:

Property
Description

TargetType

The entry type this extension applies to (e.g., typeof(CharacterEntry)).

Priority

Display order in the editor. Higher values appear earlier.

ExtensionDisplayName

Label shown in the Spark Editor.

IsCollapsible

Whether the extension section can be collapsed.

IGlobalPluginExtension

If your extension should apply to multiple entry types, implement IGlobalPluginExtension instead:

The framework wraps each supported type in a GlobalExtensionWrapper for editor rendering.

Extension Manifest

Create a PluginExtensionManifest ScriptableObject to configure how the extension appears:

  1. Right-click in your extension's Editor folder.

  2. Create a PluginExtensionManifest asset.

  3. Configure it with the extension data type, target type, and resource path.

The manifest tells the Spark Editor where to find and create extension data assets.

Extension Folder Structure

The standard folder layout for an extension:

The assembly definition for the extension references both the source plugin and the target plugin's assemblies.

Null Safety

Always guard extension data lookups. The target plugin may be installed but the extension data may not exist for every entry:

This is especially important for optional plugins. If the extension plugin is not installed, the lookup simply returns null.

Best Practices

  • Name extensions clearly: {Feature}{TargetPlugin}Extension (e.g., CombatStatsItemExtension).

  • Keep extension data focused. One extension per concern.

  • Use ShouldShowForTarget() to filter which entries actually need the extension fields.

  • Always null-check extension data at runtime.

  • Store extension data under your plugin's folder, not the target plugin's folder.

  • Add assembly references only to the plugins you actually need.

Last updated

Was this helpful?