Hello everyone, I’m trying to create a Serializable class to be used in the inspector, I need to access the hosting monobehaviour for this class, but sense it’s created by unity and serialized automatically you can’t make use of custom constructors to pass what you want.
I will give you a simple example, I’m making a multipier system for damage and so, the multiplier is not just a number but a class that has functionality, limits, some calculations method fit for the game
[Serializable]
public class Multiplier
{
private float val = 1.0f;
private Action<MonoBehaviour> action;
public float Value
{
get { return val; }
set
{
val = value;
action?.Invoke(theMono);
}
}
}
the multiplier can be basically used for anything and it can be put inside any monobehaviour, the multiplier has an event to announce that its value has changed but I need to send the changing monobehaviour with the event, as the value alone is useless
another example is that I’m making inventory with serializable class InventorySlot, that has custom property drawer and so, I need to invoke inventory updated event when the slot changes, but the slot doesn’t have access to the inventory
That is simply not possible. A class instance is a standalone object. It may be referenced by several variables of different objects. There is no “owner”. If you actually want a two way relationship you may want to make a component out of your class.
Another option is to pass the object reference you’re interested in as parameter. Of course you can’t use a property in that case but have to use an explicit method.
Finally you could implement the ISerializationCallbackReceiver in the hosting class and just set a field in your Multiplier instance in OnAfterDeserialize.
Though i still don’t quite understand the usage of that class. Keep in mind that custom serializable classes do not support inheritance when it comes to serialization. So what is the point of a seperate class here? Who is subscribing to your “action”? Doesn’t a closure work just fine? How do you subscribe to action?
While I’m not 100% certain I fully understand all that you require, it seems you have two problems to solve.
First, since you can’t create a custom constructor, you can’t obtain a linkage between the owning MonoBehaviour and these classes, be it slot, multiplier or whatever. You already realize there’s no way to discover an instance automatically (how could one know what instance to find), you have to break this deadlock by using an initialization in Awake or Start of the MonoBehaviour, where you can perform what I’ll call post construction - that which you would have performed by using a custom constructor for Multiplier, but must do so when MonoBehaviour can do that for you. You could only perform some form of lazy initialization of the connection between multiplier and the owning class is if it were a singleton, and could be discovered from a static value lazily initialized.
Since that’s not an option, you have to use Awake or Start, or some other lazy initialization means discovered from the MonoBehaviour that owns these objects.
That said, I’ll turn to the function call from within the multiplier, slot or whatever class must “callback”.
You could pass “this” from MonoBehaviour to multiplier, which would give it an instance upon which to call any member of the MonoBehaviour derivative. That assumes the function is always the same, but the generic nature of multiplier suggests this function is different for each use. For that you should consider a delegate. A delegate combines the notion of an instance and the member function to be called. It appears like a member variable you set, but calls like a function. Google provides.