Game.Modding.Toolchain.ToolchainDependencyManager
Assembly: Game
Namespace: Game.Modding.Toolchain
Type: class
Base: IEnumerable
Summary:
ToolchainDependencyManager coordinates discovery, installation, update, repair and removal of modding toolchain dependencies used by Cities: Skylines II. It maintains a list of registered IToolchainDependency instances, exposes state information for the whole toolchain, performs dependency filtering and ordering, validates disk space, manages user environment variables required by dependencies, and pushes UI notifications / error dialogs during operations. The class also contains several nested helper types (State, DependencyFilter, FilterResult and UserEnvironmentVariableManager) that encapsulate state representation, dependency filtering logic and registry-based environment variable management.
Fields
-
private const string kToolchain
Constant key/name used for notification or logging contexts related to the toolchain. -
private const string kInstallingToolchain
Notification ID / localization key for "InstallingToolchain". -
private const string kUninstallingToolchain
Notification ID / localization key for "UninstallingToolchain". -
private const string kInstallingToolchainFailed
Notification ID / localization key for install failure ("InstallingToolchainFailed"). -
private const string kUninstallingToolchainFailed
Notification ID / localization key for uninstall failure (note: value in original code mirrors install-failed key). -
public static readonly string kUserToolingPath
Default path under user cache where user tooling/modding artifacts are stored (EnvPath.kCacheDataPath + "Modding"). -
public static readonly string kGameToolingPath
Path under game content where bundled tooling is stored (EnvPath.kContentPath + "Game" + ".ModdingToolchain"). -
private readonly List<IToolchainDependency> m_Dependencies
Internal list that holds all registered toolchain dependencies. Used for enumeration, filtering and operations. Use Register() to add dependencies. -
public static readonly ILog log
Logger configured for the Modding subsystem. Used throughout to log info, warnings and errors. -
public static readonly MainDependency m_MainDependency
A pre-initialized MainDependency instance (main/top-level dependency representation). -
public State m_State
Cached internal State struct representing the overall toolchain state (status, stage, progress, details). Exposed via cachedState property. -
private const string kInstalledKey
Registry key path prefix used when tracking installation status. -
private const string kInstalledValue
Registry value name used to indicate whether the toolchain is considered installed.
Note: The class also defines several nested types (UserEnvironmentVariableManager, State, DependencyFilter, FilterResult) that are significant to its behavior but are declared as types rather than raw fields.
Properties
-
public bool isInProgress { get; private set; }
Indicates whether an Install or Uninstall operation is currently running. Readable publicly, only set by the manager. Operations will return early if isInProgress is true. -
public IReadOnlyList<IToolchainDependency> dependencies => m_Dependencies
Read-only view of registered dependencies. Use it to inspect available dependencies and their individual states. -
public State cachedState { get; set; }
Gets or sets the local cached State struct. Setting this property triggers the OnStateChanged event and posts/removes notifications to the UI NotificationSystem based on the status and progress contained in the state. -
private static bool isInstalled { get; set; }
Backed by SharedSettings.instance.modding.isInstalled. Reflects whether the toolchain is considered installed on this machine. Private to the manager but used when computing overall DeploymentState. -
public event Action<State> OnStateChanged
Event invoked whenever cachedState is updated. Subscribers (UI or other systems) can use this to react to state transitions.
Constructors
public ToolchainDependencyManager()
Default constructor (implicit). The class is typically instantiated by the toolchain/deployment framework and dependencies are registered via Register(). No special initialization logic is required by callers beyond registering dependencies.
Methods
-
public IEnumerator<IToolchainDependency> GetEnumerator()
Returns an enumerator over registered dependencies (m_Dependencies.GetEnumerator()). Allows foreach usage. -
IEnumerator IEnumerable.GetEnumerator()
Explicit non-generic enumerator implementation that forwards to the generic GetEnumerator(). -
public void Register<T>() where T : IToolchainDependency, new()
Creates and registers a new dependency instance of type T and adds it to the internal list. Typical usage: Register() at manager initialization. -
public async Task<State> GetCurrentState()
Asynchronously retrieves a fresh DeploymentState (by calling GetDeploymentState in a Task) and updates cachedState with that DeploymentState. Returns the updated cached state. This forces a refresh of dependencies and computes the overall state. -
public async Task Install(List<IToolchainDependency> dependenciesToInstall, CancellationToken token)
Performs ordered installation of the supplied dependencies. Responsibilities: - Avoids concurrent installs if isInProgress.
- Posts a start notification and updates cachedState status to Installing.
- Sorts dependencies using IToolchainDependency.InstallSorting and ensures disk space requirements via CheckFreeSpace.
- For each dependency: sets queued/downloading/installing states, downloads if needed, installs, updates env vars via UserEnvironmentVariableManager.SetEnvVars, and refreshes the dependency state.
- On completion, marks the toolchain installed and posts complete notification.
- Handles OperationCanceledException, AggregateException, ToolchainException and generic Exception with logging and user-facing error dialogs; posts failure notification on errors.
-
Ensures cachedState is reset to Idle and isInProgress = false in the finally block.
-
public async Task Uninstall(List<IToolchainDependency> dependenciesToUninstall, CancellationToken token)
Performs ordered uninstallation of the supplied dependencies. Responsibilities: - Avoids concurrent operations if isInProgress.
- Posts a start notification and updates cachedState status to Uninstalling.
- Sorts using IToolchainDependency.UninstallSorting, marks queued, and optionally prompts the user for confirmation per dependency (uses ConfirmationDialog via UI appBindings).
- For each dependency chosen to be uninstalled: sets removing state and calls Uninstall, then refreshes.
- After uninstall, removes environment variables no longer required via UserEnvironmentVariableManager.RemoveEnvVars.
- Handles exceptions similarly to Install and posts failure notification on errors.
-
Resets cachedState to Idle and isInProgress = false in the finally block.
-
private static void OpenOptions()
Helper that opens the Options UI to the Modding -> General page. Used as an action attached to notifications so a user can click the notification to open options. -
private static void ShowErrorDialog(LocalizedString message, Exception ex = null)
Displays an error dialog using ErrorDialogManager with the given localized message and optional exception details (stack trace extracted and passed as errorDetails). Used on known and unknown errors during install/uninstall. -
private void SetProgress(IToolchainDependency dependency, IToolchainDependency.State dependencyState)
Callback used by dependencies to notify progress. Updates cachedState progress and details from a dependency's reported state. -
private async Task<DeploymentState> GetDeploymentState(CancellationToken token, bool forceRefresh = false, bool throwException = true)
Internal logic that refreshes dependency states (d.Refresh(token)) and computes an aggregate DeploymentState: - If the persistent installation flag (isInstalled) is false -> NotInstalled.
- If any dependency is NotInstalled -> Invalid.
- If any dependency is Outdated -> Outdated.
- Else -> Installed.
-
Returns Unknown if cancelled or if an exception occurs and throwException == false. Logs warnings for exceptions.
-
private static bool CheckFreeSpace(List<IToolchainDependency.DiskSpaceRequirements> requirements, out string message)
Aggregates disk space requirements by drive root, queries available space (IOUtils.GetStorageStatus), and returns false if any requirement cannot be satisfied. The out message contains per-drive human-friendly size info for missing space. Sizes are formatted using KB/MB/GB heuristics and Unity.Mathematics.math.ceil is used for rounding.
Notes on nested helpers: - UserEnvironmentVariableManager: registry-based helper to Set/Remove environment variables for the current user and broadcast WM_SETTINGCHANGE so other processes pick up changes. Used to persist env vars required by dependencies. - DependencyFilter (and FilterResult): filtering logic that, given a desired DeploymentAction (Install/Uninstall/Update/Repair), computes which dependencies must be processed (accept/reject) based on dependsOnInstallation / dependsOnUninstallation relationships, current states and canBeInstalled/canBeUninstalled flags. - State struct: represents the manager's view of the overall operation status including ModdingToolStatus, DeploymentState, current and total stages, optional progress and localized details. Provides helpers to build localized strings and convert to IToolchainDependency.State.
Usage Example
// Example: Initialize manager, register dependencies and start installation.
var manager = new ToolchainDependencyManager();
// Register dependencies during initialization (types implementing IToolchainDependency)
manager.Register<SomeCompilerDependency>();
manager.Register<SomeSdkDependency>();
// Subscribe to state changes (UI or logging)
manager.OnStateChanged += state =>
{
Debug.Log($"Toolchain status: {state.m_Status} state: {state.m_State} progress: {state.m_Progress}");
};
// Request current state (async)
var currentState = await manager.GetCurrentState();
// Create a cancellation token source to control long-running operations
var cts = new CancellationTokenSource();
// Filter desired dependencies using DependencyFilter.Process if needed, or use manager.dependencies
var toInstall = manager.dependencies.Where(d => d.canBeInstalled).ToList();
// Start installation (async)
await manager.Install(toInstall, cts.Token);
// To uninstall
// await manager.Uninstall(toUninstallList, cts.Token);
This manager is intended to be used by the game's modding/toolchain deployment system; callers should handle CancellationToken and observe OnStateChanged for UI updates.