Skip to content

Instantly share code, notes, and snippets.

@s5bug
Last active August 20, 2020 23:41
Show Gist options
  • Save s5bug/bedd0fbef7c88dff2e01aa34136e1bf9 to your computer and use it in GitHub Desktop.
Save s5bug/bedd0fbef7c88dff2e01aa34136e1bf9 to your computer and use it in GitHub Desktop.
Making Everest mods in FSharp

Making Everest mods in FSharp

Prerequesites:

  • Everest installed
  • Git
  • Visual Studio 2015 or newer with the .NET Framework 4.5.2 Targeting Pack

And either:

  • Visual Studio Code
  • Iodine for Visual Studio Code

Or:

  • JetBrains Rider

Create a new project for your mod, and change directories to it:

\> dotnet new sln -o ExampleMod
\> cd ExampleMod

Initialize your mod as a Git repository so you can add Everest:

\ExampleMod\> git init
\ExampleMod\> git submodule add https://github.com/EverestAPI/Everest.git

Let's add Everest into our solution:

\ExampleMod\> dotnet sln add .\Everest\Celeste.Mod.mm\Celeste.Mod.mm.csproj

Create a new Class Library in F# for your Mod:

\ExampleMod\> dotnet new classlib -lang "F#" -o ExampleMod

There should now be an ExampleMod.fsproj under the new folder ExampleMod. Let's take a look at it:

\ExampleMod\> bat .\ExampleMod\ExampleMod.fsproj
───────┬────────────────────────────────────────────────────────────────────────────────────────────
       │ File: .\ExampleMod\ExampleMod.fsproj
───────┼────────────────────────────────────────────────────────────────────────────────────────────
   1   │ <U+FEFF><Project Sdk="Microsoft.NET.Sdk">
   2   │
   3   │   <PropertyGroup>
   4   │     <TargetFramework>netstandard2.0</TargetFramework>
   5   │   </PropertyGroup>
   6   │
   7   │   <ItemGroup>
   8   │     <Compile Include="Library.fs" />
   9   │   </ItemGroup>
  10   │
  11   │ </Project>

We need to edit this file to add the Everest imports, like so:

\ExampleMod\> bat .\ExampleMod\ExampleMod.fsproj
───────┬────────────────────────────────────────────────────────────────────────────────────────────
       │ File: .\ExampleMod\ExampleMod.fsproj
───────┼────────────────────────────────────────────────────────────────────────────────────────────
   1   │ <U+FEFF><?xml version="1.0" encoding="utf-8"?>
   2   │ <Project Sdk="Microsoft.NET.Sdk">
   3   │   <PropertyGroup>
   4   │     <TargetFramework>net452</TargetFramework>
   5   │   </PropertyGroup>
   6   │   <ItemGroup>
   7   │     <Reference Include="Celeste">
   8   │       <HintPath>..\Everest\lib-stripped\Celeste.exe</HintPath>
   9   │       <Private>False</Private>
  10   │     </Reference>
  11   │     <Reference Include="FNA">
  12   │       <HintPath>..\Everest\lib-stripped\FNA.dll</HintPath>
  13   │       <Private>False</Private>
  14   │     </Reference>
  15   │     <Reference Include="Steamworks.NET">
  16   │       <HintPath>..\Everest\lib-stripped\Steamworks.NET.dll</HintPath>
  17   │       <Private>False</Private>
  18   │     </Reference>
  19   │     <Reference Include="System" />
  20   │     <Reference Include="System.Xml" />
  21   │     <Reference Include="YamlDotNet">
  22   │       <HintPath>..\Everest\lib\YamlDotNet.dll</HintPath>
  23   │       <Private>False</Private>
  24   │     </Reference>
  25   │   </ItemGroup>
  26   │   <ItemGroup>
  27   │     <ProjectReference Include="..\Everest\Celeste.Mod.mm\Celeste.Mod.mm.csproj">
  28   │       <Name>Celeste.Mod.mm.csproj</Name>
  29   │     </ProjectReference>
  30   │   </ItemGroup>
  31   │   <ItemGroup>
  32   │     <Compile Include="Library.fs" />
  33   │   </ItemGroup>
  34   │ </Project>

