Skip to content

Developing

Anairkoen Schno edited this page Jun 13, 2019 · 27 revisions

Also take a look at the official documentation at https://beat-saber-modding-group.github.io/BeatSaber-IPA-Reloaded/index.html

Developing for IPA

This is quite similar to normal IPA (and supports standard IPA plugins, though not for long), however it is recommended that you inherit IBeatSaberPlugin instead of IPlugin and IEnhancedBeatSaberPlugin instead of IEnhancedPlugin. This variant sports a couple of changes.

  1. Instead of referencing IllusionPlugin, you now reference IPA.Loader. Everything formerly in both IllusionPlugin and IllusionInjector is now in this one file. The root namespace is now IPA. The loader WILL fix references, but that is probably temporary until this is fully adopted as the standard for Beat Saber.
  2. The old level change events were replaced with
public void OnActiveSceneChanged(Scene prevScene, Scene nextScene);
public void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode);
public void OnSceneUnloaded(Scene scene);
  1. There MUST be an embedded manifest.json in the same namespace as the main class. To embed a file in the assembly correctly, select Build Action -> Embedded Resource in the file properties in Visual Studio.

Here is the manifest for BSIPA itself:

{
  "$schema": "https://raw.githubusercontent.com/beat-saber-modding-group/BSIPA-MetadataFileSchema/master/Schema.json",
  "author": "DaNike",
  "description": "A mod loader specifically for Beat Saber.",
  "gameVersion": "0.13.2",
  "id": "BSIPA",
  "name": "Beat Saber IPA",
  "version": "3.12.15",
  "icon": "IPA.icon.png",
  "features": [
    "define-feature(print, IPA.Loader.Features.PrintFeature)",
    "define-feature(debug, IPA.Loader.Features.DebugFeature)",
    "define-feature(warn, IPA.Loader.Features.WarnFeature)",
    "define-feature(no-update, IPA.Loader.Features.NoUpdateFeature)",
    "define-feature(add-in, IPA.Loader.Features.AddInFeature)",
    "define-feature(init-injector, IPA.Loader.Features.InitInjectorFeature)",
    "define-feature(config-provider, IPA.Loader.Features.ConfigProviderFeature)"
  ],
  "links": {
    "project-home": "https://github.com/beat-saber-modding-group/BeatSaber-IPA-Reloaded/wiki",
    "project-source": "https://github.com/beat-saber-modding-group/BeatSaber-IPA-Reloaded",
    "donate": "https://ko-fi.com/danike"
  }
}

The schema for these files is defined here. For any suggested changes to the schema, make a PR there.

Your plugin can also ask for a Logger, IModPrefs, or IConfigProvider object by using them as types in the argument list for an Init() method. Ordering and name doesn't matter, and Init() can be omitted.

For example, if you wanted a Logger and IConfigProvider you could define Init() as

public void Init(Logger logger, IConfigProvider prefs)

but if you only wanted a Logger, you could put this:

public void Init(object thisWillBeNull, Logger logger)

Any unrecognized types will just be passed as their default value (given by default(Type)).

You can annotate an IConfigProvider with a PreferAttribute to specify the type of config to prefer. You can use it like

public void Init([Prefer("toml","json")]IConfigProvider config)

to prefer the config to be toml, but let it fall back to json. JSON is the default, so if none of the preferred types are registered, it will automatically fall back to JSON.

As of 3.12.15, a parameter with type PluginLoader.PluginMetadata will be automatically filled with the current plugin's metadata.

Additional Libraries

This distro of IPA comes with Ionic.Zip, Newtonsoft.Json, Harmony, SemVer, Mono.Cecil, as well as the Mono project's I18N.dll and I18N.West.dll to provide codepage 437, and Microsoft.CSharp.dll.

All third party libraries exist in the Libs folder, with a naming scheme of assemblyName.version.dll. This should be used by any plugins that want their own third-party libraries. Libraries may be put in subdirectories, however this is only recommended for additional modules that are part of your plugin, and not 3rd party libraries. Names must be unique among all subdirectories and the root. By including the version in the filename, it allows multiple plugins to use different versions of the libraries without conflicts.

After version 3.12.11, files may also be named assemblyName.dll, but one with a matching version will be preferred.

Any native library should be placed in Libs\Native for it to be loaded correctly.

THE VERSION MUST BE CORRECT OR THE LIBRARY WILL NOT LOAD!

Take a look at this file to see what kind of process works for this. Or you could just use BS Build Tools.

Debugging

To show the console after version 3.12.10, give Beat Saber the launch option --verbose.

BSIPA's config has moved to UserData/Beat Saber IPA.json. It should look something like this:

{
  "Regenerate": false,
  "ApplyAntiYeet": false,
  "Updates": {
    "AutoUpdate": true,
    "AutoCheckUpdates": true
  },
  "Debug": {
    "ShowCallSource": false,
    "ShowDebug": false
  }
}

When ShowDebug is enabled, all Debug messages will be printed to the console. When ShowCallSource is enabled, any call to Logger.Debug (and NOT Logger.Log(LogLevel.Debug, ...)) will print and log the method that it was called from in addition to the message.

In addition, if you provide the command line option --mono-debug you can enable the soft debugger, which you can attach to with MonoDevelop or SDB. With the addition of --server it acts as a debugging server, instead of a client. --debug forces Mono to load debugging information, but not activate the debugger. For your code to be debuggable, it needs to have a PDB of the same name, just with .dll replaced with .pdb, and it needs to be in the portable PDB format.

Clone this wiki locally