Skip to content

Commit

Permalink
feat: Added UpgradeModuleGadget for vehicles upgrades. (#391)
Browse files Browse the repository at this point in the history
* Made the ModuleGadget thingy. Ready for PR ?

* Now ready for PR, test may be needed, if no push in 10 minutes, then it is a valid build.

* okay fixed something, now ready for PR

* changed the name of the module gadget to UpgradeModuleGadget

* Corrected a possible bug (latest)

* Added an insane quantity of functionality, and it's only the beginning. The most advanced part is for Subnautica 1, for Below Zero I still have a loooot of work, and SN1 too but BZ more...

* *tried* to add an example upgrade module

* now the example mod should work

* Seamoth, Seatruck and Snowbike are now compatible with Upgrade Module Gadget. Almost finished the rest.

* Cleaned all unnecessary usings, as Lee asked.

* Added SeaTruck On Use delegate, should be working at 100% but test is needed, if someone can make an example mod for that (BZ) it would be great, I don't have time lastly

* Added Seamoth OnUse patch for test with Example Mod.
The delegate for SeaMoth is now working holy shit.

* Removed harmony debug attribute

* Added some stuff

* Tests are needed. Normally everything is working **EXCEPT HOVERBIKE OnUse, HOVERBIKE OnToggle and (maybe) SEATRUCK OnToggle.**
I am writing a MonoBehaviour for the Hoverbike and one for the SeaTruck (HoverbikeComplement and SeaTruckComplement, possibly renamed in the future) but I will add it in a different PR.

* Revert autoformatting & using statement reordering

* Umm... no

* What am I reverting?

* Remove Vehicle Upgrade mod csproj files

* Fix more odd oversights

* ?

* Callback shenanigans

* Remove unused using statements

* Move all example code into VehicleUpgradesExample

* Potentially fixed seamoth crush depth not changing. Debug, troubleshoot and tests are required

* Okay well.. It's working !

* bring some additional changes requested by sir Metious.

* Edited the primary problems for merge I guess

* removed the "configurable and changeable values" to be in a next PR that I will probably do very quickly so at least it's done

* Removed unnecessary using statement

* Update VehicleUpgradesExample.cs

* added a documentation page

* finished to update the doc

* This time it should be good

* VehicleUpgradesPatcher fixed, upgrades are now working totally on Exosuit too !

* Cleaned unusded usings.

* Optimized code and removed comments.

* Must be "yield return null"

* Fix typo ("POssibilities")

* Minor grammar changes

---------

Co-authored-by: LeeTwentyThree <[email protected]>
  • Loading branch information
VELD-Dev and LeeTwentyThree committed Jun 29, 2023
1 parent 8e93cb2 commit 99c3d88
Show file tree
Hide file tree
Showing 22 changed files with 1,433 additions and 18 deletions.
2 changes: 1 addition & 1 deletion Example mod/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
Expand Down
212 changes: 212 additions & 0 deletions Example mod/VehicleUpgradesExample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
#if SUBNAUTICA
using BepInEx;
using Nautilus.Handlers;
using Nautilus.Options.Attributes;
using Nautilus.Json;
using Nautilus.Assets.PrefabTemplates;
using Nautilus.Assets;
using Nautilus.Assets.Gadgets;
using System.Collections.Generic;

namespace Nautilus.Examples;

[BepInPlugin("com.snmodding.nautilus.vehicleupgrades", "Nautilus Vehicle Upgrades Example Mod", Nautilus.PluginInfo.PLUGIN_VERSION)]
[BepInDependency("com.snmodding.nautilus")]
public class VehicleUpgradesExample : BaseUnityPlugin
{
private void Awake()
{
VehicleUpgradesExampleConfig config = OptionsPanelHandler.RegisterModOptions<VehicleUpgradesExampleConfig>();

/*
* Now, we'll be doing a custom vehicle upgrade mdoule.
* It will incrase the Seamoth crush depth to 3 kilometers (3000 meters)!
*/
PrefabInfo depthUpgradeInfo = PrefabInfo.WithTechType("SeamothDepthUpgrade", "Custom Depth Upgrade", "A custom depth upgrade module for Seamoth that allows you to dive to 3000 meters!");
Logger.LogDebug("Registered depth upgrade info");

/*
* Here, we're assigning the hull icon for our item.
* You may also use a custom image icon by calling the ImageUtils.LoadSpriteFromFile method or with AssetBundles, like mentioned higher.
*/
depthUpgradeInfo.WithIcon(SpriteManager.Get(TechType.HullReinforcementModule2));
Logger.LogDebug("Registerd depth upgrade icon");

/*
* Here we are setting up an instance of CustomPrefab, as we've already done higher.
*/
CustomPrefab depthUpgrade = new CustomPrefab(depthUpgradeInfo);
Logger.LogDebug("Registered depth upgrade custom prefab");

/*
* Like before, we're creating a clone of an existing techtype so we can have basic components such as a model, a rigidbody, etc...
*/
PrefabTemplate hullModuleCloneTemplate = new CloneTemplate(depthUpgradeInfo, TechType.HullReinforcementModule);
Logger.LogDebug("Cloned prefab of HullReinforcementModule3");

/*
* Now we're setting our depth upgrade module's gameobject with the hull reinforcement one.
* Theoretically it can be whatever tech type you want, but we'll take this one.
*/
depthUpgrade.SetGameObject(hullModuleCloneTemplate);
Logger.LogDebug("Setted depth upgrade prefab");

/*
* We will not add any modifier to the item this time.
* Instead, we're directly gonna make a recipe, and set its other metadata.
*/
depthUpgrade.SetRecipe(new Crafting.RecipeData()
{
/*
* Here, we are saying the amount of the item we want to be crafted.
*/
craftAmount = 1,

/*
* And here, we're making a list of ingredients.
*/
Ingredients = new List<CraftData.Ingredient>()
{
new CraftData.Ingredient(TechType.PlasteelIngot, 3),
new CraftData.Ingredient(TechType.Copper, 1),
new CraftData.Ingredient(TechType.Aerogel, 1),
}
})
/*
* There, we're saying the fabricator type we want the item to be in.
* In our case, let's say SeamothUpgrades, it's the fabricator in the Moonpool Upgrade Console.
*/
.WithFabricatorType(CraftTree.Type.SeamothUpgrades)
/*
* With this function, we set the node to access the module in the crafting bench.
* In the seamoth upgrades, there's no subnodes, only nodes.
*/
.WithStepsToFabricatorTab("SeamothModules")
/*
* Here, we are saying that the crafting duration of the item will be 2.5 seconds.
*/
.WithCraftingTime(2.5f);
Logger.LogDebug("Registered crafting gadget of depth upgrade");

/*
* Now, we're saying that this Equipment is an Upgrade Module.
* N.B. Cyclops modules are using an other Gadget.
*/
depthUpgrade.SetVehicleUpgradeModule(EquipmentType.SeamothModule, QuickSlotType.Passive)

/*
* Here we're defining the main thing that interests us, the max depth!
* We set it to 3000f, which is the new max depth.
* They are not stackable.
*/
.WithDepthUpgrade(3000f)

/*
* You can also add an action for when the module is added and removed from the vehicle.
* We'll add a subtitle for when the module is added and for when the module is removed.
*/
.WithOnModuleAdded((Vehicle vehicleReference, int quickSlotId) =>
{
Subtitles.Add($"Warning! The max depth is now 3000 meters. Say hello to Ghost Leviathans from me!");
})
.WithOnModuleRemoved((Vehicle vehicleReference, int quickSlotId) =>
{
Subtitles.Add("Warning! The depth upgrade has been removed!");
});
Logger.LogDebug("Registered equipment and upgrade module gadgets of depth upgrade");

/*
* Finally, we register it.
*/
depthUpgrade.Register();
Logger.LogDebug("Registered depth upgrade.");


/*
* Now, let's try to do that with an interactable module !
*/
var SelfDefenseMK2Info = PrefabInfo
.WithTechType("PerimeterDefenseMK2", "Perimeter Defense MK2 for Seamoth", "A new electrical defense for Seamoth")
.WithIcon(SpriteManager.Get(TechType.SeamothElectricalDefense));

var selfDefMK2prefab = new CustomPrefab(SelfDefenseMK2Info);
var selfDefClone = new CloneTemplate(SelfDefenseMK2Info, TechType.SeamothElectricalDefense);

selfDefMK2prefab.SetGameObject(selfDefClone);

selfDefMK2prefab.SetRecipe(new Crafting.RecipeData()
{
craftAmount = 1,
Ingredients = new List<CraftData.Ingredient>()
{
new CraftData.Ingredient(TechType.SeamothElectricalDefense),
new CraftData.Ingredient(TechType.Diamond, 2)
}
})
.WithFabricatorType(CraftTree.Type.Workbench);

selfDefMK2prefab.SetVehicleUpgradeModule(EquipmentType.SeamothModule, QuickSlotType.SelectableChargeable)
.WithCooldown(2.5f)
.WithEnergyCost(10f)
.WithMaxCharge(25f)
.WithOnModuleUsed((Vehicle vehicleInst, int slotID, float charge, float chargeScalar) =>
{
var __instance = vehicleInst as SeaMoth;
ElectricalDefense defense = Utils.SpawnZeroedAt(__instance.seamothElectricalDefensePrefab, __instance.transform, false).GetComponent<ElectricalDefense>();
defense.charge = charge;
defense.chargeScalar = chargeScalar;
});
selfDefMK2prefab.Register();

/*
* And finally, a CUSTOMIZABLE-after-restart depth module!
*/

// PLANNED FOR ANOTHER PR.
/*
PrefabInfo prefabInfo = PrefabInfo.WithTechType("SeamothCustomDepthModule", "Seamoth Variable Depth Upgrade", "Customize the depth of your upgrade from the game settings!")
.WithIcon(SpriteManager.Get(TechType.SeamothReinforcementModule))
.WithSizeInInventory(new Vector2int(1, 1));
CustomPrefab prefab = new(prefabInfo);
CloneTemplate clone = new(prefabInfo, TechType.SeamothReinforcementModule);
prefab.SetGameObject(clone);
prefab.SetPdaGroupCategory(TechGroup.VehicleUpgrades, TechCategory.VehicleUpgrades);
prefab.SetRecipe(new Crafting.RecipeData()
{
craftAmount = 1,
Ingredients = new List<CraftData.Ingredient>()
{
new CraftData.Ingredient(TechType.SeamothReinforcementModule),
new CraftData.Ingredient(TechType.Diamond, 2)
}
})
.WithFabricatorType(CraftTree.Type.SeamothUpgrades)
.WithCraftingTime(4f)
.WithStepsToFabricatorTab("SeamothModules");
prefab.SetVehicleUpgradeModule(EquipmentType.SeamothModule)
.WithDepthUpgrade(() => config.MaxDepth, true)
.WithOnModuleAdded((Vehicle vehicleInstance, int slotId) => {
Subtitles.Add($"New seamoth depth: {config.MaxDepth} meters.\nAdded in slot #{slotId + 1}.");
})
.WithOnModuleRemoved((Vehicle vehicleInstance, int slotId) =>
{
Subtitles.Add($"Seamoth depth module removed from slot #{slotId + 1}!");
});
prefab.Register();
*/
}
}

// Disable the naming convention violation warning.
#pragma warning disable IDE1006

[Menu("Vehicle Upgrade Example mod")]
public class VehicleUpgradesExampleConfig : ConfigFile
{
[Slider(Format = "{0:F0}m", Label = "Seamoth Upgrade Max Depth", Min = 100f, Max = 10000f, Step = 10f,
Tooltip = "This is the max depth of the seamtoh when the depth module is equipped. It is absolute.")]
public float MaxDepth = 500.0f;
}
#endif
5 changes: 5 additions & 0 deletions Nautilus/Assets/Gadgets/EquipmentGadget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class EquipmentGadget : Gadget
public QuickSlotType QuickSlotType { get; set; }



/// <summary>
/// Constructs an equipment gadget.
/// </summary>
Expand All @@ -37,6 +38,8 @@ public EquipmentGadget(ICustomPrefab prefab, EquipmentType equipmentType) : base
EquipmentType = equipmentType;
}



