The site https://map.justgeektechs.com generates height maps and overlay images for Cities: Skylines 2 map creation.
Host the Cities: Skylines map generator locally
There are times when the Cities: Skylines Map Generator at https://heightmap.skydark.pl is not available. The free MapBox token expires because of the number of requests it serves.
We can host the site ourselves on our workstation and use it any time.
Install XAMPP
XAMPP is a free web server created by Apache Friends.
- Download the installer for your workstation’s operating system at https://www.apachefriends.org/download.html
- Install the application. As the popup will warn you, do not install it in the Program Files directory, as Windows restricts the access there.
Download the Cities: Skylines Map Generator application
The source code of the application is available on GitHub.
- With your web browser navigate to https://github.com/sysoppl/Cities-Skylines-heightmap-generator
- Click the Code button and select Download Zip

- Extract the Zip archive
Place the application in the XAMPP directory
XAMPP contains the Apache web server which can host our JavaScript web application.
- Create a directory called map in the htdocs folder of XAMPP. If you installed XAMPP to the default location, it is at C:\xampp\htdocs

- Move the images and src directories of the map generator application into the map folder

Start XMAPP
- Start the XAMPP Control Panel from the Start Menu

- Start the Apache web server

- Open your web browser and navigate to http://localhost/map/src/

Changing the MapBox access token
If the MapBox access token expires
- Create a free access token for yourself at https://www.mapbox.com/
- Update the value of mapboxgl.accessToken in the src/app.js file in line 47

To host the app from another directory
With the default configuration, XAMPP is looking for the web application in the htdocs directory within the XAMPP installation folder.
If you want to keep the Map Generator in another directory and host it from there with XAMPP:
- Open the XAMPP control panel
- Stop the Apache server

- Click the Config button and select Apache (httpd.conf)

- Place the project location into the DocumentRoot and Directory lines

- Start the Apache server

- Open your web browser and navigate to http://localhost/src/
Create a high resolution overlay image for Cities: Skylines II
The Image Overlay mod for Cities: Skylines 2 allows us to build a city based on real world locations. See Image overlay in Cities: Skylines 2 on how to install and use it.
To generate a high resolution overlay image
Create the standard resolution overlay image
Create a 2560×2560 pixel overlay image matching the height map. See Using the Map Editor in Cities:Skylines 2
Update the overlay image to high resolution
We can update the resolution to 16,384×16,384 pixels with some editing work using GIMP, the free graphics editor.
- With your web browser navigate to Cities: Skylines map generator
- Use the same location you used for the height map and the standard resolution overlay image

- Set the Map size to 2.24 km

DMV Online Learning and Tests
If you have a testing requirement for your driver’s license (DL), save some time and do it online before visiting a DMV office.
Signature verification failed, repository.json is not valid
When the Cities: Skylines II mod publishing fails with
Syncing WIP mod “…”
[L3Error_][6574][4B66][EFB4][0181] Error getting repository metadata for repository mods/cities_skylines_2/…/repo/Windows__Any, got exception: Signature verification failed, repository.json is not valid
Could not sync WIP mod: Signature verification failed, repository.json is not valid
Check the state of your mod
- With your web browser, open the My Uploaded Mods page on the Paradox Plaza,
- Click the mod to open the details page.
The Mod ID
The Mod ID is in the URL![]()
It is the number you saved in the PublishConfiguration.xml file at
If the mod is corrupted on the Paradox Plaza
If the mod is corrupted on the Paradox servers, and you cannot update it anymore with the regular publishing process, you may need to delete the corrupted copy.
Warning!!!
If you delete a mod, all users who have subscribed to it, will get the “This mod has been banned” message when they open their playsets. They have to delete it from their playsets, and add it again to their active playset.
Delete a mod from Paradox Plaza
- Hover above the pencil on the mod’s thumbnail and select Delete mod

Upload the mod again
If a mod has been deleted from Paradox Plaza, we can no longer publish updates to it to keep the same Mod ID. If we try, we get the error message: Could not publish new version of the mod: Updates are disabled for this mod.
To upload the mod again, we need to publish the mod as new.
- Right-click the project and select Publish

- On the Publish page select PublishNewMod

- When the publishing process completed, copy the new Mod ID to the clipboard
- Update the ModId value with it in the PublishConfiguration.xml file.
Cities: Skylines II Modding Resources
- Links to resources on the Cities: Skylines II Discord channel # links-modding
- Technical help from other modders on the Cities: Skylines Modding Discord channel at # mod-development
- Work In Progress mod discussion on the Cities: Skylines Modding Discord channel at # mods-wip
Creating a new mod for Cities: Skylines II
Developer tools
To create a new mod for Cities: Skylines 2, first, we need to install the developer tools.
- Start Cities: Skylines II
- In the main menu select Options

