NEBULOUS: Fleet Command

NEBULOUS: Fleet Command

28 ratings
Mission Graph Loader
2
   
Award
Favorite
Favorited
Unfavorite
Mods: Mod, Tweak
File Size
Posted
Updated
869.773 KB
12 Jan, 2024 @ 11:45pm
26 Jan @ 12:17am
6 Change Notes ( view )

Subscribe to download
Mission Graph Loader

Description
Mission Graph Loader (MGL) is a utility mod that allows other mods to add custom missions to the game, accessible in the Campaigns/Tutorials menu. Huge thanks to Lys and Someusername6 for helping me understand the code and get this project off the ground last summer!

MGL adds nothing on its own, but may be required for some of your other mods to work. If you're just grabbing MGL for that reason, you can stop reading here, the below is only for those interested in the technical aspects of the mod.

I'm curious, why does this mod exist?
The missions system in the game is slightly undercooked, which is understandable because it's only used for the tutorials and nothing else. But it means that missions don't have quite the same mod-friendliness as, say, maps or factions or ships or weapons do.

Each mission has a "mission graph" which is like a flow chart that defines the player and opponent fleets, dialogue lines, objectives, completion checks, etc. Most assets in Neb are static loaded using Unity's AssetBundle system, meaning they are loaded during the loading screen when you start the game, and remain accessible until you exit the game. But mission graphs are special, they are dynamic loaded using Unity's Addressables system, meaning they load silently in the background at some point, in this case when you select the mission in the campaign menu, and are unloaded when the mission is completed.

This is a problem, because Unity's Addressables system only looks in the basegame folder for assets. It does not pick up modded content for dynamic loading. And without loaded mission graphs, our missions can't be played. So, what do? Simple, rewrite the game's modding framework so it static loads mission graphs. That's what MGL does. It scans all enabled mods for any mission graphs, and loads them on game startup, to replace the dynamic loading that refuses to cooperate.

There are a few implications of this technical design that you might already have guessed. Mainly, it means more stuff is loaded in your computer's memory at once. Instead of the mission you are playing being loaded while you are playing it and being unloaded afterwards, every modded mission you have is in memory at all times, even when you're in the fleet editor or in multiplayer. I have been playing for a long while with this mod in the background and haven't noticed any issues, but that's no guarantee. If you find yourself experiencing performance problems, disabling MGL might help. Also, the main menu may hang for a few seconds when starting up the game with MGL enabled.

I'm a modder, what exactly did you do?
  • Reimplement the BundleManager::ProcessAssetBundle() function to allow static load of mission graphs on startup
  • Provide framework for missions to use basegame maps and maps from other mods
  • Provide framework for missions to use the facility model from Station Capture mode (credit to Someusername6 for pioneering this method in GameModePlus)
  • Add additional logging to NodeGraph code to make debugging mission graphs easier
  • Rename the button on the main menu from "Campaign/Tutorial" to "Campaign"
  • Fix basegame bug where missions' set badges would not override the player's badge
  • Fix basegame bug where missions' set badges would not apply to enemy and ally bots

If you want to dig deeper into the technical details of all this, here's the source code.[github.com]

I'm a modder, how do I use this mod?
Set up a Unity project as detailed in the game's official modding guide. Create a MissionSet, populate it with some interesting Missions and assemble a MissionGraph for each of them using the XNode plugin for Unity.[github.com] Package all that into an AssetBundle. Inside the manifest.xml file, add a pointer to your MissionSet definition:
<MissionSets> <Entry Name="Super Awesome Campaign" Address="PathTo/SuperAwesomeCampaign_MissionSet.asset"/> </MissionSets>

In the same folder as your manifest, create a new file called missions.xml and set it to be packaged in the same AssetBundle as your manifest. This file is what MGL will scan for on game startup, you use it to define what you want to happen with your mod, as follows:
<?xml version="1.0"?> <MissionLoaderManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <MissionGraphMappings> <MissionGraphEntry MissionName="Nice Mission Name" GraphAddress="Assets/YourAssetBundleFolder/PathTo/NiceMission_Graph.asset"/> <MissionGraphEntry MissionName="Cool Mission Name" GraphAddress="Assets/YourAssetBundleFolder/PathTo/CoolMission_Graph.asset"/> <MissionGraphEntry MissionName="Epic Mission Name" GraphAddress="Assets/YourAssetBundleFolder/PathTo/EpicMission_Graph.asset"/> </MissionGraphMappings> <MissionBattlespaceMappings> <MissionBattlespaceEntry MissionName="Nice Mission Name" BattlespaceName="Caltrop"/> <MissionBattlespaceEntry MissionName="Cool Mission Name" BattlespaceName="Salar"/> </MissionBattlespaceMappings> <MissionsWithStations> <string>Cool Mission Name</string> </MissionsWithStations> </MissionLoaderManifest>

In this example, this mod is telling MGL that it has three missions it wants loaded. Nice Mission will use the basegame map Caltrop, Cool Mission will use the modded map Salar (don't forget to mark that mod as a dependency to yours), and Epic Mission isn't here, so it's presumably going to use a new original map contained in the same AssetBundle as the mission graph. Cool Mission also wants to have the basegame station present. Missions in that list will have their mission graph scanned for any "Create Capture Point" nodes, and the station model will be inserted into the node's "Prefab" field.

One final step - for MGL to recognize that your mod is in need of assistance, you must set MGL as a dependency in your mod folder's ModInfo.xml file. To avoid replacing the the ProcessAssetBundle function when loading every single mod the player has enabled, which would be bad for mod compatibility, MGL checks for its own ID in the dependency list of each mod.
<Dependencies> <unsignedLong>3138206791</unsignedLong> </Dependencies>

That's the basics. For creating the actual meat of a modded campaign, the mission graphs themselves, here is an example.[github.com] It's a bunch of work, but very satisfying to finish. If you have questions, ask @NotSoLoneWolf in the #mod-development channel on the official discord.