ChilloutVR

ChilloutVR

Not enough ratings
Getting started with modding using BepInEx
By Lehti and 1 collaborators
How to create a BepInEx plugin to mod CVR, intended for people who know at least a bit about programming.
   
Award
Favorite
Favorited
Unfavorite
Prelude
First of all, I want to make one thing very clear: This guide nor its contents are endorsed by Alpha Blend Interactive, the developers of ChilloutVR. Frankly speaking, I'm not even sure if the devs will just remove this guide. I'm just a user who thinks that openly embracing wholesome modding would lead to rapid QoL improvements, and perhaps even a larger userbase.

Also before you start modding, make sure you've read the ToS of ChilloutVR[documentation.abinteractive.net].
Because this guide cannot guarantee to cover any future changes to the ToS, it's up to you to ensure that modding the game is still allowed in the ways described in this tutorial when you're reading this.
Also in case if it wasn't obvious, with great power comes great responsibility. I am certain that you will get punished if you try to do anything malicious since it'll be easy to detect due to the client-server infrastructure implementation.

Now one last thing before we get started: This guide won't teach you C#, git, or how Unity works; those things are considered out of scope. I'm sure you can use your favorite search engine to figure it out.
Installing BepInEx
To begin your modding journey, you'll want to install BepInEx, the framework we'll be using to inject the plugins into the game with. You can go read the longer BepInEx installation guide[docs.bepinex.dev], but in short:
  • Download BepInEx 6 Mono x64[docs.bepinex.dev]
  • Extract the zip to your game folder (By default `C:\Program Files (x86)\Steam\steamapps\common\ChilloutVR`)
  • Launch ChilloutVR once

After that, you might want to for example grab sinai-dev's BepInExConfigManager[github.com] (Mono version for CVR), and launch again after moving it to the `BepInEx/plugins` folder. Pressing the default F5 key should bring up a config management window in-game now. By doing this, you'll also have ensured that your installation works properly.
Setting up your project
One of the easiest ways is to just follow the official BepInEx tutorial[docs.bepinex.dev].
Visual Studio makes the setup quite easy though, just create a .NET Standard C# project, and after creating it add references to the game DLLs', which you can locate from under `ChilloutVR_Data\Managed` from the game's installation folder.


If you're going the more manual route, I'd recommend you take a look at setting up a Directory.Build.props[github.com] file at the root of your project to help to resolve the references properly regardless of platform, with a fallback to a local Libs folder. After that, to create a new plugin just create a subfolder for it, and write a .csproj file which could potentially look as simple as:
<Project Sdk="Microsoft.NET.Sdk"> </Project>

You should always ensure that you aren't publishing anything that you don't have a license to publish. So if you're using git, make sure that none of the referenced DLL files slips into any of your commits.
Also just base your .gitignore on the standard VS .gitignore[github.com] if you're publishing your creations.
Your first plugin
Again, the best source is the official BepInEx docs[docs.bepinex.dev].

You'll basically just want to create a namespace and a class inside it for your plugin and then define the BepInPlugin attribute for your class.
using System; using BepInEx; namespace ExamplePlugin { [BepInPlugin("org.example.cvr", "Example Plug-In", "1.0.0")] [BepInProcess("ChilloutVR.exe")] public class ExamplePlugin : BaseUnityPlugin { void Awake() { Logger.LogInfo("Hello, world!"); } } }
Then just build and move the plugin into the plugins folder, and you should see your plugin's message be output into the `BepInEx\LogOutput.log` file on the next start.

After that, you can follow the official Unity docs for MonoBehaviour[docs.unity3d.com] to figure out what all you can do right from the start with your plugin. You should also follow the BepInEx tutorial through though to figure out how to set up logging & configuration.
Figuring out what to do
Now I don't know if I can advocate for decompiling game code. Of course, being able to search for things by name and figure out what uses them and is used by them is quite handy for understanding how things work. But I'm not a lawyer.
Things like dnSpy[github.com] are very useful, but you'll have to very carefully read the ToS to figure out if the usage of it is allowed or not. Another similar case is with UnityExplorer[github.com].

A general tip on figuring out how you should proceed after you know what you want your plugin to do; Plan your plugin so that it touches as little game code as possible. This makes your plugin more future proof because CVR developers shouldn't care if their game updates break your plugin. So the less you interact with the game code, the less breakage I'd expect from your plugin.
Harmony patching
One essential tool that you have access to is Harmony[github.com]. With Harmony patches you can run your own code before and/or after some specific method, possibly accessing the data that the method has access to in the process.

Harmony also provides some really handy utilities like traverse[harmony.pardeike.net], which you can use to access private fields and properties. Of course, you could use C# reflections, but harmony simplifies the process a fair bit.

Another tip I have is that you'll probably want to avoid stopping whole methods if you can with harmony, even though it's possible with prefixes. You can use Harmony postfixes to run your code after the game method and for example to overwrite some fields the game code changed, instead of stopping the game code from running completely. That way there won't be surprises in the future with things not working because you stopped some crucial code from running.
Footnotes
As a general rule when modding with pretty much any game; do not report bugs or weird behavior.
You'll want to reproduce it without having any mods enabled. To do that, rename the `winhttp.dll` to `winhttp-bak.dll` for example to launch the game without BepInEx. After you've done that, you can just rename the file back to the original name to re-enable your plugins.

Also, utilize open-source licenses! If someone has licensed their code in a way that allows you to use and modify it, don't re-invent the wheel for no reason. Just follow the terms of the licenses (such as having to license your code under the same license or needing to state changes for example) if you do, since that way you can avoid wasting your time on an already solved problem.

If you're familiar with MelonLoader modding, BepInEx should be quite easy for you to pick up. You can of course also use MelonLoader too for modding, but it requires the .NET framework, which makes modding way worse to use on Linux. Also, I haven't found it to have any benefit over BepInEx, meanwhile, at least personally I found BepInEx to be a bit easier to work with. But it's just a matter of preference at the end of the day.

Hopefully, in the future, we'll have modding support available through the steam workshop even so that they can be reviewed properly. It could even just be slapped on with BepInEx.MultiFolderLoader[github.com]. But of course though the real world isn't as easy as my dreams sadly, as I'm sure there's multiple valid issues stopping the CVR devs from even considering that.

And so finally we've reached the plugging part:
Want to discuss game modding? Join the unofficial CVR Modding corner[discord.gg], or check out LJ's CVR BepInEx plugins.[github.com]
Also if you want to stick to MelonLoader, check out Shin's CVR MelonLoader hotkeys mod[github.com].