#↕️┃editor-extensions
1 messages · Page 117 of 1
Like OnDestroy but for the editor instead of runtime
OnDestroy is called in editor too. And if it is just GameObjects then what Slim suggested would work.
do I put an [ExecuteInEditMode] attribute?
Also I do need to know what gameobject was destroyed, so having an ondestroy inside it would be helpful
I remember seeing somewhere that a new feature was added in one of the latest versions of the editor, allowing drawing expandable SO inspector within another object inspector that references the said SO. Could someone point me in the right direction? Because google doesn't seem to give any related results...
Kinda like you can expand a serializable c# class/struct
Is it just my imagination? Was there no such feature added?🤔
Do what?
Basically drawing the SO properties in another object inspector(that references the so)
Oh, I see you mean show the editor of one SO in the editor of another unity object?
No, nothing was added for that. But you can already do that as is.
Okay, so how would I do that?
Is there a ready to use attribute that I can just add to my SO field? Or do I have to write editor scripts?
You have to do custom editor stuff. If you are using IMGUI, then you use Editor.CreateEditor.
If you are using UITK then you use InspectorElement
And here I thought I can just do a quick hack without spending time on learning that stuff. 😄 Oh well.
Thanks for pointing me in the right direction though
How can I avoid StackOverflowException in this code?
public class MyDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
PropertyField propertyField = new PropertyField(property); // <- Causes StackOverflowException.
DoSomething(propertyField);
return propertyField;
}
}
I don't know how to get the default property field of the property in order to apply my custom modifications on it.
that code should not cause a stackoverflow
This causes stackoverflow in my editor.
[CustomPropertyDrawer(typeof(MyAttribute), true)]
public class MyDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property) => new PropertyField(property);
}
public class MyAttribute : PropertyAttribute { }
public class MyMonoBehaviour : MonoBehaviour
{
[MyAttribute]
public int MyField;
}
[CustomEditor(typeof(MyMonoBehaviour))]
public class MyEditor : Editor
{
public override VisualElement CreateInspectorGUI() => new PropertyField(serializedObject.FindProperty(nameof(MyMonoBehaviour.MyField)));
}
Doesn't in yours?
i don't see why it should
new PropertyField(property) internal request to Unity all the custom drawers in order to get the draw the specific field. One of those custom drawers (MyDrawer) calls new PropertyField(property). So it is recursive.
Hello, I'm trying to change prefabs by the bulk but the PrefabUtility API doens't seem to be working, can someone help me with this?
var childComponents = prefabLoaded.GetComponentsInChildren<ChildComponent>();
foreach (var comp in components)
{
comp.ListInsideChildComponent.Clear();
}
PrefabUtility.SavePrefabAsAsset(prefab, prefabPath);
PrefabUtility.UnloadPrefabContents(prefab)
This doesn't seem to properly be changing the prefabs in this case.
Because you aren't telling it there is anything to save.
You need to do EditorUtility.SetDirty(prefab_
I still am a dumb and can't get Unity to display the extra stuff in VS
It caused a stack overflow in old versions of Unity, but I submitted a bug report and they fixed it
Ohh, I'm using 2020.3.25f1. I see. Thanks.
yeah. that's why i was wondering. i couldn't reproduce this
I also did that, still didn't change the prefab. Another thing, I tried pressing the "Apply All" or calling the PrefabUtility.ApplyPrefabOverrides which resulted in nothing.
How do I track changes for Undo when the target object does not derive from unity's Object class?
I want to undo a position change but the object is my own class
The class is a field/property on a UnityEngine.Object thought isn't it?
nope
Can you give more context then to what you are doing?
public class StructureConnection
{
public Vector3 position;
public Structure structure;
public StructureConnection connection;
}
I am moving a "connection point" in the scene view and I would like the ability to undo the movement. I also do not wish to use gameobjects since the point is that the game object will be created on that "connection point" later
I am rendering a sphere and handles to that point
Do you save the "connection point" so that it is saved on domain reload(script change or enter playmode)
Or does it reset?
Oh right so I need to same it on playmode, So yeah it shouldn't reset
So where are you storing it so it won't reset?
Well I might be miss understanding you but I have a list of these connection points on a gameobject. I assume that's what you were asking for earlier sorry
yeah exactly lol
So they are fields on a UnityEngine.Object 😛
So do I use Undo.RecordObject() for the List?
Nope, UndoRecordObject() for the GameObject
oh the whole game object? Ok let me try!
So that didn't work
Here is the code:
void ConnectionHandles()
{
Undo.RecordObject(structure, "Connections");
foreach(var c in structure.connections)
{
c.position = TransformHandles(c.position, new Vector3());
}
}
structure is the gameobject
You sure? Last I checked GameObject doesn't have a connections property.
OH hahah omg sorry I mean that's the component. I forget that sometimes im dumb ok hold up
Ok so it still didn't work tho
Here is the change:
void ConnectionHandles()
{
Undo.RecordObject(structure.gameObject, "Connections");
foreach(var c in structure.connections)
{
c.position = TransformHandles(c.position, new Vector3());
}
}
Really I would just use SerializedObject and SerializedProperty instead so it will automatically support Undo and prefab overrides.
how would I do that?
Check the pinned messages
The docs look like they run it in start but I need it to run in editor
using var serializedObject = new SerializedObject(structure);
SerializedProperty connectionsProperty = serializedObject.FindProperty("connections");
foreach(SerializedProperty c in connectionsProperty)
{
SerializedProperty positionProperty = c.FindRelativeProperty("position");
positionProperty.vector3Value = TransformHandles(positionProperty.vector3Value, default);
}
serializedObject.ApplyModifiedProperties();
Probably want to the SerializedObject instead of creating and destroying it though.
I am getting errors. The "FindRelativeProperty" and "Vector3Value" is red underlined
Both have do not contain definition errors
Well I wrote it in discord so there is going to be some typos haha
You should be able to start typing and get suggestions
no cause "c" is an object type and so there is no methods on it
Alright, I edited it
Oh I see, ok so its closer but now there is null reference errors for the return value of "serializedObject.FindProperty("connections")"
also whats the "using" for?
"connection" should be the name of the serialized field (not the property name)
It just calls serializedObject.Dispose() at the end of the method to dispose/release the SerializedObject.
so whats the serialized field name
You tell me 😛
I dont know what that is
you gotta understand that I don't know whats happening or what this all means
[SerializeField] private float _thisIsASerializedField;
this is what I have:
[SerializeField] public List<StructureConnection> connections = new List<StructureConnection>();
So unity serializes fields. Any public field or field with the [SerializedField] attribute.
These fields are shown in the inspector, and have their values saved to file etc.
What the SerializedObject does is allow accessing those saved fields values and getting/setting them directly.
Oh ok cool I see. So then why does the connections field show null even though I put [serializedField] on it
It... shouldn't
rippy dippy cause it does
What line does the exception take you to?
SerializedProperty connectionsProperty = serializedObject.FindProperty("connections");
That means serializedObject is null.
How do I create an EditorWindow (for which I already have a ready script with ShowWindow whish is supposed to be called to show the window) from another script? I'm asking because EditorWindow is an SO and it's not recommended to create them with new and also making the method ShowWindow static would mean I can only use static variables inside the method and static variables can't be saved into the script meta via Inspector
It's like I have a button in an Editor and what to show an EditorWindow once the button is pressed
You can still call a public static ShowWindow method, and return the window, allowing you to use the fields in that window
Static methods can be called anywhere, not just in other static methods/classes
But as I said I won't be able to use non-static vars inside it, no?
Sadly that isn't working, I tried doing:
{
var prefabLoadedContents = editingScope.prefabContentsRoot;
var components = prefabLoadedContents.GetComponentsInChildren<CustomComponent>();
foreach (var comp in components)
{
Debug.Log($"{comp.name} {comp.ArrayInComponent.Count}");
comp.ArrayInComponent.Clear();
Debug.Log($"{comp.name} {comp.ArrayInComponent.Count}");
}
}
And the fields in the child of the prefab don't change. However if I make any changes to root it works. The count print works perfectly, it shows it's filled before and that it was changed, but nothing applies.
Won't be able to use non-static vars where?
In static ShowWindow
@wintry trout
You can get the reference to the window that is being shown and set fields:
public static void ShowWindow()
{
CustomWindow window = EditorWindow.GetWindow<CustomWindow>();
window.foo = "bar";
}
This way I can use only static fields, but if I want to SerializeField something, it will be non-static
So I can't use anything serialized this way
you can still access non-static fields from the window itself
where are you trying to access data
if it's not from the window
You could make a method that the button calls and handle non-static fields in that method?
Sure I can
I have an Image with RenderTexture inside it in my EditorWindow but seems like the EditorWindow (and specifically the RenderTexture inside the Image) gets update only when cursor is over the EditorWindow, is there a way to fix it?
Requireconstantrepaint I believe is a thing now, you can also just call Repaint() after changes are made
what is Requireconstantrepaint ?
can't find it in net
If I remember correctly it's either an attribute or a method, one sec
Phones about to die, just call Repaint() at the end of your gui method and it should work
ty
doesn't fix btw
Hmmm send the code, you may be updating the texture in a weird way, @limpid linden is usually pretty good at finding that stuff
I got annoyed with the coloring system in unity so i made my own fix. If anyone wants it then dm me but i just came because i was bored
but ill also put it here
why did you package it as a unitypackage if it is literally 1 script
true that
Making an Editor button which changes value of a Vector3 field existing inside of the inspected class. But my changes do not get applied for some reason. Any ideas why? (code block from the Editor class)
private void OnDisable()
{
Debug.Log(_agent.cameraPlacementOffset);
Debug.Log("are they equal? " + (serializedObject.FindProperty("cameraPlacementOffset").vector3Value == _agent.cameraPlacementOffset));
serializedObject.FindProperty("cameraPlacementOffset").vector3Value = _agent.cameraPlacementOffset;
Debug.Log(serializedObject.ApplyModifiedProperties());
DisposeOfCameraStuff();
CloseCameraWindow();
}
ApplyModifiedProperties returns true if any changes were applied
The values are the same so no change is made so there is nothing to apply.
but how is the field of the serializedObject the same if it doesn't get serialized after???
Basically SerializedObject holds a copy of the serialized values of the object when the SerializedObject was created. ApplyModifiedProperties tells it to set any changed properties it has back to the original if you will
But how can the values be equal if I didn't save anything into the SeralizedProperty itself?
Because they are the same? How about you debug.log the serialized property too serializedObject.FindProperty("cameraPlacementOffset").vector3Value
I don't need to debug it, I already have previously shown debugs...
But I never saved anything directly into the SerializedProperty so it confuses me why it changed and why this change doesn't get serialized after
There is no change to serialize. Want to share the full code?
Sure I can
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
(I'm going to bed in a couple of minutes here, so sorry if I am a bit curt)
You're mixing direct access and SerializedProperty. Don't do that.
It makes things messy and is most likely what is causing the issue
Any place you access _agent.cameraPlacementOffset you replace it with serializedObject.FindProperty("cameraPlacementOffset").vector3Value
Though you should cache the the Serialized property by getting it in OnEnable and setting a field to id so you can access it easier and faster.
Gonna try
Changed it in saving and creating handles, doesn't work
Also now the changes to the value aren't shown in the inspector and can't be used by other code, such as prefab mode assistant camera
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
new variant, if you are still here
Uh, something feels wrong but I can't quite say what right now. I'm too tired for this haha.
I will give you a bit of homework though. Don't touch target or anything to do with it. If you want a value (to get or set it) use serialized property. Otherwise it won't save property, won't support undo, and wont support overriding with prefab variants. So try switching it all over to that.
I will @ you when I get up tomorrow to see if you are still having trouble 🙂
sure
i have this bitmask enum
[Flags, EnumToggleButtons] public enum ActorTypes { Player = 1 << 1, Enemy = 1 << 2, Wall = 1 << 3, Spawner = 1 << 4 }
but i want if i selected Player , automatically Enemy and Wall turn off , or if i selected Enemy , automatically Player and Wall get turn off
the only thing that can be selected with others, should be Spawner , for example i able to select Wall and Spawner
i searched a lot, and did many trial & error, but couldn't make it
i'm drawing with Odin , i tried what u said, but it didn't work
i will go with simple solution, spawner out of enum
how can i create nested scriptable object ?
awesome thanks
any idea why SerializedReference won't work with System.Object?
Do we need to make a wrapper for it to work?
it works with interfaces and abstracts, but not System.object, even the doc clearly states it is supported https://docs.unity3d.com/ScriptReference/SerializeReference.html
I was blind! didn't see the Must not be a C# Value type
Did ya get it working?
No
what is the correct way to get this label text to align itself after where the label title would be, so in this picture start should be aligned to the start of the slider, and if the inspector gets resized it should stay at the start of the slider
remember to call serializedObject.ApplyModifiedProperties(); at the end after you update a serialised property
between 105-107 i think you didn't call it at all, so the change isnt updated
every time? I was calling it only in OnDisable
OnDisable is called when you leave the inspector for that object, instead, call it at the last line of OnInspectorGUI()
lets try
actually, i think you have other spots where you edited the serialised property, you should probably also call it at the end of OnSceneGUI()
it works
great
then should I ponder about it too?
probably you should add it as well, OnSceneGUI is called when the scene view is modified in editor mode, so if there is some instance where the inspector isnt used , such that OnInspectorGUI isnt called, but the scene is changed, the property may not be serialised if it is not applied
Thanks
Can you tell me a bit more about ApplyModifiedProperties? Like in its docs it isn't said that I need to call every time I change a value or how it works
you actually only need to call it once, at the end after you update any number of serialised properties. Serialising a process that Unity performs to save the value of the property somewhere, such that when you come to the same property, Unity puts the saved value back to show it to you. Once you leave the inspector, the editor values are temporarily lost/reset to default, but will be restored when Unity retrieves from its serialised data. Otherwise, if there is no serialised data, it will remain as it was. When you're changing the values/references, you're changing properties in script. Apply modified properties ensures that Unity performs the serialization process so that the references/values are retrievable when when come back to it. If it is not called, then the latest serialised value/references remains as it was before the change, which is why you were not able to see the value changing just now, because it was not serialised after the change
But I was successfully using Handles, modifying values in the target script. Where were Handles taking the values from then?
if you are modifying values in the target script, then you're not using the serialised properties, you're just directly modifying the properties and hoping that unity serialises them properly. Like the other person said above, you probably should not mix access properties publicly with serialisable properties, as it does not always guarantee that the value will be serialised, although this may work for you now. Sometimes, when working with prefabs, directly accessing public properties and modifying them can cause the value to be reset to the prefab value when you leave and return to the inspector, instead of the modified value, if we do not use the serialized properties - it is not a good idea generally, I would still recommend using the serialised object and applying the changed properties to it
So when I apply changes the target changes
But when I change target, seralizedObject isn't affected...
sometimes, it is possible that if you change target, the serializedObject may remain unaffected. It's not very consistent. But if you apply modified changes, unity will make sure to serialize all the modified fields for you, its an explicit way to ensure that your changes are saved
if you change only the serialisedProperty but do not apply modified changes, the change is registered by the target, but whenever the inspector updates again, it retrieves the latest serialised data that overwrites your intended change again
So what's the target? Isolately created copy of MB?
the target is just your script
But why can't I just apply at the end?? Why do I have to do it right after modifying? What is the technical reason for it?
you can apply it at the end
It doesn't work for me
there's nothing wrong with applying at the end of the function call, but it must be somewhere after the change
Not at the end of function call, in OnDisable
OnDisable is not immediately called after OnInspectorGUI or OnSceneChange, your changes will not be saved if you call it there only - your latest unsaved changes are being overwritten constantly by the latest serialised data (the one before the change) that unity has everytime it updates your inspector
If they are overwritten constantly, why do my Handles move?
because... your handles are not using the serialised properties right? You're directly modifying the script properties and fortunately in this case, they are being serialised properly. But look at line 105-107, here you are using the serialised properties, but you did not apply them, so they are being overwritten by the last saved serialisation
wait hang on a second
no you're not directly changing the properties
the handles are taking the values of their own transforms within the scene, this isn't dependent on your script (I assume)
the position of the handles in scene is independent of your script
Let me tell you how I understand the topic so far
target is an instance of the inspected MB which is not supposed to be serialized (saved outside of RAM) but currently existing in RAM.
That's why I can change its values and use them.
serializedObject is the serialized data for the MB (probably in JSON or something similar).
So when I request data from it I do not get the changes by Handles unless I serialized this changes. That's why it is impossible to move Handles unless I serialize the data right after change.
So when I was directly modifying target and then trying to apply changes to serializedObject there was nothing to apply as non changes were made to the serialized data, only to the object in RAM
something like that, @glad mica
Actually, after writing it all down, it makes perfect sense
And probably once I apply changes to serializedObject target gets loaded from the new info
yea, something like this
I did, sorry. I see you were talking with White Bunny. Did you get it figured out?
Yea
Really late, but you can use EditorGUI.PrefixLabel or EditorGUILayout.LabelField
A small correction. target is the UnityEngine.Object (MonoBehavior), not an instance of it.
I have an custom editor script that continues to cause ArgumentException: Getting control 1's position in a group with only 1 controls when doing repaint when altering a serialized property that is a list. It happens that this location:
if (units.Count > 0)
{
EditorGUILayout.LabelField("Click to Delete");
EditorGUILayout.BeginHorizontal();
...
I am not sure what other parts of the editor I need to share but it only happens in this script where I have a conditional based on the the property being updated
you wanna say it is a class and not a class instance?
MonoBehaviour comp = ..;
var serializedObject = new SerializedObject(comp);
serializedObject.target == comp; // this is true.
wtf
If you do something that changes the amount of things being drawn, call GUIUtility.ExitGUI, which throws an exception so IMGUI doesn't freak out on the Repaint phase
got it
so is the target a property of serializedObject? (in an Editor)
What do you mean?
whether target == serializedObject.targetObject
Yes those are the same
nice
@visual stag so based on the code below where exactly do I put that ExitGUI?
...
if (!string.IsNullOrEmpty(addedUnit))
{
unitIds.Add(addedUnit);
UpdateUnitList(unitIds);
addedUnit = null;
}
if (serializedObject.ApplyModifiedProperties())
{
(target as UnitStack)?.UpdateMarker();
GUIUtility.ExitGUI();
}
...
private void UpdateUnitList(List<string>unitIds)
{
_unitProperty.ClearArray();
foreach (var unitId in unitIds)
{
_unitProperty.InsertArrayElementAtIndex(0);
var unitIdEle = _unitProperty.GetArrayElementAtIndex(0);
unitIdEle.stringValue = unitId;
}
}
Not sure what's going on, but put it at the end of the logic that you ran that led to the exception being called. I imagine you clicked something that changed the amount of things being drawn, so after that logic
This is actually being done at the end of OnInspectorGUI. One one call I open a dialog (EditorWindow) and select value that gets set to a variable in the editor script. On the next call that is when I apply that value. So literally where I have that Exit call is the end of inspector gui call
I can DM you the entire script if you want
Just link it here using the instructions in #854851968446365696
if (remove != null)
{
unitIds = unitIds.Where(id => id != remove).ToList();
UpdateUnitList(unitIds);
serializedObject.ApplyModifiedProperties();
GUIUtility.ExitGUI();
}
Something like that
The Screenshotter. You know what it does
Just rotate the main camera to adjust the position
found this api, correct me if I'm wrong.. does it mean that we can reference sceneObjects in a scriptableObject now ? https://docs.unity3d.com/ScriptReference/ExposedReference_1.html
Yes, ish. You can but you have to have a component in the scene that holds the references and then to get the references from the field on the SO you need to pass that component to it.
ah ok, so it's still a little hassle to work with.. I'll test the api.. Thanks my dude! 👍
ah got it thanks, an empty prefix label got it to align properly
Im new to unity and acceindently did this how can i fix it
@unborn bear This is not related to editor extension. Reset scale and rotation.
Hey, I am making an editor tool to find an object under the mouse.
But when I raycast in the SceneView it's not really accurate. The more to the right in the Scene view it is the more I have to aim off to the side of the object to hit it.
Ray ray = SceneView.lastActiveSceneView.camera.ScreenPointToRay(Event.current.mousePosition);
Do I need to account for the SceneView resolution and position in the editor somehow?
Actually it's inaccurate even if I detach the Scene panel and fullscreen it. What might be causing the ray to miss so much?
Is it possible to add a button to the unity bottom toolbar?
Tracking Custom Handles to Mouse
Yeah, iirc but not easily. Takes a bunch pf reflection and stuff.
hi, does someone know a extension for this ? i don't wan't to write it from scratch as i'm pretty sure there's a good option around, however i could only find 1 and it's inspector are bugging, the list elements are overlapping
You could use OnValidate() to calculate the value that each of them have
Upgrade your Unity version. Some versions do not have the fix, but it's an editor bug.
Hi, I try to add EditorGUILayout.Foldout but it does not fit correctly. It is too far left. What can I do and move little bit? I added BeginHorizontal too see the full foldout.
anyone knows where I can access this api https://docs.unity3d.com/Packages/com.unity.2d.animation@3.0/manual/CharacterRig.html
Planning to make a custom 2D rigging tool of my own for my vscripting library
Look into EditorGUI.indentLevel
you can shift the indent over for the foldout (and then once more for its contents)
the GUIContent (the icon) does not get considered when it comes to adjusting positions in groups or containers
ah yes, finally.. thanks 👍
Does anyone have any resources on how to unit tests editor extensions?
I had an ObjectField in my code that was not updating the attribute it had to, because I forgot to write it. I would like to write a unit test, to make sure it doesnt happen again. But I have no idea how to unit test those things.
I'm very confused about custom attributes and building. I have a custom attribute in an asmdef that is editor only. But I can't build my project because obviously, during building, the classes that use that attribute are throwing errors. How am I supposed to fix this?
public class EnumButtonAttribute : PropertyAttribute
{
}
[CustomPropertyDrawer(typeof(EnumButtonAttribute))]
public class EnumButtonAttributeDrawer : PropertyDrawer
{
}
And my asmdef is like this:
The drawer should be in the editor assembly, and the attribute the runtime
Oh that makes a lot of sense, thank you!