/// <summary>
/// Sets the way the game should treat this item as when in a quick slot.
/// </summary>
Expand All @@ -48,6 +51,8 @@ public EquipmentGadget WithQuickSlotType(QuickSlotType quickSlotType)
return this;
}



/// <inheritdoc/>
protected internal override void Build()
{
Expand Down
26 changes: 26 additions & 0 deletions Nautilus/Assets/Gadgets/GadgetExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO;
using System.Runtime.CompilerServices;
using Nautilus.Crafting;
using Nautilus.Handlers;
using Nautilus.Json.Converters;
Expand Down Expand Up @@ -147,6 +148,31 @@ public static EquipmentGadget SetEquipment(this ICustomPrefab customPrefab, Equi
return equipmentGadget;
}

/// <summary>
/// Sets this item as a vehicle upgrade module. Cyclops upgrades are not supported by this function.
/// <para>If you're using this function, please do not use <see cref="SetEquipment(ICustomPrefab, EquipmentType)"/>,<br/>
/// it would interefere with this and possibly make the game crash or cause the mod to not work.</para>
/// </summary>
/// <param name="customPrefab">The custom prefab to set vehicle upgrade for.</param>
/// <param name="equipmentType">The type of equipment slot this item can fit into. Preferably use something related to vehicles.</param>
/// <param name="slotType">The quick slot type</param>
/// <returns>An instance to the created <see cref="UpgradeModuleGadget"/> to continue the upgrade settings on.</returns>
public static UpgradeModuleGadget SetVehicleUpgradeModule(this ICustomPrefab customPrefab, EquipmentType equipmentType = EquipmentType.VehicleModule, QuickSlotType slotType = QuickSlotType.Passive)
{
if(customPrefab.TryGetGadget(out UpgradeModuleGadget upgradeModuleGadget))
{
customPrefab.SetEquipment(equipmentType).WithQuickSlotType(slotType);
return upgradeModuleGadget;
}
else
{
customPrefab.SetEquipment(equipmentType).WithQuickSlotType(slotType);
upgradeModuleGadget = new UpgradeModuleGadget(customPrefab);
customPrefab.TryAddGadget(upgradeModuleGadget);
return upgradeModuleGadget;
}
}

/// <summary>
/// Creates a craft tree for this prefab. The created craft tree is immediately returned after this method is executed.
/// </summary>
Expand Down
Loading

0 comments on commit 99c3d88

Please sign in to comment.