Skip to main content

Godot project architecture

Application Scopes

In GFF, aan application scope is an entry point available during a specific period of time in the application lifetime.

The applicationApplication is structured withwithin two scopes:

  • App (res://sources/App.cs): The applicationApp scope, initialized at the start of the application, released before quitting. App isact like a singleton.
  • Game (res://sources/Game.cs): The gameGame scope, initialized when starting or loading a game, released when going back to main menu.

Each scope contains Services that can be accessed from anywhere.
anywhere within the scope. Services are declared in the RegisterServices method of an application scope by filling the dependency builder with instances.

ApplicationApp Scope

The App scope is the first entry point of the Godot application. It's constructor parse command line arguments so they are accessible during the whole execution of the application.

It also have a helper to checks for the availability of a feature (method HasFeature(string tagName)). This method replace Godot's helper OS.HasFeature. In Debug mode, this method allows developers to force features (e.g., "demo", "steam") to report as available by checking specific arguments, overriding Godot feature status.

Services

The service locator pattern is a design pattern used in software development to encapsulate the processes involved in obtaining a service with a strong abstraction layer. This pattern uses a central registry known as the "service locator", which on request returns the information necessary to perform a certain task.

The service locator pattern provides global access to services without the testability issues of singletons. This pattern allows swapping implementations for testing or different platforms while maintaining a simple API for service access.

The API allows to declare services like this:

// Register a service by giving its type. A new instance will automatically be created.
dependencyBuilder.AddSingleton<Application.SaveManager>()
  
// Abstract a service behind an interface. You can get the instance using the interface type. This allows to change the instance depending on some conditions without having to change the code on the user side.
if (App.HasFeature("steam"))
{
  dependencyBuilder.AddSingleton<IDrmService, Application.Store.SteamManager>();
}
else
{
  dependencyBuilder.AddSingleton<IDrmService, Application.Store.NoDrmManager>();
}

// It's also possible to manually instantiate the service (useful when having specific instanciation rules).
dependencyBuilder.AddSingleton<Application.AppSettings>(new Application.AppSettings(this.GetTree().Root))

// You can also provide instances from the scene tree to make them globally accessible.
dependencyBuilder.AddSingleton<Core.UI.LoadingScreen>(this.GetChildren<LoadingScreen>().First())

Services are then accessible from anywhere within the scope of its service locator (the Application Scope):

AppSettings appSettings = App.Services.Get<AppSettings>();
IDrmService drmService = App.Services.Get<IDrmService>();