Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
0
Question by adriasierra · Jul 22, 2021 at 04:17 PM · scripting problemserializationscriptableobjectscript error

SerializedObject asset loses data when pressing play

I have an array inside a SerializedObject that loses all its data upon pressing play, however on the actual asset the data persists if I open it with a text editor, which is weird to me. I should also mention that I can see it populate and everything on the inspector without any issues.

This is the ScriptableObject I'm trying to persist (roomData is the array that doesn't get saved/serialized? properly):

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.Tilemaps;
 
 namespace Strata
 {
     [System.Serializable]
     public class RoomData
     {
         public string tilemap;
         public char[] chars;
     }
 
     [CreateAssetMenu(menuName = "Strata/Templates/RoomTemplate")]
     [System.Serializable]
     public class RoomTemplate : ScriptableObject
     {
         public int roomSizeX = 10;
         public int roomSizeY = 10;
 
         // Array of char arrays.
         // Size of the array is the number of different tilemaps on the project.
         public RoomData[] roomData = new RoomData[12];
 
         public bool opensToNorth;
         public bool opensToEast;
         public bool opensToSouth;
         public bool opensToWest;
 
         void OnValidate()
         {
             // Populate "jagged" array so that each tilemap has its own.
             for (int i = 0; i < roomData.Length; i++)
             {
                 RoomData data = new RoomData();
                 data.chars = new char[100];
                 roomData[i] = data;
             }
 
             // Resize them if incorrect.
             if (roomData[0].chars.Length != roomSizeX * roomSizeY)
             {
                 for (int i = 0; i < roomData.Length; i++)
                 {
                     roomData[i].chars = new char[roomSizeX * roomSizeY];
                 }
             }
         }
     }
 }

