NEBULOUS: Fleet Command

NEBULOUS: Fleet Command

Not enough ratings
WiP's Map Making Guide
By WaterIsPoison
A workflow for making custom maps in Nebulous: Fleet Command
3
   
Award
Favorite
Favorited
Unfavorite
Environment Setup
First and foremost, you should follow the steps listed in the Basics of Modding NEBULOUS guide. This will provide a walk through in setting up Unity, versioning, etc. Make sure you complete environment setup and adding the CreateAssetBundles script.
Unity Project Setup
Once you have finished the modding setup from the high level guide, you can start setting up your project. The folder layout to the right is an example we will be referencing here from a custom map called The Maw.

I created a 'Bundle' folder to work from, and a sub folder to store all the objects/files for the bundle itself (more on this later, for now you can just create some empty folders). I also added a Mesh folder to store my .obj files (or whatever assets you will put in your map) and a Materials folder to store textures. The only other folder that is useful is 'oct' which is a scratch folder we will be using later.
Creating your Game Object Hierarchy
Alright, let's get to making your map. First, you'll want to create an empty game object called "MapCenter" or something similar. Ensure it's centered at 0,0,0 with no rotation (this makes your life easier down the line). This game object will be used to perform some operations later, but isn't considered part of your map. More on this later in Generating an Octree.

Create another empty game object, this will be the root of our actual map prefab, so name it after your map (for example this is named "Maw"). In this game object you'll want to add one script, click on Add Component then search for and add Battlespace.



This script will store the majority of your map information such as naming, references to the octree, references to spawns, and objectives.

Underneath your Map game object, add two children GameObjects called "Team A Spawns" and Team B Spawns". For these game objects click Add Component then search for and add Spawn Group. Modify the spawns variable to the number of spawn locations you want for each team. For example, for a four player map set this to two.



Next, under each spawn group create empty game objects for each spawn group. These are the default spawn locations if you don't allow the players to modify them. For example, for a four player map, you'll create two spawn points per player. Name them Team A Spawn Point 1, Team A Spawn Point 2, etc. For these game objects click Add Component then search for and add Spawn Point.



Under your main map object (in this example "Maw") create an empty game object and call it "Central Objective". This will have no scripts attached.

Finally, create one last empty game object under your main map to store all of your map assets, in this example I named it "Asteroids" as it will hold all of our asteroid meshes.

If you did everything correctly, you should see a game object hierarchy that looks like this. Once you are happy, drag your main map object ("Maw") to your Bundle/Map folder to create a prefab. Every time you modify your map and want to save your work, you'll want to drag this to that same folder to update your prefab (objects are colored blue if prefabs).



Finally, looking at your scene tab you should see something like the following:

Configuring the Scripts
In this section I'll provide an overview of the script setting for all of the gameobjects and what the settings do. The list is not exhaustive, but the ones that are important for a minimal map. Critical settings/steps are bolded