- In the Options menu select Modding

- Step through the items to install the toolchain

- Download and install the latest Active version of the .NET framework from .NET/.NET Core
Start a new Visual Studio solution
- Open Visual Studio and select Create a new project

- Enter colossal into the search box and select the Cities Skylines II mod, and click the Next button at the bottom of the page

- Enter the project name, and click the button with the three dots to select the directory where Visual Studio will create a directory for the mod using the “Project name”

- Click the Next button

- Make sure The game installation path points to the C:\Program Files (x86)\Steam\steamapps\common\Cities Skylines II\Cities2_Data\Managed folder.

- Click the Create button

Deploy the mod locally for testing
To deploy the new mod and activate it in the game
- Exit Cities: Skylines II, otherwise the deployment will fail, because it cannot access the mod files in the Mods directory.
- Right-click the solution in Solution Explorer
- Select Rebuild Solution

- The new mod appears in the Mods folder at C:\Users\YOUR_USER_NAME\AppData\LocalLow\Colossal Order\Cities Skylines II\Mods

- When you open the city, the mod’s log file is created in the Logs folder at C:\Users\YOUR_USER_NAME\AppData\LocalLow\Colossal Order\Cities Skylines II\Logs

To disable the mod
To run the game without the local deployment of the mod
- Exit from the game to the desktop,
- Rename the mod folder to start the name with a period
C:\Users\YOUR_USER_NAME\AppData\LocalLow\Colossal Order\Cities Skylines II\Mods\.MY_MOD - Start the game again.
Publishing the mod
Create a Paradox account
- Navigate to Paradox Plaza
- Click Log in in the upper right corner

- Click the Create Account button

Create a forum thread for the mod
- Create a Paradox forum thread for your mod at Cities Skylines 2: User Mods. We will add the URL to the mod’s metadata, so users can ask questions, report bugs and share their experience with you and other users.
Create the Paradox account data file
To be able to publish the new mod to Paradox, we need to create the paradox account data file.
- Create a text file, the Paradox account data file, with two lines in it, and save it outside of the mod repository, like the Desktop, so it will not be pushed into source control (GitHub).
MY_PARADOX_USERNAME
MY_PARADOX_PASSWORD
- Right-click the project in the Visual Studio Solution Explorer, and select Edit Project File

- Add the file location to the PDXAccountDataPath element of the mod’s project file. The default value will point to the “pdx_account.txt” file on the Desktop:
<PDXAccountDataPath>$(USERPROFILE)\Desktop\pdx_account.txt</PDXAccountDataPath>
- Save the project file
Update the Publish Configuration
The PublishConfiguration.xml file in the Properties folder of your mod contains its metadata. We need to update it to provide the values to be displayed on the mod’s information page.
ModId
We will populate this very important value when we first publish the mod. See Publish the mod below. We will need this 5 or 6 digit number to be able to send metadata and code updates to Paradox later. For the first publishing leave it empty string.
DisplayName
This will be the name of the mod in the library where users select from the list of mods.![]()
ShortDescription
The short description of the mod, at this moment it is not obvious where it is displayed.![]()
LongDescription
The long description explains the purpose and usage of the mod. For the formatting to work, make sure all lines of the LongDescription start at the left margin of the page!!!
To make it easier to format the text, create a file in the Properties directory, many modders call it LongDescription.md
It will not be uploaded to Paradox, but the .md extension tells Visual Studio how to display the preview in the editor. Just click the Preview button in the upper left corner to see how the text will look like when Paradox displays it.
When the formatting is done,
- save the file for future reference,
- copy and paste the text into the LongDescription element of the PublishConfiguration.xml file,
- IMPORTANT: Select the pasted text in the PublishConfiguration.xml file, and press Shift-Tab twice, to move the text to the left margin. Otherwise the formatting will not work when it is displayed on the mod information page.

Thumbnail
Create a square .png or .jpg image to be the thumbnail of your mod.
Save it in the Properties folder of the mod. Update the Thumbnail element of the PublishConfiguration.xml file to point to the image.![]()
Screenshot
The screenshot images are displayed on the mod information page.
Save the .png or .jpg files in the Properties folder and update the Screenshot element. If you have multiple images, add more Screenshot lines.![]()
Tag
Regardless of the comment in the file, for code mods at this point it has to be one element with the value: “Code Mod”.![]()
ForumLink
Enter the URL of the Paradox forum thread for the mod you have created above.![]()
ModVersion
The current version of the mod.
As it is not so easy to make sure the latest version of the mod is loaded, add the version to the UI too. In the Settings.cs file where the options menu is defined.
{ m_Setting.GetOptionGroupLocaleID(Setting.kPrecipitationGroup), "Precipitation (Version 1.0.8)" },
This will display the version in the game

