AlRevolver is a set of .NET 10 libraries for building game-oriented applications with dependency injection, scoped game sessions, runtime configuration, save/load snapshots, chain-of-responsibility pipelines, request/response interactions, Godot logging, and Google Sheets asset generation.
The repository is split into small NuGet packages so projects can depend only on the parts they need. The main AlRevolver package is an umbrella package with its own core DLL and references the core runtime packages.
| Package | Purpose |
|---|---|
AlRevolver |
Core game builder, game sessions, dependency injection helpers, and umbrella dependency package. |
AlRevolver.Shared |
Shared primitives such as Unit, IAccessor<T>, and DelegateAccessor<T>. |
AlRevolver.SaveSystem |
Snapshot save/load abstractions and JSON snapshot implementations. |
AlRevolver.Configuration |
Runtime configuration provider and helpers for Microsoft.Extensions.Configuration. |
AlRevolver.ChainOfResponsibility |
Composable chain pipelines and handler abstractions. |
AlRevolver.Interactions |
Request/response interaction abstractions and delegate-backed implementations. |
AlRevolver.GodotLogger |
Microsoft.Extensions.Logging provider integration for Godot output. |
AlRevolver.GoogleSheets |
MSBuild task that generates JSON, ResX files, and designer classes from Google Sheets. |
AlRevolver references these packages:
AlRevolver.SaveSystemAlRevolver.SharedAlRevolver.ConfigurationAlRevolver.ChainOfResponsibilityAlRevolver.Interactions
AlRevolver intentionally does not reference:
AlRevolver.GodotLoggerAlRevolver.GoogleSheets
AlRevolver.GodotLogger is a Godot-specific logging integration and should be installed only by Godot projects that need it.
AlRevolver.GoogleSheets is a build-time MSBuild task and should be referenced directly by projects that need Google Sheets code/resource generation.
- .NET SDK 10.0 or newer.
- Godot .NET SDK 4.6.1 for
AlRevolver.GodotLogger. - Google Sheets API credentials only when using
AlRevolver.GoogleSheetsagainst live Google Sheets.
The solution file is:
AlRevolver.slnx
Install the umbrella package for the common runtime stack:
dotnet add package AlRevolverInstall individual packages when you only need one subsystem:
dotnet add package AlRevolver.SaveSystem
dotnet add package AlRevolver.Configuration
dotnet add package AlRevolver.ChainOfResponsibility
dotnet add package AlRevolver.InteractionsInstall Godot logging separately:
dotnet add package AlRevolver.GodotLoggerInstall Google Sheets generation separately:
dotnet add package AlRevolver.GoogleSheetsusing AlRevolver;
using Microsoft.Extensions.DependencyInjection;
var builder = Game.CreateBuilder();
builder.Services.AddSingleton<GameState>();
var game = builder.Build();
using var session = await game.StartGameSession();
var state = session.ServiceProvider.GetRequiredService<GameState>();
public sealed class GameState
{
public int Turn { get; set; }
}Game.CreateBuilder() gives you a configuration object, service collection, and logging builder. StartGameSession() creates a scoped session provider for session-bound services.
IGame exposes:
LoggerConfigurationServiceProviderCurrentGameSessionStartGameSession()StartGameSession(ISnapshot snapshot)
CurrentGameSession returns the currently active session or null when there is no active session.
using AlRevolver;
var game = Game.CreateBuilder().Build();
Console.WriteLine(game.CurrentGameSession is null);
using var session = await game.StartGameSession();
Console.WriteLine(ReferenceEquals(game.CurrentGameSession, session));Sessions implement IGameSession, which is also an IServiceScope. Use session.ServiceProvider to resolve scoped game services.
The core package includes helpers for registering accessors that resolve values from the current game session.
using AlRevolver;
using Microsoft.Extensions.DependencyInjection;
var builder = Game.CreateBuilder();
builder.Services.AddScoped<PlayerState>();
builder.Services.AddAccessor(provider => provider.GetRequiredService<PlayerState>());
var game = builder.Build();
using var session = await game.StartGameSession();
var accessor = game.ServiceProvider.GetRequiredService<IAccessor<PlayerState>>();
var player = accessor.Access;When no game session is active, the accessor returns null.
AlRevolver.SaveSystem provides snapshot abstractions and JSON-backed snapshot writers.
using AlRevolver.SaveSystem;
using System.Text.Json.Serialization;
var factory = new JsonSnapshotFactory(
GameSnapshotJsonContext.Default,
type => type.Name);
var writer = factory.CreateWriter();
writer.SetData("player", new PlayerState { Level = 3 });
var snapshot = writer.ToSnapshot();
var player = snapshot.GetData<PlayerState>("player");
public sealed class PlayerState
{
public int Level { get; set; }
}
[JsonSerializable(typeof(PlayerState))]
public partial class GameSnapshotJsonContext : JsonSerializerContext;Session services can participate in save/load by implementing ISnapshotSerializable.
using AlRevolver.SaveSystem;
public sealed class PlayerProgress : ISnapshotSerializable
{
public int Level { get; private set; }
public void Save(ISnapshotWriter writer)
{
writer.SetData("player-progress", new PlayerProgressState(Level));
}
public void Load(ISnapshot snapshot)
{
var state = snapshot.GetData<PlayerProgressState>("player-progress");
Level = state?.Level ?? 1;
}
}
public sealed record PlayerProgressState(int Level);When IGame.StartGameSession(ISnapshot snapshot) is used, registered scoped services that implement ISnapshotSerializable are created and loaded from the snapshot.
AlRevolver.Configuration adds a runtime provider that can override configuration values while the application is running.
using AlRevolver.Configuration;
using Microsoft.Extensions.Configuration;
var source = new RuntimeConfigurationSource(new Dictionary<string, string?>
{
["Gameplay:Difficulty"] = "Normal"
});
var configuration = new ConfigurationBuilder()
.Add(source)
.Build();
var runtime = new RuntimeConfiguration(source.Provider, configuration);
runtime.Set("Gameplay:Difficulty", "Hard");
var difficulty = runtime.Get("Gameplay:Difficulty");Calling Set(key, null) removes the runtime override and falls back to the underlying configuration.
AlRevolver.ChainOfResponsibility provides a pipeline that runs ordered handlers against a shared context object.
using AlRevolver.ChainOfResponsibility;
var pipeline = new ChainPipeline<DamageContext>([
new ArmorHandler()
]);
var result = await pipeline.ExecuteAsync(new DamageContext(10));
public sealed record DamageContext(int Amount);
public sealed class ArmorHandler : IChainHandler<DamageContext>
{
public int Order => 10;
public async ValueTask InvokeAsync(
ChainContext<DamageContext> context,
CancellationToken cancellationToken = default)
{
await context.NextAsync();
}
}Handlers can stop the pipeline by not calling NextAsync().
AlRevolver.Interactions provides request/response interaction interfaces and delegate-backed implementations.
using AlRevolver.Interactions;
var greet = Interaction.Create<string, string>(name => $"Hello, {name}");
var message = await greet.HandleAsync("Player");
var getScore = Interaction.Create(() => 100);
var score = await getScore.HandleAsync();Use InteractionCompletion<TResponse> when completion happens from a callback or external event.
var chooseName = Interaction.Create<string>(completion =>
{
completion.TrySetResult("Player");
});
var name = await chooseName.HandleAsync();AlRevolver.GodotLogger connects Microsoft.Extensions.Logging to Godot output.
using AlRevolver.GodotLogger;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
var services = new ServiceCollection();
services.AddLogging(logging =>
{
logging.AddGodotLogging();
});If you already have configuration, use the service collection extension:
using AlRevolver.GodotLogger;
services.AddGodotLogging(configuration);This package is intentionally separate from AlRevolver so non-Godot projects do not receive Godot dependencies.
AlRevolver.GoogleSheets is an MSBuild task package. It reads Google Sheets through the Google Sheets API and generates project files during build.
It can generate:
tables.jsonfrom regular sheets.- Neutral and culture
.resxfiles from sheets ending with.resx. - Public
*.Designer.csresource classes for generated.resxfiles.
Minimal consuming project setup:
<PropertyGroup>
<AlRevolverGoogleSheetsEnabled>true</AlRevolverGoogleSheetsEnabled>
<AlRevolverGoogleSheetsSpreadsheetId>YOUR_SPREADSHEET_ID</AlRevolverGoogleSheetsSpreadsheetId>
<AlRevolverGoogleSheetsCredentialsFile>$(MSBuildProjectDirectory)\credentials.json</AlRevolverGoogleSheetsCredentialsFile>
</PropertyGroup>Then build the consuming project:
dotnet buildIf AlRevolverGoogleSheetsCredentialsFile is not set, the task checks:
ALREVOLVER_GOOGLE_SHEETS_CREDENTIALS_FILEGOOGLE_APPLICATION_CREDENTIALS
See AlRevolver.GoogleSheets/README.md for sheet format rules, ResX generation rules, starting index support, ignored columns, and all MSBuild properties.
AlRevolver/
AlRevolver/ Core package
AlRevolver.Shared/ Shared primitives
AlRevolver.SaveSystem/ Snapshot save/load package
AlRevolver.Configuration/ Runtime configuration package
AlRevolver.ChainOfResponsibility/ Chain pipeline package
AlRevolver.Interactions/ Interaction package
AlRevolver.GodotLogger/ Godot logging package
AlRevolver.GoogleSheets/ Google Sheets MSBuild task package
AlRevolver.GoogleSheets.Staging/ Local staging project for generated assets
AlRevolver.*.Tests/ NUnit test projects
Directory.Build.props Shared NuGet metadata
AlRevolver.slnx Solution file
Restore and build the solution:
dotnet restore AlRevolver.slnx
dotnet build AlRevolver.slnx -c ReleaseBuild a single package project:
dotnet build AlRevolver\AlRevolver.csproj -c ReleaseBuild the Godot logger package separately if you are only validating Godot integration:
dotnet build AlRevolver.GodotLogger\AlRevolver.GodotLogger.csproj -c ReleaseRun the main test projects:
dotnet test AlRevolver.Tests\AlRevolver.Tests.csproj -c Release
dotnet test AlRevolver.SaveSystem.Tests\AlRevolver.SaveSystem.Tests.csproj -c Release
dotnet test AlRevolver.Configuration.Tests\AlRevolver.Configuration.Tests.csproj -c Release
dotnet test AlRevolver.ChainOfResponsibility.Tests\AlRevolver.ChainOfResponsibility.Tests.csproj -c Release
dotnet test AlRevolver.GoogleSheets.Tests\AlRevolver.GoogleSheets.Tests.csproj -c ReleaseCreate NuGet packages into artifacts/nuget:
dotnet pack AlRevolver.SaveSystem\AlRevolver.SaveSystem.csproj -c Release -o artifacts\nuget
dotnet pack AlRevolver.Shared\AlRevolver.Shared.csproj -c Release -o artifacts\nuget
dotnet pack AlRevolver.Configuration\AlRevolver.Configuration.csproj -c Release -o artifacts\nuget
dotnet pack AlRevolver.ChainOfResponsibility\AlRevolver.ChainOfResponsibility.csproj -c Release -o artifacts\nuget
dotnet pack AlRevolver.Interactions\AlRevolver.Interactions.csproj -c Release -o artifacts\nuget
dotnet pack AlRevolver\AlRevolver.csproj -c Release -o artifacts\nuget
dotnet pack AlRevolver.GodotLogger\AlRevolver.GodotLogger.csproj -c Release -o artifacts\nuget
dotnet pack AlRevolver.GoogleSheets\AlRevolver.GoogleSheets.csproj -c Release -o artifacts\nugetThe current package metadata is shared through Directory.Build.props. Individual projects define their own PackageId, Title, Description, PackageTags, and package README.
Each package project contains its own README.md, and each .csproj includes it with:
<PackageReadmeFile>README.md</PackageReadmeFile>The readme file is packed at the package root so NuGet can display package-specific documentation.
The repository currently uses a shared package version in Directory.Build.props.
<Version>1.1.0</Version>Update that value when preparing a new aligned release of the package set. If a package needs to version independently, override Version in that package's .csproj.
- Keep package-specific usage details in each package README.
- Keep repository-wide setup, package relationships, build, test, and release instructions in this root README.
- Do not add
AlRevolver.GodotLoggerorAlRevolver.GoogleSheetsas dependencies of the mainAlRevolverpackage unless the package strategy changes. - Avoid committing local Google credentials. Use local secret files or CI secrets for Google Sheets generation.