Modding API

From Cities: Skylines Wiki
Jump to: navigation, search

This article is timeless and should be accurate for any version of the game.

Contents


The Modding API is an interface for programmers to override and extend game features. It is presently minimalistic and aims to be so. The available features will evolve alongside user wishes in the future.

The game ships with a C# compiler which allows for automatic script compiling at game start.

The mod user folder is located at:

  • On Windows C:\Users\<username>\AppData\Local\Colossal Order\Cities_Skylines\Addons\Mods
  • On Mac /Users/<username>/Library/Application Support/Colossal Order/Cities_Skylines/Addons/Mods
  • On Linux /home/<username>/.local/share/Colossal Order/Cities_Skylines/Addons/Mods/

Each mod is implemented in a sub-folder of the name of the mod. The sub-folder contains a Source folder where the C# script is situated. When the game starts, it will compile all the files within the Source folder and create a .dll file at the root of the Mod folder. That dll in turn is loaded at runtime and implements the custom behaviors.
The mod implements a set of interfaces defined in the ICities assembly. It is possible to use Microsoft Visual Studio or another programming IDE to compile a dll and bypass the automatic compilation the game provides. The ICities.dll file located at <SteamFolder>\SteamApps\common\Cities_Skylines\Cities_Data\Managed\ICities.dll contains interface definitions. This assembly can be added as a reference to projects within Visual Studio, allowing developers to leverage intellisense when writing mods. Visual Studio can also be used to compile code into assemblies which allows more advanced modding techniques to be used.

The full set of the C# 3.0 language and a subset of the features of C# 4.0 are available, as well as all the functionalities provided by the UnityEngine assembly. When using Visual Studio for compilation, any language version that can be compiled to target .NET Framework 3.5 will do.

Mod can be shared through the Content Manager just like other assets. A check box allows the source code to be embedded in the Workshop item if desired.

Security considerations[edit]

The code in Mods for Cities: Skylines is not executed in a sandbox.
While we trust the gaming community to know how to behave and not upload malicious mods that will intentionally cause damage to users, what is uploaded on the Workshop cannot be controlled.
Like with any files acquired from the internet, caution is recommended when something looks very suspicious.

You can always disable Mods by setting --disableMods in the launch options of the game in your Steam library>Game settings.
This toggle will prevent the game from compiling and loading modded code. However, it might make more sense to just not download any Mods in the first place.
The toggle only applies to Mods involving custom code; assets and non-executable content remain accessible.

Custom options/settings for mods[edit]

Please refer to the page Mod Options Panel if you are looking for details on exposing options/settings in the Options panel for your mod.

Starting a mod[edit]

The first step to creating a mod is to add these lines to the C# file :

using ICities;
using UnityEngine;

Once done, you will want to add a name and a description of the mod.

To do so, the definition class must inherit from IUserMod from the namespace ICities.

Here is an example of a mod definition :


namespace UnlockAllMod {

	public class MyCustomMod : IUserMod {

		public string Name {
			get { return "My mod name"; }
		}

		public string Description {
			get { return "Here is where I define my mod"; }
		}
	}
}


The next step is to implement what you want by overriding the methods provided in the following interfaces: IUserMod, IAreasExtension, IChirperExtension, IDemandExtension, IEconomyExtension, ILevelUpExtension, ILoadingExtension, IMilestonesExtension, ISerializableDataExtension, ITerrainExtension, IThreadingExtension. The created classes and method must inherit from the needed classes. Each interface provides the OnCreated() and OnReleased() callback. These methods are invoked at creation and destruction time but also when recompiling a mod while the game is running. Each interface, targeted for the purpose their name describes also provides an interface to a "manager" in OnCreated() which allows to interact with the game managers directly. So implementing an extension interface provides the callbacks mechanic and the manager reference handle interacting with the game. It can be frustrating to work to the base interfaces as it is required to overload every single method even though you may only need one or just a few of them, for convenience we provide a non-pure abstract implementation of most extensions. IThreadingExtension non-pure counterpart would be ThreadingExtensionBase in example. Inheriting one base class instead of the pure interface will allow you to only override the required methods as well as get access to a IManagers type which links you to all managers, regardless which interface you are in.

Here are the interfaces and a description of what is proposed :

General[edit]

//Thread: Main
void OnCreated(<IRelatedManager> instance);

//Thread: Main
void OnReleased();

//Thread: Any
IManagers managers [] { get; }

These functions are in each base class at the exception of IUserMod, and are called respectively at the creation and the destruction of an instance.
The managers getter returns a global storage for each managers available across different extensions.

Official Modding API[edit]

DataTypes[edit]

Service[edit]

enum Service
{
	None,
	Residential,
	Commercial,
	Industrial,
	Citizen,
	Tourism,
	Office,
	Road,
	Electricity,
	Water,
	Beautification,
	Garbage,
	HealthCare,
	PoliceDepartment,
	Education,
	Monument,
	FireDepartment,
	PublicTransport,
	Disaster
}

Enumeration for service types

SubService[edit]

enum SubService
{
	None,
	ResidentialLow,
	ResidentialLowEco,
	ResidentialHigh,
	ResidentialHighEco,
	CommercialEco,
	CommercialLeisure,
	CommercialTourist,
	CommercialLow,
	CommercialHigh,
	IndustrialGeneric,
	IndustrialForestry,
	IndustrialFarming,
	IndustrialOil,
	IndustrialOre,
	PublicTransportBus,
	PublicTransportCableCar,
	PublicTransportMetro,
	PublicTransportMonorail,
	PublicTransportTaxi,
	PublicTransportTrain,
	PublicTransportShip,
	PublicTransportPlane,
	PublicTransportTram,
	PublicTransportTours,
	OfficeGeneric,
	OfficeHightech,
}

