Registering your UpgradeHandler - PrimeSonic/PrimeSonicSubnauticaMods GitHub Wiki
Originally introduced in the 3.0 update and later refined in the 4.0 overhaul, MoreCyclopsUpgrades can now be used as a public API, allowing other mods to integrate their own cyclops upgrade modules and have them be fully compatible with the Auxiliary Upgrade Console.
Assuming you've read about UpgradeHandler and how to create your own, here you'll learn how to send it over to the MoreCyclopsUpgrades API.
You may have noticed that the UpgradeHandler constructor requires a reference to the Cyclops SubRoot.
public UpgradeHandler(TechType techType, SubRoot cyclops)You might be asking yourself: "How do I instantiate an UpgradeHandler if I don't have the SubRoot reference?"
The answer to that question is: "You don't. MoreCyclopsUpgrades will instantiate it for you when the Cyclops is ready."
The API isn't asking you to provide your actual UpgradeHandler, but rather to provide code that it can run to create your UpgradeHandler.
This is known as an Abstract Factory Pattern.
Everything starts with a call into MCUServices.Register.CyclopsUpgradeHandler.
You'll notice that the parameter for this method isn't an UpgradeHandler instance, but instead it's expecting something that can return a new UpgradeHandler when called.
The only rule is that this registration call must happen within Patch time.
Once a Cyclops has been loaded into the game, it's too late.
The API offers a few different ways you can do this, so you can choose whichever style you find most comfortable.
/// <summary>
/// Registers a <see cref="CreateUpgradeHandler"/> method that creates a new <see cref="UpgradeHandler"/> on demand.<para/>
/// This method will be invoked only once for each Cyclops sub in the game world.
/// </summary>
/// <param name="createEvent">A method that takes no parameters a returns a new instance of an <see cref="UpgradeHandler"/>.</param>
void CyclopsUpgradeHandler(CreateUpgradeHandler createEvent);
/// <summary>
/// Registers a <see cref="CreateUpgradeHandler"/> class can create a new <see cref="UpgradeHandler"/> on demand.<para/>
/// This method will be invoked only once for each Cyclops sub in the game world.
/// </summary>
/// <param name="handlerCreator">A class that implements this <see cref="IUpgradeHandlerCreator.CreateUpgradeHandler(SubRoot)"/> method.</param>
void CyclopsUpgradeHandler(IUpgradeHandlerCreator handlerCreator);Option 1 - Using a method that returns your UpgradeHandler
This form takes in a CreateUpgradeHandler delegate method as its one parameter.
The CreateUpgradeHandler delegate defines this pattern: UpgradeHandler CreateUpgradeHandler(SubRoot);
This means that method to be used here.
- Must take in a
SubRoot cyclopsas its only parameter - Must return an object that is or inherits from
UpgradeHandler.
It is expected that you will pass the
SubRoot cyclopsreference to theUpgradeHandlerconstructor.
public static class QPatch
{
private static TechType myCyclopsUpgrade;
public static void Patch()
{
// Your patching code
....
// In this pattern, you can pass the method by name
MCUServices.Register.CyclopsUpgradeHandler(CreateMyUpgradeHandlerMethod);
}
private static CreateMyUpgradeHandlerMethod(SubRoot cyclops)
{
return new UpgradeHandler(myCyclopsUpgrade, cyclops)
{
// You could set up your UpgradeHandler right here
....
};
}
}This can also be done using anonymous methods.
As long as the anonymous method follows the same requirements, it doesn't have to have a name.
public static class QPatch
{
private static TechType myCyclopsUpgrade;
public static void Patch()
{
// Your patching code
....
// In this pattern, you can pass the method by name
MCUServices.Register.CyclopsUpgradeHandler((SubRoot cyclops) =>
{
return new UpgradeHandler(myCyclopsUpgrade, cyclops)
{
// You could set up your UpgradeHandler right here
....
};
});
}Option 2 - Using a class that implements the IUpgradeHandlerCreator interface
If passing methods as a parameter feels a little too weird to you, this alternative might serve you better.
This interface requires a class to implement a method named CreateUpgradeHandler.
Just as before, this CreateUpgradeHandler must
- Take in a
SubRoot cyclopsas its only parameter - return an object that is or inherits from
UpgradeHandler.
It is expected that you will pass the
SubRoot cyclopsreference to theUpgradeHandlerconstructor.
public static class QPatch
{
private static TechType myCyclopsUpgrade;
public static void Patch()
{
// Your patching code
....
var myMaker = new MyUpgradeHandlerMaker()
MCUServices.Register.CyclopsUpgradeHandler(myMaker);
}
}
internal class MyUpgradeHandlerMaker : IUpgradeHandlerCreator
{
public UpgradeHandler CreateUpgradeHandler(SubRoot cyclops)
{
return new MyUpgradeHandler(cyclops);
}
}
internal class MyUpgradeHandler : UpgradeHandler
{
// You could also create your UpgradeHandler as a new class
internal MyUpgradeHandler(SubRoot cyclops)
: base(QPatch.myCyclopsUpgrade, cyclop)
{
}
....
}There are many different ways to set up your UpgradeHandler,
but registering it with MCUServices boils down to either passing in a method that conforms to the CreateUpgradeHandler delegate -or- a class that implements IUpgradeHandlerCreator interface.
Either way, what you are doing is providing the API with a way to create your UpgradeHandler when the Cyclops is being set up.
Now that all of the original upgrade modules previously added directly by MoreCyclopsUpgrades have been split off into their own optional mods, you will find no shortage of examples to follow.