Migrating from SpaceWarp 1.x

From Kerbal Space Program 2 Modding Wiki
Revision as of 03:41, 29 November 2025 by Munix (talk | contribs)
Jump to navigation Jump to search
Note: This page is a work in progress.

Redux features a brand new version of SpaceWarp. While it's all shiny and cool, it breaks support with older versions. Now you're probably wondering: How do I migrate to SpaceWarp 2.x? This guide is for you.

What's different?

Since Redux has SpaceWarp built-in, there's no need to have BepInEx anymore. This means all mods get stored in a dedicated Mods folder in the main KSP2 directory called "mods"... and that you can't use BepInEx's stuff anymore.

The SpaceWarp namespace has been renamed to SpaceWarp2.

API

SpaceWarp2 now has following classes:

GeneralMod

MonoBehaviourMod

KerbalMod. (technically a Redux thing) It has access to useful game classes like Game, Assets, Messages, etc. Equivalent to BaseSpaceWarpPlugin. Found in Redux.ExtraModTypes


SpaceWarp2 also has a bunch of different members. Some of it has also been split up into ReduxLib and Redux.


SpaceWarp2.API.Configuration = ReduxLib.Configuration

SpaceWarp.API.UI.Appbar = SpaceWarp2.UI.API.Appbar

BepInExConfigFile = JsonConfigFile

Example plugin before & after migration:

Before:

using System.Reflection;
using BepInEx;
using JetBrains.Annotations;
using SpaceWarp;
using SpaceWarp.API.Assets;
using SpaceWarp.API.Mods;
using SpaceWarp.API.UI.Appbar;
using SpaceWarpModUI.UI;
using UitkForKsp2.API;
using UnityEngine;
using UnityEngine.UIElements;

namespace SpaceWarpModUI;

[BepInPlugin(MyPluginInfo.PLUGIN_GUID, MyPluginInfo.PLUGIN_NAME, MyPluginInfo.PLUGIN_VERSION)]
[BepInDependency(SpaceWarpPlugin.ModGuid, SpaceWarpPlugin.ModVer)]
public class SpaceWarpModUIPlugin : BaseSpaceWarpPlugin
{
    // Useful in case some other mod wants to use this mod a dependency
    [PublicAPI] public const string ModGuid = MyPluginInfo.PLUGIN_GUID;
    [PublicAPI] public const string ModName = MyPluginInfo.PLUGIN_NAME;
    [PublicAPI] public const string ModVer = MyPluginInfo.PLUGIN_VERSION;

    /// Singleton instance of the plugin class
    [PublicAPI] public static SpaceWarpModUIPlugin Instance { get; set; }

    // AppBar button IDs
    internal const string ToolbarFlightButtonID = "BTN-SpaceWarpModUIFlight";
    internal const string ToolbarOabButtonID = "BTN-SpaceWarpModUIOAB";
    internal const string ToolbarKscButtonID = "BTN-SpaceWarpModUIKSC";

    /// <summary>
    /// Runs when the mod is first initialized.
    /// </summary>
    public override void OnInitialized()
    {
        base.OnInitialized();

        Instance = this;

        // Load all the other assemblies used by this mod
        LoadAssemblies();

        // Load the UI from the asset bundle
        var myFirstWindowUxml = AssetManager.GetAsset<VisualTreeAsset>(
            // The case-insensitive path to the asset in the bundle is composed of:
            // - The mod GUID:
            $"{ModGuid}/" +
            // - The name of the asset bundle:
            "SpaceWarpModUI_ui/" +
            // - The path to the asset in your Unity project (without the "Assets/" part)
            "ui/myfirstwindow/myfirstwindow.uxml"
        );

        // Create the window options object
        var windowOptions = new WindowOptions
        {
            // The ID of the window. It should be unique to your mod.
            WindowId = "SpaceWarpModUI_MyFirstWindow",
            // The transform of parent game object of the window.
            // If null, it will be created under the main canvas.
            Parent = null,
            // Whether or not the window can be hidden with F2.
            IsHidingEnabled = true,
            // Whether to disable game input when typing into text fields.
            DisableGameInputForTextFields = true,
            MoveOptions = new MoveOptions
            {
                // Whether or not the window can be moved by dragging.
                IsMovingEnabled = true,
                // Whether or not the window can only be moved within the screen bounds.
                CheckScreenBounds = true
            }
        };

        // Create the window
        var myFirstWindow = Window.Create(windowOptions, myFirstWindowUxml);
        // Add a controller for the UI to the window's game object
        var myFirstWindowController = myFirstWindow.gameObject.AddComponent<MyFirstWindowController>();

        // Register Flight AppBar button
        Appbar.RegisterAppButton(
            ModName,
            ToolbarFlightButtonID,
            AssetManager.GetAsset<Texture2D>($"{ModGuid}/images/icon.png"),
            isOpen => myFirstWindowController.IsWindowOpen = isOpen
        );

        // Register OAB AppBar Button
        Appbar.RegisterOABAppButton(
            ModName,
            ToolbarOabButtonID,
            AssetManager.GetAsset<Texture2D>($"{ModGuid}/images/icon.png"),
            isOpen => myFirstWindowController.IsWindowOpen = isOpen
        );

        // Register KSC AppBar Button
        Appbar.RegisterKSCAppButton(
            ModName,
            ToolbarKscButtonID,
            AssetManager.GetAsset<Texture2D>($"{ModGuid}/images/icon.png"),
            () => myFirstWindowController.IsWindowOpen = !myFirstWindowController.IsWindowOpen
        );
    }