And this the script in charge of saving and loading these assets (with unnecessary bits cut out):

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.Tilemaps;
 using UnityEditor;
 
 namespace Strata
 {
 
     public class StrataContentEditorWindow : EditorWindow
     {
         //The currently loaded RoomTemplate which we are loading and saving from/to.
         public RoomTemplate roomTemplate;
         //The currently loaded BoardLibrary which we are reading from to match Tiles to Characters.
         public BoardLibrary boardLibrary;
         //The currently loaded BoardGenerator which we are getting available templates from.
         public BoardGenerator boardGenerator;
         //Store a reference to the Dictionary of BoardLibrary which we use to match TileBase objects to BoardLibraryEntry objects (which contain ASCII characterIds)
         private Dictionary<TileBase, BoardLibraryEntry> libraryDictionary;
 
         //Set up the Window
         [MenuItem("Tools/Strata Content Editor")]
         static void Init()
         {
             EditorWindow.GetWindow(typeof(StrataContentEditorWindow)).Show();
         }
 
         //Redraw the EditorWindow
         void OnGUI()
         {
             //Set up the Serialized Objects we need to draw in the Window and apply their properties when modified
             SerializedObject serializedObject = new SerializedObject(this);
 
             SerializedProperty serializedRoomTemplateProperty = serializedObject.FindProperty("roomTemplate");
             EditorGUILayout.PropertyField(serializedRoomTemplateProperty, true);
 
             SerializedProperty serializedBoardLibraryProperty = serializedObject.FindProperty("boardLibrary");
             EditorGUILayout.PropertyField(serializedBoardLibraryProperty, true);
                         
             SerializedProperty serializedBoardGeneratorProperty = serializedObject.FindProperty("boardGenerator");
             EditorGUILayout.PropertyField(serializedBoardGeneratorProperty, true);
 
             serializedObject.ApplyModifiedProperties();
 
 
             //Draw the Buttons and call appropriate functions when they are pressed
             if (GUILayout.Button("Load Room"))
             {
                 LoadTileMapFromRoomTemplate();
             }
 
             if (GUILayout.Button("Save Room"))
             {
                 SaveTilemapToRoomTemplate();
             }
 
             //Use to create a new RoomTemplate for authoring
             if (GUILayout.Button("Create New RoomTemplate"))
             {
                 CreateNewRoomTemplateAsset();
             }
         }
 
         //Subscribe to the delegates for scene drawing, used for drawing the red box guides in the Scene view
         void OnEnable()
         {
             SceneView.duringSceneGui += this.OnSceneGUI;
         }
 
         void OnDisable()
         {
             SceneView.duringSceneGui -= this.OnSceneGUI;
         }
 
         //Draw the red box in the shape of the loaded RoomTemplate in the Scene view
         void OnSceneGUI(SceneView sceneView)
         {
             if (roomTemplate != null)
             {
                 Handles.BeginGUI();
                 Debug.DrawLine(Vector3.zero, new Vector3(roomTemplate.roomSizeX, 0, 0), Color.red);
                 Debug.DrawLine(Vector3.zero, new Vector3(0, roomTemplate.roomSizeY, 0), Color.red);
                 Debug.DrawLine(new Vector3(roomTemplate.roomSizeX, roomTemplate.roomSizeY, 0), new Vector3(roomTemplate.roomSizeX, 0, 0), Color.red);
                 Debug.DrawLine(new Vector3(roomTemplate.roomSizeX, roomTemplate.roomSizeY, 0), new Vector3(0, roomTemplate.roomSizeY, 0), Color.red);
 
                 HandleUtility.Repaint();
                 Handles.EndGUI();
             }
         }
 
         //Use this to create and load a new RoomTemplate asset for authoring
         public void CreateNewRoomTemplateAsset()
         {
             roomTemplate = CreateAsset<RoomTemplate>("Room") as RoomTemplate;
         }
 
         //Helper function for creating all the ScriptableObject assets we'll need
         public static ScriptableObject CreateAsset<T>(string assetName) where T : ScriptableObject
         {
             var asset = ScriptableObject.CreateInstance<T>();
             ProjectWindowUtil.CreateAsset(asset, assetName + " " + typeof(T).Name + ".asset");
             return asset;
         }
 
         //This method saves Tilemaps to RoomTemplate
         public void SaveTilemapToRoomTemplate()
         {
             //Build the LibraryDictionary so that we can match Tiles to characters
             libraryDictionary = boardLibrary.BuildTileKeyLibraryDictionary();
             
             // Cycle this process for every tilemap
             for (int i = 0; i < boardGenerator.tilemapArray.Length; i++)
             {
                 //Get a reference to the Tilemap
                 Tilemap tilemap = boardGenerator.tilemapArray[i];
                 roomTemplate.roomData[i].tilemap = tilemap.gameObject.name;
 
                 //An int to store the index as we loop through the RoomTemplate
                 int charIndex = 0;
                 for (int x = 0; x < roomTemplate.roomSizeX; x++)
                 {
                     for (int y = 0; y < roomTemplate.roomSizeY; y++)
                     {
                         //Get the Tile from the Tilemap as a TileBase, this allows us to use other types of Tiles including RuleTiles, RandomTiles and other
                         //scripted tiles, as opposed to just Sprite based tiles.
                         TileBase foundTile = GetTileFromTilemap(x, y, tilemap) as TileBase;
                         
                         if (foundTile)
                         {
                             //Get the BoardLibraryEntry that matches this TileBase
                             BoardLibraryEntry entry = boardLibrary.CheckLibraryForTile(foundTile, libraryDictionary);
 
                             if (entry == null)
                             {
                                 //If we don't find a matching Entry, we need one, so let's create it in the BoardLibrary
                                 entry = boardLibrary.AddBoardLibraryEntryIfTileNotYetEntered(foundTile);
 
                                 //Set this dirty because we need to save it
                                 EditorUtility.SetDirty(boardLibrary);
                             }
                             //Set the character into the RoomTemplate to record it
                             roomTemplate.roomData[i].chars[charIndex] = entry.characterId;
                         }
                         else if (foundTile == null)
                         {
                             //Debug.Log("This shouldn't happen, foundTile is: "+foundTile);
                             //If tilemap is blank inside grid, write in default empty space character defined in board library, usually 0
                             roomTemplate.roomData[i].chars[charIndex] = boardLibrary.GetDefaultEmptyChar();
                         }
                         charIndex++;
                     }
                 }
             }
 
             //Set the RoomTemplate dirty to make sure we'll save changes
             EditorUtility.SetDirty(roomTemplate);
             //Save the AssetDatabase to write changes back to disk
             AssetDatabase.SaveAssets();
         }
 
         //This is used to convert the ASCII data stored in the RoomTemplate back into Tile data for display and editing in the Tilemap in the Scene view
         public void LoadTileMapFromRoomTemplate()
         {
             bool loaded = false;
 
             //Build up the Dictionary from the Library since we need it to match characters to Tiles
             libraryDictionary = boardLibrary.BuildTileKeyLibraryDictionary();
 
             // Cycle this process for every tilemap
             for (int i = 0; i < boardGenerator.tilemapArray.Length; i++)
             {
                 //Make sure the Tilemap is set
                 Tilemap tilemap = boardGenerator.tilemapArray[i];
 
                 tilemap.ClearAllTiles();
                 tilemap.ClearAllEditorPreviewTiles();
 
                 //Loop through the ASCII roomData.chars stored in the RoomTemplate and match them to entries in the BoardLibrary, load those Tiles
                 int charIndex = 0;
                 for (int x = 0; x < roomTemplate.roomSizeX; x++)
                 {
                     for (int y = 0; y < roomTemplate.roomSizeY; y++)
                     {
                         //Get the tile to match the character found from BoardLibrary
                         TileBase tileToSet = boardLibrary.GetTileFromChar(roomTemplate.roomData[i].chars[charIndex]) as TileBase;
                         if (tilemap == boardGenerator.tilemapArray[0])
                         {
                             //Debug.Log(tilemap+" has "+tileToSet+" char at "+x+","+y+" position. and is on the charIndex number "+charIndex+".");
                         }
                         if (tileToSet == null)
                         {
                             Debug.LogError("Attempting to load empty tiles, draw and save something first");
                         }
 
                         Vector3Int pos = new Vector3Int(x, y, 0) + tilemap.origin;
                         tilemap.SetTile(pos, tileToSet);
                         charIndex++;
                     }
                 }
             }
         }
     }
 } 

