Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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 /
avatar image
1
Question by dan_wipf · Oct 21, 2018 at 04:35 PM · c#editorinspectoreditor-scriptingout of range

Editor Script, Index Out of Range Exception after Play

Can somebody explain me why a CustomEditor based script is working fine in Editor Mode, but when I switch to PlayMode it throws me back a Index Out of Range Exception?


     IndexOutOfRangeException: Array index is out of range.
 TerrainPrototypesGroupManagerEDITOR.OnInspectorGUI () (at Assets/Editor/TerrainPrototypesGroupManagerEDITOR.cs:50)
 UnityEditor.InspectorWindow.DrawEditor (UnityEditor.Editor[] editors, Int32 editorIndex, Boolean rebuildOptimizedGUIBlock, System.Boolean& showImportedObjectBarNext, UnityEngine.Rect& importedObjectBarRect) (at /Users/builduser/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1374)
 UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)
      
      //my struct, where the error appears. 
          [System.Serializable]public struct list_TreeInstances {[SerializeField]public List < TreeInstance > m_TreeInstances;}


I've got a second struct which is kind of identical, but uses a GameObject instead of TreeInstance, where I don't have the null reference. Could this be because its properly used with a SerializedProperty in Inspector? like:



  //_GO_Groups is an Array ( list_GameObject[] _GO_Groups = new list_GameObject[0];)
  SerializedProperty s_GO_Groups = serializedObject.FindProperty("_GO_Groups");
      
      // example
       SerializedProperty s0 = s_GO_Groups.GetArrayElementAtIndex(master).FindPropertyRelative("m_GameObjects");
                  for(int i = 0; i<s0.arraySize;i++){
                      SerializedProperty s1 = s0.GetArrayElementAtIndex(i);
                          if(s1.objectReferenceValue != null){
                              EditorGUILayout.PropertyField(s1,new GUIContent(_TPGM._GO_Groups[master].m_GameObjects[i].name));
                              }


Well final and important Question, whats the best way to find the Source of causing this trouble? Sorry to tag you but, I know you both are Genius in this @JVene @Bunny83


full code is here if needed

Comment
Add comment · Show 3
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
avatar image dan_wipf · Oct 29, 2018 at 08:02 AM 0
Share

@hexagonius please don’t close that many questions.. i dont $$anonymous$$d if you close bad wrtitten and off topic questions.. but the rest i’m getting quite anoyed. like a few days you closed this question. with the link to just the docs.. well i know what a null reference exception is.. but in this case you just didn’t think about the question alot. in the end it was due to a serialized problem inside of unity(have a look below)

avatar image hexagonius dan_wipf · Oct 29, 2018 at 05:42 PM 1
Share

you're right, that was a mistake here since the cause layed further down the path and was more difficult to solve than a regular case.
but co$$anonymous$$g by the amount of questions that are asked there's not much time you have if you want to help a lot of people. the throughout quality of them is bad and repetitive. I apologize for this one.

avatar image dan_wipf hexagonius · Oct 29, 2018 at 06:13 PM 0
Share

i defently know what you mean..

alot of questions are like that

1 Reply

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

Answer by Bunny83 · Oct 22, 2018 at 12:54 AM

Unity's TreeInstance struct is not serializable. The TerrainData class is implemented in native code and is serialized in native code. The managed class is just a wrapper of the serialized native data.

When you read the treeInstances property you actually call a native method which returns the instances from native code.


So since the struct isn't marked with the Serializable attribute it's not a managed type that the Unity serializer can serialize. Therefore the List<TreeInstance> is not a serializable type either. That means whenever your data needs to be serialized / deserialized this will not be included. When you enter playmode everything gets serialized and reloaded from serialized data. That means your List will be null since it can't be serialized. You may need to create a wrapper type that can be serialized which holds the same information as the TreeInstance struct and copy the data as needed.


edit

As i said in the comment below, i would implement the conversion inside your wrapper struct. Since this is only for serialization i would use a constructor for the creation of the wrapper and an implicit conversion operator to turn our wrapper back to a TreeInstance value.

 [System.Serializable]
 public struct TreeInstanceArray
 {
     public Vector3 position;
     public float widthScale;
     public float heightScale;
     public float rotation;
     public Color32 color;
     public Color32 lightmapColor;
     public int prototypeIndex;
     public TreeInstanceArray(TreeInstance aTree)
     {
         position = aTree.position;
         widthScale = aTree.widthScale;
         heightScale = aTree.heightScale;
         rotation = aTree.rotation;
         color = aTree.color;
         lightmapColor = aTree.lightmapColor;
         prototypeIndex = aTree.prototypeIndex;
     }
     public static implicit operator TreeInstance (TreeInstanceArray aTree)
     {
         TreeInstance inst = new TreeInstance;
         inst.position = aTree.position;
         inst.widthScale = aTree.widthScale;
         inst.heightScale = aTree.heightScale;
         inst.rotation = aTree.rotation;
         inst.color = aTree.color;
         inst.lightmapColor = aTree.lightmapColor;
         inst.prototypeIndex = aTree.prototypeIndex;
         return inst;
     }
 }

Now if you have a "TreeInstanceArray" value you can simply assign or use it where a TreeInstance value would be required.

 TreeInstanceArray serializedValue = new TreeInstanceArray();
 
 // this will trigger the implicit conversion
 TreeInstance tree = serializedValue;
 
 List<TreeInstance> trees;
 // this will also trigger the implicit conversion
 trees.Add(serializedValue);

To turn a TreeInstance into a "TreeInstanceArray", just use the constructor:

 TreeInstanceArray serializedValue = new TreeInstanceArray(someTreeInstance);

Comment
Add comment · Show 7 · 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
avatar image dan_wipf · Oct 22, 2018 at 08:34 AM 0
Share

Well might you could add a comment to the way I did it.

I build a new struct in my static class. [System.Serializable]public struct TreeInstanceArray {

     [SerializeField] public Vector3 position;
     [SerializeField] public float widthScale;
     [SerializeField] public float heightScale;
     [SerializeField] public float rotation;
     [SerializeField] public Color32 color;
     [SerializeField] public Color32 lightmapColor;
     [SerializeField] public int prototypeIndex;
     }

and made a get/set function which exchange data between TerrainData.TreeInstances and the new TreeInstanceArray..

 void GetTI(){
         _TreeInstances = new CSTPG$$anonymous$$.TreeInstanceArray[_ted.treeInstances.Length];
         for(int i = 0; i<_ted.treeInstances.Length; i++){
             TreeInstance t = _ted.treeInstances[i];
             _TreeInstances[i].position = t.position;
             _TreeInstances[i].widthScale = t.widthScale;
             _TreeInstances[i].heightScale = t.heightScale;
             _TreeInstances[i].rotation = t.rotation;
             _TreeInstances[i].color = t.color;
             _TreeInstances[i].lightmapColor = t.lightmapColor;
             _TreeInstances[i].prototypeIndex = t.prototypeIndex;
         }
     }
     void SetTI(){
         _ted.treeInstances = new TreeInstance[_TreeInstances.Length];
         for(int i = 0; i<_TreeInstances.Length; i++){
             TreeInstance t = _ted.treeInstances[i];
             t.position = _TreeInstances[i].position;
             t.widthScale = _TreeInstances[i].widthScale;
             t.heightScale = _TreeInstances[i].heightScale;
             t.rotation = _TreeInstances[i].rotation;
             t.color = _TreeInstances[i].color;
             t.lightmapColor = _TreeInstances[i].lightmapColor;
             t.prototypeIndex = _TreeInstances[i].prototypeIndex;
         }
     }



right now it works quite good, but I think I could optimize the get / set function


but the important thing is you gave the right input for a solution. so I'm really really thankful!!!


dan

avatar image Bunny83 dan_wipf · Oct 22, 2018 at 09:24 AM 0
Share

I think it would make more sense to build the conversion into your wrapper class / struct. C# has type conversion operators which come in quite handy in such cases. Unity for example implemented them for Color / Color32 conversion or Vector2 / 3 / 4 conversion. I'll add an example to my answer.

avatar image Bunny83 dan_wipf · Oct 22, 2018 at 09:44 AM 0
Share

Note with the implementation i've shown in my answer your Get and Set method could be just:

 void GetTI()
 {
     _TreeInstances = new CSTPG$$anonymous$$.TreeInstanceArray[_ted.treeInstances.Length];
     for(int i = 0; i < _ted.treeInstances.Length; i++)
     {
         _TreeInstances[i] = new CSTPG$$anonymous$$.TreeInstanceArray(_ted.treeInstances[i]);
     }
 }
 void SetTI()
 {
     TreeInstance[] trees = new TreeInstance[_TreeInstances.Length];
     for(int i = 0; i < _TreeInstances.Length; i++)
     {
         // implicit conversion
         trees[i] = _TreeInstances[i];
     }
     _ted.treeInstances = trees;
 }

Note i just realised in your comment there's an error. Your SetTI method won't work TreeInstance is a struct. When you read " _ted.treeInstances[i]" into the local variable "t" you get a copy of that variable. You then change the members of "t" but you never actually change the value in "_ted.treeInstances[i]"


In addition the "treeInstances" property of the TerrainData object is a property. The array that is returned is a copy of the internal data. So changing this array won't affect the actual data. You have to assign an array of TreeInstances to the property in order to invoke the property setter method.

avatar image dan_wipf · Oct 23, 2018 at 09:08 AM 0
Share

Thanks for the detailed Edit and Solution to build a Wrapper!

right now a single TreeInstance conversion is working as expected, but if I want to convert a Array back to the the TerrainData.treeInstances Array it throws an conversion error.

 //treeInstances and serializedValue are Arrays
 //What I want to do:
 
 TerrainData.treeInstances = serializedValue;
 
 // right now I have to do this
 
     TerrainData.treeInstances = new TreeInstance[serializedValue.Length];
         for(int i = 0; i<serializedValue.Length; i++){
             TerrainData.treeInstances[i] = serializedValue[i];
         }
avatar image Bunny83 dan_wipf · Oct 24, 2018 at 11:31 AM 0
Share

Have you seen my last comment? This line doesn't work as i mentioned at the bottom of my last comment:

 TerrainData.treeInstances[i] = serializedValue[i];

That's because "TerrainData.treeInstances" is a property. Whenever you "read" that property it will call a native method which returns a copy of the internal array. So changes to that array has no effect. The property also has a set method which will allows to actually pass a temporary array with the changed instances back to the native code. That's what i actually do in the SetTI() method i've posted in my comment. Notice the temporary array and the assignment at the end:

  _ted.treeInstances = trees; // this will invoke the setter of the property.


With Linq the array conversion could be done in a single line, but it's actually a little bit more expensive and creates more temporary garbage:

 TerrainData.treeInstances = serializedValue.Select(t=>(TreeInstance)t).ToArray();

For this to work you need using System.Linq; at the top. The Select method is an extension for collections which takes a delegate which will be invoked for every element of the collection. "Select" specifically is able to return something completely different. So the return value of Select will be a new IEnumerable that contains this "new type" that was returned by the delegate. Finally we can convert the IEnumerable back into an array by ToArray. Of course all those linq enumerables requires some memory, however the thing which requires the most additional memory is the ToArray method. it actually does the same as a generic List. It iterates through the IEnumerable and adds the elements one by one and expands its internal buffer as needed. Finally a new array with the correct number of elemens is created and the values are copied over. If this doesn't happen once every frame you can go with the linq solution. However if it's time critical you better do the loop manually. Further more if you do this conversion / assignment a lot of times you may even cache the temporary array and reuse it unless the required size changes.

avatar image Bunny83 Bunny83 · Oct 24, 2018 at 11:34 AM 0
Share

Though i'm a bit confused where you actually use this code. In your original question you were using the SerializedObject / SerializedProperty in the inspector. Direct object access is possible but can cause issues when you combine it with the SerializedObject / Property.

Show more comments

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

572 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 avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image 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

Custom Editor Script resets values on Play 1 Answer

How to access one class instance in editor script? 1 Answer

How To Force an Inspector to Repaint 3 Answers

TexturePropertySingleLine in Editor class 0 Answers

Gizmos.DrawLine is dissapearing after returning to editor after Playing the scene 0 Answers


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