Description
Changelog
Reviews (0)

GDDI

A lightweight stupidly simple dependency injection and service locator plugin for Godot, built around a simple API for registering and retrieving game services.

Why GDDI?

Stop cluttering your ProjectSettings with dozens of Node-only autoloads. GDDI gives you a single, clean API to register, lazy-load, and swap lightweight RefCounted services, factory instances, or nodes on demand.

Autoload vs GDDI

Capability Godot autoloads GDDI
Register services Configure each autoload in project settings Register multiple providers by key, at runtime or with GDDInit
Supported values Node only Object, RefCounted, and Node instances
Create on demand Not built in Factories create new instances; lazy factories cache one
Remove on demand Cannot unregister services and it not advised to try to free them Remove a provider or clear all providers at runtime
Flexible node placement Default behaviour cannot be altered Assign your registered nodes wherever you want

Key Features

  • Register and retrieve dependencies with provide() and inject().
  • Register Node services and optionally set their name and scene-tree parent.
  • Keep RefCounted services alive while registered.
  • Create a fresh object on every injection with a factory, or cache the first result with a lazy factory.
  • List and remove registered providers, or clear the container.
  • Register startup services with GDDInit initializer scripts.
  • Configure timestamped GDDI logs by severity, with caller details for debugging.

Prerequisites

  • Godot Engine 4.7 or later.
  • A Godot project where you can install and enable editor plugins.

Installation

Follow these steps to set up the project locally:

  1. Copy the addons/gddi directory into your Godot project's addons directory.
  2. Open the project in Godot and go to Project > Project Settings > Plugins.
  3. Enable the GDDI plugin. It adds the GDDI autoload and the initializer setting.
  4. Use GDDI from your scripts.

Autoload warning: GDDI is an autoload, so startup order matters. Avoid using GDDI from other autoloads, or configure GDDI to load before any autoload that depends on it.

Usage / Examples

Register an ordinary object and retrieve it by key:

# Define your provider(s)
var settings := GameSettings.new()
GDDI.provide(&"settings", settings)

# Then access it any where inside your project
var shared_settings: GameSettings = GDDI.inject(&"settings")

Register a node as a service. By default, an unparented node is added under the GDDI autoload. You can choose a parent and name with the options dictionary:

var audio_service := AudioService.new()
GDDI.provide_node(&"audio", audio_service, {
    "parent": get_tree().root,
    "name": "AudioService",
})

var audio: AudioService = GDDI.inject(&"audio")

Use a factory when each injection should create a new instance, or a lazy factory when the first instance should be reused:

GDDI.provide_factory(&"enemy", func() -> Enemy:
    return Enemy.new()
)

GDDI.provide_lazy(&"profile", func() -> PlayerProfile:
    return PlayerProfile.load_or_create()
)

var new_enemy: Enemy = GDDI.inject(&"enemy")
var profile: PlayerProfile = GDDI.inject(&"profile")

A factory can inject another provider while it runs. For example, register shared settings first, then inject them when creating each game session:

GDDI.provide(&"settings", GameSettings.new())

GDDI.provide_factory(&"game_session", func() -> GameSession:
    var settings: GameSettings = GDDI.inject(&"settings")
    return GameSession.new(settings)
)

var session: GameSession = GDDI.inject(&"game_session")

Avoid self-recursion: A factory or lazy factory can inject other providers while it runs, but it must not inject itself using its own key. Doing so calls the same factory again recursively.

Factory arguments are passed to the callable through inject() or injectv():

GDDI.provide_factory(&"weapon", func(weapon_id: String) -> Weapon:
    return Weapon.create(weapon_id)
)

var sword: Weapon = GDDI.inject(&"weapon", "sword")

An initializer script can register providers during autoload startup. Add its res:// path under Project Settings > Application > GDDI > Initializers:

extends GDDInit

func _registering_dependencies(di: DI) -> void:
    di.provide_factory(&"settings", func():
        return GameSettings.new()
    )

Logging

GDDI logs provider registration, resolution, removal, initializer loading, and related warnings or errors.

Enable Verbose under Project Settings > Application > GDDI to turn on logging. In debug builds this starts at DEBUG; in non-debug builds it starts at WARNING. When Verbose is disabled, logging is off. You can change the threshold while the game is running:

GDDI.set_log_level(GDDILogger.LogLevel.INFO)

Available levels are DEBUG, INFO, WARNING, ERROR, and NONE. The threshold includes messages at that severity and above; for example, INFO emits info, warning, and error messages. NONE disables all messages.

Changelog for version v1.0.1-stable

2026-10-08 12:13:00

No changelog provided for this version.

Reviews

GDDI has no reviews yet.

Login to write a review.

Consider supporting the creators!

If you enjoyed this asset consider supporting its creator. Follow the link below.