Enumeration for sub-service types

Level[edit]

enum Level
{
	None,
	Level1,
	Level2,
	Level3,
	Level4,
	Level5,
}

Enumeration for building levels

LoadMode[edit]

enum LoadMode
{
	NewMap,
	LoadMap,
	NewGame,
	LoadGame,
	NewAsset,
	LoadAsset,
	NewScenarioFromGame,
	NewScenarioFromMap,
	LoadScenario,
	UpdateScenarioFromGame,
	UpdateScenarioFromMap,
	NewTheme,
	LoadTheme,
}

Enumeration for supported load modes

AppMode[edit]

enum AppMode
{
	Game,
	MapEditor,
	AssetEditor,
	ScenarioEditor,
	ThemeEditor,
}

Enumeration for application modes

Expansion[edit]

enum Expansion
{
	None,
	AfterDark,
	Snowfall,
	NaturalDisasters,
	InMotion,
	GreenCities,
	Parks,
	Industry
}

Enumeration for game expansions

NaturalResource[edit]

enum NaturalResource
{
	Ore,
	Sand,
	Oil,
	Fertility,
	Forest,
	Pollution,
	Burned,
	Destroyed
}

Enumeration of the resources in the Industries expansion

IAreas[edit]

AreasExtensionBase[edit]

Base class to derive from to modify areas/tiles unlocking behaviour

IManagers managers { get; }

Thread: Any
Gets global managers interfaces
For more info on IManagers, see #IManagers

IAreas areaManager { get; set; }

Thread: Any
Gets the area manager interface
For more info on IAreas, see #IAreas

void OnCreated(IAreas areas);

Thread: Main
Invoked when the extension initializes

void OnReleased();

Thread: Main
Invoked when the extension deinitializes

bool OnCanUnlockArea(int x, int z, bool originalResult);

Thread: Any
Invoked when the game checks if an area can be unlocked
Returns true if it can otherwise false
originalResult contains the default estimation from the game

int OnGetAreaPrice(uint ore, uint oil, uint forest, uint fertility, uint water, bool road, bool train, bool ship, bool plane, float landFlatness, int originalPrice);

Thread: Any
Invoked when the game calculates the price of a tile
The parameters provide information on resources and outgoing connections service to allow overriding the cost calculation
originalResult contains the default estimation from the game

void OnUnlockArea(int x, int z);

Thread: Simulation
Invoked when the game unlocks a tile
Notifies which tile index is being unlocked

IAreasExtension[edit]

Pure interface to modify areas/tiles unlocking behaviour

void OnCreated(IAreas areas);

Thread: Main
Invoked when the extension initializes
For more info on IAreas, see #IAreas

void OnReleased();

Thread: Main
Invoked when the extension deinitializes

bool OnCanUnlockArea(int x, int z, bool originalResult);

Thread: Any
Invoked when the game checks if a tile can be unlocked
Returns true if it can otherwise false
originalResult contains the default estimation from the game

int OnGetAreaPrice(uint ore, uint oil, uint forest, uint fertility, uint water, bool road, bool train, bool ship, bool plane, float landFlatness, int originalPrice);

Thread: Any
Invoked when the game calculates the price of a tile
The parameters provide information on resources and outgoing connections service to allow overriding the cost calculation
originalResult contains the default estimation from the game

void OnUnlockArea(int x, int z);

Thread: Simulation
Invoked when the game unlocks a tile
Notifies which tile index is being unlocked

AreasExtensionBase[edit]

Base class to derive from to modify areas/tiles unlocking behaviour

IManagers managers { get; }

Thread: Any
Gets global managers interfaces
For more info on IManagers, see #IManagers

IAreas areaManager { get; set; }

Thread: Any
Gets the area manager interface
For more info on IAreas, see #IAreas

void OnCreated(IAreas areas);

Thread: Main
Invoked when the extension initializes

void OnReleased();

Thread: Main
Invoked when the extension deinitializes

bool OnCanUnlockArea(int x, int z, bool originalResult);

Thread: Any
Invoked when the game checks if an area can be unlocked
Returns true if it can otherwise false
originalResult contains the default estimation from the game

int OnGetAreaPrice(uint ore, uint oil, uint forest, uint fertility, uint water, bool road, bool train, bool ship, bool plane, float landFlatness, int originalPrice);

Thread: Any
Invoked when the game calculates the price of a tile
The parameters provide information on resources and outgoing connections service to allow overriding the cost calculation
originalResult contains the default estimation from the game

void OnUnlockArea(int x, int z);

Thread: Simulation
Invoked when the game unlocks a tile
Notifies which tile index is being unlocked

IBuilding[edit]

