Engine Plugins
Orchestrator is game-engine agnostic. Unity is the default and primary supported package, and GameCI also ships built-in configurations for other engines such as Godot and Unreal. For custom engines or custom behavior, you can plug in a new engine provider without forking the orchestrator.
An engine plugin tells the orchestrator how to handle engine-specific concerns like cache folders and container lifecycle hooks. Everything else (provisioning, git sync, logging, hooks, secrets) works the same regardless of engine.
How It Works
The orchestrator only needs to know two things about your engine:
- Which folders to cache between builds (e.g.
Libraryfor Unity,.godot/importedfor Godot) - What to run on container shutdown (e.g. Unity needs to return its license)
That's the entire EnginePlugin interface:
interface EnginePlugin {
name: string; // 'unity', 'godot', 'unreal', etc.
cacheFolders: string[]; // folders to cache, relative to project root
preStopCommand?: string; // shell command for container shutdown (optional)
}
Built-In Configurations
Unity is the default engine configuration. When you don't specify --engine or --engine-plugin,
the orchestrator behaves exactly as it always has - caching the Library folder and returning the
Unity license on container shutdown.
GameCI also includes built-in engine configurations for other supported engines. Use engine to
select one of those configurations when the build is not a Unity build. No plugin is required unless
you need a custom engine or want to override the built-in behavior.
Using a Different Engine
Set engine to select a built-in engine configuration, or set both engine and enginePlugin to
load a community or custom engine provider:
# GitHub Actions with a built-in engine configuration
- uses: game-ci/unity-builder@v4
with:
engine: godot
targetPlatform: StandaloneLinux64
# CLI with a built-in engine configuration
game-ci build \
--engine godot \
--target-platform linux
Use enginePlugin only when you need a custom engine provider or when you want to override the
built-in configuration:
- uses: game-ci/unity-builder@v4
with:
engine: custom-engine
enginePlugin: '@your-org/custom-engine-provider'
Plugin Sources
Engine plugins can be loaded from three sources:
| Source | Format | Example |
|---|---|---|
| NPM module | Package name or local path | @game-ci/godot-engine, ./my-plugin.js |
| CLI executable | cli:<path> | cli:/usr/local/bin/my-engine-plugin |
| Docker image | docker:<image> | docker:gameci/godot-engine-plugin |
When no prefix is specified, the plugin is loaded as an NPM module.
NPM Module
The simplest way to distribute an engine plugin. Publish an NPM package that exports an
EnginePlugin object:
// index.ts
export default {
name: 'godot',
cacheFolders: ['.godot/imported', '.godot/shader_cache'],
};
Supports default export, named plugin export, or module.exports:
// CommonJS
module.exports = {
name: 'godot',
cacheFolders: ['.godot/imported'],
};
Install the package in your project, then reference it:
enginePlugin: '@your-org/godot-engine'
Or point to a local file during development:
enginePlugin: './my-engine-plugin.js'
CLI Executable
For plugins written in any language (Go, Python, Rust, shell, etc.). The executable receives a
get-engine-config argument and must print a JSON config on stdout:
$ my-engine-plugin get-engine-config
{"name": "godot", "cacheFolders": [".godot/imported"], "preStopCommand": ""}
Reference it with the cli: prefix:
enginePlugin: 'cli:/usr/local/bin/my-engine-plugin'
Docker Image
For containerized plugin distribution. The image is run with
docker run --rm <image> get-engine-config and must print JSON config on stdout:
FROM alpine
COPY config.json /config.json
ENTRYPOINT ["sh", "-c", "cat /config.json"]
Reference it with the docker: prefix:
enginePlugin: 'docker:your-org/godot-engine-plugin'
Writing an Engine Plugin
To create a plugin for your engine, you need to answer two questions:
What folders should be cached? These are directories that take a long time to regenerate but don't change between builds. For Unity this is
Library, for Godot it's.godot/imported.Does your engine need cleanup on container shutdown? Unity needs to return its license. Most engines don't need anything here -just omit
preStopCommand.
Example: Minimal Godot Plugin
export default {
name: 'godot',
cacheFolders: ['.godot/imported', '.godot/shader_cache'],
};
Example: Engine with License Cleanup
export default {
name: 'my-engine',
cacheFolders: ['Cache', 'Intermediate'],
preStopCommand: '/opt/my-engine/return-license.sh',
};
What the Plugin Controls
The engine plugin only controls orchestrator-level behavior that varies by engine:
| Behavior | Controlled by plugin | Notes |
|---|---|---|
| Cache folders | Yes | Which project folders to persist between builds |
| Container preStop hook | Yes | Shell command run on K8s container shutdown |
| Docker image | No | Passed by the caller via customImage or baseImage |
| Build scripts | No | Owned by the builder action (e.g. unity-builder) |
| Version detection | No | Handled by the caller or builder action |
| License activation | No | Handled by the builder action's entrypoint |
This keeps plugins minimal. A complete engine plugin is typically 3-5 lines of config.
Programmatic Usage
If you're building a custom integration, you can use the engine plugin API directly:
import { setEngine, getEngine, loadEngineFromModule } from '@game-ci/orchestrator';
// Load from an NPM package
const plugin = loadEngineFromModule('@game-ci/godot-engine');
setEngine(plugin);
// Or set inline
setEngine({
name: 'godot',
cacheFolders: ['.godot/imported'],
});
// Check current engine
console.log(getEngine().name); // 'godot'