-
Notifications
You must be signed in to change notification settings - Fork 0
Mod Creation: First Mod
The very basics.
- Wizard of Legend
-
Visual Studio Community
- when you install, make sure you have the .net 3.5 component
- Any knowledge of c# (or even just willingness to learn)
We're going to start with a simple template for you to be able to start modding and build an example mod.
- Download or clone this repo anywhere on your computer.
- Open the WolModExample.csproj in visual studio (now's the time to download it if you don't have it).
- At the top, go to
Build > Build WolModExample
.
And we're good! The you have just built the mod. You can now add the mod to your game:
- Navigate to
Plugin-Example-Guide/WolModExample/bin/Debug/
and find yourWolModExample.dll
. - Add that to your
BepInEx/plugins
folder and you can run the game with the mod. - In game, press F1 and F2 to zoom in/out the camera, and if you have a second controller handy, go into coop mode and run around freely.
Let's take a deeper look at this project so know just what's needed to make a mod.
- If you've downloaded the template repo, you should be clear to open the project and skip to the next section. It's a working project environment you can use to create a mod.
- To know how to set up a project from scratch, Follow this guide.
The basis of every mod looks like this:
[BepInPlugin("CoolAuthorName.CoolModName", "Cool Mod Name", "0.1.0")]
public class MyCoolModPlugin : BaseUnityPlugin
{
void Awake()
{
}
}
Let's go through this line by line and see what's happening.
(If you've cloned the template repo, you can also read the extensive comments in WolModExamplePlugin.cs.)
[BepInPlugin("CoolAuthorName.CoolModName", "Cool Mod Name", "0.1.0")]
-
[BepInPlugin]
- This is an attribute that bepin will use to load our mod into the game
- if you don't know what an attribute is, now's the time to learn some C#
-
"CoolAuthorName.CoolModName"
- This is the identifier for your mod.
- This one simply follows the convention of
"AuthorName.YourModName"
.
-
"Cool Mod Name"
- This is the human-readable name of your mod.
- It can be literally anything, truthfully.
-
"0.1.0"
- This is the version.
- As you'd expect, useful for differing between updates.
- This one follows the customary Semantic Versioning (
major.minor.patch
). - I usually keep it as
0.1.0
while developing, and put out a1.0.0
when I feel the mod is complete.
- This is the version.
public class MyCoolModPlugin : BaseUnityPlugin
- BaseUnityPlugin is the main class that gets loaded by bepin.
- It inherits from MonoBehaviour, so it gains all the familiar Unity callback functions you can use:
- Awake, Start, Update, FixedUpdate, etc.
void Awake()
{
}
- Awake is the most important of the MonoBehaviour classes above.
- It gets called by the game at the start of the class being initialized, i.e. as soon as your mod is loaded by bepin.
- This is usually where you will write hooks (explained next), add things to things, change things, do whatever you like.
There are two main ways to write code in a bepin plugin. MMHooks, and HarmonyPatches. For simplicity, I'll just be going over MMHook here. You can read more about Harmony here
Hooks are a powerful tool that lets us write code that executes alongside the code of the game.
To create a hook, it looks something like this:
On.someclass.somefunction += someclass_somefunction;
- Start with the
On.
namespace, then go to the class and function you want to hook. Then type+=
and press thetab
key. this will autofill thesomeclass_somefunction
part, as well as create a function for the hook to run.
private void someclass_somefunction(someclass.orig_somefunction orig, someclass self)
{
//only nerds allowed past this point
}
- This function will have auto-filled parameters for the hook: the original function
orig
, and the original referenceself
.-
orig
is the original function of the game. -
self
is the reference to the instance of that original class.
-
Somewhere in the code you'll call orig(self)
.
private void someclass_somefunction(someclass.orig_somefunction orig, someclass self)
{
orig(self);
//our code here.
}
- This is very important. This runs the original code of the game.
- With this you can simply decide to run your code before or after the original code runs.
- Note that if you don't call
orig(self)
, the original function (and any other mods that hook onto it) won't run, and your code will override it.
Let's run through an example:
private void CameraController_Awake(On.CameraController.orig_Awake orig, CameraController self)
{
orig(self);
self.maxHorizontalDistBetweenPlayers = 100;
self.maxVerticalDistBetweenPlayers = 100;
//now we can run really far from each other!
}
In this example, we've hooked on to CameraController.Awake
.
- When that function is called, our hook function will also be called
- We call
orig(self)
so the original code runs - Then we modify variables of the
self
instance.- So the
self
in that function refers to that particularCameraController
that shows up in the game. - We simply mess with a few variables of that instance.
- So the
- Take a look at the overly commented WolModExamplePlugin.cs and see if you can follow what's going on.
Absolutely get DNSpy if you haven't, so you can look at the game's code. (link stolen from ror2 modding wiki (but applies here of course)) - If you'd like to make custom Relics (Items), Robes (Outfits) or Arcana (Skills), refer to the
Custom Content
pages on this wiki --> - If you have any questions go ahead and ask in the Wizard of Legend discord (#modding-extravaganza) and/or ping
thetimesweeper
he craves attention.
Also of course any and all feedback on this guide will be very appreciated. Thanks thanks have a lovely evening c: