Your Second Mod
In this guide you'll build on what you learned in Your First Mod by doing something that actually affects gameplay adding speed to the player.
This will introduce you to the core workflow of ULTRAKILL modding: decompile the game's code, find what you need, and patch it.
- Completed Your First Mod
- Either DnSpy installed or access to the web decompiler
Add to your referenced dlls UnityEngine.PhysicsModule.dll if you have forgotten it is in First Mod
Decompiling the Code
Before you can modify the game, you need to read the code.
ULTRAKILL's code is in ULTRAKILL_Data/Managed/Assembly-CSharp.dll.
With DnSpy
- Open DnSpy: Go to where you installed it and run
dnSpy.exe - Open the ULTRAKILL assembly:
- (Top left) Click
File>Open - Navigate to your ULTRAKILL installation folder
- Select
ULTRAKILL_Data\Managed\Assembly-CSharp.dll
- (Top left) Click
- Optional but recommended — Set DnSpy as the default program for
.dllfiles so you can open them by double-clicking.
With the Web Decompiler
- Open the website: https://dll_decompiler.dolfelive.org/
- Load the DLL:
- Top right, click Browse...
- Navigate to your ULTRAKILL installation folder
- Select
ULTRAKILL_Data\Managed\Assembly-CSharp.dll
Finding the Player Class
Searching for NewMovement
The class that controls player movement is called NewMovement. Here's how to find it:
- DnSpy: In the left panel, expand
Assembly-CSharp→Assembly-CSharp.dll→(no namespace). Scroll toNewMovement, or useEdit→Search Assembliesand typeNewMovement. - Web Decompiler: Type
NewMovementinto the search bar at the top left and click the result.
Reading the Decompiled Code
The first thing you'll see at the top of the file is the class declaration:
public class NewMovement : MonoSingleton<NewMovement>, ITarget, IPortalTraveller
Breaking this down:
public— this class is accessible from anywhere in the codeclass NewMovement— the name of the class we're working withMonoSingleton<NewMovement>— this means there is only ever one instance ofNewMovementin the game, and you can access it from anywhere usingNewMovement.Instance. This is very helpful because it means you don't need to find or store a reference to the player, you can just ask for it.
What you're reading is not the original source code. The game is compiled for performance which sacrifices human readability for speed, and decompilers reconstruct C# from that. The result is functionally equivalent but will look different from what the developers actually wrote.
Finding the Fields You Care About
Scroll past the class declaration and you'll see a long list of fields — these are the variables that hold the player's state. The ones most relevant to movement are near the top:
public float walkSpeed;
public float jumpPower;
Fields marked public can be read and written from other classes including your mod. Fields marked private cannot be accessed directly from outside the class, which you'll need to work around using Harmony patches or reflection.
walkSpeed is exactly what it sounds like the speed the player walks at. That's what we'll be modifying.
A Shortcut: Decompile from Your IDE
If switching between your code editor and the decompiler gets tedious, you don't have to. In almost any IDE you can Ctrl+Click any class name to have the IDE decompile and display the code..
Adding Speed to the Player
// TODO: Speed modification code here