Skip to content

Script Mods

Script mods are class libraries written in C# and loaded into game by BepInEx loader. To make a script mod, you'd need the follow tools:

Code Editor/IDE

Pick your poison and make sure you have .NET development package installed for Visual Studio families.

Decompiler

To modify game code, you'd need to know what to modify first. You'll want a .NET decompiler to browse the game source code.

No, do not solely rely on your IDE's auto decompiling, use an actual decompiler from the following:

If you are using dnSpyEx, don't forget to turn off metadata tokens and RVA display, you won't need those info.

Simply open the Elin/Elin_Data/Managed/Elin.dll in the decompiler and load its dependencies, now you can freely browse game source code, search for constants, and analyze usages.

C# Project

If you want to use MinusGix's template mod, you can skip to Debugging.

Note

MinusGix's template targets netstandard 2.1 with .NET SDK, you might encounter mscorlib dependency problem if you want to use CodeMatcher/Transpilers.

Target framework

Example with Rider, create a new class library project with target .NET framework 4.7.2: rider new

You could theoretically target netstandard 2.0/2.1 too, but since noa suggests mod authors to target .NET framework, we'll stay on that path. Besides there's really not much differences because you get to use C# 12/13 features with both anyway.

Dependencies

An Elin script mod will of course depend on Elin's libraries. Let's first add the dependencies to the project: deps

Then add the following basic libraries from game folder, you can multi-select:

  • Elin_Data\Managed\Elin.dll
  • Elin_Data\Managed\Plugins.BaseCore.dll
  • Elin_Data\Managed\UnityEngine.dll
  • Elin_Data\Managed\UnityEngine.CoreModule.dll
  • BepInEx\core\0Harmony.dll
  • BepInEx\core\BepInEx.Core.dll
  • BepInEx\core\BepInEx.Unity.dll

You should always reference from game folder, so that you get the updated libraries as the game updates. You can also add more libraries when you need, or just add a bunch of them at the start(excluding any System.* libraries) and refactor them at the end.

After adding dependences, for each reference, set Copy Local to false so they won't be copied to your output folder.

For Rider users, you need to manually edit the project file and add <Private>False</Private> to each reference, like so: edit csproj

xml
<Reference Include="Plugins.BaseCore">
    <HintPath>$(ElinGamePath)\Elin_Data\Managed\Plugins.BaseCore.dll</HintPath>
    <Private>False</Private>
</Reference>

Project Setup

In the properties setting, you can set C# language version to 12/13/preview, which simplifies a lot of syntaxes: cs ver

For the output dir, you should use ElinGamePath\Package\Mod_$(AssemblyName)\ so that you always build into mod folder and ready to test.

Again, for Rider users, you need to manually edit the project file again and change the <OutputPath> for both Debug and Release configurations:

xml
<OutputPath>$(ElinGamePath)\Package\Mod_$(AssemblyName)\</OutputPath>

Basic Plugin

We are making a BepInEx plugin, so it's all the same stuff. Create file MyElinMod.cs at the project root:

cs
using BepInEx;
using HarmonyLib;

namespace MyMod;

internal static class ModInfo
{
    internal const string Guid = "dk.elinplugins.myelinmod";
    internal const string Name = "My Elin Mod";
    internal const string Version = "1.0";
}

[BepInPlugin(ModInfo.Guid, ModInfo.Name, ModInfo.Version)]
internal class MyElinMod : BaseUnityPlugin
{
    private void Awake()
    {
        Logger.LogInfo("My mod...loaded?!")
    }
}

Here we chose the same Guid as mod ID in package.xml. This needs to be an unique identifier for your mod, so make it very unique.

After building the project and launching the game, you should see the message in the log output, either via BepInEx console or Player.log at %localappdata%low\Lafrontier\Elin\Player.log.

Enable BepInEx Console

Open the BepInEx config file at Elin\BepInEx\config\BepInEx.cfg and change the following:

ini
[Logging.Console]

## Enables showing a console for log output.
# Setting type: Boolean
# Default value: false
Enabled = true