-
-
Notifications
You must be signed in to change notification settings - Fork 97
Home
Project Tango (name to change later) is an experimental Cities Skylines multiplayer mod. The mod will provide an experience where everything is synced between players (using the client-server model). Players will share money, costs, roads, resources etc. In the future it would be nice to add the ability to players to control individual cities, but this is a HUGE if.
I'm currently developing this in my free-free time (most of my time being spent studying/working and developing SoundByte) so I'd love help! The following information aims to help understand how this mod works and will work in the future, how to set it up, how to use it and how to help develop it.
Setting up the mod is very easy. You will need to have Visual Studio 2017 installed (free version works), have not tested on older versions.
- Create a new folder in your cities skylines mod directory (
%LOCALAPPDATA%\Colossal Order\Cities_Skylines\Addons\Mods
) calledTango
. - Change your project config to Release and Any CPU.
- Right-click the
Tango
Project and select build. Building the project should automatically copy the required files to the newly createdTango
folder in AppData. - If the build did not automatically copy the required files, copy
Tango.dll
frombin\Release
into this new folder. - Copy
Lidgren.Network.dll
from theAssemblies
folder into theTango
folder. - Run cities skylines and enable the mod.
- Create a new game / open an existing game.
- Click the
Show Multiplayer Menu
button in the top-left of your screen. - To host a game click on
Host Game
. - To join a game click on
Join Game
and enter the required information.
This mod uses the client-server model. A user will setup their game as a server and transmit information like currency, roads, needs etc. to all connected clients. Clients will connect to the server and retrieve currency, roads, needs etc. from the server, updating the client UI.
This is all done by running a UDP server alongside Cities Skylines. This UDP server will interact with the extension methods in the ICities DLL. It is important that we extend and override the base methods for these extensions (as we override some values).
Here is a list of extensions that can be used in the ICities.dll (not much documentation elsewhere).
We can use these extension methods to sync which areas have been bought.
Method | Return |
---|---|
OnCanUnlockArea(int x, int z, bool originalResult) |
originalResult |
OnGetAreaPrice(uint ore, uint oil, uint forest, uint fertility, uint water, bool road, bool train, bool ship, bool plane, float landFlatness, int originalPrice) |
originalPrice |
OnUnlockArea(int x, int z) |
VOID |
We can use this to find out where builds are. Looks like it may be quite complicated. Guess we will see.
Method | Return |
---|---|
SpawnData OnCalculateSpawn(Vector3 location, SpawnData spawn) |
spawn |
OnBuildingCreated(ushort id) |
VOID |
OnBuildingRelocated(ushort id) |
VOID |
OnBuildingReleased(ushort id) |
VOID |
This really is not that important, (I personally don't really like the "Twitter" like feature), but it can still be implemented. On Server we send the new chirper message to the clients on OnNewMessage
event. Client side we ignore these chirpers.
Method | Return |
---|---|
OnNewMessage(IChirperMessage message) |
VOID |
This extension will allow us to synchronize demand across all connected clients. More research is required, but from what I understand, we need to override the OnCalculate*Demmand
methods to grab the calculated demand from the server. On the server we will access the demand manager to get the current demand. The OnUpdateDemand
method will also be used for server-client syncing.
Method | Return |
---|---|
OnCalculateResidentialDemand(int originalDemand) |
originalDemand |
OnCalculateCommercialDemand(int originalDemand) |
originalDemand |
OnCalculateWorkplaceDemand(int originalDemand) |
originalDemand |
OnUpdateDemand(int lastDemand, int nextDemand, int targetDemand) |
nextDemand |
Currently looking at implementing OnUpdateMoneyAmount
to sync money between clients. Some basic testing showed that this was only updating the UI? Need to look further into it.
Method | Return |
---|---|
OnAddResource(EconomyResource resource, int amount, Service service, SubService subService, Level level) |
amount |
OnFetchResource(EconomyResource resource, int amount, Service service, SubService subService, Level level) |
amount |
OnPeekResource(EconomyResource resource, int amount) |
amount |
OnGetConstructionCost(int originalConstructionCost, Service service, SubService subService, Level level) |
amount |
OnGetMaintenanceCost(int originalMaintenanceCost, Service service, SubService subService, Level level) |
amount |
OnGetRelocationCost(int constructionCost, int relocationCost, Service service, SubService subService, Level level) |
amount |
OnGetRefundAmount(int constructionCost, int refundAmount, Service service, SubService subService, Level level) |
amount |
OnUpdateMoneyAmount(long internalMoneyAmount) |
internalMoneyAmount |
This has a different naming scheme for some reason? This would be used for syncing disasters (going to be interesting to setup)
Method | Return |
---|---|
OnDisasterCreated(ushort disasterID) |
VOID |
OnDisasterStarted(ushort disasterID) |
VOID |
OnDisasterDetected(ushort disasterID) |
VOID |
OnDisasterActivated(ushort disasterID) |
VOID |
OnDisasterDeactivated(ushort disasterID) |
VOID |
OnDisasterFinished(ushort disasterID) |
VOID |
todo
todo
todo
todo
todo
todo
todo