Battlespace
  • Long Name : The top rendered name in the map loading animation (usually something like "AE3091-4 The Maw"
  • Location Name : Subtitle for rendred name in map loading animation (usually something like "XYZ Sector, XYZ System" etc.)
  • Flavor Description : Even more space to for lore
  • Map Image : Preview image at the game lobby. Drag a png/jpg here of a screenshot.
  • Radius : The max radius of the game sphere. This is rendered by the red sphere. Make sure this is always larger than the Spawn Radius. For a four player game, this could be set to something like 1250
  • Spawn Radius : The max radius of the spawn area for the players. This is rendered by the green sphere. Make sure this is small than the Spawn Radius. For a four player game, this could be set to something like 1000
  • Max Players : Max number of players for the map
  • Allow Spawn Selection : Tick this box if you want players to select their spawn point
  • Team A Spawns : Drag your Team A Spawns game object here
  • Team B Spawns : Drag your Team B Spawns game object here
  • Pathfinding : This will store a reference to your octree (covered later)
  • Lighting : I think you can do custom lighting here, but haven't tested it yet
  • Skybox : I think you can do a custom skybox here, but haven't tested it yet
  • Central Objective Position : Drag your Central Objective Game Object here

Spawn Group
  • Spawns : Set it to the number of players per team. It should create a list of elements. Drag your Team X Spawn Y game objects here (see example below)
  • Appraoch Vector Ang : The max angle players can jump in from. A good default is 45 degrees

Spawn Point
Good to just leave the defaults here I think...
  • Ships Per Column : Default number of ships per column if default spawns are used
  • Spacing : Horiztonal Distance between ships when spawned
  • Half Vertical Spacing : Half of the vertical distance between ships when spawned

Map Layout
Now we can finally start laying out the map.

Map Radius

Find a good map radius you like (good default for 4p is something like 1250) that will encompass your assets and leave enough room for maneuvering. Remember you want to have enough coverage to provide some radar occlusion, but not so much people can't find each other.

Move your Spawn Groups

You'll need to shift your spawn groups to either side of the map. For this take your Team A Spawns game object and shift it by something like half the radius of the map on the negative Z axis (so set Position Z to -650). Do the opposite for Team B Spawns (Position Z to 650).

When you do this you should see the spawn cones render like below and you should see the spawn points shift as well (you can find adjust these as you see fit, feel free to play test this distance to see what works for your map).


Central Objective
You can move your central objective game object to where you see fit. This defines the station/facility objective for the capture station game mode.

Capture Points
For the capture points game mode, you'll want to add however many points you want players to fight over in the Battlespace script under the Distributed Objective Positions. Shift the X,Y,Z elements to where you see fit (they show up in the Scene as blue crosses).
Add your environment objects
I'm not going to give you much guidance on how to make your environmental objects as it's not really my specialty. You'll want to look up tutorials on modelling and texturing. However, I want to cover a couple of important points. Here is an example asteroid from the Maw map



An important note is that it utilizes a mesh collider rather than a sphere or capsule collider, and it has the same mesh as the object itself. This will be useful for rendering collision data.

Second, you need to set the Layer at the very top right of the Game Object menu to Layer 9 or "Not in Reflector" otherwise your objects won't show up in the tactical view camera in game.

Other than that, this is where the meat and potatoes of your map will be. Make sure you consider gameplay as you playout your objects and ensure they stay within the game sphere.

Setup for building an Octree
AI path information is generated through a datastructure called an octree[en.wikipedia.org]. An octree recursively splits a volume of 3D space into tree of voxels. Luckily, the developers have implemented scripts to create this data for us.

Go back to your MapCenter game object, we will need to add two scripts to this game object.

First, click on Add Component and then search for 'Space Partitioner'. This is an included script in the Nebulous.dll that will be used to generate the octree data.

Next, you'll need to create a custom C# script (for now) that will add some functions to your editor to call the partitioning functions. Create the file "SpacePartitionerBuilder.cs" and add it to your Assets/Scripts folder (create it if you don't have it).