GameVersion
It is the version of the game, your mod is compatible with. When the new version of the game is released, all users will automatically receive it at the same time. It is important to test your mod with it, and update this value, otherwise a warning sign will appear on the mod’s information page telling all users, your mod is not compatible with their game version. At the time of writing the game’s “major.minor” version is 1.1 Most likely you mod will work fine until at least the next minor version, so today 1.1.* will provide the correct game version value.![]()
Dependency
If the mod depends on other mods, list them here.
If the mod does not have any dependencies, leave the value an empty string.![]()
ChangeLog
This will generate the change log entries on the mod info page. After publishing the first version of the mod, this is not yet displayed anywhere. Starting with the second version, it will be appended to the list on the right margin of the mod info page. 
To make the ChangeLog formatting easier, like what we did for the LongDescription above, create the LatestChangelog.md file. It will not be uploaded to Paradox, but using it makes the text formatting a better experience.
There are two options to send information to the change log: One line, or multiple lines.
One line change log entry
The ChangeLog Value element can only have one formatted line.![]()
Multi-line change log entry
The ChangeLog element can have multiple formatted lines. To use it, comment out or delete the ChangeLog Value element, and uncomment the ChangeLog start and end tags. List the changes of the current update, for the formatting to work, make sure all lines start at the left margin.
ExternalLink
The URLs of YouTube videos, Discord servers, GitHub repositories, PayPal donation pages.
Publish the mod
- Exit Cities: Skylines II, so the build process can overwrite the mod in the Mods directory
- Right-click the mod’s project and select Publish

- If this is the first time you publish this mod
- On the Publish page select the action, for the first time, leave PublishNewMod selected, and click the Publish button

- Copy the Mod ID from the output window

- Save it in the PublishConfiguration.xml file. It is required to publish updates in the future.

- On the Publish page select the action, for the first time, leave PublishNewMod selected, and click the Publish button
- If the mod has already been published at least one
- Make sure there is no error message in the Output window at the bottom of the screen.
- Check the Paradox web site to make sure the mod has been successfully published there. Navigate to Mods for Cities: Skylines II
- Find your mod and make sure the latest version is there.
- Remove the local copy of your mod from the game directory. Other wise always that will be active in your game, not the one installed from the Paradox web site. See To disable the mod above
Troubleshooting
Error
Error MSB3231 Unable to remove directory “C:\Users\…\AppData\LocalLow\Colossal Order\Cities Skylines II\Mods\…”. Access to the path ‘…_win_x86_64.dll’ is denied. C:\Users\…\AppData\LocalLow\Colossal Order\Cities Skylines II.cache\Modding\Mod.targets
Solution
Visual Studio cannot deploy the new version of the mod, because Cities: Skylines II is running. Exit the game to the Desktop and build the solution again in Visual Studio.
Error
PDX account data file is not found. Please check the ‘PDXAccountDataPath’ property value of your project. If you have no such file, you should create it. It is a simple text file where the first line is your PDX account login and the second line is your PDX account password.
Solution
Create and reference the Paradox account data file, see Create the Paradox account data file above.
Error:
Error while processing args
ChangeLog must be set in configuration
Solution:
To be able to publish an update to the mod, we need to add to the ChangeLog value in the PublishConfiguration.xml file
<ChangeLog Value="Updated metadata and added screenshot image" />
<!--ChangeLog>
Error:
Could not update the mod configuration: Couldn’t upload all files to the backend
Solution:
Make sure the image file name does not contain spaces.
Decompiling the Cities: Skylines II code
To be able to view the source code code of Cities: Skylines 2, we need a few tools.
Visual Studio
Visual Studio Community edition is a free IDE to write .NET code in C# and other languages.
- Install Visual Studio Community Edition from the Microsoft site atVisual Studio Community Edition
Decompiler
To decompile the game code to the source code, we will use the ILSpy Visual Studio extension.
- Search for the link to the latest version on the ILSpy GitHub page at ILSpy
- At the time of writing, ILSpy 2022 is the latest version, download it from ILSpy 2022
- Double-click the downloaded .vsix file
- Restart Visual Studio if it was running at the time of the extension installation
Decompiling Cities: Skylines II
- Start Visual Studio
- Select Continue without code to start a new project
- In the Tools menu select ILSpy

- In the ILSpy window select File, Open

