Modding API
阅读
2023-12-14更新
最新编辑:Lu_23333
阅读:
更新日期:2023-12-14
最新编辑:Lu_23333
Overview
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.
In summary, a C# mod can achieve the following things:
- Gameplay: Affect in-game economy and building levels;
- Data Interoperability: Read and save city data (e.g. create map drawing exports);
- Editing: Dynamically create and destroy buildings.
What the API cannot do:
- (Pending...)
More overview information is also available in Category:Programming.
File Location
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
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
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
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"; }
}
}
}
For snippets on more practical examples, see Basic Snippets.
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
//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.
Debugging
By adding a reference to ColossalManaged.dll
and Assembly-CSharp.dll
, we can use DebugOutputPanel.AddMessage()
to add debug message to our mod.
Use F7
to open the in-game console.
Official Modding API
DataTypes
Service
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
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
enum Level
{
None,
Level1,
Level2,
Level3,
Level4,
Level5,
}
Enumeration for building levels
LoadMode
enum LoadMode
{
NewMap,
LoadMap,
NewGame,
LoadGame,
NewAsset,
LoadAsset,
NewScenarioFromGame,
NewScenarioFromMap,
LoadScenario,
UpdateScenarioFromGame,
UpdateScenarioFromMap,
NewTheme,
LoadTheme,
}
Enumeration for supported load modes
AppMode
enum AppMode
{
Game,
MapEditor,
AssetEditor,
ScenarioEditor,
ThemeEditor,
}
Enumeration for application modes
Expansion
enum Expansion
{
None,
AfterDark,
Snowfall,
NaturalDisasters,
InMotion,
GreenCities,
Parks,
Industry
}
Enumeration for game expansions
NaturalResource
enum NaturalResource
{
Ore,
Sand,
Oil,
Fertility,
Forest,
Pollution,
Burned,
Destroyed
}
Enumeration of the resources in the Industries expansion
IAreas
AreasExtensionBase
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
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
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
IBuilding
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
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
IChirperMessage
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
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
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
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
enum ChirperAnchor
{
TopLeft,
TopCenter,
TopRight,
BottomLeft,
BottomCenter,
BottomRight,
}
Supported chirper anchors
IDemand
IDemand
Demand manager
IManagers managers { get; }
Thread: Any
Gets global managers interfaces
IDemandExtension
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
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
IEconomy
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
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
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
enum EconomyResource
{
None,
ConstructionCost,
MaintenanceCost,
LoanAmount,
LoanPayment,
PrivateIncome,
CitizenIncome,
TourismIncome,
PublicIncome,
RewardAmount,
PolicyCost,
BailoutAmount,
RefundAmount,
LandPrice,
All,
}
ILevelUp
ILevelUp
IManagers managers { get; }
Thread: Any
Gets global managers interfaces
ILevelUpExtension
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
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
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
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
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
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
ILoading
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
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
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
IManagers
Helper interface which stores get 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
IMilestones
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
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
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
IResource
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
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
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
ISerializableData
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
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
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
ITerrain
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
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
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
IThreading
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
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
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
ICamera
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
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
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
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
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
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
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
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
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
IUserMod
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
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
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