Skip to content

Game.Modding.Toolchain.Dependencies.UnityModProjectDependency

Assembly:
Namespace: Game.Modding.Toolchain.Dependencies

Type: class

Base: BaseDependency

Summary:
This dependency manages the "Unity Mods Project" tool shipped with the Cities: Skylines 2 modding toolchain. It knows where the ZIP and the extracted project live, can check if the extracted project is installed and up-to-date (by comparing Unity project version and package dependency lock files), deploys the project by unzipping and launching Unity to let it initialize, and removes the extracted project on uninstall. It integrates with the toolchain's dependency management (logging, state reporting, required disk space). It relies on utilities such as ZipUtilities, CliWrap (to run Unity), LongFile/LongDirectory (long-path aware I/O), and Colossal JSON/YAML helpers.


Fields

  • public const string kProjectName = "UnityModsProject"
    Name identifier for the project bundle shipped with the toolchain.

  • public const string kProjectVersionTxt = "ProjectSettings/ProjectVersion.txt"
    Relative path inside the Unity project ZIP to the ProjectVersion.txt file.

  • public const string kProjectSettingsAsset = "ProjectSettings/ProjectSettings.asset"
    Relative path inside the Unity project ZIP to ProjectSettings.asset (contains bundleVersion YAML).

  • public const string kProjectPackageManifest = "Packages/manifest.json"
    Relative path inside the Unity project ZIP to the packages manifest.

  • public const string kProjectPackageLock = "Packages/packages-lock.json"
    Relative path inside the Unity project ZIP to the packages lock file.

  • public static readonly string kProjectUnzipPath = ToolchainDependencyManager.kUserToolingPath + "/UnityModsProject"
    Full path where the Unity Mods Project is extracted for use (user tooling folder).

  • public static readonly string kProjectZipPath = ToolchainDependencyManager.kGameToolingPath + "/UnityModsProject.zip"
    Full path to the ZIP archive that holds the Unity Mods Project (game tooling folder).

  • public static readonly string kModProjectsUnityVersionPath = kProjectUnzipPath + "/ProjectSettings/ProjectVersion.txt"
    Full path to the extracted project's ProjectVersion.txt.

  • public static readonly string kModProjectsVersionPath = kProjectUnzipPath + "/ProjectSettings/ProjectSettings.asset"
    Full path to the extracted project's ProjectSettings.asset (used to read bundleVersion).

  • public static readonly string kModProjectPackages = kProjectUnzipPath + "/Packages/packages-lock.json"
    Full path to the extracted project's packages-lock.json (used to compare package versions).

Properties

  • public static bool isUnityOpened { get; }
    Returns true when a running Unity process has the mods project open. Implemented as a getter that calls IsUnityOpenWithModsProject(kProjectUnzipPath). Used to avoid deploying/updating while Unity has the project open.

  • public override string name { get; }
    Friendly name shown in toolchain UI: "Unity Mod Project".

  • public override string icon { get; }
    Icon path used in the UI: "Media/Menu/ColossalLogo.svg".

  • public override string version { get; protected set; }
    The dependency version. When first read, if ProjectSettings.asset exists in the extracted project and base.version is null, it will read the YAML bundleVersion from that asset and set version to the shortVersion. The setter stores the value via the base implementation.

  • public override IEnumerable<string> envVariables { get; }
    Environment variables exported by this dependency when active:

  • CSII_PATHSET
  • CSII_UNITYMODPROJECTPATH
  • CSII_UNITYVERSION
  • CSII_ENTITIESVERSION
  • CSII_ASSEMBLYSEARCHPATH

  • public override Type[] dependsOnInstallation { get; }
    Other dependencies required for installation: UnityDependency and UnityLicenseDependency.

  • public override LocalizedString installDescr { get; }
    Localized description shown when installing this dependency: "Options.WARN_TOOLCHAIN_INSTALL_MOD_PROJECT" (identifier).

Constructors

  • public UnityModProjectDependency()
    Default constructor (no explicit constructor defined in source). Inherits base initialization from BaseDependency.

