stride icon indicating copy to clipboard operation
stride copied to clipboard

Create a new asset type equivalent to Unity's ScriptableObject.

Open dfkeenan opened this issue 5 years ago • 13 comments

Hi,

Though I have never used Unity I feel that the ScriptableObject is quite valuable. Being able to design a data object and save it with various values so scripts can share instances can really improve design time support in editor.

cheers, dfkeenan

dfkeenan avatar Aug 04 '18 09:08 dfkeenan

I support this idea

Sasino97 avatar Jun 13 '19 07:06 Sasino97

for me is a long no-go for xenko. game data asset is crucial

brmassa avatar Feb 16 '20 05:02 brmassa

Just wanted to show support for this feature. I think a scriptable data asset would be a great addition to the engine. At the moment it is sort of possible in a hacky kind of way by using a prefab with an empty entity and single script, but I think a dedicated asset would be excellent. Many games need to store read only data that doesn't need to be in an external file for things like item configurations, level data etc. It makes sense to use the powerful editor and serialization that is already available.

Here's how I imagine it could be added:

1: Create a new base class 'DataScript' or similar that users would inherit from along with adding all the asset serializers and processors etc. 2: Add a way to create an asset from these scripts. 'Add Asset/Scripts/Data Script'? or something like that or maybe there is a better way. 3: Allow the content system to return instances of these scripts from the load methods. For example: 'MyDataScript a = Content.Load<MyDataScript>("Example");' 4: Enjoy better data support for your games.

I'm no expert, but those are my thoughts on the idea and think it would be a useful addition for many users.

scottyboy805 avatar May 01 '20 15:05 scottyboy805

I'm of the opinion the c# environment is powerful enough that scriptableobject isn't really needed. Yes, what you end up doing in Xenko is creating an entity with priority -1, and add a script to it. The script will be a class with a static reference to itself (Singleton), which holds whatever game data you need. That is how I'm currently handling it. I don't think we need a special entity to represent these easy steps.

makotech222 avatar May 01 '20 16:05 makotech222

Yes, that is fair enough. But what if the data should be accessible in multiple scenes? Then you would either have to load the data scene first and keep it alive, or clone the data which comes with its own issues, namley keeping the data in sync between scenes. This is why I use a prefab to store data but it just seems clumbsy and hacky. I come from a Unity background and when they added a scriptable object asset i didn't really see the point either. However, once you use it and see the flexibility and endless number of uses, it really does become a great feature to have.

scottyboy805 avatar May 01 '20 16:05 scottyboy805

Just for my understanding, the main feature is that you can edit the values in the editor, right? Otherwise, there are many ways to achieve that with common programming patterns, like singleton, services, and so on...

tebjan avatar May 01 '20 18:05 tebjan

Yes that is one of the main benefits, but also the fact that they are not coupled to a scene instance or entity in any way. It's a bit like reading in a file and deserializing it as a class instance, except that you get all the editor and serialization features of xenko instead of having to do that manually.

scottyboy805 avatar May 01 '20 18:05 scottyboy805

As far as I understand a similar functionality can be achieved by creating a custom Configuration and adding it to the GameSettings asset. But if we wanted to get a bit closer to the ScriptableObject we need to be able to create potentially many instances of the asset in the editor (same type but different contents). The asset management system already does reference counting for Content.Load<>, so it would have a singleton behaviour.

A good next question is: should the data in the asset be mutable? If so, it might be necessary to create a new game system that would manage these objects, otherwise when the reference count goes to 0 and later the asset gets reloaded it would lose the modified state.

manio143 avatar Oct 21 '20 20:10 manio143

An easy way to add custom asset types might be enough. That's the main thing I am missing about scriptable objects. Raw assets can be used for this at the moment but it lacks the advantage of type safety that a proper solution would yield.

johang88 avatar Nov 10 '20 12:11 johang88

You can already create custom data assets, quite easily. I've prepared a small demo project: https://github.com/manio143/StrideCustomAsset The only downside right now is that you have to reference design time assemblies in your game project.

manio143 avatar Nov 10 '20 23:11 manio143

Oh nice 👍

johang88 avatar Nov 11 '20 10:11 johang88

Note that custom asset types discussed in #1120 Plugin system RFC would solve this with minor overhead.

manio143 avatar Jul 18 '22 18:07 manio143

Posting in support of scriptable objects being a core feature for Stride. I can live without a lot of things, but data objects aren't one of them

RavenheimStudio avatar Jul 19 '22 03:07 RavenheimStudio

I have seen multiple different descriptions what people used ScriptableObject for - so maybe this feature needs to be described on its own in order to get a clear scope that can be worked with.

To make matters worse 😂, I'll add a description of my use case - which is even more complex to implement than what I have heard so far, but also a huge advantage for teams with specialized roles.


I have the following class in Unity:

[CreateAssetMenu(menuName = "Epics/DamageType")]
public class DamageType : ScriptableObject
{
    public Color color;
}

The first line (the CreateAssetMenu attribute) in combination with the class being a ScriptableObject
means in the editor (= Game Studio) I can now select Create asset => Epics => DamageType.
I can call the file "Fire", and when I select it, in the inspector I get a color selector which I can set to red. I do it again, call this next file "Ice", and select the color blue.

But I guess "the magic" is that if a script now has a field public DamageType damageType;,
I can drag-drop my "Fire" file onto that. Or, even more convenient actually, click on the field
in the inspector and it shows me all the DamageType assets I have in the project.
Very similar to how the property drawer works for other asset types on entities, really.

It can also reference other assets. For example, I could add a field public Material material; in DamageType, and then drag a material asset onto it in the editor. Or a prefab. Or another ScriptableObject.


I actually do have a chain like this:

  • Script WeaponUser has a field public Weapon weapon;
  • Weapon is a ScriptableObject and references a prefab as its projectile
  • A projectile prefab usually has a DamageDealer script with a field public DamageType damageType;

Script => ScriptableObject => Prefab => Script => ScriptableObject


The main point is that in a whole bunch of cases, it's a rather quick way to
allow a design decision to be made without touching code. For teams with design specialists that saves a lot of time.
But even as a solo dev, every time I don't touch the code, I don't create a new bug.

However, I also realize that there are multiple parts to implementing this.

On the engine side, I think it's mostly "just" deserializing a referenced file into the specific subclass on scene start. Well, plus recursion.

But on the Game Studio side, off the top of my head

  • Make Game Studio find all subclasses of a certain class, then for each of them
  • Add an option in the "Create asset" menu
  • Read out the properties, fields etc according to DataContract for the class
  • Serialize it to a file
  • In the property drawer, only allow the specific subclass (I think file ending = asset type? That would be an issue)

Uiuiui. Big cost, big reward, eh?

raphaelschmitz00 avatar Sep 19 '23 22:09 raphaelschmitz00

Important to note this feeature likely isnt far. Manios POC mostly works here https://github.com/manio143/StrideCustomAsset but just requires you restart the editor when code changes are made.

Uiuiui. Big cost, big reward, eh?

Doprez avatar Sep 19 '23 22:09 Doprez

Once we make progress on #1120 I'm hoping I will be able to effectively provide single line attribute similar to what is described above which would run a source generator over a Content class and create the asset definition and the asset compiler for it. Or alternative try again with https://github.com/manio143/stride/tree/dataAsset where I was providing an in-engine generic solution. Not sure yet which will be best but I'm hoping to minimize user effort in creating simple data based assets while providing the flexibility of use cases mentioned.

manio143 avatar Sep 20 '23 21:09 manio143