    /// <summary>
    /// Loads all the assemblies for the mod.
    /// </summary>
    private static void LoadAssemblies()
    {
        // Load the Unity project assembly
        var currentFolder = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory!.FullName;
        var unityAssembly = Assembly.LoadFrom(Path.Combine(currentFolder, "SpaceWarpModUI.Unity.dll"));
        // Register any custom UI controls from the loaded assembly
        CustomControls.RegisterFromAssembly(unityAssembly);
    }
}

After:

using JetBrains.Annotations;
using Redux.ExtraModTypes;
using SpaceWarp2.UI.API.Appbar;
using SpaceWarpModUI.UI;
using UitkForKsp2.API;
using UnityEngine;
using UnityEngine.UIElements;

namespace SpaceWarpModUI;

public abstract class SpaceWarpModUIPlugin : KerbalMod
{
    [PublicAPI] public const string ModGuid = "SpaceWarpModUI"; // ModGuid here
    [PublicAPI] public const string ModName = "SpaceWarpUIMod"; 
    //[PublicAPI] public const string ModVer = MyPluginInfo.PLUGIN_VERSION;

    /// Singleton instance of the plugin class
    [PublicAPI] public static SpaceWarpModUIPlugin Instance { get; set; }

    // AppBar button IDs
    internal const string ToolbarFlightButtonID = "BTN-SpaceWarpModUIFlight";
    internal const string ToolbarOabButtonID = "BTN-SpaceWarpModUIOAB";
    internal const string ToolbarKscButtonID = "BTN-SpaceWarpModUIKSC";

    /// <summary>
    /// Runs before the game is loaded, as early as possible. 
    /// You would want to use this to register loading actions (like loading JSONs from addressables).
    /// </summary>

    public override void OnPreInitialized()
    {
        Debug.Log("Pre Initialized");
    }
    
    /// <summary>
    /// Runs after the game is loaded and after your mod assets are loaded.
    /// </summary>

    public override void OnInitialized()
    {
        Debug.Log("Is Initializing"); // You can use Debug.Log to log things.
        Instance = this;

        // Load the UI from the asset bundle
        var myFirstWindowUxml = Assets.LoadAssetAsync<VisualTreeAsset>(
            // The case-insensitive path to the asset in the bundle is composed of:
            // - The mod GUID:
            $"{ModGuid}/" +
            // - The name of the asset bundle:
            "SpaceWarpModUI_ui/" +
            // - The path to the asset in your Unity project (without the "Assets/" part)
            "ui/myfirstwindow/myfirstwindow.uxml"
        ).Result;

        // Create the window options object
        var windowOptions = new WindowOptions
        {
            // The ID of the window. It should be unique to your mod.
            WindowId = "SpaceWarpModUI_MyFirstWindow",
            // The transform of parent game object of the window.
            // If null, it will be created under the main canvas.
            Parent = null,
            // Whether the window can be hidden with F2.
            IsHidingEnabled = true,
            // Whether the UI will use the "Scale" option in the settings.
            UseStockScale = true,
            // Whether to disable game input when typing into text fields.
            DisableGameInputForTextFields = true,
            MoveOptions = new MoveOptions
            {
                // Whether the window can be moved by dragging.
                IsMovingEnabled = true,
                // Whether the window can only be moved within the screen bounds.
                CheckScreenBounds = true
            }
        };

        // Create the window
        var myFirstWindow = Window.Create(windowOptions, myFirstWindowUxml);
        // Add a controller for the UI to the window's game object
        var myFirstWindowController = myFirstWindow.gameObject.AddComponent<MyFirstWindowController>();

        // Register Flight AppBar button
        Appbar.RegisterAppButton(
            ModName,
            ToolbarFlightButtonID,
            Assets.LoadAssetAsync<Texture2D>($"{ModGuid}/images/icon.png").Result,
            isOpen => myFirstWindowController.IsWindowOpen = isOpen
        );

        // Register OAB AppBar Button
        Appbar.RegisterOABAppButton(
            ModName,
            ToolbarOabButtonID,
            Assets.LoadAssetAsync<Texture2D>($"{ModGuid}/images/icon.png").Result,
            isOpen => myFirstWindowController.IsWindowOpen = isOpen
        );

        // Register KSC AppBar Button
        Appbar.RegisterKSCAppButton(
            ModName,
            ToolbarKscButtonID,
            Assets.LoadAssetAsync<Texture2D>($"{ModGuid}/images/icon.png").Result,
            () => myFirstWindowController.IsWindowOpen = !myFirstWindowController.IsWindowOpen
        );
    }

    /// <summary>
    /// Runs after all mods have done their 2nd stage initialization.
    /// You would want to use this to interact with game systems, since they're guaranteed to be loaded on this stage.
    /// </summary>

    public override void OnPostInitialized()
    {
        Debug.Log("Post Initialized");
    }


    // You can create controls directly in Unity. No need for this method anymore.
    //private static void LoadAssemblies()
    //{
    //    // Load the Unity project assembly
    //    var currentFolder = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory!.FullName;
    //    var unityAssembly = Assembly.LoadFrom(Path.Combine(currentFolder, "SpaceWarpModUI.Unity.dll"));
    //    // Register any custom UI controls from the loaded assembly
    //    CustomControls.RegisterFromAssembly(unityAssembly);
    //}
}

For more examples you can look at some of the "Reduxed" mods we've made for Redux here: https://github.com/orgs/KSP2Community/repositories?type=all