I'm really confused since as you can see I'm serializing everything, I got rid of the jagged array I was using because those can't be serialized, I'm using SetDirty on the assets so they're saved (and they're, since this is what the .asset shows: as you can see roomData has data here).

 %YAML 1.1
 %TAG !u! tag:unity3d.com,2011:
 --- !u!114 &11400000
 MonoBehaviour:
   m_ObjectHideFlags: 0
   m_CorrespondingSourceObject: {fileID: 0}
   m_PrefabInstance: {fileID: 0}
   m_PrefabAsset: {fileID: 0}
   m_GameObject: {fileID: 0}
   m_Enabled: 1
   m_EditorHideFlags: 0
   m_Script: {fileID: 11500000, guid: 184007c02a596bb4ab011e3ac438387b, type: 3}
   m_Name: First Room
   m_EditorClassIdentifier: 
   roomSizeX: 12
   roomSizeY: 10
   roomData:
   - tilemap: Platforms
     chars: 5300
   - tilemap: OneWayPlatforms
     chars: 4200
   opensToNorth: 1
   opensToEast: 1
   opensToSouth: 0
   opensToWest: 1

And this .asset data never gets lost even after pressing play on Unity. And as I said, the Inspector shows the roomData array without issues before pressing play and it all vanishes upon pressing it. Oddly enough the other parameters don't "reset", they persist, so I'm guessing it's an issue with Unity being unable to serialize this array but I thought this was a working substitute for jagged arrays? I'd appreciate any help since I'm stuck.

Thanks in advance.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by adriasierra · Jul 23, 2021 at 12:24 AM

I'm dumb, OnValidate() on RoomTemplate.cs is also called when the game starts and it was resetting the array, I made these changes to OnValidate() which make it only populate the array if it's null and now it works:

         void OnValidate()
         {
             Debug.Log("Validated.");
             // Populate jagged array so that each tilemap has its own.
             for (int i = 0; i < roomData.Length; i++)
             {
                 if (roomData[0] == null)
                 {
                     RoomData data = new RoomData();
                     data.chars = new char[100];
                     roomData[i] = data;
                 }
             }
 
             // Resize them if incorrect.
             if (roomData[0].chars.Length != roomSizeX * roomSizeY && roomData[0] == null)
             {
                 for (int i = 0; i < roomData.Length; i++)
                 {
                     roomData[i].chars = new char[roomSizeX * roomSizeY];
                 }
             }
         }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

269 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

ScriptableObject not Serializing? 0 Answers

Question on SerializeField? 1 Answer

Help with a C# script .SetActive 1 Answer

Help with Script 1 Answer

MyClockScript.cs(6,14): error CS0101: The namespace `global::' already contains a definition for `MyClockScript' 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges