](xref:Nautilus.Handlers.EnumBuilder`1) type.
+
+Below we will talk about the necessary changes you will need to make your custom enum values work for each of the aforementioned handlers.
+
+
+### Configuring Custom TechType Objects
+
+- TechType customTech = TechTypeHandler.AddTechType("CustomTech", "Custom Tech", "Custom Tech that makes me go yes.", SpriteManager.Get(TechType.Titanium), unlockedAtStart: false);
++ TechType customTech = EnumHandler.AddEntry<TechType>("CustomTech")
++ .WithPdaInfo("Custom Tech", "Custom Tech that makes me go yes.", unlockedAtStart: false)
++ .WithIcon(SpriteManager.Get(TechType.Titanium));
+
+
+### Configuring Custom CraftData.BackgroundType Objects
+
+- CraftData.BackgroundType customBG = BackgroundTypeHandler.AddBackgroundType("CustomBackground", SpriteManager.GetBackground(TechType.Battery));
++ CraftData.BackgroundType customBG = EnumHandler.AddEntry<CraftData.BackgroundType>("CustomBackground")
++ .WithBackground(SpriteManager.GetBackground(TechType.Battery));
+
+
+### Configuring Custom EquipmentType Objects
+
+- EquipmentType customEquipment = EquipmentHandler.AddEquipmentType("CustomEquipment");
++ EquipmentType customEquipment = EnumHandler.AddEntry<EquipmentType>("CustomEquipment");
+
+
+### Configuring Custom PingType Objects
+
+- PingType customPing = PingHandler.RegisterNewPingType("CustomPing", SpriteManager.Get(SpriteManager.Group.Pings, PingType.Signal.ToString()));
++ PingType customPing = EnumHandler.AddEntry<PingType>("CustomPing")
++ .WithIcon(SpriteManager.Get(SpriteManager.Group.Pings, PingType.Signal.ToString()));
+
+
+### Configuring Custom TechCategory and TechGroup Objects
+
+- TechGroup customGroup = TechGroupHandler.AddTechCategory("CustomGroup", "Custom Group");
++ TechGroup customGroup = EnumHandler.AddEntry<TechCategory>("CustomGroup").WithPdaInfo("Custom Group");
+
+- TechCategory customCategory = TechCategoryHandler.AddTechCategory("CustomCategory", "Custom Category");
+- TechCategoryHandler.TryRegisterTechCategoryToTechGroup(customGroup, customCategory);
++ TechCategory customCategory = EnumHandler.AddEntry<TechCategory>("CustomCategory").WithPdaInfo("Custom Group")
++ .RegisterToTechGroup(customGroup);
+
+
+### Configuring Custom CraftTree.Type Objects
+
+- ModCraftTreeRoot root = CraftTreeHandler.CreateCustomCraftTreeAndType(CustomTree, out CraftTree.Type customTree);
++ CraftTree.Type customTree = EnumHandler.AddEntry<CraftTree.Type>("CustomTree")
++ .CreateCraftTreeRoot(out ModCraftTreeRoot root);
+
+root.AddTabNode("SomeTab");
+
+
+___
+
+## Options
+Lorem ipsum dolor sit amet. Qui error architecto in officiis molestiae sit molestiae perspiciatis non necessitatibus voluptatibus sit fugiat veritatis eos aliquam rerum. Et ducimus provident est veniam magni nam veniam possimus aut molestiae explicabo cum doloribus atque? Ut adipisci aspernatur eos modi adipisci in sapiente rerum. Qui velit quis sed quia nobis et aspernatur repudiandae.
+
+Qui internos autem id recusandae inventore est autem voluptas et repudiandae vitae qui dolorem sapiente aut corporis dolor. Cum earum voluptate ut odit mollitia sit veritatis quos vel maiores fuga sit omnis nisi et quos repellat qui magnam mollitia.
+
+___
+
+## Assets
+The Assets system received a complete rewrite in Nautilus, making it the biggest change of this version.
+
+With this rewrite, asset classes are no longer an inherited chain mess, meaning `Buildable`, `Craftable`, `CustomFabricator`, `Equipable`, `FishPrefab`, `PdaItem`, `Spawnable` and `ModPrefab` classes have been removed.
+
+As of Nautilus, the asset system will have three main parts: Custom Prefabs, Gadgets, and Prefab Templates.
+
+The following table represents all the previous asset classes and what they have been replaced with in Nautilus.
+
+| SML 2.0 (old) | Nautilus (new) |
+|------------------------|--------------------------------------------------------------------|
+| `ModPrefab` | [CustomPrefab](xref:Nautilus.Assets.CustomPrefab) |
+| `Buildable`, `PdaItem` | [ScanningGadget](xref:Nautilus.Assets.Gadgets.ScanningGadget) |
+| `Equipable` | [EquipmentGadget](xref:Nautilus.Assets.Gadgets.EquipmentGadget) |
+| `CustomFabricator` | [FabricatorGadget](xref:Nautilus.Assets.Gadgets.FabricatorGadget) |
+| `Craftable` | [CraftingGadget](xref:Nautilus.Assets.Gadgets.GadgetExtensions#) |
+| `Spawnable` | `ICustomPrefab.SetSpawns` |
+
+
+### Custom Prefabs
+`CustomPrefab` is a class that takes care of registering gadgets and also the game object into the game.
+This class is essentially equivalent to the previous `ModPrefab` class. It is what you will use to actually make a custom prefab.
+
+### Gadgets
+To put it simply, Gadgets are classes that take certain data and register them to the game for our custom prefab item.
+They are pretty much equivalent to the different asset classes and their properties we had before.
+Gadgets will be our primary way of interacting with game systems and to add functionality to a tech type and/or class ID.
+
+> [!NOTE]
+> Gadgets only interact with tech types and/or class IDs. They don't have any business with a prefab's game object.
+
+### Prefab Templates
+Previously on SML 2.0, asset classes optionally also provided game objects (E.G: `CustomFabricator`). To allow for diversity in the game object template you choose from
+and also to make it easier to manage such functionality and modularize game objects, we have moved game object templates to their own system: Prefab templates.
+
+Prefab templates will be our main way of providing a base game object for custom prefabs. There are a couple of options you can choose from that suit your needs, however, it is not enforced to choose one;
+you can still build up a game object from scratch.
+
+A couple of prefab templates that will be available in Nautilus are the following:
+ - CloneTemplate
+ - EnergySourceTemplate
+ - FabricatorTemplate
+
+
+## Custom Prefab Examples
+In this example, we will demonstrate how you can change an SML 2.0 custom prefab to the Nautilus system.
+
+### SML 2.0
+```csharp
+public class SeamothBrineResistanceModule : Equipable
+{
+ public static TechType TechTypeID { get; protected set; }
+ public SeamothBrineResistanceModule()
+ : base("SeamothBrineResistModule",
+ "Seamoth brine resistant coating",
+ "Makes the Seamoth resistant to corrosive brine pools, by means of a protective coating.")
+ {
+ OnFinishedPatching += () =>
+ {
+ TechTypeID = this.TechType;
+ };
+ }
+ public override EquipmentType EquipmentType => EquipmentType.SeamothModule;
+ public override TechType RequiredForUnlock => TechType.BaseUpgradeConsole;
+ public override TechGroup GroupForPDA => TechGroup.VehicleUpgrades;
+ public override TechCategory CategoryForPDA => TechCategory.VehicleUpgrades;
+ public override CraftTree.Type FabricatorType => CraftTree.Type.SeamothUpgrades;
+ public override string[] StepsToFabricatorTab => new string[] { "SeamothModules" };
+ public override QuickSlotType QuickSlotType => QuickSlotType.Passive;
+ public override GameObject GetGameObject()
+ {
+ var prefab = CraftData.GetPrefabForTechType(TechType.SeamothElectricalDefense);
+ var obj = GameObject.Instantiate(prefab);
+ return obj;
+ }
+ protected override TechData GetBlueprintRecipe()
+ {
+ return new TechData()
+ {
+ craftAmount = 1,
+ Ingredients =
+ {
+ new Ingredient(TechType.Polyaniline, 1),
+ new Ingredient(TechType.CopperWire, 2),
+ new Ingredient(TechType.AluminumOxide, 2),
+ new Ingredient(TechType.Nickel, 1),
+ },
+ };
+ }
+}
+```
+
+### Nautilus
+```csharp
+// Create a custom prefab instance and set the class ID, friendly name, and description respectively
+var seamothBrineResistanceModule = new CustomPrefab(
+ "SeamothBrineResistModule",
+ "Seamoth brine resistant coating",
+ "Makes the Seamoth resistant to corrosive brine pools, by means of a protective coating.");
+
+// Set our prefab to a clone of the Seamoth electrical defense module
+seamothBrineResistanceModule.SetPrefab(new CloneTemplate(seamothBrineResistanceModule.Info, TechType.SeamothElectricalDefense));
+
+// Make our item compatible with the seamoth module slot
+seamothBrineResistanceModule.SetEquipment(EquipmentType.SeamothModule)
+ .WithQuickSlotType(QuickSlotType.Passive);
+
+// Make the Vehicle upgrade console a requirement for our item's blueprint
+ScanningGadget scanning = seamothBrineResistanceModule.SetUnlock(TechType.BaseUpgradeConsole)
+
+// Add our item to the Vehicle upgrades category
+scanning.WithPdaGroupCategory(TechGroup.VehicleUpgrades, TechCategory.VehicleUpgrades);
+
+var recipe = new RecipeData()
+{
+ craftAmount = 1,
+ Ingredients =
+ {
+ new CraftData.Ingredient(TechType.Polyaniline, 1),
+ new CraftData.Ingredient(TechType.CopperWire, 2),
+ new CraftData.Ingredient(TechType.AluminumOxide, 2),
+ new CraftData.Ingredient(TechType.Nickel, 1),
+ },
+};
+
+// Add a recipe for our item, as well as add it to the Moonpool fabricator and Seamoth modules tab
+seamothBrineResistanceModule.SetRecipe(recipe)
+ .WithFabricatorType(CraftTree.Type.SeamothUpgrades)
+ .WithStepsToFabricatorTab("SeamothModules");
+
+// Register our item to the game
+seamothBrineResistanceModule.Register();
+```
+
+This example is based off of a real mod. You can get access to the full source code [here](https://github.com/Metious/MetiousSubnauticaMods/tree/master/SeamothBrineResist).
+
+---
+
+## Audio and FMOD
+In the last few versions of SML 2, we made a lot of changes to the audio system SML offered, this was because of FMOD.
+FMOD is the sound engine Subnautica uses. It is more advanced and flexible compared to the built-in Unity audio system.
+
+Since we discovered the best practices and better ways to deal with custom sounds, we have deleted a bunch of previously-obsolete methods from
+`CustomSoundHandler` and `AudioUtils` classes, as well as the `SoundChannel` enumeration in Nautilus.
+
+Beginning with Nautilus, all custom sounds will require a bus instead of a SoundChannel to determine the effects (E.G: reverb, muffling, low-pass, etc..) and the volume slider.
+Additionally, the `PlaySound` signature was also modified and renamed to `TryPlaySound`.
+
+
+- Channel channel = AudioUtils.PlaySound(soundPath, SoundChannel.Music);
++ if (AudioUtils.TryPlaySound(soundPath, AudioUtils.BusPaths.Music, out Channel channel))
++ {
++ // do something with channel
++ }
+
+
+- Channel channel = AudioUtils.PlaySound(soundPath, SoundChannel.Voice);
++ if (AudioUtils.TryPlaySound(soundPath, AudioUtils.BusPaths.PDAVoice, out Channel channel))
++ {
++ // do something with channel
++ }
+
+
+- Channel channel = AudioUtils.PlaySound(soundPath, SoundChannel.Ambient);
++ if (AudioUtils.TryPlaySound(soundPath, AudioUtils.BusPaths.UnderwaterAmbient, out Channel channel))
++ {
++ // do something with channel
++ }
+
+
+- Channel channel = AudioUtils.PlaySound(soundPath, SoundChannel.Master);
++ if (AudioUtils.TryPlaySound(soundPath, "bus:/", out Channel channel))
++ {
++ // do something with channel
++ }
+
+
+
+> [!WARNING]
+> Creating or playing a custom sound on the master bus is il-advised as it is dangerous and has the possibility of breaking the audio for a game session.
+> Try to set an appropriate bus for your sound instead of the master one.
+
+---
\ No newline at end of file
diff --git a/Nautilus/Documentation/guides/toc.yml b/Nautilus/Documentation/guides/toc.yml
new file mode 100644
index 000000000..891125cb5
--- /dev/null
+++ b/Nautilus/Documentation/guides/toc.yml
@@ -0,0 +1,5 @@
+- name: Overview
+ href: overview.md
+
+- name: Updating to Nautilus
+ href: sml2-to-nautilus.md
\ No newline at end of file
diff --git a/Nautilus/Documentation/images/tutorials/command-results.png b/Nautilus/Documentation/images/tutorials/command-results.png
new file mode 100644
index 000000000..e2058bdf8
Binary files /dev/null and b/Nautilus/Documentation/images/tutorials/command-results.png differ
diff --git a/Nautilus/Documentation/index.md b/Nautilus/Documentation/index.md
new file mode 100644
index 000000000..b537bfb9b
--- /dev/null
+++ b/Nautilus/Documentation/index.md
@@ -0,0 +1,6 @@
+# Nautilus: Subnautica Modding Library
+
+Nautilus is a modding library that aims on enhancing developer productivity by offering common helper utilities as easy to use and robust as possible.
+
+Nautilus offers systems such as adding/editing items, icons, spawns, sounds and so much more!
+
diff --git a/Nautilus/Documentation/toc.yml b/Nautilus/Documentation/toc.yml
new file mode 100644
index 000000000..1b07229a9
--- /dev/null
+++ b/Nautilus/Documentation/toc.yml
@@ -0,0 +1,16 @@
+- name: API Documentation
+ href: api/
+
+- name: Guides
+ href: guides/
+ topicHref: guides/overview.md
+
+- name: Tutorials
+ href: tutorials/
+ topicHref: tutorials/overview.md
+
+- name: Discord
+ href: https://discord.gg/UpWuWwq
+
+- name: GitHub
+ href: https://github.com/SubnauticaModding/Nautilus
\ No newline at end of file
diff --git a/Nautilus/Documentation/tutorials/background-type.md b/Nautilus/Documentation/tutorials/background-type.md
new file mode 100644
index 000000000..1c50b54a7
--- /dev/null
+++ b/Nautilus/Documentation/tutorials/background-type.md
@@ -0,0 +1,45 @@
+## How does the game handle background colors for items?
+The game has a built-in enum called `BackgroundType`, which sits in the `CraftData` class. The possible values for this enum are listed below.
+
+```csharp
+public enum BackgroundType
+{
+ Normal,
+ Blueprint,
+ PlantWater,
+ PlantWaterSeed,
+ PlantAir,
+ PlantAirSeed,
+ ExosuitArm
+}
+```
+
+## How can I create a custom background type?
+To create a new custom background type, you will need to register an image as the background for some `BackgroundType` instance.
+
+Fortunately, the custom enums system has made this step really simple. All you will have to do is name your brand new `BackgroundType` instance, then register an image for it.
+```csharp
+private void Awake()
+{
+ var myCustomBackground = EnumHandler.AddEntry("CustomBackground")
+ .WithBackground(ImageUtils.LoadSpriteFromFile(pathToImage));
+}
+```
+
+And that's it. Now you can use the new `CraftData.BackgroundType` instance anywhere you want.
+
+## How can I change an item's background?
+To edit an item's background type, you need to call the `CraftDataHandler.SetBackgroundType` method sitting in the `Nautilus.Handlers` namespace
+
+
+### Examples
+The following example demonstrates the usage of `SetBackgroundType` That makes the titanium background color green.
+
+```csharp
+CraftDataHandler.SetBackgroundType(TechType.Titanium, CraftData.BackgroundType.PlantAirSeed);
+```
+
+Similarly, if we wanted to set the titanium's background to our custom background from earlier, it would look like the following:
+```csharp
+CraftDataHandler.SetBackgroundType(TechType.Titanium, myCustomBackground);
+```
\ No newline at end of file
diff --git a/Nautilus/Documentation/tutorials/console-commands.md b/Nautilus/Documentation/tutorials/console-commands.md
new file mode 100644
index 000000000..a5afda596
--- /dev/null
+++ b/Nautilus/Documentation/tutorials/console-commands.md
@@ -0,0 +1,129 @@
+# Adding Custom Console Commands
+
+Nautilus provides a simple API for allowing you to define custom console commands for your mod to respond to when the user types them into the in-game dev console, with simple parameter type checking to enable user- and developer-friendly error reporting, both on-screen and in the log.
+
+
+
+## Supported Parameter Types
+Currently, only the following types are supported by the API:
+- `string`
+- `bool`
+- `int`
+- `float`
+- `double`
+
+If you wish to use a type not in this list, it is recommended to use `string` (as that is what the value coming from the user will be anyway) and handle converting and error-checking the value for yourself.
+
+If the user provides incorrect parameters for a command, they will be notified of the expected parameters on-screen and in the log file.
+
+## Registering a Custom Console Command
+There are three ways to register custom console commands, so you can use whichever suits your purpose or coding-style best.
+
+> [!WARNING]
+> Registered commands must be unique. If any mod has already added the command, your command will be rejected.
+
+> [!NOTE]
+> A command can have a return type, but it is not necessary. If it does return any type, it will be printed on-screen and in the log file.
+
+### Registering a `delegate` (Callback) as a Command
+By calling `ConsoleCommandsHandler.RegisterConsoleCommand(string command, T callback)`, you can pass an instance of the delegate, whether it is an anonymous lambda or reference to a method that implements the delegate signature to register your callback as a response to the command.
+
+Note that with a `delegate` command, it is not possible to use optional parameters.
+If you want optional parameters, it is recommended to [register a `public static` method as a command](#registering-a-public-static-method-as-a-command) instead.
+
+In the example below, we are registering a console command by the use of a delegate. The delegate will respond to the "delegatecommand"
+command from the dev console in the game.
+
+You can also use `System.Func` or `System.Action` delegates to define the signature for your command signature.
+
+```csharp
+using BepInEx;
+using Nautilus.Handlers;
+
+[BepInPlugin(PluginInfo.GUID, PluginInfo.MOD_NAME, PluginInfo.VERSION)]
+public class MyPlugin : BaseUnityPlugin
+{
+ private void Start()
+ {
+ ConsoleCommandsHandler.RegisterConsoleCommand("delegatecommand", (myString, myInt, myBool) =>
+ {
+ return $"Parameters: {myString} {myInt} {myBool}";
+ });
+ }
+
+ private delegate string MyCommand(string myString, int myInt, bool myBool);
+}
+```
+
+The command: `delegatecommand foo 3 true` is a valid signature for the code above.
+
+### Registering a `public static` Method as a Command
+By calling `ConsoleCommandsHandler.RegisterConsoleCommand(string command, Type declaringType, string methodName, Type[] parameters = null)`, you can specify a `public static` method as a response to the command. The API here is similar to Harmony in that it will search for the method in the given type, using the optional `Type[] parameters` to target overloads.
+
+In the example below, we are registering a console command by specifying a target method. The method will respond to the "methodcommand"
+command from the dev console in the game.
+
+```csharp
+using BepInEx;
+using Nautilus.Handlers;
+
+[BepInPlugin(PluginInfo.GUID, PluginInfo.MOD_NAME, PluginInfo.VERSION)]
+public class MyPlugin : BaseUnityPlugin
+{
+ private void Start()
+ {
+ ConsoleCommandsHandler.RegisterConsoleCommand("methodcommand", typeof(MyMod), nameof(MyCommand));
+
+ Logger.LogInfo("Patched successfully!");
+ }
+
+ public static string MyCommand(string myString, int myInt, bool myBool = false)
+ {
+ return $"Parameters: {myString} {myInt} {myBool}";
+ }
+}
+```
+
+The command: `methodcommand foo 3 true` is a valid signature for the code above.
+
+### Registering Multiple `public static` Methods Within a Class as Commands
+By calling `ConsoleCommandsHandler.RegisterConsoleCommands(Type type)`, you can register all `public static` methods decorated with the `ConsoleCommandAttribute` as console commands.
+
+In the example below, we are registering all console commands specified in the `MyConsoleCommands` types as console commands.
+Methods decorated with the `ConsoleCommandAttribute` will respond to the specified command from the dev console in the game.
+
+```csharp
+using BepInEx;
+using Nautilus.Commands;
+using Nautilus.Handlers;
+
+[BepInPlugin(PluginInfo.GUID, PluginInfo.MOD_NAME, PluginInfo.VERSION)]
+public class MyPlugin : BaseUnityPlugin
+{
+ private void Start()
+ {
+ ConsoleCommandsHandler.RegisterConsoleCommands(typeof(MyConsoleCommands));
+
+ Logger.Log(Logger.Level.Info, "Patched successfully!");
+ }
+}
+
+public static class MyConsoleCommands
+{
+ /// The MyAttributedCommand method will respond to the "attributedcommand" command from the dev console.
+ [ConsoleCommand("attributedcommand")]
+ public static string MyAttributedCommand(string myString, int myInt, bool myBool = false)
+ {
+ return $"Parameters: {myString} {myInt} {myBool}";
+ }
+}
+```
+
+The commands:
+- `attributedcommand foo 3 true`
+- `attributedcommand foo 3`
+are both valid signatures for the code above.
+
+> [!NOTE]
+> [Optional arguments](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments) can be ignored when executing a command in the dev console.
+> When ignored, the specified default value will be used instead.
\ No newline at end of file
diff --git a/Nautilus/Documentation/tutorials/crafting-recipes.md b/Nautilus/Documentation/tutorials/crafting-recipes.md
new file mode 100644
index 000000000..fa9934d00
--- /dev/null
+++ b/Nautilus/Documentation/tutorials/crafting-recipes.md
@@ -0,0 +1,51 @@
+# Editing Crafting Recipes
+
+Recipes in Subnautica are combining one or multiple items to craft a new and more advanced item in various crafting stations.
+
+Nautilus offers the [RecipeData](xref:Nautilus.Crafting.RecipeData) class with sufficient data for recipes.
+
+Below is a table of all the parameters you may interact with in the RecipeData class.
+
+| Parameter Name | Type | Description |
+|----------------|----------------------|----------------------------------------------------------------|
+| craftAmount | int | Amounts of copies of the item that is created for this recipe. |
+| Ingredients | List<TechType> | A list of ingredients required for this recipe. |
+| LinkedItems | List<TechType> | Items that will also be created when this recipe is crafted. |
+
+
+To register or edit recipes, use the `Nautilus.Handlers.CraftDataHandler.SetRecipeData()` method.
+
+## Examples
+The following examples demonstrate the usage of the `SetRecipeData` method.
+```csharp
+// Set the Titanium Ingot's recipe to only two titaniums
+RecipeData titaniumIngotRecipe = new RecipeData(new CraftData.Ingredient(TechType.Titanium, 2));
+
+// register the recipe
+CraftDataHandler.SetRecipeData(TechType.TitaniumIngot, titaniumIngotRecipe);
+
+
+// Make the scrap metal recipe yield 10 titaniums instead of 5
+RecipeData scrapMetalRecipe = new RecipeData
+{
+ // We don't want to get a new scrap metal in this recipe, so it should be 0.
+ craftAmount = 0,
+
+ // Require a scrap metal for the recipe
+ Ingredients =
+ {
+ new CraftData.Ingredient(TechType.ScrapMetal)
+ },
+
+ // Yield 10 titaniums when crafted
+ LinkedItems = Enumerable.Repeat(TechType.Titanium, 10).ToList()
+};
+
+// register the recipe
+CraftDataHandler.SetRecipeData(TechType.ScrapMetal, scrapMetalRecipe);
+```
+
+## See also
+- [SetRecipeData()](xref:Nautilus.Handlers.CraftDataHandler.SetRecipeData(TechType,Nautilus.Crafting.RecipeData))
+- [SetRecipeData()](xref:Nautilus.Handlers.CraftDataHandler.GetRecipeData(TechType))
+- [RecipeData](xref:Nautilus.Crafting.RecipeData)
\ No newline at end of file
diff --git a/Nautilus/Documentation/tutorials/equipment-type.md b/Nautilus/Documentation/tutorials/equipment-type.md
new file mode 100644
index 000000000..13d3ca762
--- /dev/null
+++ b/Nautilus/Documentation/tutorials/equipment-type.md
@@ -0,0 +1,63 @@
+## What are equipment types?
+`EquipmentType` is an enum that handles special items. The possible values for this enum are listed below.
+
+```csharp
+public enum EquipmentType
+{
+ None, // Normal item
+ Hand, // The item can be equipped in the Hand slot
+ Head, // The item can be equipped in the Head slot
+ Body, // The item can be equipped in the Body slot
+ Gloves, // The item can be equipped in the Gloves slot
+ Foots, // The item can be equipped in the Feet slot
+ Tank, // The item can be equipped in the Oxygen Tank slot
+ Chip, // The item can be equipped in the Chip slots
+ CyclopsModule, // The item can be equipped in the Cyclops as an upgrade module
+ VehicleModule, // The item can be equipped both in the Seamoth and in the Prawn Suit as an upgrade module
+ NuclearReactor, // The item can be used in a Nuclear Reactor
+ BatteryCharger, // When batteries are thrown in it, they get charged (for buildables)
+ PowerCellCharger, // When power cells are thrown in it, they get charged (for buildables)
+ SeamothModule, // The item can be equipped in the Seamoth as an upgrade module
+ ExosuitModule, // The item can be equipped in the Prawn Suit as an upgrade module
+ ExosuitArm, // The item can be equipped in the Prawn Suit as an arm
+ DecoySlot // (Need actual name) Possibly for the decoy tube thing in the cyclops
+}
+```
+
+## How can I create a custom background type?
+Since equipment types are simply just enums, we can use the enum handler to create a new instance.
+```csharp
+private void Awake()
+{
+ var myCustomEquipmentType = EnumHandler.AddEntry("CustomEquipmentType");
+}
+```
+
+And that's it. Now you can use the new `CraftData.BackgroundType` instance anywhere you want.
+
+## How can edit an item's equipment type?
+To edit an item's equipment type, you need to call the `CraftDataHandler.SetEquipmentType` method sitting in the `Nautilus.Handlers` namespace
+
+### Examples
+The following example demonstrates the usage of `SetEquipmentType` that enables the player to wear titanium on their head.
+
+```csharp
+CraftDataHandler.SetEquipmentType(TechType.Titanium, EquipmentType.Head);
+```
+
+Similarly, if we wanted to set the titanium's equipment type to our custom equipment type from earlier, it would look like the following:
+```csharp
+CraftDataHandler.SetBackgroundType(TechType.Titanium, myCustomEquipmentType);
+```
+
+If you're setting the equipment type for a custom prefab, we recommend using the `ICustomPrefab.SetEquipment` method instead.
+```csharp
+var customPrefab = new CustomPrefab("CustomItem", ".", ".");
+customPrefab.SetEquipment(EquipmentType.Head);
+// rest of the custom prefab configuration is omitted for brevity.
+```
+
+> [!WARNING]
+> It is dangerous to edit equipment types for items that already have one, because they can break.
+> For instance, modifying the equipment type for the Radiation Helmet will disable the player from wearing it.
+
diff --git a/Nautilus/Documentation/tutorials/localization.md b/Nautilus/Documentation/tutorials/localization.md
new file mode 100644
index 000000000..d87affe76
--- /dev/null
+++ b/Nautilus/Documentation/tutorials/localization.md
@@ -0,0 +1,89 @@
+# Localization
+
+In Subnautica, localization is a key-value string dataset where the key represents a unique identifier that is the same on all languages, and the value represents the translation in a language.
+
+Nautilus provides a few different approaches to go about adding localization in the [LanguageHandler](xref:Nautilus.Handlers.LanguageHandler) class.
+
+## Json Files Localization
+The most common method of adding localization in game development is via json files where the json file name represents the language name (I.E: `English.json` for English).
+
+The json files contain a key-value pair where the key is the language key and the value is the translation.
+
+
+### Examples
+The following examples demonstrate the usage of json-file-based localizations.
+
+Json files:
+```json
+// English.json
+{
+ "TitaniumClone": "Titanium Clone",
+ "Tooltip_TitaniumClone": "Titanium clone that makes me go yes."
+}
+```
+```json
+// Spanish.json
+{
+ "TitaniumClone": "Clon de Titanio",
+ "Tooltip_TitaniumClone": "Clon de Titanio que me hace decir que sí"
+}
+```
+
+To register json-file-based localizations, all you will have to call is one line of code:
+```csharp
+LanguageHandler.RegisterLocalizationFolder();
+```
+
+> [!NOTE]
+> By default, Nautilus expects these json files to be located in the {modFolder}/Localization folder.
+
+The following example registers the `Translations` folder as the localization folder:
+```csharp
+LanguageHandler.RegisterLocalizationFolder("Translations");
+```
+
+## Dictionary Localization
+Nautilus also offers to register string key-value dataset as localization.
+
+### Examples
+The following examples demonstrate the usage of dictionary-based localization.
+```csharp
+Dictionary _languageEntriesEng = new()
+{
+ { "TitaniumClone", "Titanium Clone" }, { "Tooltip_TitaniumClone", "Titanium clone that makes me go yes." }
+};
+
+Dictionary _languageEntriesEsp = new()
+{
+ { "TitaniumClone", "Clon de Titanio" }, { "Tooltip_TitaniumClone", "Clon de Titanio que me hace decir que sí" }
+};
+
+// Register our English language entries to the English language
+LanguageHandler.RegisterLocalization("English", _languageEntriesEng);
+
+// Register our Spanish language entries to the Spanish language
+LanguageHandler.RegisterLocalization("Spanish", _languageEntriesEsp);
+```
+
+---
+
+## Singular Translation
+
+Another approach that can be used is translating one key to any desired language.
+Additionally, all Nautilus methods that interact with language keys also offer modders to choose the language to translate for.
+
+### Examples
+The following examples demonstrate the usage of singular translations.
+```csharp
+LanguageHandler.SetLanguageLine("TitaniumClone", "Titanium Clone", "English");
+LanguageHandler.SetLanguageLine("TitaniumClone", "Clon de Titanio", "Spanish");
+
+// Adds Spanish translation instead of English
+PrefabInfo info =
+ PrefabInfo.WithTechType("TitaniumClone",
+ "Clon de Titanio",
+ "Clon de Titanio que me hace decir que sí", "Spanish");
+```
+
+## See also
+- [LanguageHandler](xref:Nautilus.Handlers.LanguageHandler)
\ No newline at end of file
diff --git a/Nautilus/Documentation/tutorials/overview.md b/Nautilus/Documentation/tutorials/overview.md
new file mode 100644
index 000000000..8c7323dcf
--- /dev/null
+++ b/Nautilus/Documentation/tutorials/overview.md
@@ -0,0 +1,21 @@
+# Tutorials
+
+This section covers step-by-step tutorials on how to get some of the useful features of Nautilus done with images, demos, and working code. If you've used SML 2.0 before, please start with our [Updating to SML 3.0 Guide](../guides/sml2-to-nautilus.md).
+
+## Sections
+
+### Adding Content
+* [Spawns](spawns.md)
+* [Custom Console Commands](console-commands.md)
+* TODO: [Audio (FMOD)](https://www.youtube.com/watch?v=dQw4w9WgXcQ)
+
+
+### Editing Content
+* [Background Type](background-type.md)
+* [Equipment Type](equipment-type.md)
+* [Crafting Recipes](crafting-recipes.md)
+
+
+### Utilities
+* [Localization](localization.md)
+* TODO: [In-Game Options](https://www.youtube.com/watch?v=dQw4w9WgXcQ)
\ No newline at end of file
diff --git a/Nautilus/Documentation/tutorials/spawns.md b/Nautilus/Documentation/tutorials/spawns.md
new file mode 100644
index 000000000..f163d5904
--- /dev/null
+++ b/Nautilus/Documentation/tutorials/spawns.md
@@ -0,0 +1,151 @@
+# Adding Spawns
+
+Most of the time in Subnautica, the game uses two different ways to spawn objects; static spawns that always have a fixed position in the world to spawn in,
+and loot distribution which is biome-based and sudo-random.
+
+Nautilus offers modders to add spawns to either systems. You can add spawns for your own custom item, you can also edit vanilla spawns,
+or straight up remove them.
+
+## Coordinated Spawns
+Coordinated spawns is Nautilus' version of the aforementioned static spawns. With this system, you are allowed to specify exact world position and rotation spawns for an item.
+You may register one or more coordinated spawn(s) for any item by providing either their class ID, or their tech type.
+
+### Examples
+The following examples demonstrate the usage of [CoordinatedSpawnsHandler](xref:Nautilus.Handlers.CoordinatedSpawnsHandler) methods.
+
+```csharp
+private void Awake()
+{
+ // Adds a Reaper Leviathan to the lava lakes
+ SpawnInfo reaperInfo = new SpawnInfo(TechType.ReaperLeviathan, new Vector3(280f, -1400f, 47f)); // Lava Lakes
+ CoordinatedSpawnsHandler.RegisterCoordinatedSpawn(reaperInfo);
+
+ // Adds multiple spawn infos at once
+
+ // Sand Shark's class ID
+ string sandSharkId = "5e5f00b4-1531-45c0-8aca-84cbd3b580a4";
+
+ var spawnInfos = new List()
+ {
+ new SpawnInfo(TechType.Seamoth, Vector3.zero),
+ new SpawnInfo(sandSharkId, new Vector3(10, -4, 5), Vector3.up * 90f) // rotate its Y axis 90 degrees
+ }
+ CoordinatedSpawnsHandler.RegisterCoordinatedSpawns(spawnInfos);
+
+ // Spawns a batch of titaniums around 10, -3, 15 world position
+ var randomPositions = RandomPositions(new Vector3(10f, -3f, 15f));
+ CoordinatedSpawnsHandler.RegisterCoordinatedSpawnsForOneTechType(
+ TechType.Titanium, randomPositions);
+}
+
+private List RandomPositions(Vector3 centerPosition)
+{
+ var result = new List();
+ for (int i = 0; i < 5; i++)
+ {
+ result.Add(centerPosition + (Random.insideUnitSphere * i));
+ }
+ return result;
+}
+```
+
+For custom prefabs, it is advised to use the [ICustomPrefab.SetSpawns(SpawnLocation[])](xref:Nautilus.Assets.Gadgets.GadgetExtensions#Nautilus_Assets_Gadgets_GadgetExtensions_SetSpawns_Nautilus_Assets_ICustomPrefab_Nautilus_Assets_SpawnLocation___) method instead of directly interacting with the [CoordinatedSpawnsHandler](xref:Nautilus.Handlers.CoordinatedSpawnsHandler) class.
+
+The example below demonstrates the usage of the `SetSpawns` method.
+```csharp
+var blueReaper = new CustomPrefab(PrefabInfo.WithTechType("BlueReaper", "Blue Reaper Leviathan", null));
+
+// Creates a clone of the Reaper Leviathan prefab and colors it blue, then set the new prefab as our Blue Reaper's game object.
+var blueReaperPrefab = new CloneTemplate(blueReaper.Info, TechType.ReaperLeviathan)
+{
+ ModifyPrefab = prefab => prefab.GetComponentsInChildren().ForEach(r => r.materials.ForEach(m => m.color = Color.blue))
+};
+blueReaper.SetPrefab(blueReaperPrefab);
+
+// Adds a spawn for our Blue Reaper Leviathan in the lava lakes.
+blueReaper.SetSpawns(new SpawnLocation(280f, -1400, 47f));
+
+// Register the Blue Reaper Leviathan to the game.
+blueReaper.Register();
+```
+
+## Loot Distribution
+Loot distribution system is by far the most widely used spawning system in the game. Unlike static spawns, Nautilus does not have it's own version of this system, so
+we will be registering distributions into the game's system.
+Loot distribution only allows adding or editing distributions using a class ID and prefab file name. You normally will also need to provide a biome type, probability, and count for each loot you want to add.
+
+Below is a table of all the parameters you may interact with in the loot distribution system.
+
+| Parameter Name | Type | Description |
+|-------------------|--------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
+| classId | string | The classId of the entity to add loot for. |
+| prefabFileName | string | The internal file path of the entity to add. |
+| biomeDistribution | LootDistributionData.BiomeData | The biome data in which this entity might spawn in. |
+| probability | float | The chance of this entity spawning. This value can only be between 0-1 inclusive. 0 being no chance of spawning, while 1 is guaranteed to spawn. |
+| count | float | Multiplies 1 with this value. This multiplication is accounted everytime this entity has the highest chance to spawn, not a global count. |
+| srcData | LootDistributionData.SrcData | A class that combines the prefab file name and biome distribution to one data type. |
+| entityInfo | WorldEntityInfo | Contains information on how to spawn this entity. E.G: The size it should spawn in as, and how far it can stay before unloading. |
+
+> [!WARNING]
+> An Entity Info for each class ID to spawn via loot distribution is required. If an entity info does not have one, the loot distribution will ignore it.
+
+> [!NOTE]
+> Usually, vanilla prefabs do have a world entity info assigned to them. While you can, you don't have to register a new one for those that already have one.
+
+### Examples
+The following examples demonstrate the usage of [LootDistributionHandler](xref:Nautilus.Handlers.LootDistributionHandler) methods.
+
+```csharp
+// Drillable Sulphur's class ID
+string drillableSulphurClassId = "697beac5-e39a-4809-854d-9163da9f997e";
+
+var biomes = new LootDistribution.BiomeData[]
+{
+ // Lost river's bones field ground
+ new LootDistributionData.BiomeData { biome = BiomeType.BonesField_Ground, count = 1, probability = 0.07f },
+
+ // Inactive Lava Zone floor, near the lava
+ new LootDistributionData.BiomeData { biome = BiomeType.InactiveLavaZone_Chamber_Floor_Far, count = 1, probability = 0.05f }
+};
+
+// Add spawn for the drillable sulphur
+LootDistributionHandler.AddLootDistributionData(drillableSulphurClassId, biomes);
+
+string rockgrubClassId = CraftData.GetClassIdForTechType(TechType.Rockgrub);
+
+// Prevents the rockgrub from spawning in the Bulb zone caves.
+LootDistributionHandler.EditLootDistributionData(rockgrubClassId, BiomeType.KooshZone_CaveWall, 0f, 0);
+```
+
+For custom prefabs, it is advised to use the [ICustomPrefab.SetSpawns(LootDistributionData.BiomeData[])](xref:Nautilus.Assets.Gadgets.GadgetExtensions#Nautilus_Assets_Gadgets_GadgetExtensions_SetSpawns_Nautilus_Assets_ICustomPrefab_Nautilus_Assets_SpawnLocation___) method instead of directly interacting with the [LootDistributionHandler](xref:Nautilus.Handlers.LootDistributionHandler) class.
+
+The example below demonstrates the usage of the `SetSpawns` method.
+```csharp
+PrefabInfo titaniumCloneInfo = PrefabInfo.WithTechType("TitaniumClone", "Titanium Clone", "Titanium clone that makes me go yes.");
+
+// Set the vanilla titanium icon for our item
+titaniumCloneInfo.WithIcon(SpriteManager.Get(TechType.Titanium));
+
+CustomPrefab titaniumClone = new CustomPrefab(titaniumCloneInfo);
+
+// Creates a clone of the Titanium prefab and colors it red, then set the new prefab as our Titanium Clone's game object.
+PrefabTemplate cloneTemplate = new CloneTemplate(titaniumCloneInfo, TechType.Titanium)
+{
+ // Callback to change all material colors of this clone to red.
+ ModifyPrefab = prefab => prefab.GetComponentsInChildren().ForEach(r => r.materials.ForEach(m => m.color = Color.red))
+};
+titaniumClone.SetPrefab(cloneTemplate);
+
+titaniumClone.SetSpawns(
+ // Adds a chance for our titanium clone to spawn in Safe shallows grass, x4 each time.
+ new BiomeData { biome = BiomeType.SafeShallows_Grass, count = 4, probability = 0.1f },
+ // Adds a chance for our titanium clone to spawn in Safe shallows caves, once each time.
+ new BiomeData { biome = BiomeType.SafeShallows_CaveFloor, count = 1, probability = 0.4f });
+
+// Register the Titanium Clone to the game.
+titaniumClone.Register();
+```
+
+## See also
+ - [CoordinatedSpawnsHandler](xref:Nautilus.Handlers.CoordinatedSpawnsHandler)
+ - [LootDistributionHandler](xref:Nautilus.Handlers.LootDistributionHandler)
\ No newline at end of file
diff --git a/Nautilus/Documentation/tutorials/toc.yml b/Nautilus/Documentation/tutorials/toc.yml
new file mode 100644
index 000000000..9c5bcd60c
--- /dev/null
+++ b/Nautilus/Documentation/tutorials/toc.yml
@@ -0,0 +1,26 @@
+- name: Overview
+ href: overview.md
+
+- name: Adding Content
+ items:
+ - name: Spawns
+ href: spawns.md
+ - name: Custom Console Commands
+ href: console-commands.md
+
+- name: Editing Content
+ items:
+ - name: Background Type
+ href: background-type.md
+ - name: Equipment Type
+ href: equipment-type.md
+ - name: Crafting Recipes
+ href: crafting-recipes.md
+
+- name: Utilities
+ items:
+ - name: Localization
+ href: localization.md
+
+
+
\ No newline at end of file
diff --git a/Nautilus/Nautilus.csproj b/Nautilus/Nautilus.csproj
index 4b7ef8afa..bd1daa830 100644
--- a/Nautilus/Nautilus.csproj
+++ b/Nautilus/Nautilus.csproj
@@ -15,7 +15,7 @@
Copyright @ 2023
Core library for modding Subnautica.
-
+
bin\SN.STABLE\
SUBNAUTICA;SUBNAUTICA_STABLE
@@ -40,5 +40,5 @@
-
+
\ No newline at end of file
diff --git a/Nautilus/docfx.json b/Nautilus/docfx.json
new file mode 100644
index 000000000..804bb4ead
--- /dev/null
+++ b/Nautilus/docfx.json
@@ -0,0 +1,68 @@
+{
+ "metadata": [
+ {
+ "src": [
+ {
+ "files": [
+ "*.csproj"
+ ],
+ "exclude": [
+ "**/obj/**",
+ "**/bin/**",
+ "_site/**"
+ ]
+ }
+ ],
+ "shouldSkipMarkup": true,
+ "dest": "Documentation/api",
+ "filter": "filter.yml",
+ "properties": {
+ "Configuration": "SN.STABLE"
+ }
+ }
+ ],
+ "build": {
+ "content": [
+ {
+ "files": [
+ "**/*.yml",
+ "**/*.md"
+ ],
+ "src": "Documentation"
+ }
+ ],
+ "resource": [
+ {
+ "files": [
+ "logo.svg",
+ "favicon.ico"
+ ],
+ "src": "DocFX"
+ },
+ {
+ "files": [
+ "Documentation/images/**/*"
+ ]
+ }
+ ],
+ "overwrite": [
+ {
+ "files": [
+ "apidoc/**.md"
+ ],
+ "exclude": [
+ "obj/**",
+ "_site/**"
+ ]
+ }
+ ],
+ "globalMetadata": {
+ "_enableSearch": true
+ },
+ "dest": "_site",
+ "template": [
+ "default",
+ "DocFX/darkfx"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/Nautilus/filter.yml b/Nautilus/filter.yml
new file mode 100644
index 000000000..402f241df
--- /dev/null
+++ b/Nautilus/filter.yml
@@ -0,0 +1,8 @@
+apiRules:
+ - exclude:
+ hasAttribute:
+ uid: System.ComponentModel.EditorBrowsableAttribute
+ ctorArguments:
+ - System.ComponentModel.EditorBrowsableState.Never
+ - exclude:
+ uidRegex: ^Nautilus\.PluginInfo
\ No newline at end of file
diff --git a/common.props b/common.props
index 1a2dc3eaa..b2fd1491c 100644
--- a/common.props
+++ b/common.props
@@ -1,6 +1,6 @@
-
+