Search Unity

Question Create a new ScritpableObject with C# code

Discussion in 'Scripting' started by TiggyFairy, Apr 21, 2023.

  1. TiggyFairy

    TiggyFairy

    Joined:
    Dec 22, 2019
    Posts:
    506
    Can I spawn a new ScritpableObject file in a live game with C# code? I know you can
    Instantiate
    temporary Scriptable Objects at runtime, and you can make new objects with code that relies on the Unity Editor (see bellow). However, I can't see a way for my players to just make a new Scriptable Objects at runtime. This is worrying me, because I've built my entire game around them. Can anyone help?

    Code (CSharp):
    1. //This code is dependent on you being in the editor.
    2.  
    3. MyScriptableObjectClass asset = ScriptableObject.CreateInstance<MyScriptableObjectClass>();
    4.  
    5.         string name = UnityEditor.AssetDatabase.GenerateUniqueAssetPath("Assets/NewScripableObject.asset");
    6.         AssetDatabase.CreateAsset(asset, name);
    7.         AssetDatabase.SaveAssets();
    8.  
    9.         EditorUtility.FocusProjectWindow();
    10.  
    11.         Selection.activeObject = asset;
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,923
    Why do you want players to 'create' them at run time? You will need to give us more detail here to explain what you mean exactly (this is not the first time I've asked you for more detail either).

    If you Instantiate a scriptable object at run time, it will hang around until it's purposefully destroyed. If you want created at runtime by the player, you just need some system which allows player input for their generation. But you should know that you cannot mutate the files of built project at run time.

    So again, it depends what you intend exactly.
     
  3. TiggyFairy

    TiggyFairy

    Joined:
    Dec 22, 2019
    Posts:
    506
    Well, I wanted to use them to store data on my ingame items - with the player able to make custom items using certain rules.. I also had a vague idea about maybe using them as save files, but if you can't make new files in a built project I guess I've lost most of the reasons I was using them....... Are you sure you can't, though? I've found some generic file copying code just now that I've been adapting. Though I don't know if it works or how fast/dangerous it is.

    Code (CSharp):
    1. // Create a new instance of the ScriptableObject type
    2.         Object newObject = ScriptableObject.CreateInstance<Object>();
    3.  
    4.         // Serialize the original object to a byte array
    5.         BinaryFormatter bf = new BinaryFormatter();
    6.         MemoryStream ms = new MemoryStream();
    7.         bf.Serialize(ms, ass);
    8.         byte[] bytes = ms.ToArray();
    9.  
    10.         // Deserialize the byte array to the new object
    11.         ms = new MemoryStream(bytes);
    12.         newObject = (Aspect)bf.Deserialize(ms);
    .
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,727
    Not appropriate. Yes you can but it takes lots of effort and gets you nothing over just normal load/save steps.

    Load/Save steps:

    https://forum.unity.com/threads/save-system-questions.930366/#post-6087384

    An excellent discussion of loading/saving in Unity3D by Xarbrough:

    https://forum.unity.com/threads/save-system.1232301/#post-7872586

    Loading/Saving ScriptableObjects by a proxy identifier such as name:

    https://forum.unity.com/threads/use...lds-in-editor-and-build.1327059/#post-8394573

    When loading, you can never re-create a MonoBehaviour or ScriptableObject instance directly from JSON. The reason is they are hybrid C# and native engine objects, and when the JSON package calls
    new
    to make one, it cannot make the native engine portion of the object.

    Instead you must first create the MonoBehaviour using AddComponent<T>() on a GameObject instance, or use ScriptableObject.CreateInstance<T>() to make your SO, then use the appropriate JSON "populate object" call to fill in its public fields.

    If you want to use PlayerPrefs to save your game, it's always better to use a JSON-based wrapper such as this one I forked from a fellow named Brett M Johnson on github:

    https://gist.github.com/kurtdekker/7db0500da01c3eb2a7ac8040198ce7f6

    Do not use the binary formatter/serializer: it is insecure, it cannot be made secure, and it makes debugging very difficult, plus it actually will NOT prevent people from modifying your save data on their computers.

    https://docs.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide
     
    Ryiah likes this.
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,481
    Assuming you've not already, I would certainly recommend going through the e-book on ScriptableObjects here also the blog post here.

    Page 19 does answer your question.
     
    spiney199 and Ryiah like this.
  6. TiggyFairy

    TiggyFairy

    Joined:
    Dec 22, 2019
    Posts:
    506
    Oh. That's even worse. I thought they were like meta files you could just freely copy and distribute. Well, that sucks.

    Is that basically the reverse of what Xarbrough means by "You can even use a ScriptableObject as the data model and then serialize it to JSON."? Or are they referring to some sort of automatic copying method?

    Ah, okay....
     
  7. Sluggy

    Sluggy

    Joined:
    Nov 27, 2012
    Posts:
    989
    ScriptableObjects are basically barebones unity objects with enough functionality to support being serialized for the sake of the inspector and being saved as an in-engine asset. If you want read-only data that can be easily created and modified in the editor then they are excellent but that's about it. What you seem to be looking for is data persistence of some kind. That's going to require good old-fashioned techniques like what Kurt suggested. Text files, binary files, databases, or remote file servers, etc...
     
    Ryiah likes this.