#↕️┃editor-extensions
1 messages · Page 97 of 1
@gloomy chasm hey u said u could get it through reflection?
I'm trying to do the same without using fieldinfo
That even possible?
I even tried printing all the properties inside the Target object through reflection, but that just printed the properties of the game object it's attached to
So we have access to it's game object, but not its own object?! That's ... Seems not practical... Or maybe I'm missing something?
Can you give some more context
let me just show u the debug , maybe it is in fact its own object
I printed all the properties from getProperties(). None were the object we were drawing ( I'm talking about inside property drawer)
The property you get passed is the object
If you want an instance and it's a non Unity object then you have to use reflection no other way
It is reflection , mate. I'm talking specifically about reflection
yeah I'm tryina open Unity. My PC just shut itself down because of power
I dunno why steam opens itself everytime PC is restarted... Even with it's checkbox disabled ( and it's as an administrator )
so, this :
var parent = property.objectReferenceValue;
var props = parent.GetType().GetProperties();
prints this :
Boolean useGUILayout : True
Boolean runInEditMode : False
Boolean allowPrefabModeInPlayMode : True
Boolean enabled : True
Boolean isActiveAndEnabled : True
UnityEngine.Transform transform : Main Camera (UnityEngine.Transform)
UnityEngine.GameObject gameObject : Main Camera (UnityEngine.GameObject)
System.String tag : MainCamera
System.String name : Main Camera
UnityEngine.HideFlags hideFlags : None
@wanton arrowhey, i remembered what it was i was using ! it's
var target = property.objectReferenceValue as [name of your object];
That doesn't work for non unity objects
yeah...
Anyways, you can use the property.propertyPath field to determine what properties you need to traverse to get to your struct/class
Then use reflection to get the value of that field
That is what I do here if you want to just use it. https://github.com/MechWarrior99/Bewildered-Core/blob/main/Editor/Extentions/SerializedPropertyValueExtensions.cs
I mean helper function
works for just any class. be it monobehaviour or not
It can get tricky to make sure it supports serializing by reference with the [SerializeReference] attribute.
I mean I can try it but theres no way it works
its not like it can magically hold a value that It isn't
Safe casting works, but non unity types are not exposed in objectReferenceValue and thus you'll get null
yeah
see, considering this class is named Rotatable, i even have access to it's private variables this way
you can't cast an Object to a Non-Object
lemme see the whole thing
the whole thing is a big class consist of 170 lines though...
but this system.serializable is important
In this case it is not important since it is a MonoBehaviour which is a UnityEngine.Object which Unity already serializes without the System.Serializable attribute.
Normally you would be right though.
yeah i see the prob...
Also directly accessing fields like that is frowned upon
@gloomy chasmhey sorry for keep askin , but will this work without probs ?
full code. the class is not of type UnityEngine.Object
or this, to be safer with builds
then with this, it also now saves the property
this would show how it can also use private properties ( i mean c# properties with set/get )
(though it wont work on arrays)
Why not use SerializedProperty? You're just making things complicated for no apparent reason
for using c# properties ( which is not possible with SerializedProperty)
If you're making a property drawer for something that has some property logic in it why not just copy that logic to the drawer if you need it
that's not a good practice. you may wanna use the property as part of the logic for the actual class. beware that any editor script you write will be literally deleted in the final build
Sure, you can have the code in both
copy-pasting same code in multiple places is also not a good way a good programmer would do...
imagine you needed to change it and u already copied it to 9 different places
To me messing about making some over complicated property drawer that bypasses editor functionality and isn't guaranteed to dirty things that the property could touch is bad practice
nah it is guaranteed. the SetDirty is not supposed to mess things up , mate
You do you then
what do u mean :?
I'm not here to argue, if you wanna do it this way go ahead 👍
whatever...
@visual stag as for the complexity u mentioned, it'd be wise to turn the nasty part into some method :) now it's as clean as an Editor's OnInspectorGUI() ... even less code than that ;)
yeah making things simple to use is a major factor
Though, it doesn't support undo
even that's possible with some tweaking ;)
Sure, none of that's the issue I have with it really.
im not gonna argue with u about choosing the easier (lazier ? ) way to achieve less functionalities while two more new lines would open up a whole new potentials !
seems like just using CheckForChange does that . the Apply thing wasnt needed at all
even gives this blue effect
You're setting the property via a property field, that does it
yes
And seeing as it's a property drawer it added the blue to the declared area
The change check is irrelevant to that functionality
Begin-end property handles the blue actually, but not sure if it's required in a property drawer
Could be wrong though
yeah i dont know too, but i read it in docs sometime back , that it's needed for some behind the scenes stuff which im not remembering correctly. so im just adding it for being sure everything is alright
i tested it though. the blue magic only happens if we change something from the property , so i assigned the serialized hidden value from property to non-serialized target value. so the non-serialized could be used to save thorugh the serialized one
this is the properties i tested with
So much redundant work for little to no gain
sorry, this was
i dont know, sometimes this little C# properties save lots of hours of time. for me personally I always find myself using them over GetValue/SetValue , which is a c++/java thing to do , but properties are C#-ish and i personally use them everywhere
definately depends on usecase though
You're setting the backing value to the value that sin returns, which then executes sin again on it when you use it again
Yes it changes all the time , which I did to test
I'm at a bit of loss as to why this is so slow. I right-click to make a node. I left-click on the node, but notice how long it takes for the UI to go from painting a Label to instead painting a textbox. That's in real-time.
Guessing you need to call repaint
I want to make a field in my custom editor that lets you pick an image from the assets in your folder, like the native Image picker.
But I cannot figure out which Editor class has the functionality to make such a picker.
Which picker speicfically?
So if you wanna work with UI Images in Unity, you have a picker for that specific thing. You click it and it opens up your asset folder so you can look for the image you want to insert.
How would I achieve that for a custom editor?
It's just an object field
^
When I tried to use an ObjectField the IDE said it was obsolete.
Differnet overload
Use the overload that isn't
Yes, look at the docs
ok
Can I somehow give the ObjectField a Rect so I can control better where I want it to be on the screen?
Or is that in the GUILayout options somehow?
EditorGUI
Thank you
It was pretty hard to search for this stuff because I didn't really know what to search
Though, as I often say if anyone's making a node tool in Unity these days if it is at all complicated it's best to use GraphView, which is Unity's built in library for node editors (there is a tutorial pinned to this channel)
It has a learning curve as it uses UI Elements, but so does IMGUI, and it doesn't have scaling for free
I wanted to avoid UI Elements because it's a dependency that not that many people seem to have jumped on yet
It's there in every version since 2018
I've tried to install it before in different versions and I had several issues with errors even when I didn't use it. I generally stayed away from it after that until someone would be like "Yeah it's good now."
There is no need to install anything
Editor has had it built in and functional for many versions now
UIBuilder and runtime UI are a different story
Hm
Okay
So far I'm doing okay with IMGUI. I think after I get to a point where I might be okay with this version, I'll try UIElements
So I'm having some issues using OpenGL to draw a line. As you can see in the gif, the line is always offset quite a lot. If I move the node around the lines origin and end point will also change relative to the nodes location..
private void DrawLine()
{
if (_isConnecting == true)
{
Event current = Event.current;
if (current.keyCode == KeyCode.Escape)
{
_isConnecting = false;
}
else
{
GUILayout.BeginHorizontal();
Vector2 nodePos = _nodes[_mousedNode].CanvasRect.position;
Vector2 mousePos = current.mousePosition;
if (current.type == EventType.Repaint)
{
GUI.BeginClip(_gridRect);
GL.PushMatrix();
GL.Begin(GL.LINES);
GL.Color(Color.cyan);
GL.Vertex3(nodePos.x, nodePos.y, 0);
GL.Vertex3(mousePos.x, mousePos.y, 0);
GL.End();
GL.PopMatrix();
GUI.EndClip();
}
GUILayout.EndHorizontal();
}
}
}
One thing is the origin point maybe not being correct, but even the mouse position is not correct either so what am I missing about the GL.LINES
Is the node's position perhaps relative to the canvas and so is not taking in to account inspector thing on the left?
Hm, I tried to subtract the Left panel from my X value but that didn't adjust the value as expected
This is practically perfectly on the mouse. But I don't get why 1.6f is the difference.
GL.Vertex3(nodePos.x - (node.CanvasRect.width + _gridPadding), nodePos.y + node.CanvasRect.height * 0.5f, 0);
GL.Vertex3(mousePos.x - (node.CanvasRect.width * 1.6f), mousePos.y, 0);
Does moving the editor window change where the lines are drawn? (I can't remember of GL works per window or on screen)
Again, this is all taken care of with GraphView, I really do recommend using it instead.
Careful of the sunk cost fallacy 😉
Oh it's just a free tool I'm releasing on my open repo
after that I can look at a GraphView version
Hi! I've drawn a reorderable list and wanted to customize the add/remove callbacks, but i'm faced with a problem: how can i indicate the actual selected element properly?
My callback for now:
private void OnRemoveCallback(ReorderableList list)
{
//indexToDelete = list.focusedElement;
ActionSO toDelete = (ActionSO)leafActionsSp.GetArrayElementAtIndex(indexToDelete).objectReferenceValue;
DestroyImmediate(toDelete, true);
if (leafActionsSp.arraySize != 1)
{
leafActionsSp.MoveArrayElement(indexToDelete, leafActionsSp.arraySize - 1);
}
leafActionsSp.arraySize--;
}```
And of course, list.focusedElement is a pure product of my mind and does not exist. Any tips?
No, the sunk cost fallacy is when you have put so much in to something already(whether that is time, or money, or something else) you feel like you would lose all that if you stopped to do something 'cheeper'. When in actuality you spend even more on the thing then if you had just switched to the other thing.
I know exactly what Sunk Cost Fallacy is
This is not that, because I'm not keeping from switching due to a lot of time used here that I don't wanna feel like is wasted. I wanna finish this so I can make a Graph View version after this.
Alrighty, suit yourself! 🙂
It's nice learning
list.SelectedIndex
Yeah, for sure!
Think so?
well, one way to find out lmao
Yup. And you can always see what comes up when you type select
If you are using VS, you can click on the ReorderableList class and hit F12 and it will show you all of the methods and properties of it.
:/
Does index work?
this index variable works though! hehe
Good.
thanks a bunch!
Do i have a fan
yooooo no way
my spanish teacher named me this way 5 years ago
since then, i was reborned
is there an easy way to get this to just draw with the GameEvent propertyDrawer?? I want to be able to make tons of these and just change the default message
its [System.Serializable]
sorry I found it its setting the second param (useForChildren) in the [CustomPropertyDrawer] to true 
I know this is old, and forgot who asked, but, as i keep learning, I came across this (Event.current.type == EventType.ValidateCommand && Event.current.commandName == "UndoRedoPerformed") that can be used in undoing
Does anyone know how to use serializedObject.ApplyModifiedProperties to save properties on a scriptable object?
Undo.undoPerformed also works.
You call serializedObject.ApplyModifiedProperties() when you want to save the SerializedProperty's values that changed.... idk what you are looking for sorry.
I've got a scriptable object that's not saving a list when i play the game, I'm thinking it's something that can be fixed with serialize object
Are u also calling serializedProperty.Update() ?
Oh, I'll try that
you can also simplify the code a lot
public class BlockedGameEvent : GameEvent
{
public override string GetDefaultMessage(object o)
{
return (o is Exit e) && !string.IsNullOrEmpty(e.keyString) ? "This exit is locked" : "This exit is blocked";
}
}
When i exit playmode, i get spammed in the console, Relating to if((Selection.Contain))
How can i solve this?
Does anybody know which element do i need to modify in order to overwrite the row and column labels?
i mean the 0,1,2,3.....
i cant find how to modify that
first, value == null will never happen when checked this way as a bool returns false or true. You either need to make bool a nullable type or change the logic. Other than that, the code for those labels isn't present in the code you showed, so, I'm assuming you have a loop somewhere that is using Drawer and is using some kind of field to display which index number that is.
yes i know value==null will never happen its because i was using another type but chaged just to see how to modify that
the field that displays the index is probably being drawn automatically by Odin
but I was expecting to be able to overwrite it from inside the drawer
Oh, I don't know anything about Odin, so without more code, I can't really help, sorry :/
just... which is the correct property i have to modify?
i mean..
LabelField creates a label inside
I have no idea based off the code you gave. The code you gave is displaying the label correctly
i mean the labels in the sides... the 0,1,2 are those for unity the same as the ones with 'myLavel' text?
what i want to change is the 0,1,2.... and i was wondering if thats another type of control or.....
the labels inn the sides and the top i mean
again, whatever method you are using to determine how many of those labels to use, is where the code probably is for those labels
IDK how you have your IDE setup, but, you can sometimes click on method names to open up the file they are located in
sorry again, I haven't used Odin so can't really help directly with that. I like to try and make all my own things haha
yeah sure, no prob, probably i should try to create the matrix by myself
unless the odin guys help me with this
How can do in visual studio after I right a dot(.) it give me options on what to write?
Just do a null check on the GameObject first.
Hello guys, any ideas on how could I stack 100 prefabs, one on top of another exactly, a distance of approx 4 units? It's to make multiple floors in a building
as in... if (( Selection != null && Selection.Contains(gameObject))) ?
since i dont know how gameObject can ever be null
No, a class can never be null... (or any value for that matter)
What is GrassPainter? Whatever it is you are trying to access it after it has been destoryed. So put a null check before where ever you are accessing it from.
@gloomy chasm Its an asset used for painting grass, sometimes when i leave playmode, it'll spam the console with errors indefinatly untill i close unity and reopen it
I gave you the solution.
if (gameObject != null &&(Selection.Contains(gameObject))) i will try it
No, reread my last message where I ask about grassPainter.
that part of code is inside GrassPainter
Just read the console error, it should be clear how to fix it and if not just copy paste in to google and someone will have already asked what the error means and how to fix it.
got it, thank you 🙂
i didnt got it, i googled some forums, and it says its todo with a bad unity version? I'd understand if i was instantiating things in OnDestroy but im not
if (gameObject.GetComponent<GrassPainter>() != null && (Selection.Contains(gameObject)))
sorry guys, I know these are noob questions, but, I'm trying to take advantage of propertydrawers more. I don't quite understand the difference between public override VisualElement CreatePropertyGUI(SerializedProperty property)
and doing
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// Using BeginProperty / EndProperty on the parent property means that
// prefab override logic works on the entire property.
EditorGUI.BeginProperty(position, label, property);
I read If the PropertyDrawer is used inside a UIElements-based inspector or EditorWindow, the UIElements implementation will be used if PropertyDrawer.CreatePropertyGUI is overwritten with a fallback on any IMGUI implementation. If the PropertyDrawer is used inside an IMGUI-based inspector or EditorWindow, only the IMGUI implementation will display. You cannot have UIElements running inside IMGUI
So, does that mean one is used in editorwindows, while one would be used for inspectors, but, isn't the inspector an editor window? Why ever use one over the other instead of one that can be used in both?
It means that if the thing drawing the property (Editor or EditorWindow) is using UITK then CreatePropertyGUI will be used.
Currently all Editors for components use IMGUI unless you make a custom editor for the component and use UITK. So if you only use CreatePropertyGUI then the property cannot be drawn by default in the inspector.
EditorGUI.PropertyField(..) is IMGUI and will use OnGUI(..) (This is how the inspector works by default), where new UnityEditor.UIElements.PropertyField(..) is UITK and will use CreatePropertyGUI if it is implemented, otherwise it will use OnGUI.
is there a benefit to using UIElements over IMGUI? I see that the fallback exists for IMGUI, but, you an IMGUI inspector takes priority. Should I try to make everything in IMGUI? I know we talked about the UITK before and part of why this is coming up is trying to delve more into these things it made me wonder if I should waste my time with it?
UITK generally has better performance, and is much easier and much faster to style. If it is a PropertyDrawer, I would use IMGUI still, but personally I use UITK for everything else.
I find it's harder to style UITK to "look like" another control, which I find myself doing in IMGUI a ton, but I'm in mostly the same position
"look like" in what way? I guess if you want to mimic the look of a more complex element that you can't just add a uss class to, than yeah IMGUI will still be a bit easier.
I pass different EditorStyles to controls all the time, ones that don't match the type of the control. Making toggles look like buttons is a main one
Ah yeah, yeah.
To get any of that done in UITK I have to do a lot of experimentation, exploration of their codebase, mess around with making my own classes, it's really time consuming
Oh really?
When they get back to making editor stuff UITK (once they're settled with their runtime stuff) I'll be happy 😄
They are so inconsistent with their use of UITK in the editor xD
But I too will be happy when more of the editor is UITK. They finally made ListView be able to fully mimic the ReorderableList.
At least you can easily use IMGUI in UITK, that means you can always make the base of something UITK and then give up
Oh thank god
LOL
that was one of the main reasons to not use it
*in 2021.2 beta
They also made it so the items can have variable height now.
Oooh that's gonna be a bit of a game changer
They must of done massive refactors of the ListView like 4 times now...
It has changed so much.
We're likely going to finally get a UITK channel btw. I think we must just be finalising something
Which is rather annoying since I have used it used it in 'advanced' ways and had to re-implement stuff my self like reordering in 2020.3.
Oh really!? That's great! I wonder how much editor stuff will/should be in that channel.
I have only made a few basic things that didn't exist in the past, HelpBox is one that comes to mind. Everything else I've run into has just been a "fuck this" moment
How much do you want to bet that they never actualy rename the namespace from UIElements to UIToolkit?
Anything UITK-specific should probably move there, I think the separation is clear enough. Though runtime will be more and more of UITK as it gets more feasible to use it
I would be a tiny bit worried that it could get messy, but hope not. Either way having a UITK specific channel will be nice.
Anyone aware if this UV mess of the LineRenderer corners is fixable in some way? Or should I consider using a 3rd party asset or code my own renderer instead? 😅
Wrong channel, wouldn't expect it to be easily fixable though
I'm still getting this spammed to in the console after playmode, I've tried to check if the component is null or not but it just wont stop
Relating to line 109
Had a similar issue. Fixed by nullchecking this, then this.gameobject
Let me try it
You're probably not unsubscribing from an event
That seems to of done the trick
this is an asset, i didnt think i'd have to go into it and fix it haha
As in from the assetstore?
If so leave a bad review
Especially if you paid for it
Nah, its MinionsArt grass shader, free on her patreon
i dont know if you know about them
Ah, bad luck then
ha! im using the same asset.
fun thing about the way they set that up is the grass length is tied to uvs, so you can update the height at runtime 🙂
Can i dm you about it? I have some questions 😄
Sure
is there a way to draw Handles.PositionHandle with only the X & the Y axis ?
the available arrow handle is lacking return values so i can't use it to move stuff
Think you'd have to look at how it's implemented internally and copy it
ArrowHandleCap is a Cap function
you provide it to other functions
in this case, Slider I think
thanks
working on a custom A* :)
is there a way to capture scene save event ?
I have cloned a material from sharedMaterial during edit mode ( instead of using renderer.material which will be used in play mode )
but when i save the scene the cloned material is invisible
the render shows MyMat ( instance ) in the field , and it still exits but it won't render
my guess is that the instance variables are reset ... so im looking for a way to listen to Scene Save Event - so i can reapply the material properties
ok i solved it , so here is what i did
class MyMono : MonoBehaviour
{
public static event System.Action OnSceneSave;
#if UNITY_EDITOR
class ListenToSceneSaveEvent : UnityEditor.AssetModificationProcessor
{
static string[] OnWillSaveAssets(string[] paths)
{
var active = SceneManager.GetActiveScene().path;
foreach ( var path in paths )
if( path == active ) OnSceneSave?.Invoke();
return paths;
}
}
#endif
void OnEnable() => OnSceneSave += StartDelayedValidate;
void OnDisable() => OnSceneSave -= StartDelayedValidate;
void StartDelayedValidate() => StartCoroutine( DelayedValidate() );
IEnumerator DelayedValidate()
{
yield return null;
OnValidate();
}
void OnValidate() { ... } // <- code for material property update
}
😉
thanks , it works as well
on the plus side , don't need the delayed callback anymore
Can I turn off objects in a certain layer in the scene editor?
I mean hide not turn off
Top right of Unity, Layers dropdown.
Tyvm!
I have a CustomPropertyDrawer that I want to, in some cases, show a popup editor window- just for display purposes. In particular a Popup window type (https://docs.unity3d.com/ScriptReference/PopupWindow.html?_ga=2.2619440.1834653439.1632164879-1758085936.1506183559) but it SEEMS like as soon as the window is opened, it closes immediately, and so, blinks on screen. Can I NOT use editor windows for display purposes, from inside a customPropertyDrawer?
[debug logs show that everytime I call PopupWindow.Show my popup content class shows BOTH a onOpen and onClose get called.]
PopupWindowContent.OnClose is called when the popupwindow is closed, so, if you have a debug inOnOpen and OnClose of course it should show a debug for those. You haven't provided any code, so, I can't really say for sure, but, somewhere you are opening and closing it, which, I would assume is in your propertydrawer based on the question. Make sure you aren't creating a new PopupWindow every time.
specifically, this example is important to reference
void OnGUI()
{
{
GUILayout.Label("Editor window with Popup example", EditorStyles.boldLabel);
if (GUILayout.Button("Popup Options", GUILayout.Width(200)))
{
PopupWindow.Show(buttonRect, new PopupExample());
}
if (Event.current.type == EventType.Repaint) buttonRect = GUILayoutUtility.GetLastRect();
}
}
if you haven't done something like this. You have 2 events that are important in GUI, 1 is Repaint, the other is Layout
filteredListContent = new FilterWindowContent(displayList);
PopupWindow.Show(pos, filteredListContent);``` this is the critical bit I thin.. shows window "contents" are only created once. Perhaps I need a flag to see if I already called "Show"?
is that in your public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) ?
(I want it to display when my property drawer is in a particular state, rather than when the user presses a button.) Think I missed your point about the events.....
yes, called in there...
(when display state is true)
sounds like I may need to change it to.. when the display state GOES true
Well since you are having trouble, there is clearly more than this bit of code that is critical 😉
perhaps, but I'm not specifically "closing" the window, nor even referencing it anywhere else.. not sure what else is pertinent ... anything in particular I should be showing that I'm not?
Context around that code is important in this case. Are you calling .Show() multiple times?
yes
That is the problem
Only one popup can be open at once and you are opening a new one each time you call Show()
bool isOpen = false;// in class
//in function
if (!isOpen)
{
PopupWindow.Show(pos, filteredListContent);
isOpen = true;
}``` did as a test- no more blinking- but also dont see it...
check out https://docs.unity3d.com/ScriptReference/EventType.Repaint.html and https://docs.unity3d.com/ScriptReference/EventType.Layout.html
I mentioned them from the example in PopupWindow because of things like GUILayoutUtility.GetLastRect only work in the repaint event, which, can not only be used (not the only way mind you, just trying to help diagnose the problem with little info provided) to give the window the proper rect, but, to help maintain the window opened, if it was the last rect
Can you please put the full code in to a hastebin (or whatever one you like) and share it
The context around your code and where/when/how it is being called is important.
Note that GUIlayout related things cannot and should not be used in property drawers.
yeah, that also ^
which I know this is a layout thing... I actually thought it was weird to do a an editor window from a propertydrawer to begin with, but, I don't like using propertydrawers much yet hehe
what I would do is put something in your propertydrawer that would do https://docs.unity3d.com/ScriptReference/EditorWindow.GetWindow.html that is me personally
I removed the excess stuff, to get the same issue.... https://hastebin.com/cuzefapupi.csharp note- if line 41 is remarked out I get the strobing, as expected now, but with it NOT remarked out: logs show a single open AND close- and the popup is not visisble.
hmm.. is it possible it IS open.. but just hidden "beneath" the editor window or something? gonna try different RECT to test that
I think what is happening is that the control is losing focus because it is being given to the window?
It is not, no.
I think this is true.. but that would just mean Show isn't getting called AGAIN (as intended)
(I mean certainly , this logic is NOT perfect.. but I expected to see the popup with it)
You keep typing which would put the focus back on the control.
You know I just remembered that I'm like 98% sure that popups auto-close when they lose focus.
I tested by just clicking the control, not typing.. (though I tried typing.. which is how it became clear it had indeed lost focus, as you mentioned)
clicing on it yields this in the debug log:
trying a button for sanity sae now
worked fine with a button for the conditional- AND repeated clicks on the button toggle it on and off!!! so it seems like the second call to Show is turning it OFF! Did I just miss that part of the docs?!
ok I got it working, but somthing odd is going on ... this works: isOpen = true; PopupWindow.Show(position, editorWindowContents); but this does not!!! PopupWindow.Show(position, editorWindowContents); isOpen = true;
is almost seems like control is not returning... PopupWindow.Show(position, editorWindowContents); Debug.Log("POST show log"); that log is never displayed, even when the popup is opened
no exceptions shown in log.. hmm that is VERY odd...
well, anyway- got it going now.. thanks for the help @gloomy chasm@opaque zenith
GG! Glad to hear, hope we helped somehow haha
ExitGUIException are internally handled by Unity.
can you use https://docs.unity3d.com/ScriptReference/Event.Use.html to stop excessive repainting? I know that it says Events of type EventType.Repaint and EventType.Layout should not be used. Attempting to call this method on such events will issue a warning. but, if you set it up to only repaint based off the current event use?
sorry, just read about event.use and trying to understand it more I guess
You can't prevent an already executing Layout/Repaint Event
Try to think early in the process
"Who is triggering this repaint?"
I'm more of thinking about that uhh what would you call it, in the profiler the huge spike a full editor repaint?
wantsMouseMove, RequiresConstantRepaint(), a user interaction, Repaint()
oh okay. I've been using Repaint(), well, I stopped using repaint when I realized I wasn't just using serializedObject.Update(); I'll check out the mousemove and constantrepaint, ty!
UnityEditor.EditorApplication.Internal_RepaintAllViews triggers a full repaint
That's really good to know. I've been fiddling around more with registering to editorapplication things. I'm going to check that out!
Many ways to repaint stuff, low & high levels
If you don't mind me asking. I can probably just google it, but I enjoy the convo hehe. Is low & high level where lower is more barebones coding, and higher takes the barebones and creates more user friendly of the lower levels? I'm been seeing this used more often in things I'm looking up and just assumed that was what it is
Repaint() is high level, the highest
Lower is more like through Reflection triggering a repaint from a View
oh okay
Is there a callback or way of identifying when a prefab stage is opened and closed?
For open I have:
private void OnValidate()
{
if (PrefabStageUtility.GetCurrentPrefabStage() != null) Debug.Log("I'm open");
}```
Which works alright... but how do I identify when it's closed?
(I have prefabs which are loaded in URP and SRP and it would be great to switch the editor into those modes when editing those prefabs)
PrefabUtility.GetPrefabInstanceStatus I think
you can also use Selection to determine that also
Hmmm 🤔 I'm not sure that works here.
I was hoping for something like OnEnable and OnDisable.
I can check PrefabUtility.GetPrefabInstanceStatus or similar, every update but when the prefab is closed I wont know any more, and I cant see a "OnPrefabStageClosed" type thing
oh, I highly recommend not using prefabutility for that, use selection
But selection is just what's selected in Scene or Project
register to Selection.selectionChanged for example
Ideally I'm after OnOpenPrefab > Check which render pipeline it is built for > Switch editor to that pipeline
what do you mean by this? Aren't those the only 2 options? lol
Yes but selecting a prefab in the project isnt the event I'm trying to capture
It's opening and closing it
right, but, you use selection to perform your prefabutility check
🤔 could you elaborate a little?
Cheers
its experimental though... so you know... might break
Like most things in this project 😉
Not anymore
This old one is experimental:
https://ngtools.tech/uv/UnityEditor.Experimental.SceneManagement.PrefabStage/prefabStageClosing-/
[Serializable]
Typepublic sealed class UnityEditor.Experimental.SceneManagement.PrefabStage
2018.3.0f2⟩2021.1.22f1
Doc
Eventpublic static prefabStageClosing { add; remove; }
2018.3.0f2⟩2021.1.22f1
Doc
[GitHub](https://ngtools.tech/r.p...
Ahh yeah, I'm in the old world for now
LTS keeps you sane
Most of the time yes 🙂
from the LTS version you can look into the future and see what will happen... cant do that with bleeding edge 😉 ... i.e. never trust a roadmap
for example, if you register to the selection change event, in the method your registered with, you can add
if (Selection.gameObjects.Length != 0)
{
foreach (GameObject go in Selection.gameObjects)
{
if (PrefabUtility.GetPrefabObject(go) != null)
{
PrefabUtility.GetPrefabInstanceStatus(go);
}
}
}
obviously add more for your intended purpose of finding the instance status, but, this will work for that
I now have this on a script on the Prefab
private void OnValidate()
{
if (PrefabStageUtility.GetCurrentPrefabStage() != null)
{
switch (renderPipeline)
{
case RenderPipeline.StandardRenderPipeline:
if (GraphicsSettings.renderPipelineAsset != null) GraphicsSettings.renderPipelineAsset = null;
break;
case RenderPipeline.UniversalRenderPipeline:
RenderPipelineAsset RPA = (RenderPipelineAsset)AssetDatabase.LoadAssetAtPath("Assets/Framework/Render Pipeline/UniversalRenderPipelineAsset.asset", typeof(RenderPipelineAsset));
if (GraphicsSettings.renderPipelineAsset != RPA) GraphicsSettings.renderPipelineAsset = RPA;
break;
}
}
PrefabStage.prefabStageClosing -= OnClosePrefabEditMode;
PrefabStage.prefabStageClosing += OnClosePrefabEditMode;
}
private void OnClosePrefabEditMode(PrefabStage obj)
{
RenderPipelineAsset RPA = (RenderPipelineAsset)AssetDatabase.LoadAssetAtPath("Assets/Framework/Render Pipeline/UniversalRenderPipelineAsset.asset", typeof(RenderPipelineAsset));
if (GraphicsSettings.renderPipelineAsset != RPA) GraphicsSettings.renderPipelineAsset = RPA;
PrefabStage.prefabStageClosing -= OnClosePrefabEditMode;
}
Opening and closing the prefab handles the events itself and only calls them once.
so, I setup an editorscript of sorts that is auto added to a scene gameobject when I select it, then removed when I unselect. I feel like I can do something different though without having a constant adding and removing. I haven't messed with Editor.CreateEditor and wondering if that is possible what I should be doing instead?
Since you don't say why you are adding and removing it is hard to say what a better solution would be.
It's for my mesh manipulation. I have a MeshManager script basically that is auto added that include OnSceneGUI and custom inspector things
but I was thinking maybe I should just make a class that is registered to events that does this
this is probably super simple but does anybody know how to change the orientation of New Shapes in probuilder
whenever i create new shapes, they're locked to face a certain direction regardless of where the viewport camera is located
Does anyone know how to get the screen width and height while in editor? I only know how to get the current view width and the default Screen.Width and Screen.Height return my gameview dimensions.
Screen.width/height return the height of the window they are called in. You want the width/height of the unity editor application window?
yeah, I found some stuff in Display but it returns the gameview dimensions for me also
Why do you want it?
You can get the size of the main view area 'easy' enough if that will do I guess.
I'm creating some editor windows to have popup at certain positions specifically if opened. between currentview and handlesGUI I have been able to do most editor ui things this way, but, now I'm curious about this lol. I don't need it at all, just one of those things I'm determined to figure out now
Ah, got it. Well you can get the main view by using Resources.FindAllOfType and use the internal type UnityEditor.MainView. It has a rect property called position that you can then get.
I think there is another way, but I don't remember what it is.
UnityEditor.Handles.GetMainGameViewSize();?
I think that is still the gameview, but wondering if that was what you might have been thinking about
No, the MainView != GameView
dang
The MainView is the area below the top toolbar and the bottom app status bar.
The area where you can dock windows
ohhh okay, well, you answered me next question. Realized I don't actually know what the main view is
Yeah, btw it is internal so you need to use a bit of reflection and stuff as I said.
EditorGUIUtility.GetMainWindowPosition?
Yup that would be it.
yay!
okay cool, with this I was able to use the max values to basically get the proper screen width and height
I feel like this is excessive, but, I can't think of a better way? Rect r = new Rect((mainWindowMax.x - mainWindowMin.x - window.position.width) / 2.0f, (mainWindowMax.y - mainWindowMin.y - window.position.height) / 2.0f, window.position.width, window.position.height);
for the center
for example
actually, think I did that wrong. Think I want to add the mins to offset anything the screen would be forcing the min higher than 0 to give the appearance of being centered on the screen, vs this being centered off the main window
okay, realized the min doesnt matter at all for screen, so. ended up with
Rect r = new Rect(mainWindowMax.x / 2.0f - window.position.width / 2.0f, mainWindowMax.y / 2.0f - window.position.height / 2.0f, window.position.width, window.position.height);
is the most accurate to center and can build off that I guess
Hello everyone, is there a way to call FindObjectOfType from an editor script ?
it always return null value 😦
I cloned a material form a public variable in my script on OnEnable() and settings the Renderer material during edit mode - then destroying and setting it to null on OnDisable() with [ExecuteInEditMode] and its fine - updating the material properties OnValidate()
But when i copy and paste the same game object - changing one value in the script changes the copy material as well.
Which is strange because when i clone the object i give it random name and looking at the inspector's renderer it has two different materials
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[ExecuteInEditMode]
public class TestScript : MonoBehaviour
{
public Material original;
MeshRenderer render;
[System.NonSerialized] Material mat;
bool is_ready = false;
void OnEnable()
{
render = GetComponent<MeshRenderer>();
ApplyMaterial(true);
is_ready = true;
}
void OnDisable()
{
DestroyMaterial();
is_ready = false;
}
bool ApplyMaterial(bool forceNew = false)
{
if (original == null) return false;
if (forceNew && mat != null) DestroyMaterial();
if (forceNew || mat == null)
{
mat = new Material(original);
mat.name += " (preview) " + ( (int) ( Random.value * 9999 ) );
}
if( mat != null ) render.material = mat;
return true;
}
void DestroyMaterial()
{
if (Application.isPlaying) Destroy(mat);
else DestroyImmediate(mat);
}
private void Update()
{
if( ! is_ready || Application.isPlaying ) return;
ApplyMaterial( false );
UpdateMaterial();
}
private void OnValidate() => UpdateMaterial();
public Vector3 row0 = new Vector3( 1, 0, 0 );
public Vector3 row1 = new Vector3( 0, 1, 0 );
public Vector3 row2 = new Vector3( 0, 0, 1 );
public Vector2 shift = Vector2.one * 1.5f;
public float extend = 0.5f;
void UpdateMaterial()
{
if( mat == null ) return;
mat.SetVector("ComposeRow0", row0 );
mat.SetVector("ComposeRow1", row1 );
mat.SetVector("ComposeRow2", row2 );
mat.SetVector("ComposeShift", shift );
mat.SetFloat("ComposeExtend", extend );
}
}
the only explanation i can find that when doing a copy paste to the game object it retains the same reference to the cloned material mat ( but it should be impossible as im destroying it onEnable )
which isn't the case as the names are different :
...
to simplify : my question is , when writing a material property something like
mat.SetVector("ComposeRow0", row0 );
during edit mode , why does it effect every single cloned instance based on the original and how to avoid it * ?
you need to copy the material and apply it. As in, make a new material, apply what you want to that material based off the original material, then use that material
Resources.FindObjectOfType
treat the material like you would a models prefab
render.material = new Material(original); ?
right, but, when you change the original, it will effect all of the clones of it. Don't alter the original, ever, unless that is what you want to do. Treat the Original only as a template basically. They all share sharedMaterial
that's what i did
^
so, I'm not actually 100% sure on this, but, figured I'd see if you want to try it. in your render.material = new Material(original); try changing the original to be a shader instead of a material. So, something like render.material = new Material(Shader.Find("MyShader"));
good idea
just realized you are copying based off a material, I do all my copying based off a shader
quick question , any ideas how to Find shader grpah asset ?
The normal way to find any shader.
If you want the actual shader graph then you have to use the AssetDatabase.
kk
All it is is a json file with a shader as a subasset.
Shader.Find can be used to switch to another shader without having to keep a reference to the shader. name is the name you can see in the shader popup of any material, for example "Standard", "Unlit/Texture", "Legacy Shaders/Diffuse" etc.
Also, and this is important depending on what you are doing
Note that a shader might be not included into the player build if nothing references it! In that case, Shader.Find will work only in the editor, and will result in pink "missing shader" materials in the player build. Because of that, it is advisable to use shader references instead of finding them by name. To make sure a shader is included into the game build, do either of: 1) reference it from some of the materials used in your Scene, 2) add it under "Always Included Shaders" list in ProjectSettings/Graphics or 3) put shader or something that references it (e.g. a Material) into a "Resources" folder.
IDK what a shader graph is, I've only used surface shaders, sorry 😦
A shader graph is a shader created for either the HDRP or the URP using the Shader Graph package (node based shader creator).
ohhh fun. Eventually I'm going to delve more into shaders on my mesh manipulation once I get my handles more in a place I like, is this a package you would recommend? (Sorry, I always really appreciate your advice)
Well it is better than writing them by hand if ya don't know shaders already 😛
I have found it to be a little buggy and laggy though so I am still using Amplify Shader Editor. (Further discussion should be in #archived-shaders as to keep things on topic)
sounds good! Thanks
No offense, but, this isn't an editor extension question, and is quite literally probably the basics of script/class naming convention in Unity. Have you done any tutorials?
och sorry
It's okay, just thinking it might want to try #💻┃code-beginner and checkout https://learn.unity.com/tutorial/classes-5 I saw what the problem was, but, worried correcting it might be better to give a learning link
o thx
So given this code, Unity just tells me that Creating the asset failed at the given location. But it doesn't tell me anything about why it failed. What could be possible causes?
private void SaveAs()
{
string path = EditorUtility.SaveFilePanel("Save DialogueChain", "", "NewDialogueChain.asset", "DialogueChain");
if (path.Length != 0)
{
DialogueChain chain = CreateInstance<DialogueChain>();
chain.Nodes = _nodes;
AssetDatabase.CreateAsset(chain, path);
_instanceId = AssetDatabase.LoadAssetAtPath<DialogueChain>(path).GetInstanceID();
}
}
why are you using EditorUtility.SaveFilePanel and if (path.Length != 0) for what you are doing? If you are using AssetDatabase.CreateAsset
I just checked out an example on the Unity API docs
I want to give the user of the editor control over where an asset file is saved
So I just searched how to call up the save dialogue and went from there
in terms of dialogue check out https://docs.unity3d.com/ScriptReference/EditorUtility.DisplayDialog.html
if that is what you want?
well, regardless, not relevent to your question, let me look more.
The flow is pretty straight forward.
Use my custom editor to make a thing that can be stored as an .asset file.
Click the Save Button.
Choose where to save the asset.
how is the string being saved? Have you happened to do a debug check on it? Is it possible that when you create the asset, the path isn't actually a valid path?
Hm, let me see.
Oh I think I see the issue. It's not that the path is invalid.
It's that the resulting file has an invalid name
I didn't quite understand how the dialogue work it seems.
.../Assets/Data/NewDialogueChain.asset.DialogueChain
And now it complains about not using a relative path
Aight
Well that makes this something I can continue with. Thanks @opaque zenith
np, I haven't tried writing this way, but I usually use StreamWriter if that is a route you are interested in
StreamWriter could be an option yes, though I was thinking that since CreateAsset() exists and it just needs a path, then it would likely be some easy work done for me to just ask Unity to make the asset for me at the specified path
Yeah! It's very ez this way. I'm still a noob, so not familiar with the tool you are using, that's why I thought it was weird. I would personally just remove
string path = EditorUtility.SaveFilePanel("Save DialogueChain", "", "NewDialogueChain.asset", "DialogueChain"); if (path.Length != 0){
all together
But why?
I still need to ask where the user wants to save the file so
how else would I obtain that path?
and then just a path string with whatever you want in it if you want to use it multiple time, or in this case, something like string path = "assets/Folder/NewDialogueChain.asset"
But that's a static path
the user needs to be able to tell the editor where they want to save the file
How would I do that without the savefile dialog?
They do the same thing?
well, to be more precise how I CURRENTLY have it
is I use and object field for default assets
You are describing a use-case that isn't mine
yeah
I need to be able to make a lot of these objects as they are used for dialogues. It's a node editor.
The OpenFolderPanel and SaveFilePanel appears to largely do the exact same thing
but basically the way I did it (which is probably easier ways, most my ways are convoluted from lack of experience) but, I have a text field that the user can enter to has a validation check for if a valid path so if the user wants to type in it, but, also an object field where they can select a folder path. I then use AssetDatabase to get the asset path, and in the previous text field have that path displayed
Why not just give them the native desktop saving dialogue?
That seems a lot more intuitive
Ease of use
I haven't altered this code for many months, since I was just barely learning, and just how I did it
I also find popups to be annoying. I just altered some of my code for example to remove some dialogues I had done to be EditorGUILayout.HelpBox instead
I mean, no matter which OS you use there will be some type of popup that will be useful. Like a dialogue to let you choose where to save a file.
Unless you are using strictly commandline OS'ses but that's kind of pointless to this discussion
I was recently trying to find a way to auto close dialogue, but couldn't find anything, idk if you know of something
EditorUtility.DisplayDialog has DialogOptOutDecisionType but not quite what I was looking for
oh also https://docs.unity3d.com/ScriptReference/EditorUtility.DisplayDialogComplex.html may interest you if you are into dialogue stuff
They are almost the same, the difference is that one you select a folder, and the other you set the name and folder location. Btw you are doing it all correctly using CreateAsset and such. I assume the problem was that it was a none relative path, yes? Did you get it working?
Also btw a 'better' way for checking a string is to use string.IsNullOrEmpty(path) since it handles if the string is null and also imo a bit clearer to read.
Just for your info, StreamWriter would not in fact be an option because it can't write a UnityEngine.Object to YAML (which is what Unity Object assets are saved as).
oh okay, good to know!
Hello,
I'm trying to get into Editor Scripting for some tools development.
I came across a video which uses the new UI Toolkit, in the video they use the Unity Royale demo and create a custom "Card Creator" Tool.
I want to take a look at the code under the hood, but the demo does not seem to contain that section at all. Am I missing something?
In this video, we are walking you through the basics of creating Property Drawers and Editor Windows using UI Toolkit.
🌏 Check out our Docs to learn more about UI Toolkit:
https://on.unity.com/3kR2LC6
🌏 Learn more about Editor Scripting using IMGUI here:
https://on.unity.com/3oZ3oMq
🌏 Download Unity Royale here:
https://on.unity.com/3jXV9fX
...
This is the repo https://github.com/Unity-Technologies/UIToolkitUnityRoyaleRuntimeDemo
Which is in turn build on this one https://github.com/ciro-unity/UnityRoyale-Public
This is a sample project to introduce the use of UI Toolkit in Runtime - GitHub - Unity-Technologies/UIToolkitUnityRoyaleRuntimeDemo: This is a sample project to introduce the use of UI Toolkit in ...
Yes I did get it working eventually. Just took a bit of fiddling
Suggestions?
private void SaveAs()
{
string path = EditorUtility.SaveFilePanel("Save DialogueChain", "Assets", "NewDialogueChain", "asset");
if (path.Length != 0)
{
DialogueChain chain = CreateInstance<DialogueChain>();
chain.Nodes = _nodes;
chain.name = $"{path.Split('/').Last().Replace(".asset", "")}";
path = $"{path.Substring(path.IndexOf("Assets"))}";
AssetDatabase.CreateAsset(chain, path);
_instanceId = AssetDatabase.LoadAssetAtPath<DialogueChain>(path).GetInstanceID();
}
}
There's no editor folder created for the project in there.
Use System.IO.Path.FileNameWithoutExtension(..) to get a name of a file from a path without the extension.
Use I believe it is UnityEditor.FileUtil.GetProjectRelativePath(..) to get the project relative path. If that doesn't work then subtract Application.dataPath.Length - "Assets".Length from the path instead.
Yeah, took a look and there isn't any.
They are explicitly referenced in the video tho, and they exist in there too. Strange.
Anyways, is there any project you would recommend to get started with this kinda thing?
Also, the instance ID will be the same before/after you save so no need to load it after. (I am like 85% sure at least)
I am never entirely sure with Instance IDs in Unity
they seem to change when I don't expect it
So thought I'd be on the safe side
At least, if the Load does work, then I know for sure that the Save worked?
😂
What are you wanting? If you just want to learn than the Unity Learn course is good. If you want projects then there is the examples which should still work I think.
https://github.com/Unity-Technologies/UIElementsExamples/tree/master/Assets/Examples/Editor
This is extremely helpful. I'm mostly just looking for general use cases and examples.
is there an event called resulting from the closing of an editor window after OnDestroy()?
basically, resulting in doing something like
protected static void ShowWindow()
{
window = Instantiate(instance);
window.Show();
}
to essentially do what I was looking for
hey. any idea how to make this OnStart happen after each domain reload ?
InitializeOnLoad
that doesnt work for non-static methods
I ended up using [AlwaysExecute] and putting my method inside OnEnable()
I think [ExecuteInEditMode] will do maybe?
that's the same. except it'd be editor only
Assuming you got ExecuteAlways / ExecuteInEditMode - Before domain reload - OnDisable will be called , after domain reload OnEnabled will be called
look into a somewhat singleton pattern if you want to use InitializeOnLoadMethod or just make everything in that script static. ExecuteInEditMode is not only just editor, however, doesn't take prefab mode into account natively. Looks like you found your solution with ExecuteAlways which is great! Just make sure you have checks with Application.IsPlaying to help separate any logic you want different from editor and play mode
why not make a static event and dispatch it OnDestroy() ?
When you close an EditorWindow there is an internal Close() that is called that calls a DestroyImmediate(). It was late when I was looking into this so about to delve back into it, but, that is something I'm looking into, however, I'm trying to figure out how I would approach how to handle the event. The DestroyImmediate() is the last thing to happen, so when OnDestroy() is called, the instances of the window still exists
not sure what you need, when you say something like window = Instantiate(instance);window.Show();
are you trying to capture after DestroyImmediate ? Why ?
I have an editor script that is my global editor manager script, I guess you could call it. I do different things with this manager script. So, when I want to display it as a window, I'm instantiating it to copy instances instead of creating a new one, then window.Show() to show it. I could simply use GetWindow but that doesn't solve my issue of wanting to maintain the reference rather than have it destroyimmediate when closed. Sorry for slow response, my daughter keeps requiring my attention while trying to respond
so basically I'm resulting in saving and copying, and wondering if there is a way to just cancel the destroyimmediate from .close. IDK if through something like Event.use or ExitGUI or something
like one approach I'm doing is EditorUtility.SetDirty(); in OnDestroy() but I'm not sure if that is the bestroute
doubt its possible , have a look at this https://github.com/Unity-Technologies/UnityCsReference/blob/61f92bd79ae862c4465d35270f9d1d57befd1761/Editor/Mono/EditorWindow.cs#L931
yeah, I was looking at that and was trying to figure out where the .close is actually called from when closed.
also i don't think making a global window manager is the best route for component based architecture - everything should be modular and as self reliant as possible ( at least that is my opinion ) - u could make a scriptable object that lives as an asset in your project and stores the editor window internal states and restores them on demand
i think whenever you close it manually ?
Right, but, what event detecting this so use Close(). For example, if you try to use Close() in OnDestroy or OnDisable you get an error because it has already been called
because it is already null ?
( im just guessing at this point )
no, it isn't null till the very end, which is the problem I'm having. The error is because of
// Guard against multiple call to Close in the same stack
// (since we call DestroyImmediate at the end of Close()).
if (!this)
return;
try looking at this as well : https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/ContainerWindow.cs
line 312
Maybe what I should be doing is rather than using the default .Show() and GetWindow() I instead should do something like PopupWindow
rather, EditorWindow.ShowPopup
¯_(ツ)_/¯
thanks for looking with me! Always appreciate anything!
Thanks. Yeah that checking with play mode is a pain...
yeah, it's actually why I don't ever use things like if UNITYEDITOR and stuff of the sorts and just make editor scripts in the editor folder so I never need to worry about these things
I solved a lot of my problems just saving the data and just not caring if it persists or not since the first instance will always be off that
Is there really no way for the default drawer to hide/show parts of struct/class based on condition?
have your propertyfield not show children, then, use FindRelativeProperty to display the fields you want
or get the struct, break it up and just doing normal EditorGUI things on the fields you want
Im using polymorphic list for the different kinds of element type, but its getting kinda a hassle to maintain
Considering going a struct to hold all the possible values and only show based on some bool/enum
Is this worth the simplification?
Oh and can struct be a target for CustomEditor?
I did it, but, if you don't have a great understanding of serializedObjects and serializedPropeties, it can lead into multiple headaches, at least it did for me. Just when I thought I had things working it turns out it was broken for something else
dealing with .Next and .NextVisible was especially annoying
Yeah i got it working already too. But now i wanted to add this same structure list to a list of.. basically something that i now want it to be the polymorphic list + a bit extra thing just for this part
And thinking of having to do a whole writing again just for this little "variant" makes me so cbf...
CustomInspector can be for non mono too, right?
This way i can make the custom once for this struct and put it in whatever else variant and itll do just that
check out https://catlikecoding.com/unity/tutorials/editor/custom-list/ I found this link to be especially good and was the basis for my custom list
you can do anything with the editor, just, as you delve away from Unity features sometimes you just have to do more work. For example, if you wanted to display an int, you would have to use EditorGUI.IntField. There isn't a default EditorGUI thing for lists for example
so you have to build a custom one
and ones like the one I linked still rely on serializedProperty, but, yeah
There is other things to like EditorGUI.BeingProperty() you can make a wrapper with and stuff, but, I haven't found a great way I like personally of doing those things yet. ATM, I just just have a serializedProperty extension that spits the property into the type it is then picks it apart to display specific data, but, I haven't done anything for this outside of serializedProperties yet. TBH, I've been messing around in the editor for months and still kinda confused by serializedObject and serializedProperty do hehe.
Its just data representation of what the editor keeps. Theres no way around not using it
Im building mine with ui toolkit and even with the provided BindProperty and such, i still occassionally look via serializedProperty
About to sleep now actually. Gonna go thru that stuff again tmorrow
Im probably in this situation due to both over engineering via polymorphic list+ sub asset SO and.. well.. experimenting with the shiny new ui toolkit
Code's such a mess but i gotta clean this up now
is there anything wrong with making editor windows with scriptable objects like I use scriptable objects in builds? Never really thought about using polymorphism with them for some reason
that's fine. not the usual use case.....but should still very much work
awesome! Might try it out instead of this other route I was going, see if I like it more. I think I'll like it more than doing a generic editor window class.
I dont fully get this one. Like a editor window that displays all the SO, then the window displays the SO accordingly to the type?
My use case is, theres a main SO called ActiveSkill, and the subasset it holds are of various types like the targetting (unit/point/aim/self), the onFinishCast actions (damage/projectile/aoe/etc), each also got formula which has parts that pulls in stats or states of the caster/target
Or ur not referring to my case... But i wanna understand what u mean anyways
I meant more for creating polymorphism and lazy mode creating editor windows with virtual methods to remove some of the default things I might do. I already do that currently with my generic editor window, but, I like the layout of scriptableobjects for more organization I guess you could say
If its polymorphic then each subclass can override their own part, right. I just have a virtual void AppendInspector(VisualElement theContainerPassedByRootOnInspectorGui)
{theContainer.Add(someIntField) etc}
I guess this part is not the hassly part in my case..
Wait just woke up i forgot what was a hassle that i wanna change..
yes, but you have the option to call base to essentially save time basically. Like, if you want your editor window to subscribe to specific events you could just have the base class do it and then just call base in the override for the rest
@real ivy I skimmed the conversation. Maybe a PropertyDrawer is what you are wanting?
Yes thats the one
Does this work if i make a drawer for struct Abc
Then i have list<Abc> anAbcList, it'll work, polymorphically?
And then no matter where i have anAbcList, whether its in a struct Xyz and have a list<Xyz> itll work too?
And it works with ui toolkit? At least if i display it with PropertyField and let the drawer do it?
PropertyDrawer works on all serializable types. It determines how the the property of the type is drawn. It has two overrides, one for IMGUI and one for UITK. The UITK one only works if the thing drawing the property is using UITK, (aka new PropertyField(..)).
By default the editor for components and ScriptableObjects use IMGUI so the UITK override will not work and you will need the IMGUI override.
Whats the uitk override called?
Ehh... I think CreatePropertyGUI?
It is the one with Create in it's name.
Alright2 ill get to it when i get out of bed
Thanks a lot. Feels a lot more ready to tackle this big sphagetti monster
Alright, good luck!
Yep got that. Is this what ure gonna do or already doing?
I guess my editor skill is still very narrow. Like i never knew propertydrawer works with uitk so i didnt bother learning it
The decision to have these sub SO part polymorphic is i think still correct. Its just the displaying them that i did it all in some "property drawer" done in the main SO class for a somewhat specific "location" in the total inspector spot. Something that's "only" for anAbcList on its own
This is why when i wanna have a variant of where this anAbcList to be (now inside struct Xyz), its such a hassle
Its so spaghetti that i should stop even trying to describe it. Ill get back after my progress..
I'm not sure what is the correct way of doing things when it comes to this, so I can't tell you. I think it's just more of a preference thing. I keep trying to get into propertydrawers and just find... I suck at it, so I still to basically just doing my organization through the editor script itself
in terms of editor windows, it actually could be more work than it's worth depending on how you set up your polymorphism. Sometimes it's just easier to just inherit from editorwindow, do whateve you need, and call it a day
I'm trying to setup some things through EditorApplication.Update Selection.selectionChanged and SceneView.duringSceneGui that just will make it easier if I can have a base editorwindow for
which I already have through my generic way, but, for some reason I don't like the generic way and moving over, and what I mean is basically my public abstract class SingletonEditorWindow<T> : EditorWindow where T : SingletonEditorWindow <T> and changing it to just something like public abstract class BaseEditorWindow : EditorWindow and using asset menu to create a scriptableobject and put options and things onto that
there is also https://docs.unity3d.com/2020.1/Documentation/ScriptReference/ScriptableSingleton_1.html that can be used, but I never really got into it
I'm currently still just reading
This guy is posting his generic solution everywhere and i might try it
https://forum.unity.com/threads/custompropertydrawer-for-polymorphic-class.824667/#post-6702670
Anyone have tried it?
And.. propertydrawer can draw when called from inside CustomInspector right? Why do i have the impression that u only do one or the other?
A propertyDrawer is used when you do EditorGUI.PropertyField(..), or EditorGUILayout.PropertyField(..), or with UITK new PropertyField(..)
By default a inspector just calls EditorGUILayout.PropertyField(..) for each SerializedProperty in the component.
PropertyDrawer can't be for plain c# class?
My case is a nested list
List<NumberFormula>
class NumberFormula {List<MathEntity>}
abstract MathEntity : SO
Currently i'm drawing List<NumberFormula> as a whole with a Foldout CreateDamageFormula(List<NumberFormula>) kinda method that draws the whole thing wrapped in a Foldout, including the buttons to add/remove NumberFormula. And inside each NF, a button to remove MathEntity, or add (with dropdown to select concrete MathEntity type)
And then now i'm making another nested list
List<StatFormula> stats
class StatFormula {someVarA, someVarB, List<NumberFormula>}
PropertyDrawer can help me draw override SO class (altho this one i already did it with AppendVisualElement overrides that's called from CustomInspector)
I guess for this edge case, i just need to make another method that then calls CreateDamageFormula inside it. PropertyDrawer seems not very relevant anymore in my case
I was hoping i can do
pf = new PropertyField();
pf.BindProperty(statsProp)```
And define the custom PropertyDrawer on `StatFormula` and so can define the buttons etc, but StatFormula is plain c#..
Property fields works on plain classes just fine. In fact... that's one of the main uses cases for it.
Your description is very over complicated so I cannot really speak to the problem though
Ahaha yea. Well somewhere in there i described my plan and that works just fine, so.. solved!
Well hold up
I guess my real question is: can PropertyDrawer be used for List<SomeClass>, as a "bundle" ?
You can't make your own property drawer for a list, if that's what you're asking
I'll give you an example from catlikecoding. You make a class that is serialized, it has a field for vector3 and color that are both serialized. In the propertydrawer you say this is how I want that vector3 and color to be displayed if someone uses it Now, whenever anyone uses that class, it will be displayed as such in the inspector. If someone puts that class into a serialized array (array or list) *(there is more to this, but, irrelevant for this) unity will use their default EditorGUILayout.PropertyField to display the array while the elements will be display with the propertydrawer of those elements. This can actually be kinda wonky depending on how you have your propertydrawer setup, but, irrelevant atm so lets just assume the propertydrawer is setup fine.
Anyways, so, what you do here is either create an extension, which referring back to catlikecoding, they actually have a tutorial that shows how to use propertydrawer that goes into a custom list right after, or just do it in the editor script you want, you get the Serialized Property for the array, and break it up, and display/add other GUI features you want into it.
For example, based off their extension example, you do EditorList.Show(SerializedProperty) and if it is an array it will use the custom list
Yeah just read thru the catlike and i'm already doing the same thing (at least until the buttons)
I'm currently building it thru CustomInspector, so it does the job including drawing all the List<NF> as a bundle with buttons etc
PropertyDrawer will make my code cleaner tho, maybe, but i'm skipping it bcoz i'm already drawing them all in CustomInspector (and this main SO will ever be the only place all this matters)
yeah, I ignore propertydrawer atm because I use layout in a lot of my things and the propertydrawer just kinda gets in the way of that atm for me
Almost end up trying this and maybe this is a good idea (at least in terms of organizing code)
Currently my override drawing code is done in the derived SO class too, on the bottom under #IF UNITY_EDITOR
I want to get the current folder a scriptable object is in (from that scriptable object) and retrieve a bunch of scriptable objects but am Unsure where to start, can anyone give me a method or something I'd require to do this
I've figured out how to get the string asset path, but I am unsure on what to do from there to get assets from that path
I've been tryna use LoadAllAssetsAtPath, but it returns nothing despite the path being correct
void Autofill()
{
string assetPath = UnityEditor.AssetDatabase.GetAssetPath(GetInstanceID());
string[] splitAssetPath = assetPath.Split('/');
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < splitAssetPath.Length - 1; i++)
{
strBuilder.Append(splitAssetPath[i] + "/");
}
Debug.Log(strBuilder.ToString());
Object[] assets = UnityEditor.AssetDatabase.LoadAllAssetsAtPath(strBuilder.ToString());
List<Wave> waves = new List<Wave>();
foreach(object obj in assets)
{
Debug.Log(obj.GetType().Name);
if(obj is Wave wave)
{
waves.Add(wave);
}
}
Waves = waves;
}
All you do is remove the asset name from the path and then you can either use System.IO's classes to get the files in the folder, or iirc you can use AssetDatabase.Find(folderPath)
Unity allows what are called sub-assets which are basically assets nested instead other assets. LoadAllAssetsAtPath is what you use to load one of those sub-assets.
string[] assetLocations = UnityEditor.AssetDatabase.FindAssets(strBuilder.ToString());
List<Wave> waves = new List<Wave>();
foreach(string str in assetLocations)
{
waves.Add(UnityEditor.AssetDatabase.LoadAssetAtPath<Wave>(str));
}
tried this but it doesn't work either
Did I misunderstand?
@gloomy chasm
It returns asset guids not asset paths
How can I use that GUID to get the asset?
AssetDatabase.GUIDToPath(..) or something like that
Problem is string[] assetLocations = UnityEditor.AssetDatabase.FindAssets(strBuilder.ToString()); is returning 0
items
The path is Assets/t/
which is current
currect*
CORRECT*
ah, the path is the second one
I think just using System.IO will be cleaner to read and I think more performant, but maybe not.
Show code pls
string assetPath = UnityEditor.AssetDatabase.GetAssetPath(GetInstanceID());
string[] splitAssetPath = assetPath.Split('/');
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < splitAssetPath.Length - 1; i++)
{
strBuilder.Append(splitAssetPath[i] + "/");
string[] assetLocations = UnityEditor.AssetDatabase.FindAssets("", new string[] { strBuilder.ToString() });
Debug.Log(assetLocations.Length);
List<Wave> waves = new List<Wave>();
foreach(string str in assetLocations)
{
waves.Add(UnityEditor.AssetDatabase.LoadAssetAtPath<Wave>(UnityEditor.AssetDatabase.GUIDToAssetPath(str)));
Debug.Log(UnityEditor.AssetDatabase.LoadAssetAtPath<Wave>(UnityEditor.AssetDatabase.GUIDToAssetPath(str)).name);
}
Gotta remove the ending /
That was it, thank you!
There's something i still dont understand about the new UITK
The last thing i did was
FloatField simpleValue = new FloatField("Value");
simpleValue.SetValueWithoutNotify(number.simpleValue);
simpleValue.RegisterValueChangedCallback((f) =>
{
number.simpleValue = f.newValue;
});```
Number is just a serializable c# class
As shown there, there is no BindProperty, no setting floatValue to serializedProperty, no ApplyModifiedProperties, SetDirty, SaveAssets, Refresh, etc whatsoever
But this... works. Restarted editor, went into play mode n back, the value survives all that
Looking at my past codes and they're all using Bind and ApplyModifiedProperty and whatnot bcoz i guess, either i couldnt make it persist, setting the value on the actual object itself, or i actually didn't think of just trying it out
It will not support prefabs (like overriding values) and doesn't support undo/redo.
But if this is just for SO editing static data, it works fine?
I guess, there is still no undo/redo though and if unity doesn't close properly before you have saved, the changes will be lost iirc.
Definitely not my recommended way to do it at all.
So maybe SetDirty is the only thing i really need here
No
Yeah, i'm just surprised it persists
tbh I am too. Maybe something else is setting it dirty?
SetDirty wouldn't fix the saving problem. All that does is tell Unity that any given asset/object needs to be saved. And when Unity quits properly, it auto saves.
Yeah at least that, it'll prompt to save before closing
I think the first time i close unity i didnt hit save. But i thiiink the values still saved...? Maybe (And yeah it didnt promp to save before closing)
And yea i'm still (pleasantly) surprised. Still checking these 3 things after any close open play whatever and they're still reliably there
Like I said before. Unity automatically saves when quitting.
Is it possible to move this toggle to snap to the right?
I tried setting any flex to FlexEnd and it doesn't change anything
The parent VE flex-direction is set to Row. Only if it's set to Column then this toggle snaps to the right, but then it'll be on a new line..
Ehh, could try reverse row maybe (may have to be one of the child elements and not the main one)?
Worst case ya just add a label.
Oh, setting the "Stat Number" label to flex-grow 1 actually pushes the toggle all the way to right, so this works
Oh, well glad you got it working.
(I miss-read what you said anyway)
where can I find a good visual basic dark theme?
I have checked the market place and found one dark pro
but I want another one
any idea?
Firstly #497872469911404564 would be the proper channel. This channel is for discussing creating custom editor windows and inspectors and the such.
Secondly, ya can't even use visual basic with unity...
Hi all
I'm in the process of changing some data structure, and cant seem to properly "port over" existing data to the new structure
So in my SO i used to have say
List<NF> duration
It's already got several NF data and all is good
Then i wanna stop storing it as List and instead in another class:
class Number{public List<NF> formula}
Then i make a new variable instead of replacing the existing duration
public Number durationNew = new Number();
So i did this in OnValidate:
durationNew.formula = duration;
And all is good, the data reference carried over
And then... what?
I got rid of the old duration, then compiled, and durationNew.formula still holds the data. Cool
Then.. i wanna rename durationNew to duration
I did, and compiled, and the data reference are gone
I guess i can use FormerlySerializedAs?
But what if i really wanna rename and not use that attribute?
Ah i guess i can trigger the OnValidate 2x. First from old duration to durationNew, then change duration to Number, then do from durationNew to duration
You can rename, use the attribute, then remove the attribute.
Aah u can do that..
Well i'll remember next time
My way is like 1 step longer..
you can't alter structs like this. You are trying to alter the original essentially through a copy. Either use a class instead, or, get the struct data, set it, then set it back. Right now, you are getting it, setting it, then not setting it back.
At least if I understand structs correctly. I don't actually use them a lot since I'm scared of not using them correctly
sorry for dumb question, but, just to make sure I understand correctly (ignoring the order of execution) a static class does NOT need [InitializeOnLoad] and the constructor is automatically called on domain reload, but, methods in it would either need to be called through the constructor or with [InitializeOnLoadMethod]. A non static class with a static constructor needs [InitializeOnLoad] or a static method with [InitializeOnLoadMethod]?
That was said confusingly for me. But to make it clear.
[InitializeOnLoad]is calls the static constructor of the class it is on after a domain reload.- The class does not need to be static to have a static constructor.
- A static constructor is called automatically before the fist instance of the class is created or any static member is referenced.
[InitializeOnLoadMethod]acts the same as[InitializeOnLoad]but class the method it is on instead of the static constructor of a class.
getting more into UITK. This UITK Builder is so fun
I'm not sure how to best organize things yet though. I have a StyleSheet and UXML just called Editor and Runtime atm
Is there a way to make the canvas size in UITK match the sceneview?
Guys what would be the best method to run an editor window in the background of my game
basically
the user opens the window then closes it
but i want the winow to be consistently running events if it is open or closed
Hey guys I've just downloaded unity on a computer in a closed network (no internet access)
And I got this error Failed to find csc.exe in the console
Anyone knows a solution
Your install is corrupt
I’m using EdiotrGUI.PropertyField to draw a List in my custom property drawer. Why do I get a different output in my custom drawer than when disable it (remark out [CustomPropertyDrawer] attribute), and just let it use the default property drawer? Am I calling EditorGUI.PropertyField improperly, somehow?
are you setting the EditorGUI.PropertyField() to includechildren to false? I'm not sure, would have to check, but, have you tried adding an element to see if the property drawer just doesn't draw 0 elements? I've never checked for a list or an array with nothing in it with a propertyfield lol, so no idea
also, CustomPropertyDrawer doesn't, well shouldn't, be using Layout
so you have to do things like the indentation yourself
oh! I didn't specify anything about children, perhaps I need to specify true? I'll try that. Yes, tested with a single element added, and with an int list (rather than a custom object)- alas same result. testing "children" thing now...
🍒 that "children" thing was it! thank you sir!
yes If true the property including children is drawn; otherwise only the control itself (such as only a foldout but nothing below it).
EditorGUI.PropertyField(position, fieldsAndControlsProperty,true); <- that's all I had to do- always forget about that darn param- thanks again bud
It's actually a nice way you can create foldouts for all serialized properties to essentially hide rendering of things easier (imo at least). Since you can do things like if (EditorGUILayout.PropertyField(serializedProperty)) or if (serializedProperty.isExpanded)
kinda lost me at the last post there.. shouldn't the property drawer of the serializedProperty itself handle the drawing when the serializedProperty.isExpanded?
what I'm talking about is a serializedProperty default has a bool field to check if it is expanded or not(every serializedProperty, doesn't have to just be a list and/or array). You can use this to your advantage if you ever write any serialized property extensions
Hi, In a PropertyDrawer I'm using GUI.skin.label.CalcSize to get the width for some text, however this text gets cut off in the middle, suggesting that the value returned has too small width. I feel like I'm missing something here? I've tried grabbing the label from EditorStyles as well but that is even shorter? rect is the Rect argument in OnGUI.
Here's relevant code & image:
var itemLabelContent = new GUIContent("Item");
var itemLabelSize = GUI.skin.label.CalcSize(itemLabelContent);
var itemLabelRect = new Rect(rect.x, rect.y, itemLabelSize.x, rect.height);
var itemRect = new Rect(rect.x + itemLabelSize.x, rect.y, rect.width * 0.5f - itemLabelSize.x, rect.height);
var itemWidth = itemLabelRect.width + itemRect.width;
EditorGUI.LabelField(itemLabelRect, itemLabelContent);
EditorGUI.PropertyField(itemRect, itemProperty, GUIContent.none);
Why not use the propertyfield with the label param
you can use EditorGUIUtility.currentViewWidth to get the current windows width. In the example you have, I don't see where the rect field is, so, just assuming here, it's larger than it should be and is therefore on top of item. Since you aren't using Layout you have to be precise in calculations. Also, if you are using EditorGUI.Indent you need to calculate for that
rect is from OnGUI on my PropertyDrawer, like so: public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label) I don't see why I would need window width here as the rect passed in should be the one I am allowed to draw on. I am not using indentation here.
well, that helps know more. I couldn't tell if this was a propertydrawer or not from the provided code. That being said, you probably need to account for the EditorGUI.IndentLevel I'm assuming you have
what that is doing is cutting off the size you provide for the Item label
so if you were to remove the indentlevel, for example, you would see item just fine
Actually, outlining my allowed rect seem to indicate that my label starts drawing a bit offset to the right, as if the label is offset x-pixels. I think this is where the issue is but I'm not sure what is causing it
Blue here is my calculated Label's rect
Pretty sure it's indent
So yeah it seems to be indentation that's screwing with me
are you using EditorGUI.indentLevel...
lol
I am not
try doing this, hold on
// at beginning of property drawer
int oldIndentLevel = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
// at end of property drawer
EditorGUI.indentLevel = oldIndentLevel;
you can also do something like this to check
contentPosition = EditorGUI.IndentedRect(position);
outside of that, make your field more precise. The width you have for it could be much larger with rect.width * 0.5f - itemLabelSize.x, than you are expecting possibly
IndentedRect will assume that it's drawing in the whole row and subtract the amount it moved it by
So you need to change it yourself
I think this is what I want, setting indentation to 0 fixes the text being clipped but obviously breaks indentation.
yeah, since you aren't using Layout, the indent needs to be accounted for somewhere. Also, you could make your field width smaller and more precise using EditorStyles.ObjectField.Calcsize
I'll look at it if needed, I assumed that the rect I got sent was already had the indentation part cut off, I.E rect.x was offset from the left.
Yeah, got it to work as expected now 😃
So to summarize if someone else runs in to this problem; my issue was that I was calculating all rects etc with indentation set and also drawing with indentation. So simply resetting indentation before doing the actual drawing fixes the issue. I also fix my provided rect to be indented at the start with rect = EditorGUI.IndentedRect(rect);
hello everyone, my project keeps crashing with the same error:
Got a SIGSEGV while executing native code.
UITK makes turning fields into serialized properties so much easier
How so? Maybe I'm confused as to what you mean, but both have PropertyDrawer
For example, I just use a field in my editor window, like, something like this
[SerializeField]
Object selectedObject;
I have a method as
public void SelectedObject(Object ob)
{
selectedObject = ob;
}
And it's serialized in the inspector. For some reason I feel like this was causing me headaches outside of UITK
well, I have visualElement.Add(new PropertyField(){bindingPath = nameof(selectedObject)}); also
I don't really see the difficulty in imgui
I'm a nnnnooobbbbb
The first section goes over it in IMGUI
https://help.vertx.xyz/?page=programming/editor-issues/serialisation/serializedobject-how-to
UITK's binding path is a neat wrapper, but imo I'd only use it for top level properties and still use SerializedProperty otherwise
@visual stag could you tell me who can help me with the crash unity?
Nobody can help. This is a community server
This channel is for authoring extensions for the editor. You should ask in #💻┃unity-talk if anything
ok thanks
there are two users with this nickname on the server, could you tell me # code
It's literal, not a user.
Hey everyone. I'm trying to draw a hex grid using handles - it works but it runs very slow. Seconds-per-frame slow. I suspect I might be doing something wrong regarding drawing the handles, or maybe handles are too expensive and not a good way to draw a grid. Here's my code: https://paste.ofcode.org/3bqSNdtSKvWbR75U8GMAxfC
Also, I'm managing its properties in a separate EditorWindow class here: https://paste.ofcode.org/uUPG9d5giGXjHXJWYJj2hi
Maybe how the HexagonalGrid class is instanced in the EditorWindow?
Ok - I just updated the properties in my EditorWindow and it drew the new grid on top of the old grid. So I'm definitely doing something wrong.
Nevermind. I restarted Unity and it runs smoothly now - no FPS loss unless I make the gridSize more than 50
It seems the grid is sticking around after assembly reloads
I reported a bug that OnDisable wasn't being called for an Editor not long ago, so I'm not sure if that was a more general problem
Ok I got it working. OnDisable is called for the EditorWindow but not for Editor object instances created in the EditorWindow class. In my case the HexMapEditor class's OnDisable was called, but not HexagonalGrid's. I fixed it by calling all of the instanced object's OnDisable code as a public method from within the EditorWindow class.
Uh, I didn't notice how you were instancing the editor. That's not how Editor should work. In your case there's no reason to inherit from Editor at all unless you are using [CustomEditor...] above the class and the editor is appearing elsewhere.
Seeing as Editor is a ScriptableObject if you are instancing it you need to Destroy it when you are done
But if you're not actually using any features of Editor or ScriptableObject, just make it a normal class and call Enable and Disable methods of your own.
I thought of that but then I cant make a SerializedObject out of it
And therefore no SerializedProperties either.
I'm honestly confused why you're doing that, you're not using the editor outside of this window
Does that only really help with Undo? If so maybe I can handle the undo cases myself
Just serialize the values in the EditorWindow imo
If you make HexagonalGrid a normal serializable class you can just serialize that into the window
I was under the impression that using the Serialized Property fields was considered best practice - it's in much of the example code in the documentation. Honestly though from a code organization perspective it would be nice to not have to manage two versions of every single field. Especially as I continue to add more functionality to my tool
I can't remember the reason it was listed as best practice but I'm pretty sure it has something to do with setting the scene dirty and undo
But like you said I'd much rather just make the class serializable and the fields I want in that class serializable as well.
Hi so i have my enum StatType, some are like so:
AtkMelee, AtkMeleePercent
ArmorPhysical, ArmorMagical, etc
I wanna make an enum/popup that takes these enum but inserts a "/" in the PascalCase string, so the popup will categorize them
I guess i have to parse PascalCase then .Replace("/","") myself?
Just asking if there's something similar built in, or know of some gist i can just copaste
Ok so i found ObjectNames.NicifyVariableName maybe can start with that
Coool. So neat now
Hi, I recall there is a way to get a persistent identifier for a scene object like a GUID, but can't find it will trying to search for it.
What I'm trying to solve is a tool to search through a bunch of scenes and store a way to select them if I open up the scene again.
Hi i'm trying to make property drawer for a NON UITK custom editor (just for in default inspector)
It seems like it doesnt work?
It seems i have to use OnGUI for custom property drawer in default inspector?
What do you mean? If it's a non-UITK editor it uses OnInspectorGUI
If you're making an IMGUI property drawer it uses PropertyDrawer's OnGUI
Yeah i'm following this https://docs.unity3d.com/ScriptReference/PropertyDrawer.html
And the UITK version doesn't work
Post your code
I found this post
https://forum.unity.com/threads/getting-no-gui-implemented-with-custompropertydrawer-2020-1-even-in-official-example.964862/
But im not sure if this is the same case as mine
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
// Create property container element.
var container = new VisualElement();
// assume that property.enumValueIndex is enum's int value. not index of order of the enum indexing
PopupField<StatType> statPopup = Utils.MakeEnumPopup((StatType)property.enumValueIndex, (t) =>
{
//Debug.Log("Selected add: " + t.newValue);
property.enumValueIndex = (int)t.newValue;
EditorUtility.SetDirty(property.objectReferenceValue);
});
container.Add(statPopup);
return container;
}```
Utils.MakeEnumPopup is just a method to make the popup. It works in anywhere in my other custom editor UITK
So you're drawing in an IMGUI editor?
Yes.. i think? Default inspector for SO without custom editor is... IMGUI right?
So default is not UITK?
Omg yea why did i think otherwise..
Hi all, i'm getting a type is not a enum value
Am i right to be using property.enumValueIndex?
StatType currentSelected = Utils.statsAll[statProp.enumValueIndex];
Debug.Log("Cur enum value index: " + statProp.enumValueIndex);
Func<StatType, string> format = s =>
{
var regex = new Regex(Regex.Escape(" "));
var newStatTypeext = regex.Replace(ObjectNames.NicifyVariableName(s.ToString()), "/", 1);
return newStatTypeext;
};
int result = EditorGUI.Popup(amountRect, "Stat", statProp.enumValueIndex, Utils.statsAll.Select(format).ToArray());
property.enumValueIndex = result;```
This line
Debug.Log(result);
property.enumValueIndex = result;```
Result is 2, which is totally a valid index in the enum
But it throws that error..
Try int value
type is not a supported int value
I'm now just doing this property.intValue = 1;// result;
So 1 is not supported it seems..
Omg wait
Sorry, it was a stupid mistake
I should be using "statProp" instead of "property"..
But now the popup is still not drawing
🤦
Why cant i draw a single damn popup field? This thing is not clickable and i'm not sure what those excess boxes are...
var nameRect = new Rect(position.x, position.y, 40, position.height);
var statRect = new Rect(position.x + 40, position.y, 40, position.height);
var valueRect = new Rect(position.x + 100, position.y, 60, position.height);```
Code is really similar from the docs
The floatfield is editable tho
If you're drawing a really thin element with a label it usually comes out wrong
you should pass GUIContent.none into the label field if you're drawing something small
and manually draw the label with another call if you still want it
Are they thin tho? 40 width and using position.height
They're displayed with reasonable rect size but positioning wise it's wrong
The "NumNum:0" on the left is... i dont know where that's from actually
Before i started making this drawer, i'm using the "first string of a serialized class is what the default inspector uses to display the entry in a list", and "NumNum: 0" is what the string is
But why is it still being drawn even when nothing in the custom property drawer is drawing it?
40 width sounds tiny
if you're drawing an element with a label the label will crush it to death
Ooooo like that. The width is already shared with the label
Ok yea i got it working, at least the popup is clickable
But the left "NumNum: 0" is still a mystery. How is that "immune" to custom prop drawer?
But whatever, my fields are clickable so it's functional now
you might have thought otherwise because Unity does have in many UI documents that state in it the plan is eventually to make UITK the default
That they made the default (presents first) editor docs all UITK before they even had parity was rather irritating
It's still a mess in that regard
Is it worth putting in reports of documents that seem like a "mess" when coming across them? I came across some recently that I just put off as probably already known, so didn't waste my time as to not be spam basically
I have no idea. I only report stuff that's unclear or incorrect. The UITK/IMGUI editor stuff... it's just a lot to explain
Does anyone know how to disable EditorApplication.Beep? I have some movement controls in interactiveGUI that makes it go nuts
I'll try using Event.Use I guess
That works fine, but, if someone has an explanation of why, please let me know? All I'm assuming is while I'm using input the beeping is happening from a GUIEvent trying to accept that input for something else and EventType.used is preventing it
Are you on mac?
If so then when you use a event you need to Use() the event.
yeah.
Also iirc when you use a mouse down you also need to use the mouse up and vise versa.
Oh, okay, I've really only dealt with checking event types haha. This is the first time I've forced one
did u make it ? my list keeps growing >_<
Not yet, other things came up. Idk how much longer I can put it off though, my list keeps growing too...
how did u reflect a sealed class ?
What do you mean?
[NativeHeader("Editor/Src/MenuController.h")]public sealed class Menu
(Oh yeah I also remember the other reason I hadn't yet, I realized that they completely rewrote the internals of the menu in 2021.2...)
The same as any other calls. Sealed just means you can't inherit from it.
No, it is just that they completely rewrote how it works internally. The way the function is basically completely different.
oh ... i get it now
So I would need to make two separate systems basically for the same thing. The new system is much better and works properly, the old/current system is rather limited and doesn't always seem to work.
Are you looking at the github source reference?
just do what u need for your needs , if u make it FOSS others will adapt
yes.
https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/Menu.bindings.cs#L38
this is 2019
Ah, yeah. I just use dnSpy now. Github hasn't updated since 2020.1 I think it is.
ah i c now , https://github.com/Unity-Technologies/UnityCsReference/blob/2020.2/Editor/Mono/Menu.bindings.cs
this is the latest branch
but still not 21
2020.2.0a13 is the newest version it was updated for. 16 months ago.
dnSpy from softx64.com ?
this is amazing
Yeah, I will, it is just demoralizing to know that it won't work on a newer version and the new (internal) api is sooo much better...
From github. https://github.com/dnSpy/dnSpy
why not make a bunch of interfaces that sit in the middle between the reflection and the editor window tool ?
Yeah, I could have some layer of abstraction between them. It has been a couple of weeks since I looked at it, but from what I remember they don't even have a lot of the same methods.
do u know which dll holds the editor classes ?
The UnityEditor.dll one 😉
ah found it Editor\Data\Managed
from the looks of it Menu is not the actual ContextMenu
but rather the window toolbar
.
Menu is just a utility iirc. All the menus in the hierarchy and project window are also in the window toolbar.
or do i just modify anything under Assets/... and it will auto fetch it into the context
i do see the similarity , gonna try that
@gloomy chasm im not sure its possible to edit them without losing the Action bind
there is the add method
but nothing returns the callback for the current path
but it might still be possible to just disable alot of clutter i don't use 🤔
There should be another one that lets you just change a path.
I don't remember now, but there is a way.
nothing that i can see in that Menu class
although MenuUtils has this beefy method
One version there is a method called "AddExistingMenuItem"
I would need to go look at the code to figure out to do it. A hint if you want to try and figure it out, look at "EditorModeService" (or something like that)
It uses the Menu to add items.
yeah its UnityEditor.ModeService that uses UnityEditor.CommandService *
but there isn't a straight forward way for getting a command index from path
@gloomy chasm well i made this simplified thing that deletes items and it works ok but it loses any changes after assembly reload >_<
anyhow if u end up making your thing give me a ping , i'd like to check it out
Nice, yeah that is expected. Will do!
Couldn't hurt.
I have a general question for everyone - how do you all go about structuring your scripts around an editor window to work with Unity's serialization? Is there a neat and organized way to do it without one giant monolithic editor window class?
What do you mean "...editor window to work with Unity's serialization"?
monolithic classes are still readable if u use #region ))
I'm working on a project with one single editor window that has lots of different functionality. I started making individual classes for each function but to get each field from each class into my editorwindow Serialized and displayed properly is proving very difficult
Generally you want to avoid using #region to make your class readable. (Some people may differ in this opinion)
i mean u can make 20 classes inside a single file 😛
not that i would recommend if you like to preserve you sanity that is , but i sometimes don't mind )
It shouldn't be difficult to serialize them... You just add a Serializable to the class.
No, don't do this... ever... please no.
whahaha
"Split things in to separate class" is all I can really say. Anything more is too specific really.
can u use EditorGUILayout.PropertyField for [System.Serializable] class like it does in the inspector ?
Of course, a serialized property is a serialized property.
i mean if the class has multiple fields
would it draw them all in a single call ?
i.e : my class Klacc()has A, B and C and calling EditorGUILayout.PropertyField( klass ) would draw 3 fields ?
Of course.
So I have a separate class that does the function I need and it does it well. It has five fields, all of which I want to include in my editor window. First I have to instantiate the class, then pull in data from all the fields (which means I have to make them all public). Plus since I'm not using SerializedObjects and SerializedProperties, I have to handle Undo and make things dirty myself. I can make my function class inherit from ScriptableObject and then use SerializedObject on it which works - but now I'm duplicating fields everywhere. It all just feels messy.
in a single call ? - if so that's amazing
But would I need to make a separate Custom Property Drawer for this too?
You can make SerializedObjects from EditorWindows.
Do you need one for drawing it in the inspector?
Yes I've done that with my EditorWindow but it doesn't have the fields I need
Unless I'm content with the default foldout menu it creates
Do you mean because they are the other class?
Yes
Ideally I'd like them to be in the other class as private fields
SerializedFields of course
All of this other stuff works but it doesn't feel clean
Then you just do windowSerializedObject.FindProperty("otherClassField").FindReletiveProperty("theFieldYouWant");
That sounds good
I just spent an hour digging through documentation and never found Find RelativeProperty
I think that's exactly what I need actually. Thank you
You can also do windowSerializedObject.FindProperty("otherClassField.theFieldYouWant") (Works with FindReletiveProperty(..) too)
👀 didn't know that ^
And that even works if the field is a private SerializedField?
All of your fields that you serialize should be [SerializeField] private. Using public fields is against C# design guidlines.
They are
That was one of things I didn't want to do lol
I think I can also set up events from my EditorWindow for OnEnable and OnDisable too so that I can trigger each class to load and save EditorPrefs
Well, I guess I can just use a constructor for the OnEnable part
No need, just serialize the fields in the editor window
They save automatically?
class MyWindow : EditorWindow
{
[SerializeField] private int _myfield;
}
It saves on editor reload just like ScriptableObject assets do.
What about the private fields in my other classes
no?
Well if they are serialized of curse they will.
"serialized "
As long as the fields are serialized, and the class/struct has the Serializable attribute.
It wasn't working for me earlier - probably because I create a new instance of the function classes in OnEnable - I'll play around with it
That is exactly why. It was saving, you were just overriding the save.
Basically if I put 5 in the field, closed the EditorWIndow and reponed it, it would be reset to its default value
Yes
Yeah that's what I thought
Closing the EditorWindow destroys the window ScriptableObject.
If he wants to save data when closing the window. There is also SessionState which lets you save data for just the unity editor session.
However if you are doing anything more than extremely simple data I recommend ScriptableSingleton.
in the docs it says this sill survive assembly reloading , but would it also hold pointers ?
two years ago i made this console editor window https://cdn.discordapp.com/attachments/632735345276092429/641385218024144899/unknown.png
but whatever i did , it never could re-attach to the same cmd process ( after assembly reload )
If you mean to normal C# classes then no, references to normal C# classes are lost when deserialzing.
Or more accurately are never serialized.
I assume the problem was that you were using the Process class right?
i think so ( iirc )
oh well , its dead then
Unless you can find it again.
Maybe? Idk I never touched Process or anything like that until just last weekend 😛
if there is some lib that can give me ID's instead of pointer then it would be possible
back then i remember trying a lot of tricks and hacks but nothing seemed to work /
FYI I did have to load the property data to editor prefs using a custom event called from the Editor Window class. Apparently you can't use EditorPrefs.GetInt in a constructor.
So I just have OnEnable and OnDisable in my regular C# class, both called by events in my EditorWindow's respective methods. Seems to work great.
Is this so you can keep the data when the window is closed?
Yeah. Ideally if you set a handful of values, close the window and reopen it, those values should be right where you left them
Also assembly reloads seem to clear out data as well, EditorPrefs works nicely to preserve that
Also I have to subscribe and unsubscribe to SceneView.duringSceneGUI in at least one of my classes, likely more as I continue adding more functions
But calling so.FindProperty("classInstance.classField") works great. Thank you for that. That cleans up my code a lot
I thought I was going to end up declaring, updating, and applying modified properties to a dozen SerializedObjects. This is much better
Idk what you are doing, but maybe consider splitting it in to multiple windows?
I did consider that. I have it set up with tabs right now, which I quite like. Plus a lot of it needs to be done in sequence. It's an editor I'm setting up for myself to help me with a hextile strategy game I'm working on. This window will let me display a hex-shaped grid, set the size of the map and create it, and eventually place prefab tiles , objects, and units. But, for example, I don't want to be able to place prefabs until I've created the map base first. Some of it will involve terrain generation, placing roads/trees/rivers, etc. It's a big project.
But I ran into a problem making the game wherein making a map would take waaaay too long. It's going to be multiple levels/worlds, so I need something to speed up the process and also make it all saveable in the end.
It's all coming together now - this feels much cleaner: https://paste.ofcode.org/Ed7ieQysXHhkgfTrrwxCck
Having a weird issue with ObjectFields inside of an EditorWindow. For some reason, the dialogue to select an asset doesn't work, but dragging and dropping an asset does. Anyone know why this would be?
This is my code for this line - should work, right?
ReferencedConversation = EditorGUI.ObjectField( RelativeRect(new Vector2( 0, 30 ), new Vector2( 270, 40 ), padding ), ReferencedConversation, typeof(Conversation), false ) as Conversation;```
object type and what I'm trying to write to are both ScriptableObjects if that helps at all
Can PropertyDrawer be not for a class, but an enum?
So anywhere i have the enum, whether in c# plain class or UE.Object, it'll draw it custom?
Sure
Super awesome. Trying it now real quick and mind about to be blown
I thought this is what Attributes are for but this is even better
Attributes are for when you want to more generally apply a drawer to multiple types
Awesome all working! And doesnt clash with the UITK part bcoz that's not using custom prop (UITK) anyways
Or conditionally to the same type
Or if you need to pass some parameters per field
Is there a way to manually set the UUID of an asset in the database? I have a tool which generates assets, but each time I regenerate one it gets assigned a new UUID and so breaks references
(in my case, it's modifying animation assets to change the keyframes)
Not really, you can manually edit the meta file but that's a bit tricky as well
Something like this
Match guidMatch = Regex.Match(metaText, "guid:.([A-Za-z0-9]{32})");
if (guidMatch.Success && guidMatch.Groups.Count == 2)
{
string guidToAssetPath;
string newGuid;
do
{
newGuid = AssetBundleVariantGenerator.RandomGUID(random);
guidToAssetPath = AssetDatabase.GUIDToAssetPath(newGuid);
}
while (
!guidToAssetPath.Equals(assetPath) &&
!string.IsNullOrWhiteSpace(guidToAssetPath) &&
!guidToAssetPath.Contains("__DELETED_GUID_Trash") );
metaText = Regex.Replace(metaText, "guid:.([A-Za-z0-9]{32})", $"guid: {newGuid}");
}```
thanks Navi, I worried that might be the only option! it seems prone to errors or breaking changes. Is there a way to reduce the asset to an empty container and then put something else in it?
I mean for instance, if the original asset is an AnimationClip, and the updated one is also an AnimationClip - rather than create a new asset through the AssetDatabase, is it possible to do the equivalent of clearing the AnimationClip and then populating it with the new data, so it's still technically the same asset
My vague understanding is that some assets can be containers for multiple SOs
I mean you can just modify the AnimationClip you have
My goal is to have a source asset and a modified version, and when someone clicks 'generate' it recreates the modified one from the source asset (but using the same UUID as any previously generated modified version, so it doesn't eg break references). Ideally I'd copy the source into modified and then run my process over that - it seems the easiest way to prevent any kind of error occuring on subsequent regeneration, because it only depends on the state of the source asset and not of the generated
(whereas modifying the generated asset could potentially lead to bugs where it depends on the state of a previously generated asset, e.g. say some field doesn't get reset correctly)
Ah, subassets might be possible but they'll still get a unique id
Hi! I've got a little conversion problem. I've got an array of Leaves (yeah, again :) ) on an object. On it's Editor script, i get those leaves on a serialized property. here's the script where i fetch the leaves:
ScenarioTree tree = (ScenarioTree)target;
Leaves.ClearArray();//I clear the array of the sp
Object[] o = AssetDatabase.LoadAllAssetsAtPath("Assets/Scenarios/" + tree.ScenarioTreeKeyID + "/Leaves/Leaves " + tree.ScenarioTreeKeyID + ".prefab");//I get all the leaves that are on the same object
int count = 0;
for (int i = 0; i < o.Length; i++) {
if (o[i].GetType() == typeof(ScenarioLeaf)) {
count++;//I get the future length of the array
}
}
ScenarioLeaf[] pLeaves = new ScenarioLeaf[count];
for (int i = 0; i < o.Length; i++) {
if (o[i].GetType() == typeof(ScenarioLeaf)) {
pLeaves[i] = (ScenarioLeaf)o[i];//I set the values on the array
}
}
Leaves.objectReferenceValue = pLeaves;//Can't do that, i can't convert ScenarioLeaf[] to an object.
So two problems:
- Can't i minimise the two foreach in one? I hate lists, i got told using arrays when you can is more efficient, so i tend to use them here too
- How to set the Leaves SP?
AssetDatabase.LoadAllAssetsAtPath("...").OfType<ScenarioLeaf>().FirstOrDefault(); is what I'd use
@tough stream
oooh nice! what's first or default?
effectively! okok
but i need the whole array though:
ScenarioTree tree = (ScenarioTree)target;
Leaves.ClearArray();
ScenarioLeaf[] pLeaves = AssetDatabase.LoadAllAssetsAtPath("Assets/Scenarios/" + tree.ScenarioTreeKeyID + "/Leaves/Leaves " + tree.ScenarioTreeKeyID + ".prefab").OfType<ScenarioLeaf>().ToArray();
Leaves.objectReferenceValue = pLeaves;
soTarget.ApplyModifiedProperties();```
cast still isn't possible though
if (GUILayout.Button("Fetch Leaves")) {
ScenarioTree tree = (ScenarioTree)target;
Leaves.ClearArray();
ScenarioLeaf[] pLeaves = AssetDatabase.LoadAllAssetsAtPath("Assets/Scenarios/" + tree.ScenarioTreeKeyID + "/Leaves/Leaves " + tree.ScenarioTreeKeyID + ".prefab").OfType<ScenarioLeaf>().ToArray();
Leaves.arraySize = pLeaves.Length;
for (int i = 0; i < pLeaves.Length; i++) {
Leaves.GetArrayElementAtIndex(i).objectReferenceValue = pLeaves[i];
}
soTarget.ApplyModifiedProperties();
}```
i've done this, and it seem to work quite well! Do not hesitate to ping me if you have any workaround, i am hungry for knowledge
That's what I'd do
No need to use ClearArray though if you're setting all the values afterwards though
posted in wrong channel originally - moved here.
Hi all, is it possible to make a custom UI inspector for a Scriptable Object or do they need to be a mono? My goal is to be able to define a list of Vector2 points and be able to see the result in the UI Inspector when editing the SO. My goal is to be able to see the objects in the editor. e.g. in my screenshot, we would just see a straight-line.
@knotty herald I have done this on a SO using imgui by just having a customeditor class for the SO. then the GUI will appear if u inspect the SO asset in the project folder
@primal heron ok thank you, I am currently going down this rabbit hole - https://docs.unity3d.com/ScriptReference/PropertyDrawer.html but I'm not getting any results from that yet
This is all I have so far though; so no real element displaying - so I am definitely using it wrong
[CustomPropertyDrawer(typeof(TetrisShape))]
public class TetrisShapeDrawer: PropertyDrawer {
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
// Create property container element.
var container = new VisualElement();
Debug.Log("CreatePropertyGUI called");
return container;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
Debug.Log("OnGUI called");
}
}
@knotty herald if it’s simple imgui is easier IMO but hard to do stuff like reorderable lists etc.
Ok thank you, I'll have to read up on imgui then
Do you know of any good resources out there otherwise I will just try the docs first
@knotty herald I learned by trial and error but for an asset look at editorguilayout.
You probably want an Editor instead of a property drawer