Add this code to the SpacePartitionerBuilder.cs script

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using Game.Map; [RequireComponent(typeof(SpacePartitioner))] public class SpacePartitionerBuilder : MonoBehaviour { private SpacePartitioner _tree { get { if (__tree == null) __tree = GetComponent<SpacePartitioner>(); return __tree; } } private SpacePartitioner __tree; [ContextMenu("Build Tree")] public void Build() { _tree.Editor_Build(); } [ContextMenu("Clear Tree")] public void ClearTree() { _tree.Editor_ClearTree(); } [ContextMenu("Convert Tree To Graph")] public void BuildGraph() { _tree.Editor_BuildGraph(); } #if UNITY_EDITOR [ContextMenu("Save Tree to Asset")] public void SaveTreeToAsset() { string path = EditorUtility.SaveFilePanel("Save Nav Tree", "Assets/", "Map Navigation Tree", "asset"); if (string.IsNullOrEmpty(path)) return; path = FileUtil.GetProjectRelativePath(path); _tree.SerializeTreeToAsset(path); } #endif }
Generating the Octree
Once you are happy with the layout (or each time you change the layout of your map) you'll need to generate the octree. There are three main steps for this.

Build the Tree
Go back to your MapCenter object and the Space Partitioner script. There are three variables you'll need to mess with.

  • Debug Draw : Set this to Nodes to see the voxels
  • Leaf Radius : This is the size of the voxels that split up the each cube in the tree. The smaller this is, the higher the resolution.
  • Min Depth: The minimum number of steps the algorithm will perform per voxel.
  • Max Depth: The maximum number of recursions the algorithm will perform per voxel.

When you are ready to generate your tree, click on the options menu (three vertical dots) on the Space Partitioner Builder script component in your game object and click on "Build Tree"


In general, a small leaf radius will give you a higher resolution, at the expense of generation time and size. The script will generate a white cube as your change leaf radius and max depth. You'll want to play with these two variables to make sure the entire map (the red sphere) is within the white cube.

If you want a higher resolution, you'll need to do more iterations to capture the space. If you are ok with a lower resolution, you can do a large leaf radius and smaller max depth. The balance will depend on your map.

If you are visualizing correctly, you should see something like this:


Here green squares are the voxels of the octree, you can see where there is an object, it gets subdivided recursively until red squares detect the mesh collider of the objects. You can see that we get a good deal of resolution defining the boundaries of the objects.
The settings for this was:
  • Leaf Radius : 25
  • Min Depth : 1
  • Max Depth : 6
An example of an octree that doesn't have enough resolution is the following:


Here the squares are too low resolution and the red squares are blocking off large areas of open space, which will prevent AI from traversing.
The settings for this was:
  • Leaf Radius : 250
  • Min Depth : 1
  • Max Depth : 2

Here is probably a too high resolution octree. There are a lot of redundant points which will add to the size. Generating this took several minutes


The settings for this was:
  • Leaf Radius : 2
  • Min Depth : 1
  • Max Depth : 10

Build the Nav Graph
Once you are happy with your octree, you need to generate the nav graph. Click on the same three dots of the option menu and select Convert Tree to Graph. If you want to debug this, you can change the Debug Draw dropdown to Graph. This is the following debug visualization for this.



Save to assets
Finally, go back to the three dot option menu and hit Save Tree to Asset, which will bring up a file picker dialog. Select the Assets/oct folder we created at the beginning. Finally, for file name add the map name (I used "maw"). This will generate two file, mawNavGraph, and mawNavTree.

Create an Octree Asset
In your Assets/Bundle/Map folder, right click and go to Create->Nebulous->Octree. This will create a new asset which you can rename to MapOctree.



When you click on this asset, you will see to variables. Drag your new files to these variables (navGraph file to Graph and navTree file to Tree). And finally, drag this new Octree asset to your Battlespace script Pathing variable.

Creating your Asset Bundle and Mod
Once you are ready to test your map you'll need to create your asset bundle. At this point your bundle folder should look like this:


The manifest.xml was created similar to the original modding guide, but for completion here is an example:

manifest.xml
<?xml version="1.0"?> <BundleManifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xds="http://www.w3.org/2001/XMLSchema"> <BasePath>Assets/Bundle/Maw</BasePath> <Maps> <Entry Name="Maw" Address="Maw.prefab"/> </Maps> </BundleManifest>

For each of these files in your Bundle/Map folder you need to add them to your asset bundle. To do this, click on them, go to the bottom right of unity and ensure they are in the same bundle (if one doesn't exist create it, I named mine maw). Again, do this for every file (manifest.xml, your map prefab, map image, and octree).


Finally, we are ready to generate the AssetBundle. At the topline menu go to Tools->Assets->Build AssetBundle. When you are done (and hopefully no errors show up) you'll see the following in your Assets/AssetBundles folder (this should be autogenerated).


The ModInfo.xml file will need to be created by you. Here is mine, note the AssetBundles is name matches the name of the file just generated, "maw" here:

<?xml version="1.0"?> <ModInfo xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <ModName>The Maw</ModName> <ModDescription>In Testing. Note Tactical View Shader currently does not function. Provide Feedback to WaterIsPoison in Discord</ModDescription> <ModVer>0.1</ModVer> <AssetBundles> <string>maw</string> </AssetBundles> </ModInfo>


Once you have generated this Asset Bundle, you can copy it over to your Nebulous game directory. The location is Nebulous/Mods/(Some Mod name)


Now you should be able to start the game, load your mod, and test our your map! When you are happy with it, go ahead a publish it according to the modding guide. Make sure you test all game modes, both spawns, and play around with it a bunch to make sure nothing is obviously broken.

And that's it! If you have any questions, reach out to me on the Nebulous Discord at WaterIsPoison or ping the #mod-development channel. Good luck!


3 Comments
Illustrious 27 Apr @ 4:19am 
Oh no shame on the post but the octree instructions are outdated and there's now a tool for it you can find in the mod dev channel in neb. It'll help you get craft working.
uberdrück 3 Nov, 2024 @ 9:37pm 
The current neb build doesn't visualize deployment cones and octree data like shown in the guide - but you can use these scripts to make them show up again (put into "Scripts" folder).
All credit goes to Puppy fromHell, I'm just reposting from Discord to make it easier to find.

Add to both deployment groups:
https://pastebin.com/MVddzsh7
Add to battlespace (you need to generate and attach octree data first):
https://pastebin.com/yg1Y5riy
Angel24Marin 31 Mar, 2023 @ 6:41am 
Should you perform any change in the Scene to view the wireframe of each scrip? I place the objects with the scrips but the spawn cone and similar don't show. I can place a default sphere and see the wireframe of that and i can put tags in gizmos to see each objet placed and their realtive position but they lack the related gameplay "shapes". I deleted the default scene and created a new working scene as in the Basic guide.