So, this is my first go at this. I wanted to announce it at a point that I feel is fairly early, in hopes that maybe some other people could help me make it better and actually start building some cool stuff with it.
I made a new project I've named Inceptor. Inceptor is a command-line application which will modify the core code of the game to allow you to inject your own method calls supplementing and/or replacing the core game logic. It uses Mono.Cecil to accomplish this and is basically the equivalent of decompiling the code, modifying the code a bit to call my assembly, and then recompiling it. I originally made this out of frustration with how limited the official modding API is and because I work a lot with IL and the lower level bits of .NET, and it seemed like a fun thing to mess with.
The extender is located at https://github.com/Earlz/Inceptor I'm still deciding on a license. It'll be either GPL or BSD, haven't decided yet. You need to run it across the core game DLL (Assembly-CSharp.dll) and replace that, and then place the Inceptor assembly in the same folder.
Afterwards, you can actually go to making some really awesome mods using stuff that is not even imaginable with the official API. For instance, if you want to set the pollution rate of all industrial builds to 0 (without affecting any other building) you can with this:
It's some pretty low level stuff and is hard to use, but it makes a ton of new things possible. The eventual goal is for the end-user to run an "installer" program once, and then mods can be loaded easily and even distributed from the workshop utilizing this extender.
Note: If you want to understand what method you actually need to inject into and how to modify the code and/or what the various parameters even mean, you should use a decompiler such as ILSpy to disassemble the Assembly-CSharp.dll file and read it's equivalent C# code (note some of it will be rough around the edges and there will of course be no comments)
Also, I've made an example mod using it at https://github.com/Earlz/CitiesTestMod
I made a new project I've named Inceptor. Inceptor is a command-line application which will modify the core code of the game to allow you to inject your own method calls supplementing and/or replacing the core game logic. It uses Mono.Cecil to accomplish this and is basically the equivalent of decompiling the code, modifying the code a bit to call my assembly, and then recompiling it. I originally made this out of frustration with how limited the official modding API is and because I work a lot with IL and the lower level bits of .NET, and it seemed like a fun thing to mess with.
The extender is located at https://github.com/Earlz/Inceptor I'm still deciding on a license. It'll be either GPL or BSD, haven't decided yet. You need to run it across the core game DLL (Assembly-CSharp.dll) and replace that, and then place the Inceptor assembly in the same folder.
Afterwards, you can actually go to making some really awesome mods using stuff that is not even imaginable with the official API. For instance, if you want to set the pollution rate of all industrial builds to 0 (without affecting any other building) you can with this:
Code:
public class InjectionPoint: LoadingExtensionBase
{
static string locker = "";
public override void OnLevelLoaded(LoadMode mode)
{
ChirpLogger.ChirpLog.Debug("hmmm something");
ChirpLogger.ChirpLog.Info("loaded");
InceptorInterceptor.Add("System.Void IndustrialBuildingAI::GetPollutionRates(System.Int32,System.Int32&,System.Int32&)", new InceptorInterceptor.Interceptor((@this, name, parms) =>
{
//note: chirplogger is apparently broken when using from different threads or in some way can not handle this and will silently fail to log anything
StringBuilder sb = new StringBuilder(); //we log the previous values here...
sb.AppendLine("--begin--");
int i=0;
foreach (var p in parms)
{
sb.AppendFormat("parms[{0}] = {1}\r\n", i, p == null ? "null" : p.ToString());
i+=1;
}
sb.AppendLine("--end--");
lock(locker)
{
File.AppendAllText("C:\\dev\\debug.txt", sb.ToString());
}
//when a parms element is set for reference types (ones ending in a &), then the value will be persisted back in the method
parms[1] = 0; //ground pollution
parms[2] = 10; //noise pollution
return new object(); //return an object to tell the intercepted method to return immediately after this (return null to tell it to continue through with the body of the method
}));
base.OnLevelLoaded(mode);
}
public override void OnCreated(ILoading loading)
{
base.OnCreated(loading);
}
}
It's some pretty low level stuff and is hard to use, but it makes a ton of new things possible. The eventual goal is for the end-user to run an "installer" program once, and then mods can be loaded easily and even distributed from the workshop utilizing this extender.
Note: If you want to understand what method you actually need to inject into and how to modify the code and/or what the various parameters even mean, you should use a decompiler such as ILSpy to disassemble the Assembly-CSharp.dll file and read it's equivalent C# code (note some of it will be rough around the edges and there will of course be no comments)
Also, I've made an example mod using it at https://github.com/Earlz/CitiesTestMod