How does one model two-way relationships for scriptable objects?
Let's say we have a number of items in-game, and each item can be obtained by different conditions. Some may require you to complete a certain mission, some may be purchasable from an NPC, some may be dropped from an enemy, and some may require you to purchase a DLC...
Given an item, we would like to know what are the ways that it could be obtained; and given a mission/npc/enemy/dlc, we would like to know what items it grants.
What are the best ways to model two way relationships like this?
For items alone, it may be easiyeasy to handle... but as you can imagine, there are a lot more two-way relationships in games, between missions and NPC, missions and missions, DLC and NPC... and so on.
I could come up with a number of ways:
Have two scriptable objects references each other, but it's error prone. So we will need to have some validation logic, or an editor script that updates relationship automatically when one was changed. Also it would be time consuming to write scripts for all different relationships that needs to be accessed two-ways.
Make one-way reference only, and have the two-way relationships initialized at runtime. But what if we want to have the relationship displayed in the Unity Editor two-way? A possible solution is to write a script that iterate through all scriptable objects and build a relationship graph between scriptable objects, but it would also be very time consuming.
Use an actual relational database like SQL to store the relationship, and perhaps an id/guid reference to the actual scriptable object for easy editing within the Unity Editor. There also seem to be some relational databases specifically made for Unity, with Unity data types support, but I personally haven't tried using them.
Use a solution similar to 2, but create a base class/interface for all relational scriptable objects, thus reducing the time needed to create the custom editors. Then, let each class reports their relationship (and sub-relationship) through an abstract property, and iterate from the root object to build the relationship graph for both edit and play mode.
Use a third scriptable object to store the relationship, and create custom tooling to make the editing process as smooth as possible. Perhaps by adding a [OneToOne][ManyToOne] etc. Attribute on the desired property, and have a editor script automatically create and populate the property with the relationship scriptbable object, with two-way sync.
Yet, none of the methods seems to be the proper solution and each have their benefits and issues. Before committing to refactoring our game (We are using method 2 at the moment), I figure it would be great to ask for some advices in this site. How do you usually deal with this kind of issues?
Thank you!