Methods

  • public override Task<bool> IsInstalled(CancellationToken token)
    Checks whether the mods project is installed by verifying that the extracted directory contains a Library folder and the ProjectVersion.txt exists. Returns completed Task.

  • public override Task<bool> IsUpToDate(CancellationToken token)
    Performs an up-to-date check:

  • Reads the extracted project's Unity version (ProjectVersion.txt).
  • Compares to the Unity version provided by UnityDependency.sUnityVersion.
  • Reads bundleVersion from the extracted ProjectSettings.asset and from the ZIP's ProjectSettings.asset; if the extracted project's bundleVersion is older than the ZIP's bundleVersion, it's not up-to-date.
  • Ensures packages-lock.json exists in the extracted project.
  • Loads the extracted packages-lock.json and the ZIP's manifest.json; compares the dependency entries and their versions. If any mismatch is found, returns false.
  • Any exception during checks will be logged and result false.

  • public override Task<bool> NeedDownload(CancellationToken token)
    Always returns false — this dependency uses a prepackaged ZIP available in the toolchain paths and doesn't download from a remote URL.

  • public override Task Download(CancellationToken token)
    No-op; returns completed Task because no download step is required.

  • public override async Task Install(CancellationToken token)
    Installs the mods project by:

  • Throwing if the token is canceled.
  • If Unity currently has the extracted project open, waits (and reports state) until Unity closes that project.
  • Deletes any existing extracted folder, unzips kProjectZipPath into kProjectUnzipPath.
  • Launches Unity with -projectPath -logFile - -quit to let Unity perform initial project setup. Uses CliWrap to run Unity and listens to the process output (logs StandardOutput as debug and StandardError as error).
  • Catches and wraps unexpected exceptions in a ToolchainException with ToolchainError.Install.

  • public override async Task Uninstall(CancellationToken token)
    Uninstalls by deleting the extracted project directory (kProjectUnzipPath). Updates state and logs actions. Wraps unexpected exceptions in a ToolchainException with ToolchainError.Uninstall.

  • public override Task<List<IToolchainDependency.DiskSpaceRequirements>> GetRequiredDiskSpace(CancellationToken token)
    Returns a list of disk space requirements for installation. For this project it returns a single requirement:

  • Path: kProjectUnzipPath
  • Size: 1073741824 (1 GiB)

  • private static Colossal.Version ReadUnityProjectVersion(string path)
    Reads ProjectVersion.txt lines, takes first line, splits on ':', trims and constructs a Colossal.Version representing the Unity version the project was created with.

  • private static Colossal.Version ReadYAMLVersion(IEnumerable<string> lines)
    Parses lines of a YAML asset file (ProjectSettings.asset) and returns the bundleVersion value as a Colossal.Version. Throws an Exception if no "bundleVersion:" entry is found.

  • private static bool IsUnityOpenWithModsProject(string projectPath)
    Checks running processes named "unity" and attempts to retrieve each process' command line. Uses Mono.Options.OptionSet to parse a --projectpath= option from the Unity command line. If any Unity process has a projectPath that, when canonicalized, equals the provided projectPath, returns true. Logs an issue if command-line retrieval fails or exceptions occur; returns false by default.

Usage Example

// Example: ensure the Unity Mods Project is installed and up-to-date from an async toolchain flow.
var dependency = new UnityModProjectDependency();
var cts = new CancellationTokenSource();

if (!await dependency.IsInstalled(cts.Token))
{
    // Report or prompt user that install will start
    await dependency.Install(cts.Token);
}
else if (!await dependency.IsUpToDate(cts.Token))
{
    // Re-install to update (unzip + run Unity to refresh)
    await dependency.Uninstall(cts.Token);
    await dependency.Install(cts.Token);
}

// You can query required disk space:
var requirements = await dependency.GetRequiredDiskSpace(cts.Token);
foreach (var r in requirements)
{
    Console.WriteLine($"Path: {r.m_Path}, RequiredBytes: {r.m_Size}");
}

Notes and caveats: - Installation invokes Unity in batch-like mode to initialize the project; ensure the Unity executable path in UnityDependency.unityExe is valid and licensed. - The up-to-date logic compares both the Unity editor version and per-package versions using packages-lock.json vs manifest.json, so mismatches will force reinstallation. - LongFile/LongDirectory and ZipUtilities are used to support long paths and ZIP extraction; exceptions from those utilities are wrapped into ToolchainException for clearer toolchain-level error handling.