Naming Folder And Files
This is a Community-Made Guide to get everyone on track with naming standards for folders and files that are used by code mods.
The goal of having standardized naming and folder locations is to make it easier for the players to manage their content.
Most of the time, mods will work within subfolders the game's user data path, a.k.a. C:\Users\%USERNAME%\AppData\LocalLow\Colossal Order\Cities Skylines II
on Windows.
This path must be obtained in code via the Colossal.PSI.Environment.EnvPath.kUserDataPath
variable.
It is discouraged to use any other folder, in order to:
- Maximize compatibility across platforms (macOS, console, Linux on Proton, etc);
- Maximize compatibility with other mods and tools like Skyve's configuration and log-viewing features;
- Limit the amount of surprise for the user seeking to manage their mods' files.
Logs (Logs/YourMod.log)
[edit | edit source]
Besides Unity's famous Player.log in the main user data directory, the game natively stores mods' logs as separate files for each mod in the {EnvPath.kUserDataPath}/Logs
directory.
You do not have to create and manage that file manually, all you have to do is to create a standard Cities: Skylines logger:
public sealed class Mod : IMod {
internal static ILog Log { get; } =
LogManager.GetLogger(nameof(YourMod)).SetShowsErrorsInUI(true);
}
We recommend using your mod namespace as the logger name (or any unique name), and in any case to use that exact same name for your settings file.
If you intend to have multiple loggers, you may append a suffix, ex. LogManager.GetLogger($"{nameof(YourMod)}.{nameof(SubFeature)}")
.
- See also: Logging
Settings (ModsSettings/YourMod/YourMod.coc)
[edit | edit source]
As with logging, the game offers a native way to manage settings files, but indirectly encourages mods (via the official mod template) to create their log file in the root data directory, leading to a lot of clutter and making backups harder to do.
As a community standard, modders are encouraged to store their settings in a {EnvPath.kUserDataPath}/ModsSettings/YourMod
directory.
Inside this directory, it's your realm and you can manage files how you like.
However, most mods only need one config file, and for that use-case we recommend you to create a single YourMod.coc
file.
[FileLocation($"ModsSettings/{nameof(YourMod)}/{nameof(YourMod)}")]
public sealed class Settings(IMod mod) : ModSetting(mod) {
}
We recommend using your mod namespace as the settings directory and file name (or any unique name), and in any case to use that exact same name for your log file.
Note that you don't need to ensure that ModsSettings is created yourself, the game will handle that for you.
- See also: Creating a Settings File
Migrating from YourMod.coc
to ModsSettings/YourMod/YourMod.coc
[edit | edit source]
If you wish to migrate an existing mod and its users to the community-standard ModsSettings
, it's not too late!
You may use this code in your mod's OnLoad()
method, before loading settings, to transparently migrate your users' settings without disruption:
var oldLocation = Path.Combine(EnvPath.kUserDataPath, $"{nameof(YourMod)}.coc");
if (File.Exists(oldLocation)) {
var directory = Path.Combine(
EnvPath.kUserDataPath,
"ModsSettings",
nameof(YourMod));
var correctLocation = Path.Combine(
directory, nameof(YourMod) + ".coc");
Directory.CreateDirectory(directory);
if (File.Exists(correctLocation)) {
File.Delete(oldLocation);
}
else {
File.Move(oldLocation, correctLocation);
}
}
Volatile Data and User custom data (ModsData/YourMod/*)
[edit | edit source]
If you need to store data that is neither settings or logs, another community standard is to use {EnvPath.kUserDataPath}/ModsData/YourMod/
.
Its use cases are:
- Storing cached persistent data, downloaded files, etc.
- Let the user put custom resources that your mod may consume (ex. an asset importer, translations, UI customizations, etc).
- But NOT settings.
Your mod must be able to recover from a deletion of ModsData
folder with its settings preserved.
Temporary and Cache Data[edit | edit source]
If you need to store temporary and/or cache files and don't want to use ModsData
, you may use:
EnvPath.kCacheDataPath
, which resolves toC:\Users\%USERNAME%\AppData\LocalLow\Colossal Order\Cities Skylines II\.cache
on Windows.EnvPath.kTempDataPath
, which resolves toC:\Users\%USERNAME%\AppData\Local\Temp\Colossal Order\Cities Skylines II
on Windows. Note that this is not in the game's user data path. This can be an interesting choice as this is a folder that Windows natively considers as cache data, and will cleanup automatically when Storage Sense is enabled or when the user explicitly uses the Disk Cleanup utility (or other tools like CCleaner). However, we'd strongly argue against its use as users won't generally know about this folder, and be able to troubleshoot/clear cache properly.
Again, we would encourage mod authors to use your mod namespace as a subfolder name in those directories.
However, we encourage mod authors to avoid creating temporary files as much as possible, unless it has a clear positive value and that users are aware of it.
Ideally, the end user should not know and have to worry about cache files at all, and introducing them is introducing more risk of corrupted files and clueless users.
Before considering using cache/temporary files, think twice about whether this should better be a ModsData
file, and if not, ensure your mod handles these files in a robust ways: when are files cleaned up? what happens if files are corrupted? etc.
Code Example[edit | edit source]
Here's an example class that ensures those folders are created as soon as possible (when your assembly is loaded).
using Colossal.PSI.Environment;
using System.IO;
namespace MyCustomMod
{
internal static class Folders
{
internal static string ContentFolder { get; }
internal static string SettingsFolder { get; }
internal static string TempFolder { get; }
static Folders()
{
ContentFolder = Path.Combine(EnvPath.kUserDataPath, "ModsData", nameof(MyCustomMod));
SettingsFolder = Path.Combine(EnvPath.kUserDataPath, "ModsSettings", nameof(MyCustomMod));
TempFolder = Path.Combine(EnvPath.kTempDataPath, nameof(MyCustomMod));
Directory.CreateDirectory(ContentFolder); // Only create those
Directory.CreateDirectory(SettingsFolder); // folders if you
Directory.CreateDirectory(TempFolder); // need them
}
}
}