Hello, I’m sure this question has come up a lot, as I can tell from my endless google searches.
I’m looking for a way to save variables for an object for use only within an Editor script.
Take this example:
class MyClass : MonoBehavior {
public string myString = "hello";
//do not want this variable exposed to other runtime scripts
public bool isExpaned;
}
class MyClassEditor : Editor {
public override void OnInspectorGUI() {
((MyClass)target).isExpanded = GUILayout.Toggle(((MyClass)target).isExpanded);
}
}
How can I limit the access to “isExpanded” so that only the MyClassEditor can read/write it?
some thoughts:
Make it private and Serialized, use Reflection to change?
Make a ScriptableObject which contains the “isExpanded” info, but, how can I link the MyClass object to the Scriptable object? In other words, how can I load a scriptable object based on another object: “MyClass”?
that would still enable other classes (at edit time) to still access the “isExpanded” variable.
there’s nothing technically wrong with that, however it doesn’t make much sense having a variable in a class which has no purpose during runtime. IsExpanded is purely used by the editor for the “MyClass” object, nothing else needs to know/care about it.
SerializedObject would require quite a major rewrite of my Editor, I’m dealing with heavily nested data within arrays.
I looked into saving a .asset file with a scritpable object inside, but the flow was a little ugly for the end user. Especially when you’re dealing with Prefabs, Prefab instances and scene objects. I did attempt to create a master .asset file, but trying to keep that in-sync with all objects was becoming messy.
If you truly want each individual object to know whether it is “isExpanded” or not then simply use it within the GameObject as you have and use:
#if UNITY_EDITOR
publicbool isExpanded;
#endif
… as suggested by hpjohn, remember this won’t be compiled into your game so it’ll only exist within the editor, which is what you want? right? In my opinion there’s really no need to overcomplicate this.
However, if you don’t mind it being expanded / unexpanded in the same state for all inspector views for that same type then simply rather use something like:
the “isExpanded” is just an example. When I say Editor only variables, I mean variables which can only be accessed by the CustomEditor for the specific object. Example:
class MyClass : MonoBehavior {
public string myString = "hello";
//do not want this variable exposed to other runtime scripts
public bool isExpaned;
}
class MyClassEditor : Editor {
public override void OnInspectorGUI() {
((MyClass)target).isExpanded = GUILayout.Toggle(((MyClass)target).isExpanded);
}
}
class MyOtherClass : MonoBehavior {
void Awake() {
MyClass mc = GetComponent<MyClass>();
//don't want to allow this below, no other class should be able to access the "isExpanded" property,
//or even know of its existence
mc.isExpanded = false;
}
}
Adding “UNITY_EDITOR” around the “isExpanded” property still allows “MyOtherClass” to access it when running inside Unity.
EditorPrefs are not an ideal solution. Imagine exporting your package to a .unitypackage file and then import into a new project. You editor prefs are lost.
Reflection is super simple:
class MyClassEditor : Editor {
public override void OnInspectorGUI() {
FieldInfo field = target.GetType().GetField("isExpanded", BindingFlags.NonPublic | BindingFlags.Instance);
field.SetValue(target, GUILayout.Toggle((bool)field.GetValue(target), "isExpanded"));
}
}
With some more advanced coding you could probably come up with a way to cache these fieldInfo’s if there’s any performance concern
nothing, and that’s part of the problem. I would prefer not having the “isExpanded” variable in the “MyClass” at all.
Reflection was a simple way to hide these properties (for the most part) while still enabling the custom editor access.
If there’s a standardized way of handling this situation I’d love to hear it. For example, with 2d toolkit, .asset files are created for SpriteCollections and SpriteAnimations which contain editor only data relating to those objects. These .asset files seem to be created in a “Resources/tk2d” directory, and referenced by the objects GUID for lookup. However, since in my API, Components can be created on Scene, Prefab and Prefab Instance objects, sometimes an object doesn’t have a GUID, so creating a .asset file and linking it to its related object is a little messy. For example, creating an object in the scene, adding the component, creating the asset file, then creating a prefab out of that object. As a result, the object receives a GUID and the instanceID changes, resulting in another .asset file, which seems very messy to me.
so without using EditorPrefs, SerializedObjects (which still enables Reflection) how can I save editor only data for an object? given that the object can be a SceneObject, Prefab, Prefab instance and be interchanged between those types.
*The reason I’m doing this - I’m building an API/Editor and don’t want variables exposed in the API that don’t make sense. Say if “MyClass” was “Player” and “isExpanded” was “scrollBarPosition”. That variable doesn’t make sense in the context of Game logic. However, it does in the Editor logic.
I think you’ve covered all the problems & there is, as far as I’m aware having also looked into this, no clean way to separate editor data – because it’s so tied in with the actual object itself. The “cleanest” way (in my opinion, and for your own sanity) to do this still exposes the editor settings within the gameobject however it’s obviously removed from actual game (runtime) api and isn’t included in an actual game compile and that is doing something like this (which I’ve done with some of my editior extensions that required it):
[System.Serializable]
class MyClassEditorSettings
{
public bool isExpanded;
// ... etc ...
}
class MyClass : MonoBehaviour
{
public bool myRuntimeSetting;
public int myOtherRuntimeValue;
#if UNITY_EDITOR
public MyClassEditorSettings editorSettings;
#endif
// ... etc ...
}
At least then it’s obscured from the end-user somewhat and folded into an obvious area. That said, this also allows them access (through the API) to actual editor settings if they need it, for example by extending your editor extension with their own small script to, say, set “isExpanded” to true if they add some other component.
Glad I could (kinda) help. Hope it works for you, at least if you choose to use private/reflection within a separate class it’ll mean you only have to do it to get to the settings object at which point you can just use all your settings normally.