- Select Game.dll in the “C:\Program Files (x86)\Steam\steamapps\common\Cities Skylines II\Cities2_Data\Managed” directory
- On the left side expand the Game node

Save the game code
To save the game code as a Visual Studio project
- Right-click the Game node and select Save Code…

Examining the original game code
- In the Visual Studio File menu select Open, Project/Solution

- Open the Game.csproj C# project

- To search for words in the game source code press CTRL-F or open the Quick Find dialog box


How to stop the rain and snow in Cities: Skylines II
The snow makes it hard to see the image overlay in Cities: Skylines II. To stop the rain and snow we can
- use the Weather+ mod or
- make temporary changes in Developer mode.
Weather+ mod
- Install the Weather+ mod in the main menu

Temporary change in Developer mode
The Override Precipitation setting in Developer Mode is not saved in the city, so every time you open the city, you need to set it again.
- Enable Developer mode, see https://pinter.org/archives/15586
- Start the game and open the city
- Press the Tab key to open the Developer menu
- On the Climate tab check Override Precipitation, the Precipitation value should automatically set to zero.
- Close the Developer menu with the Tab key
- To melt the snow, click the fast forward icon to forward to summer

Argument of type ‘(number | null)[]’ is not assignable to parameter of type ‘(err: Error, result: QueryResult) => void’
The latest “npm install @types/pg –save-dev” command changed the “@types/pg” Node.js module version in the package.json file from to “^8.11.4”.
Since that, the build of my TypeScript applications fail with the error message below, if the PostgreSQL .query function contains mixed “value” types, like this:
const query = "INSERT INTO ..."
const values = [string, number, stringArray, nullableValue]
const result = await conn.query(
query,
values
);
The error message is:
.. : error TS2769: No overload matches this call.
The last overload gave the following error.
Argument of type ‘(number | null)[]’ is not assignable to parameter of type ‘(err: Error, result: QueryResult) => void’.
Type ‘(number | null)[]’ provides no match for the signature ‘(err: Error, result: QueryResult): void’.
or
…: error TS2769: No overload matches this call.
The last overload gave the following error.
Argument of type ‘(string | number)[]’ is not assignable to parameter of type ‘(err: Error, result: QueryResult) => void’.
or
… : error TS2769: No overload matches this call.
The last overload gave the following error.
Argument of type ‘(string | number | null)[]’ is not assignable to parameter of type ‘(err: Error, result: QueryResult) => void’.
Type ‘(string | number | null)[]’ provides no match for the signature ‘(err: Error, result: QueryResult): void’.
Solution
I can see two solutions:
Make sure all elements of the array have the same data type
If possible, make sure the type of all value elements is the same, the simplest is to
- convert numeric values to strings,
- specify default values for “null” values,
- convert string arrays to strings, or get the first element if only that has value.
const values = [number.toString(), canBeNullString || '' (canBeNullNumber || 0).toString(), stringArray[0]]
A better solution is to centralize the database access
If the database access is centralized in a function, and the values are passed in as “any” type, the TypeScript compiler will not reject it, because it does not iterate through all references of the function.
This is an example of the centralized PostgreSQL database call.
Install the required Node.js packages with
npm install typescript --save-dev
npm install @types/node --save-dev
npm install dotenv
npm install pg
npm install @types/pg --save-dev
The centralized PostgreSQL access file
// db.js
import * as dotenv from "dotenv";
dotenv.config()
import pg from 'pg'
// Create the reusable pool to the PostgreSQl database
// Read config values from environment variables
let conn = new pg.Pool({
user: process.env.USER_NAME,
password: process.env.PASSWORD,
host: process.env.HOST,
port: parseInt(process.env.PORT || "5432"),
database: process.env.DATABASE,
});
// Call the "query" method of the pool to execute the text of the query with optional parameters
export const query = async (text: string, params: any) => {
let res;
try{
if (params) {
// There are parameters, send them with the query text
res = await conn.query(text, params)
} else {
// There are no parameters
res = await conn.query(text)
}
} catch (e) {
// There is an error executing the query, log the error, the text of the query and the parameters
console.log('error', e)
console.log('query', text)
console.log('params', params)
}
return res
}
export default query ;
Call the centralized function with
// selectData.ts
import * as conn from './db';
export async function selectData (id: string) {
let result;
let query;
let values;
try {
// Build the query
const baseQuery = "SELECT * FROM table";
query = baseQuery + ' ' + "WHERE id = $1";
values = [id]
// Query the database
result = await conn.query(
query
, values
);
return result?.rows[0];
} catch ( error ) {
console.log("In selectData", error);
console.log("result: ", result);
console.log("query: ", query);
console.log("values: ", values)
return null;
}
};