IBuilding[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces
For more info on IManagers, see #IManagers

 IEnumerable<string> BuildingTypes();

Thread: Main
Description follows..

 void CreateBuilding(UnityEngine.Vector3 position, float angle, string buildingType);

Thread: Main
Description follows..

 void ReleaseBuilding(ushort id);

Thread: Main
Description follows..

 void RelocateBuilding(ushort id, UnityEngine.Vector3 position, float angle);

Thread: Main
Description follows..

BuildingExtensionBase[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces
For more info on IManagers, see #IManagers

 IBuilding buildingManager { get; set; }

Thread: Any
Gets the building manager interface

 void OnBuildingCreated(ushort id);

Thread: Main
Description follows..

 void OnBuildingReleased(ushort id);

Thread: Main
Description follows..

 void OnBuildingRelocated(ushort id);

Thread: Main
Description follows..

 ICities.SpawnData OnCalculateSpawn(UnityEngine.Vector3 location, ICities.SpawnData spawn);

Thread: Main
Description follows..

 void OnCreated(ICities.IBuilding building);

Thread: Main
Description follows..

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

IChirper[edit]

IChirperMessage[edit]

Chirper message

 string senderName { get; }

Name of the sender

 string text { get; }

Content of the chirp message

 uint senderID { get; }

Citizen id of the sender

IChirper[edit]

A lightweight interface to interact with the Chirper

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 Vector2 builtinChirperPosition { get; set; }

Thread: Main
Gets/Sets the position of the Chirper in UI screen coordinates

 bool DestroyBuiltinChirper();

Thread: Main
Exterminate the Chirper :(

 bool ShowBuiltinChirper(bool show);

Thread: Main
Temporarily show or hide the Chirper panel

 bool SetBuiltinChirperFree(bool free);

Thread: Main
Default chirper configuration is to remain centered on the screen, call this method to turn this behaviour on or off

 bool SetBuiltinChirperAnchor(ChirperAnchor anchor);

Thread: Main
Allows to set the anchor of the chirper panel, it will expand considering the anchor does not move
TopLeft causes the chirper to expand toward the BottomRight, BottomCenter toward TopCenter and so forth...

 void SyncMessages();

Thread: Main
Causes the Chirper to synchronize the messages. Will trigger OnMessagesUpdated()

 void DeleteMessage(IChirperMessage message);

Thread: Main
Deletes a Chirper message

IChirperExtension[edit]

Pure interface to modify the Chirper behaviour

 void OnCreated(IChirper chirper);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 void OnUpdate();

Thread: Main
Called once per frame.

 void OnMessagesUpdated();

Thread: Main
Invoked when the Chirper synchronize messages (after loading a save i.e)

 void OnNewMessage(IChirperMessage message);

Thread: Main
Invoked when the Chirper receives a new message

ChirperExtensionBase[edit]

Base class to derive from to modify the Chirper behaviour

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 IChirper chirper { get; set; }

Thread: Any
Gets the chirper manager interface

 void OnCreated(IChirper c);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 void OnMessagesUpdated();

Thread: Main
Invoked when the Chirper synchronize messages (after loading a save i.e)

 void OnUpdate();

Thread: Main
Called once per frame.

 void OnNewMessage(IChirperMessage message);

Thread: Main
Invoked when the Chirper receives a new message

ChirperAnchor[edit]

 enum ChirperAnchor
 {
   TopLeft,
   TopCenter,
   TopRight,
   BottomLeft,
   BottomCenter,
   BottomRight,
 }

Supported chirper anchors

IDemand[edit]

IDemand[edit]

Demand manager

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

IDemandExtension[edit]

Pure interface to modify demand logic

 void OnCreated(IDemand demand);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 int OnCalculateResidentialDemand(int originalDemand);

Thread: Simulation
Invoked when the game calculates residential demand
originalDemand is the demand calculated by the game, return a different value to override it
The demand is in the range 0 to 100

 int OnCalculateCommercialDemand(int originalDemand);

Thread: Simulation
Invoked when the game calculates commercial demand
originalDemand is the demand calculated by the game, return a different value to override it
The demand is in the range 0 to 100

 int OnCalculateWorkplaceDemand(int originalDemand);

Thread: Simulation
Invoked when the game calculates workplace demand
originalDemand is the demand calculated by the game, return a different value to override it
The demand is in the range 0 to 100

 int OnUpdateDemand(int lastDemand, int nextDemand, int targetDemand);

Thread: Simulation
Returns a smoothed demand for each demand type

DemandExtensionBase[edit]

Base class to derive from to modify demand logic

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 IDemand demandManager { get; set; }

Thread: Any
Gets the demand manager interface

 void OnCreated(IDemand demand);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 int OnCalculateResidentialDemand(int originalDemand);

Thread: Simulation
Invoked when the game calculates residential demand
originalDemand is the demand calculated by the game, return a different value to override it
The demand is in the range 0 to 100

 int OnCalculateCommercialDemand(int originalDemand);

Thread: Simulation
Invoked when the game calculates commercial demand
originalDemand is the demand calculated by the game, return a different value to override it
The demand is in the range 0 to 100

 int OnCalculateWorkplaceDemand(int originalDemand);

Thread: Simulation
Invoked when the game calculates workplace demand
originalDemand is the demand calculated by the game, return a different value to override it
The demand is in the range 0 to 100

 int OnUpdateDemand(int lastDemand, int nextDemand, int targetDemand);

Thread: Simulation
Returns a smoothed demand for each demand type

IEconomy[edit]

IEconomy[edit]

Economy manager

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 long currentMoneyAmount { get; }

Thread: Main
Returns the current money amount being displayed in the UI

 long internalMoneyAmount { get; }

Thread: Simulation
Returns the current money amount internally used by the simulation thread

IEconomyExtension[edit]

Pure interface to modify economy logic

 bool OverrideDefaultPeekResource { get; }

Thread: Simulation
This override must return true to take control of OnPeekResource

 void OnCreated(IEconomy economy);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 long OnUpdateMoneyAmount(long internalMoneyAmount);

Thread: Simulation
Invoked once every four seconds with the simulation set to normal speed. Triggers every time the Economy Manager updates the current money amount.

 int OnPeekResource(EconomyResource resource, int amount);

Thread: Simulation
Invoked when the simulation evaluates if a resource is available.
The amount parameter specifies the amount being evaluated, a return value not equal to the amount parameter notifies the system the player does not have enough resource available.

 int OnFetchResource(EconomyResource resource, int amount, Service service, SubService subService, Level level);

Thread: Simulation
Invoked when the simulation uses resources. Return value is the actual amount to be reduced from money amount.

 int OnAddResource(EconomyResource resource, int amount, Service service, SubService subService, Level level);

Thread: Simulation
Invoked when the simulation adds resources. Return value is the actual amount to be added to money amount.

 int OnGetConstructionCost(int originalConstructionCost, Service service, SubService subService, Level level);

Thread: Any
Return value is construction cost for anything player can build.

 int OnGetMaintenanceCost(int originalMaintenanceCost, Service service, SubService subService, Level level);

Thread: Any
Return value is maintenance cost for anything player can build. This is reduced from money amount 16 times per week.

 int OnGetRelocationCost(int constructionCost, int relocationCost, Service service, SubService subService, Level level);

Thread: Any
Return value is relocation cost for buildings owned by player.

 int OnGetRefundAmount(int constructionCost, int refundAmount, Service service, SubService subService, Level level);

Thread: Any
Return value is refund amount when bulldozing recently build buildings or roads.

EconomyExtensionBase[edit]

Base class to derive from to modify economy logic

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 IEconomy economyManager { get; set; }

Thread: Any
Gets the economy manager interface

 bool OverrideDefaultPeekResource { get; }

Thread: Simulation
This override must return true to take control of OnPeekResource

 void OnCreated(IEconomy economy);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 long OnUpdateMoneyAmount(long internalMoneyAmount);

Thread: Simulation
Invoked once every four seconds with the simulation set to normal speed. Triggers every time the Economy Manager updates the current money amount.

 int OnPeekResource(EconomyResource resource, int amount);

Thread: Simulation
Invoked when the simulation evaluates if a resource is available.
The amount parameter specifies the amount being evaluated, a return value not equal to the amount parameter notifies the system the player does not have enough resource available.

 int OnFetchResource(EconomyResource resource, int amount, Service service, SubService subService, Level level);

Thread: Simulation
Invoked when the simulation uses resources. Return value is the actual amount to be reduced from money amount.

 int OnAddResource(EconomyResource resource, int amount, Service service, SubService subService, Level level);

Thread: Simulation
Invoked when the simulation adds resources. Return value is the actual amount to be added to money amount.

 int OnGetConstructionCost(int originalConstructionCost, Service service, SubService subService, Level level);

Thread: Any
Return value is construction cost for anything player can build.

 int OnGetMaintenanceCost(int originalMaintenanceCost, Service service, SubService subService, Level level);

Thread: Any
Return value is maintenance cost for anything player can build. This is reduced from money amount 16 times per week.

 int OnGetRelocationCost(int constructionCost, int relocationCost, Service service, SubService subService, Level level);

Thread: Any
Return value is relocation cost for buildings owned by player.

 int OnGetRefundAmount(int constructionCost, int refundAmount, Service service, SubService subService, Level level);

Thread: Any
Return value is refund amount when bulldozing recently build buildings or roads.

EconomyResource[edit]

 enum EconomyResource
 {
   None,
   ConstructionCost,
   MaintenanceCost,
   LoanAmount,
   LoanPayment,
   PrivateIncome,
   CitizenIncome,
   TourismIncome,
   PublicIncome,
   RewardAmount,
   PolicyCost,
   BailoutAmount,
   RefundAmount,
   LandPrice,
   All,
 }

ILevelUp[edit]

ILevelUp[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

ILevelUpExtension[edit]

 void OnCreated(ILevelUp LevelUp);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 ResidentialLevelUp OnCalculateResidentialLevelUp(ResidentialLevelUp levelUp, int averageEducation, int landValue, ushort buildingID, Service service, SubService subService, Level currentLevel);

Thread: Simulation
Update levelup data for a residential building

 CommercialLevelUp OnCalculateCommercialLevelUp(CommercialLevelUp levelUp, int averageWealth, int landValue, ushort buildingID, Service service, SubService subService, Level currentLevel);

Thread: Simulation
Update levelup data for a commercial building

 IndustrialLevelUp OnCalculateIndustrialLevelUp(IndustrialLevelUp levelUp, int averageEducation, int serviceScore, ushort buildingID, Service service, SubService subService, Level currentLevel);

Thread: Simulation
Update levelup data for an industrial building

 OfficeLevelUp OnCalculateOfficeLevelUp(OfficeLevelUp levelUp, int averageEducation, int serviceScore, ushort buildingID, Service service, SubService subService, Level currentLevel);

Thread: Simulation
Update levelup data for an office building

LevelUpExtensionBase[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 ILevelUp levelUpManager { get; set; }
 void OnCreated(ILevelUp levelUp);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 ResidentialLevelUp OnCalculateResidentialLevelUp(ResidentialLevelUp levelUp, int averageEducation, int landValue, ushort buildingID, Service service, SubService subService, Level currentLevel);

Thread: Simulation
Update levelup data for a residential building

 CommercialLevelUp OnCalculateCommercialLevelUp(CommercialLevelUp levelUp, int averageWealth, int landValue, ushort buildingID, Service service, SubService subService, Level currentLevel);

Thread: Simulation
Update levelup data for a commercial building

 IndustrialLevelUp OnCalculateIndustrialLevelUp(IndustrialLevelUp levelUp, int averageEducation, int serviceScore, ushort buildingID, Service service, SubService subService, Level currentLevel);

Thread: Simulation
Update levelup data for an industrial building

 OfficeLevelUp OnCalculateOfficeLevelUp(OfficeLevelUp levelUp, int averageEducation, int serviceScore, ushort buildingID, Service service, SubService subService, Level currentLevel);

Thread: Simulation
Update levelup data for an office building

ResidentialLevelUp[edit]

Levelup data for residential buildings

 Level targetLevel;

If target level is greater than current level, building tries to level up

 int educationProgress;

Current education progress to reach next level.
Range 1..15 or 0 if it cannot be calculated right now

 int landValueProgress;

Current landvalue progress to reach next level.
Range 1..15 or 0 if it cannot be calculated right now

 bool landValueTooLow;

Set to true if landvalue is too low for current building level.
Triggers notification icon and eventually causes building to be abandoned

CommercialLevelUp[edit]

Levelup data for commercial buildings

 Level targetLevel;

If target level is greater than current level, building tries to level up

 int wealthProgress;

Current wealth progress to reach next level.
Range 1..15 or 0 if it cannot be calculated right now

 int landValueProgress;

Current landvalue progress to reach next level.
Range 1..15 or 0 if it cannot be calculated right now

 bool landValueTooLow;

Set to true if landvalue is too low for current building level.
Triggers notification icon and eventually causes building to be abandoned

IndustrialLevelUp[edit]

Levelup data for industrial buildings

 Level targetLevel;

If target level is greater than current level, building tries to level up

 int educationProgress;

Current education progress to reach next level.
Range 1..15 or 0 if it cannot be calculated right now

 int serviceProgress;

Current service progress to reach next level.
Range 1..15 or 0 if it cannot be calculated right now

 bool tooFewServices;

Set to true if service coverage is too low for current building level.
Triggers notification icon and eventually causes building to be abandoned

OfficeLevelUp[edit]

Levelup data for office buildings

 Level targetLevel;

If target level is greater than current level, building tries to level up

 int educationProgress;

Current education progress to reach next level.
Range 1..15 or 0 if it cannot be calculated right now

 int serviceProgress;

Current service progress to reach next level.
Range 1..15 or 0 if it cannot be calculated right now

 bool tooFewServices;

Set to true if service coverage is too low for current building level.
Triggers notification icon and eventually causes building to be abandoned

ILoading[edit]

ILoading[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 bool loadingComplete { get; }

Thread: Any
Returns true when the loading of a map/save is completed, otherwise false

 AppMode currentMode { get; }

Thread: Any
Returns the current application mode
Allows to know if the game state is currently in-game, in map editor or in asset editor

 string currentTheme { get; set; }

Thread: Any
Forces a new theme to be applied to the next save. Will only become active when reloading
Options are: "Sunny", "North", "Tropical"

ILoadingExtension[edit]

 void OnCreated(ILoading loading);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 void OnLevelLoaded(LoadMode mode);

Thread: Main
Invoked when a level has completed the loading process
The mode defines what kind of level was just loaded

 void OnLevelUnloading();

Thread: Main
Invoked when the level is unloading (typically when going back to the main menu or prior to loading a new level)

LoadingExtensionBase[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 ILoading loadingManager { get; set; }

Thread: Any
Gets the loading manager interface

 void OnCreated(ILoading loading);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 void OnLevelLoaded(LoadMode mode);

Thread: Main
Invoked when a level has completed the loading process
The mode defines what kind of level was just loaded

 void OnLevelUnloading();

Thread: Main
Invoked when the level is unloading (typically when going back to the main menu or prior to loading a new level)

IManagers[edit]

IManagers[edit]

Helper interface which stores getter to all available game managers

 IAreas areas { get; }

Thread: Any
Gets the areas/tiles manager

 IDemand demand { get; }

Thread: Any
Gets demand manager

 IEconomy economy { get; }

Thread: Any
Gets the economy manager

 ILevelUp levelUp { get; }

Thread: Any
Gets the levelup manager

 IMilestones milestones { get; }

Thread: Any
Gets the milestones manager

 ISerializableData serializableData { get; }

Thread: Any
Gets the serialization manager

 ITerrain terrain { get; }

Thread: Any
Gets the terrain manager

 IThreading threading { get; }

Thread: Any
Gets the threading manager

 ILoading loading { get; }

Thread: Any
Gets the loading manager

IMilestones[edit]

IMilestones[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 string[] EnumerateMilestones();

Thread: Any
Returns an array of string containing the name of all the unlockable milestones

 void UnlockMilestone(string name);

Thread: Simulation
Unlocks the Milestone designated by the name parameter. Use EnumerateMilestones() to list all the available milestone strings

IMilestonesExtension[edit]

 void OnCreated(IMilestones milestones);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 void OnRefreshMilestones();

Thread: Simulation
Called every time the game checks updates the user progression status

 int OnGetPopulationTarget(int originalTarget, int scaledTarget);

Thread: Any
Returns the number of citizens needed to reach to the next milestone
The originalTarget parameter is the number of citizens desired to pass the milestone as foreseen by the developers
The scaledTarget parameter is the number of citizens expected to pass the milestone as calculated by the game accounting for the buildable area

MilestonesExtensionBase[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 IMilestones milestonesManager { get; set; }

Thread: Any
Gets the milestone manager interface

 void OnCreated(IMilestones milestones);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 void OnRefreshMilestones();

Thread: Simulation
Called every time the game checks updates the user progression status

 int OnGetPopulationTarget(int originalTarget, int scaledTarget);

Thread: Any
Returns the number of citizens needed to reach to the next milestone
The originalTarget parameter is the number of citizens desired to pass the milestone as foreseen by the developers
The scaledTarget parameter is the number of citizens expected to pass the milestone as calculated by the game accounting for the buildable area

IResource[edit]

IResource[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 int gridResolution { get; }
 float cellSize { get; }
 int maxDirt { get; }
 void WorldToGridPosition(UnityEngine.Vector3 pos, out int x, out int z);
 UnityEngine.Vector3 GridToWorldPosition(int x, int z);
 byte GetResource(int x, int z, NaturalResource type);
 void SetResource(int x, int z, NaturalResource type, byte value, bool refresh);
 int GetDirt();
 void SetDirt(int dirt);

IResourceExtension[edit]

 void OnCreated(IResource resource);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 int OnGetDirt();
 void OnAfterResourcesModified(int x, int z, NaturalResource type, int amount);
 void OnBeforeResourcesModified(int x, int z, NaturalResource type, int desiredAmount);

ResourceExtensionBase[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 IResource resourceManager { get; }

Thread: Any
Gets the resource manager interface

 void OnCreated(IResource resource);

Thread: Main
Invoked when the extension initializes

 int OnGetDirt();
 void OnAfterResourcesModified(int x, int z, NaturalResource type, int amount);
 void OnBeforeResourcesModified(int x, int z, NaturalResource type, int desiredAmount);

ISerializableData[edit]

ISerializableData[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 string[] EnumerateData();

Thread: Any
Returns an array containing the name of the keys for the serialized data

 byte[] LoadData(string id);

Thread: Any
Load the data associated to the key as a byte array

 void SaveData(string id, byte[] data);

Thread: Any
Serialize the data from the byte array under the key id

 void EraseData(string id);

Thread: Any
Removes the data associated to the key id

 bool SaveGame(string saveName);

Thread: Main
Serialize the current game with the name saveName in the default Save user data folder

 bool LoadGame(string saveName);

Thread: Main
Deserialize the save game with the name saveName from the default Save user data folder and set it active

ISerializableDataExtension[edit]

 void OnCreated(ISerializableData serializedData);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 void OnLoadData();

Thread: Simulation
Invoked when the save game is deserialized
Gives an opportunity to deserialize custom data if needed

 void OnSaveData();

Thread: Simulation
Invoked when the save game is serialized
Gives an opportunity to serialize custom data if needed

SerializableDataExtensionBase[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 ISerializableData serializableDataManager { get; set; }

Thread: Any
Gets the serialization manager interface

 void OnCreated(ISerializableData serializableData);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 void OnLoadData();

Thread: Simulation
Invoked when the save game is deserialized
Gives an opportunity to deserialize custom data if needed

 void OnSaveData();

Thread: Simulation
Invoked when the save game is serialized
Gives an opportunity to serialize custom data if needed

ITerrain[edit]

ITerrain[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 int heightMapResolution { get; }

Thread: Any
Returns the size of the heightmap (1080)

 float cellSize { get; }

Thread: Any
Returns the distance between two texels of the heightmap in meters (16)

 float RawToHeight(ushort rawHeight);

Thread: Any
Converts an unsigned short raw height to an internal float representation of that height

 ushort HeightToRaw(float height);

Thread: Any
Converts an internal float representation of that height to an unsigned short raw height

 void PositionToHeightMapCoord(float x, float z, int heightX, int heightZ);

Thread: Any
Converts a worldspace XZ position to its position in the heightmap

 void HeightMapCoordToPosition(int heightX, int heightZ, float x, float z);

Thread: Any
Converts a position in the heightmap to its worldspace XZ position

 void GetHeights(int heightX, int heightZ, int heightWidth, int heightLength, ushort[] rawHeights);

Thread: Simulation
Gets an array representing the raw heights for the area starting at (heightX, heightZ) and of size (heightWidth, heightLength)
The array needs to be allocated prior to calling the method

 void SetHeights(int heightX, int heightZ, int heightWidth, int heightLength, ushort[] rawHeights);

Thread: Simulation
Sets the raw heights for the area starting at (heightX, heightZ) and of size (heightWidth, heightLength)

 float SampleTerrainHeight(float x, float z);

Thread: Any
Gets the terrain height at the XZ worldspace position

 float SampleWaterHeight(float x, float z);

Thread: Any
Gets the water height at the XZ worldspace position

ITerrainExtension[edit]

 void OnCreated(ITerrain terrain);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 void OnAfterHeightsModified(float minX, float minZ, float maxX, float maxZ);

Thread: Simulation
Invoked after the terrain heights have been modified
The parameters defines the area which was modified

TerrainExtensionBase[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 ITerrain terrainManager { get; set; }

Thread: Any
Gets terrain manager interface

 void OnCreated(ITerrain terrain);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 void OnAfterHeightsModified(float minX, float minZ, float maxX, float maxZ);

Thread: Simulation
Invoked after the terrain heights have been modified
The parameters defines the area which was modified

IThreading[edit]

IThreading[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 DateTime renderTime { get; }

Thread: Main
Simulation date/time that is smoothly interpolated to be used from main thread

 uint renderFrame { get; }

Thread: Main
Simulation frame that is used for current rendering frame

 float renderFrameOffset { get; }

Thread: Main
Offset between current and next simulation frame that is used to interpolate current rendering frame
Range: 0..1

 DateTime simulationTime { get; }

Thread: Simulation
Current simulation date/time

 uint simulationFrame { get; }

Thread: Simulation
Current simulation frame. Updated 60 times per second on normal (1x) speed

 uint simulationTick { get; }

Thread: Simulation
Current simulation tick. This is updated 60 times per second even when simulation is paused

 bool simulationPaused { get; set; }

Thread: Simulation
Is simulation paused

 int simulationSpeed { get; set; }

Thread: Simulation
Simulation speed. Range: 1..3
Actual simulation speed is 1x/2x/4x in game, or 1x/3x/9x in map editor

 TimeSpan timePerFrame { get; }

Thread: Any
How much one frame changes simulationTime

 void QueueMainThread(Action action);

Thread: Any
Add an action to be executed in main thread

 void QueueSimulationThread(Action action);

Thread: Any
Add an action to be executed in simulation thread

IThreadingExtension[edit]

 void OnCreated(IThreading threading);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 void OnUpdate(float realTimeDelta, float simulationTimeDelta);

Thread: Main
Called once per rendered frame
realTimeDelta is seconds since previous frame
simulationTimeDelta is smoothly interpolated to be used from main thread. On normal speed it is roughly same as realTimeDelta

 void OnBeforeSimulationTick();

Thread: Simulation
Called before simulation tick, 60 times per second

 void OnBeforeSimulationFrame();

Thread: Simulation
Called before simulation frame, 60 times per second on normal (1x) speed

 void OnAfterSimulationFrame();

Thread: Simulation
Called after simulation frame, 60 times per second on normal (1x) speed

 void OnAfterSimulationTick();

Thread: Simulation
Called after simulation tick, 60 times per second

ThreadingExtensionBase[edit]

 IManagers managers { get; }

Thread: Any
Gets global managers interfaces

 IThreading threadingManager { get; set; }
 void OnCreated(IThreading threading);

Thread: Main
Invoked when the extension initializes

 void OnReleased();

Thread: Main
Invoked when the extension deinitializes

 void OnUpdate(float realTimeDelta, float simulationTimeDelta);

Thread: Main
Called once per rendered frame
realTimeDelta is seconds since previous frame
simulationTimeDelta is smoothly interpolated to be used from main thread. On normal speed it is roughly same as realTimeDelta

 void OnBeforeSimulationTick();

Thread: Simulation
Called before simulation tick, 60 times per second

 void OnBeforeSimulationFrame();

Thread: Simulation
Called before simulation frame, 60 times per second on normal (1x) speed

 void OnAfterSimulationFrame();

Thread: Simulation
Called after simulation frame, 60 times per second on normal (1x) speed

 void OnAfterSimulationTick();

Thread: Simulation
Called after simulation tick, 60 times per second

ICamera[edit]

ICamera[edit]

Interface to control cinematic camera. When your cinematic camera script starts, an ICamera handle will be passed to your ICameraExtension's OnStart implementation, which can be used to call camera control methods. This API is also mirrored in CameraExtensionBase, so you can just call the corresponding base class methods instead.

All methods in this class are to be called from OnStart routine, or any routines started from it with StartRoutine.

Instant Low level controls[edit]

Used to instantly control the camera. Often used with timeDelta to smooth any camera movement over variable-length frames, and "yield return WaitForNextFrame();" when finished for current frame.

 void SetPosition(float x, float y, float z, bool dodgeObjects = false);

Set camera position in world space. Use dodgeObjects to automatically elevate the camera above any trees, buildings, and other objects.

 void SetRotation(float horizontal, float vertical, float tilt);

Set camera rotation in world space.

 void FaceTowards(float x, float y, float z);

Face camera towards given coordinates.

 void SetCameraTarget(float x, float y, float z, float distance = 50.0f, float verticalAngle = 45.0f, float horizontalAngle = 0.0f);

Set the camera position with given distance and angle from target point, face towards the point, and focus to it.

 void SetFade(float amount);

Set the camera fade-to-black effect's amount. 1.0 for fully black, 0.0 for no fade.

 void SetFocusDistance(float distance);

Focus the camera to given distance.

 void SetAperture(float aperture);

Set the aperture of the camera. Smaller values will increase the amount of blur in out-of-focus areas).

 void MoveCamera(float x, float y, float z, bool relativeAngle = true);

Move camera from current position by given values. Set relativeAngle to true to move relative to camera's current rotation instead of world space (x for sideways, z for forward/backward).

 void RotateCamera(float horizontal, float vertical, float tilt);

Rotate the camera from its current rotation.

 float timeDelta { get; }

Get the time delta for current frame.

 void GetCameraPosition(out float x, out float y, out float z);
 void GetCameraAngle(out float horizontal, out float vertical, out float tilt);

Get the current camera position and angle.

Routine Handling[edit]

The camera script can have multiple routines running at the same time. Use these to start, end, and temporarily halt routines.

 int StartRoutine(IEnumerator routine);

Start a new custom routine. Routines will always start on the following frame. Returns the routine ID.

 void AbortRoutine(int routineID = 0);

Abort a routine with given ID. Use 0 to abort the whole script and return to game.

 object WaitForRoutineToFinish(int routineID);

"yield return WaitForRoutineToFinish(id);" to halt current routine until the other finishes.

 object WaitForNextFrame();

"yield return WaitForNextFrame();" when finished for current frame. The script will continue from this on the next frame.

 object Wait(float seconds);

"yield return Wait(5);" to halt the current routine for 5 seconds.

World Objects[edit]

Used to get information about any objects such as buildings, vehicles, etc.

 ushort GetRandomBuilding(Service service = Service.None, SubService subService = SubService.None, Level level = Level.None);
 ushort GetBuildingWithName(string name);
 ushort GetNearestBuilding(float x, float y, float z);
 bool GetBuildingPosition(ushort id, out float x, out float y, out float z, out float angle);
 ushort GetRandomVehicle(Service service = Service.None, SubService subService = SubService.None, Level level = Level.None);
 ushort GetVehicleWithName(string name);
 ushort GetNearestVehicle(float x, float y, float z);
 bool GetVehiclePosition(ushort id, out float x, out float y, out float z, out float angle);
 uint GetRandomCitizen();
 uint GetCitizenWithName(string name);
 uint GetNearestCitizen(float x, float y, float z);
 bool GetCitizenPosition(uint id, out float x, out float y, out float z, out float angle);
 ushort GetRandomRoad();
 ushort GetRoadWithName(string name);

Get IDs for random objects, and use them to fetch their position and horizontal angle. Use Service.None, SubService.None, or Level.None to accept objects with any service type, subservice type, or service level. Only objects with custom given names will be fetched when searching by name. GetXPosition will return false if the object with given ID doesn't exist.

Built-in Routines[edit]

These methods will start built-in routines and return their IDs. Using duration of 0.0 or less will cause the routine to run indefinitely or until manually aborted. Using negative speeds will reverse the direction of the routine.

 int OrbitBuilding(ushort id, float speed = 10.0f, float duration = 0.0f, float distance = 100.0f, float verticalAngle = 45.0f, float horizontalAngle = 0.0f);

Start a routine that will orbit the camera around the building with given ID. Use negative speed for counter-clockwise orbit. Use horizontalAngle to control the starting point around the building.

 int FollowCitizen(uint id, float duration = 0.0f, float distance = 50.0f, float verticalAngle = 45.0f, float horizontalAngle = 0.0f, bool relativeAngle = false);

Start a routine that will follow the citizen with given ID. Use duration of 0.0 or less to run the routine indefinitely or until manually aborted. Set relativeAngle to true to use horizontal angle relative to target citizen's angle instead of world space (for example to always follow the citizen from behind when using 0 horizontal angle).

 int FollowVehicle(ushort id, float duration = 0.0f, float distance = 50.0f, float verticalAngle = 45.0f, float horizontalAngle = 0.0f, bool relativeAngle = false);

Start a routine that will follow the car with given ID.

 int FollowRoad(ushort roadID, float speed = 20.0f, float duration = 0.0f, float distance = 50.0f, float verticalAngle = 30.0f, float horizontalAngle = 0.0f, bool relativeAngle = true, RoadJunctionHandler junctionCallback = null);

Start a routine that will move along the given road. Use a custom RoadJunctionHandler to manually resolve which way to go when facing crossroads (the camera will take random turns by default).

 int FadeIn(float seconds = 1f);

Start a routine that will fade the screen in from black over given time.

 int FadeOut(float seconds = 0.5f);

Start a routine that will fade the screen out to black over given time.

 int Dolly(float startX, float startY, float startZ, float endX, float endY, float endZ, float duration);

Start a routine that will move the camera from start point to end point over given duration in seconds.

 int SetApertureSmooth(float aperture, float speed = 1.0f);

Start a routine that will change the aperture from current to target with given speed of stops per second.

 int SetFocusDistanceSmooth(float focusDistance, float speed = 100.0f);

Start a routine that will change the focus distance from current to target with given speed of meters per second.

 void GetCameraPosition(out float x, out float y, out float z);

ICameraExtension[edit]

Implement this or CameraExtensionBase which contains the same methods but also mirrors the ICamera methods in base class.

 void OnCreated(ICamera Camera);

Invoked when the camera script initializes.

 void OnReleased();

Invoked when the camera script is released.

 IEnumerator OnStart(ICamera camera);

Invoked as a routine when the camera script is started by the player. This is the "entry point" of your cinematic camera script.

 void OnAbort();

Invoked when the camera script is aborted by the player.

 string Name();

The name of your script as shown in the in-game cinematic camera menu.

Misc[edit]

 public delegate ushort RoadJunctionHandler(ushort[] roadIDs);

For creating custom intersection handler for the built-in FollowRoad-routine, which can be used to select which way to go in an intersection. Receives a list of road segment IDs leading out from the intersection. Return one of the IDs. Returning an invalid ID will cause the camera to take a random turn. This might get invoked long before the camera reaches the intersection.

IAssetData[edit]

This extension API is used for saving and reading custom data in asset packages. OnAssetSaved and OnAssetLoaded will only be called once for the main asset in the package, so for example prop variations and sub-buildings don't get a call separately. All calls to the extension from the game happen in main thread.

IAssetDataExtension[edit]

 void OnCreated(IAssetData assetData);

Called when the extension initializes.

 void OnReleased();

Called when the extension is released.

 void OnAssetSaved(string name, object asset, out Dictionary<string, byte[]> userData);

Called when an asset is being saved. The asset-parameter contains the boxed asset PrefabInfo. Save any custom data to userData dictionary.

 void OnAssetLoaded(string name, object asset, Dictionary<string, byte[]> userData);

Called after an asset has been loaded and added to collections. The userData-parameter contains previously saved custom data.

IUserMod[edit]

IUserMod[edit]

Interface to derive from to get a mod for Cities: Skylines to display in the Content Manager

 public void OnEnabled();
 public void OnDisabled();

OnEnable and OnDisabled are special methods and not part of the base class. Hence it is not necessary to override them. If declared in your class, the game will invoke them whenever the mod is enabled/disabled (at game start/end and when toggle the active checkbox). This is particularly handy to run initialization and cleanup code which can't wait for an in-game callback to trigger.

 public void OnSettingsUI(UIHelperBase helper);

OnSettingsUI is a special methods which is not part of the base class. If implemented, it will add your mod to the Options panel categories and you will be able to customize a dedicated space for your mod options/settings. More info can be found here.

 string Name { get; }

Name of the mod

 string Description { get; }

Short description of the mod


Prefabs[edit]

To retrieve the possible prefab indices try code such as this:

   public class LoadingExtension : LoadingExtensionBase {
       public override void OnCreated(ILoading loading) {
           base.OnCreated(loading);
           for (uint i = 0; i < PrefabCollection<NetInfo>.PrefabCount(); ++i) {
               string name = PrefabCollection<NetInfo>.PrefabName(i);
               DebugOutputPanel.AddMessage(PluginManager.MessageType.Message, i + ":" + name);
           }
   }

Interfacing with the Unity Engine[edit]

By including the Unity Engine namespace with using UnityEngine; direction, it is possible to access Unity's scripting API. http://docs.unity3d.com/ScriptReference/
Only the API from UnityEngine is available (Editor and others will not be).
It is possible to create GameObjects dynamically, as well as MonoBehaviours and use the standard callback mechanic Unity provides.

Examples[edit]