Let's add it to our solution:

\ExampleMod\> dotnet sln add .\ExampleMod\ExampleMod.fsproj

Next, let's replace Library.fs:

\ExampleMod\> bat .\ExampleMod\Library.fs
───────┬────────────────────────────────────────────────────────────────────────────────────────────
       │ File: .\ExampleMod\Library.fs
───────┼────────────────────────────────────────────────────────────────────────────────────────────
   1   │ <U+FEFF>namespace ExampleMod
   2   │
   3   │ module Say =
   4   │     let hello name =
   5   │         printfn "Hello %s" name

with something that gets loaded as a mod:

\ExampleMod\> bat .\ExampleMod\Library.fs
───────┬────────────────────────────────────────────────────────────────────────────────────────────
       │ File: .\ExampleMod\Library.fs
───────┼────────────────────────────────────────────────────────────────────────────────────────────
   1   │ <U+FEFF>namespace Celeste.Mod.Example
   2   │
   3   │ open Celeste.Mod
   4   │
   5   │ type ExampleModule() =
   6   │     inherit EverestModule()
   7   │     override this.Load() = ()
   8   │     override this.Unload() = ()

Now, we should be able to build our project:

\ExampleMod\> dotnet build

This should build ExampleMod.dll.

Lastly, we need our everest.yaml, which should start out like:

\ExampleMod\> bat everest.yaml
───────┬────────────────────────────────────────────────────────────────────────────────────────────
       │ File: everest.yaml
───────┼────────────────────────────────────────────────────────────────────────────────────────────
   1   │ - Name: ExampleMod
   2   │   Version: 0.0.1
   3   │   DLL: ExampleMod.dll
   4   │   Dependencies:
   5   │     - Name: Everest
   6   │       Version: 1.1908.0

Replacing 1908 with the build of Everest installed.

To use the mod, navigate to your Mods folder (which should already exist from Everest) under your Celeste folder and create a new folder ExampleMod. You're going to want to copy over the following files into this folder:

  • \ExampleMod\ExampleMod\bin\Debug\net452\ExampleMod.dll
  • \ExampleMod\ExampleMod\bin\Debug\net452\ExampleMod.pdb
  • \ExampleMod\ExampleMod\bin\Debug\net452\FSharp.Core.dll
  • \ExampleMod\everest.yaml

The folder should look like this:

Folder Screenshot

When you boot up Everest, if you go to Mod Options → Enable or Disable Mods, you should see ExampleMod listed.

You should now be able to open \ExampleMod\ in VSCode or Rider. Select ExampleMod.sln in the Iodine prompt at the top after VSCode loads the folder, or select ExampleMod.sln in the "Open Solution" dialog in Rider. Any additional non-programming steps (adding resources, etc) should work the same way as in C# projects.

TODO:

  • Document adding packages.
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net452</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Reference Include="Celeste">
<HintPath>..\Everest\lib-stripped\Celeste.exe</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="FNA">
<HintPath>..\Everest\lib-stripped\FNA.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Steamworks.NET">
<HintPath>..\Everest\lib-stripped\Steamworks.NET.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="YamlDotNet">
<HintPath>..\Everest\lib\YamlDotNet.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Everest\Celeste.Mod.mm\Celeste.Mod.mm.csproj">
<Name>Celeste.Mod.mm.csproj</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="Library.fs" />
</ItemGroup>
</Project>
namespace Celeste.Mod.Example
open Celeste.Mod
type ExampleModule() =
inherit EverestModule()
override this.Load() = ()
override this.Unload() = ()
- Name: ExampleMod
Version: 0.0.1
DLL: ExampleMod.dll
Dependencies:
- Name: Everest
Version: 1.1909.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment