#↕️┃editor-extensions
1 messages · Page 42 of 1
@onyx harness Thanks, I'll check that out, the fileFolder thing works but the object field would be better!
You can not exactly force the object picker to filter only JSON. But you can post check if it is a JSON file
How you guys accomplish that OnValidate doesn't trigger from Enable/Disable of a script?
hello everyone! i can seek for help here right?
Is there a way to do rich text in new UI Elements using Label?
Hey, do you know how to create editor window that targets game object? Like inspector or animator?
So I will be able to do some stuff to currently selected (valid) game object with option to lock it and so on
@orchid pelican not yet as far as I know, I had to hack it in myself
there's clearly support coming, but as far as I've seen they've not enabled it
I there a list of GUI icons?
@visual stag thanks.
I used this code:
// ...
private void OnEnable()
{
// Adding selection checks
Selection.selectionChanged += Repaint;
UpdateSelection();
// Loading needed textures
unlockedTexture = (EditorGUIUtility.isProSkin ?
EditorGUIUtility.Load($"builtin skins/darkskin/images/{unlockedButton}") :
EditorGUIUtility.Load($"builtin skins/lightskin/images/{unlockedButton}")) as Texture2D;
lockedTexture = (EditorGUIUtility.isProSkin ?
EditorGUIUtility.Load($"builtin skins/darkskin/images/{lockedButton}") :
EditorGUIUtility.Load($"builtin skins/lightskin/images/{lockedButton}")) as Texture2D;
// Setting style's icon based on state of "locked"
lockIconStyle.normal.background = locked ? lockedTexture : unlockedTexture;
}
// ...
private void ShowButton(Rect rect)
{
rect.height = lockedTexture.height;
rect.width = lockedTexture.width;
if (GUI.Button(rect, GUIContent.none, lockIconStyle)) {
locked ^= true;
lockIconStyle.normal.background = locked ? lockedTexture : unlockedTexture;
}
}
```To make this. Is there any better way?
@zealous ice Oh yeah you can do better XD
How? This is only way I was able to achieve this
Hi! Is it possible to add a field in a custom editor by type alone? (as long as the type is serializable?)
@marsh tusk I'm not sure I understand
Hm , how do i prettily paste code? 😃
my
code
thanks
public class MonoBehaviourEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
Type type = target.GetType();
MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public);
foreach (MethodInfo method in methods) {
AutoButtonAttribute autoButtonAttribute = method.GetCustomAttribute<AutoButtonAttribute>();
if (autoButtonAttribute != null) {
ParameterInfo[] parameterInfos = method.GetParameters();
foreach (ParameterInfo parameterInfo in parameterInfos) {
Type parameterType = parameterInfo.ParameterType;
//Draw Inspector field for parameter type here given parameterType is serializable
if (GUILayout.Button(parameterInfo.Name)) {
//replace invoke with data from the fields in the inspector.
method.Invoke(target, new object[0]);
}
}
}
}
}
}
Hope it's readable. So, I'm pulling all the methods from a monobehaviour. If the method has an AutoButton attribute on it I find out what parameter that method has and then i want to create a field in the inspector for that type type.
pressing the button would then invoke the method using the properties from the inspector.
There's a few examples around of doing this without the parameters but it would be even more powerful if it could deal with arbitrary serializable parameters.
@zealous ice Use this:
https://pastebin.com/rK0zQ0Du
@onyx harness // I used this, for some reason, "IN lock" (or something like that) was not working with EditorGUIUtility.FindTexture
@zealous ice Because you are not using the right style
Use "IN LockButton"
this.isLock = GUI.Toggle(r, this.isLock, GUIContent.none, "IN LockButton");
Oh.... you can make locks like that...
Well being locked is a boolean, toggle was made for boolean.
That simplifies things a lot, I will try it tomorrow (±13:00 UTC+0)
So I just have to replace all that toggling logic with this one line?
Yep
This is the look fo my ShowButton:
protected virtual void ShowButton(Rect r)
{
this.isLock = GUI.Toggle(r, this.isLock, GUIContent.none, GeneralStyles.LockButton);
}
GeneralStyles is something built in or your own shortcut for strings?
What do you mean?
I don't want to create classes for constants and so on for only one window
Also, looks like using GUI's toggle solves problem with icon size, right?
Using the given Rect is fine.
Oh no, don't implement a class to handle style, it's fine.
Mine is not just storing constants, I do other stuff for my stuff.
Also, In Unity's documentation I can't find (Rect, bool, GUIContent, string) overload
Oh, that's handy. Anyway, as I said, I will try it tomorrow
Hey @visual stag, did you have a chance to try dnSpy?
nah sorry, I'll download it now if my internet will let me
I can't talk politics, sorry 😛
hehe
@onyx harness It's definitely more powerful, but the search seems slower amongst other things. I'll have to trial it for a longer period to really see if I get any worth out of it.
Though, I can search for "Class.Method", which is super good, because ILSpy doesn't allow me to do that and it's always been irritating
that alone might be enough to get me to switch
Hehehe I knew it
The most powerful feature I see is modifying an assembly on the fly
Yeah, it's not something I plan on ever needing personally 😛
And the dark theme, it is just the cherry on the cake
I just use ILSpy to hunt for internal methods, and finding additional details like performance problems with methods I use
When I'm telling people about methods on here I often look them up to make sure I'm giving all the detail I can
So much extern though ):
yeah I see
DnSpy pretty much works the same as IlSpy except for that they have a decompiling debugger
Which sometimes works great but not always
I tend to use DotPeek and Resharper's decompiling feature mostly nowadays
They use the ILSpy libraries in dnSpy I think
so it makes sense they're similar
I'm just trying to avoid bloat to get what I need, but as I said, the search being more advanced beats out the fact it's a little slower
@visual stag dnSpy is much better than ilSpy
@hardy locust thanks for that input 🙃
It has tons of improvements over basic ilSpy libraries
For example, normal ilSpy fails to decompile our game, while dnSpy does it successfully
(no obfuscation)
Hey guys,
I've written a property attribute and drawer for Scriptable Object dropdown.
The problem which I have is multi editing part. When I select multiple objects which has that property attribute and each of them has different selected item in dropdown, all of them change to the first selected object, selected item in dropdown.
I read by using EditorGUI.showMixedValue I can use Mixed Value in multi editing but it doesn't work for me and I don't know.
Could you tell me what I did wrong ?
@onyx harness // Thanks, it works like a charm :D
@onyx harness // Do you maybe know what name eye visibility icon has?
If any even exist in 2018.4...
Download the guistyle viewr from the assetstore
@zealous ice Use the script I gave you.
Yes I know it, but I'm not in front of my computer.
Yeah, that script has some problem with displaying icons, however I found this one
https://forum.unity.com/threads/advanced-editor-styles-viewer-free.284148/
It shows all buttons and switches in interactive form
I used "CircularToggle" (or something like that, switches between line and circle) at the end
Good pick
@zealous ice You asked for an eye visibility:
EditorGUIUtility.FindTexture("d_ViewToolOrbit")
EditorGUIUtility.FindTexture("d_ViewToolOrbit On")
Anyone happen to know why https://pastebin.com/C03CDasA is returning 0,0,0. The actual rigidbody on the object does have a set velocity on start and is clearly moving in game.
@placid viper the editor scripting channel is about extending the editor. General code questions are in #💻┃code-beginner
Is there a way in the editor to select all of the children of a gameobject that contain a SpriteRenderer?
@hazy basalt just set Selection.objects to your gameobjects
@visual stag Hey man, do you remember when I talked about doing overlay menus?
You mean the pie menu thing?
Yeah
I will soon prepare an alpha/beta test.
Doing a video to show its potential.
Topic in the WIP forum, etc.
If you are still interested, I might make you test things first, just to take the temperature
Yeah alright, I probably can't go too deep in it but I can give initial feedback
By "soon", it can be few days, but thanks for the interest
Im new here, but I would like to ask a very beginner question, that I assume is very simple. can anyone help me?
Im trying to flip a sprite in unity3d alone the x axis, but when I insert my code, the sprite continually flips, so it appears to flicker
it works around an angle that I set up. Its a gun that rotates around another game object, so when its facing left, the gun is supposed to flip. when I transform.localscale, it seems as if its continually flipping when left.
This channel is for extending the editor not asking gameplay code questions
Hi, how would I make Visual Studio my default C# editor for unity?
I have tried going into Edit, then Preferences, then changing the External script editor
but when I try to find the location of VS it does not give me a file location
😃
errm, I have another problem.
I have 2 errors in my Unity debug log:
"The referenced script on this behaviour is missing!"
You probably changed the name of a class or deleted it
No worries
I am still very new to all this stuff. My bad
Anyone know about my problem ?
Hey guys,
I've written a property attribute and drawer for Scriptable Object dropdown.
The problem which I have is multi editing part. When I select multiple objects which has that property attribute and each of them has different selected item in dropdown, all of them change to the first selected object, selected item in dropdown.
I read by using EditorGUI.showMixedValue I can use Mixed Value in multi editing but it doesn't work for me and I don't know.
Could you tell me what I did wrong ?
Instruction:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(menuName = "Create Resource")]
public class ResourceStats : ScriptableObject
{
public string name;
}```
You should put those scriptable objects in Resources folder.
How to use the attribute:
`[ScriptableObjectDropdown] public ResourceStats _stats;`
Or
`[ScriptableObjectDropdown(grouping = ScriptableObjectGrouping.ByFolder)] public ResourceStats _stats;`
Any way to check value change in inspector other than OnValidate? Because it also being called with OnEnable and OnDisable.
Well it is part of it, it's not a bug.
I'm making a custom polygon editor in scene-view. User can click and drag points or press the "G" key to start moving a previously selected point.
It works great when I click and drag, but if I press the g-key, and move the mouse outside the Unity window, I start getting an error of "Screen position out of view frustum" when I try to call SceneView.currentDrawingSceneView.camera.ScreenToWorldPoint(screenPos)
I think it has something to do with window focus? It's just weird - the exact same code runs in an
if(currentEvt.type == Eventype.MouseDrag || currentEvt.type == EventType.MouseMove){...}
block regardless of how the drag is initiated. Does Unity handle MouseDrag events differently than MouseMove events in the background?
@ionic valley you will need a custom editor/property drawer for that
@smoky radish is there a reason you are not using Unity built-in EditorGUI.Popup / EditorGUILayout.Popup for that?
EditorGUI.showMixedValue is meant to be used with EditorGUI / EditorGUILayout stuff
also, this
property.objectReferenceValue = DrawScriptableObjectSelectionControl(position, label, property.objectReferenceValue as ScriptableObject, property, attribute);
should be this
using (var changeCheckScope = new EditorGUI.ChangeCheckScope())
{
var value = DrawScriptableObjectSelectionControl(position, label, property.objectReferenceValue as ScriptableObject, property, attribute);
if (changeCheckScope.changed)
{
property.objectReferenceValue = value;
}
}
or something similar (not sure if the ChangeCheckScope works out-of-the-box for non EditorGUI stuff)
@regal jasper Hey there,
Thanks for the response. I fixed it and the problem was what you said.
I don't use Popup because it isn't good for the list which items in it are sorted automatically like ScriptableObjects in the project. If you add new thing, selected item in dropdown is selected wrongly.
@smoky radish I see, that makes sense, but as you are holding the reference you could always detect the correct selected index using it. Well, glad you were able to fix it anyway!
@spark zodiac its because that uses the sceneview camera, u might have to use the mouse delta from current event
So just to be sure OnValidate also runs while playing, but only in the editor, not in standalone/production?
Yep
So this just fires if anything changes. Is there a way to know what changed, or to only listen for changes to certain field?
So for example I'm only interested if any descendent is moved, add, or removed.
Nope, unfortunately, we have no information at all
You need to monitor that yourself
That's too bad.
Hakuna matata
"Hakuna matata" is a Swahili phrase; translated, it roughly means "No problems"
😉
that aside, @brittle cosmos you can always read an article about it: https://blogs.unity3d.com/2019/05/13/introducing-the-profile-analyzer/
I think we all watched Lion King XD
Anyone played around with the graphview, or is it documented anywhere outside of basic scripting docs?
@kind linden
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(LabelAttribute))]
public class LabelAttributeDrawer : PropertyDrawer {
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label){
LabelAttribute a = attribute as LabelAttribute;
EditorGUI.PropertyField (position, property, a.label);
}
}```
```cs
using UnityEngine;
public class LabelAttribute : PropertyAttribute {
public GUIContent label;
public LabelAttribute (string label){
this.label = new GUIContent(label);
}
}```
noted but for now I'm keeping it the way it is
👍 though I see now that perhaps you mean the X and Y labels. In that case I'd still use the same method of property attributes. They're a good tool even if you're using a custom editor as they're used whenever you use PropertyField, which the editor also does by default. Means you have highly reusable customisation without making static functions or copying code around
@humble remnant Thanks yo, tho I was already using it 😔 Finding the bigger issue for me is there's still a lot of lost info on MouseMove events vs MouseDrag. Can't figure out how to:
- Keep the Unity editor focused so that mouse jumping (ie
EditorGUIUtility.SetWantsMouseJumping(1);) works on aMouseMovelike it does onMouseDrag - As soon as the cursor leaves the Unity application window, no more
MouseMoveevents fire (they do onMouseDrag
There has to be some sort of focus the editor is given on mouse down/drag events that it doesn't get on plain old mouse move events, but I haven't figured out how to force that same behavior in code yet 😦
Something I think should be simple but I'm having trouble with it? I need to display an object in the editor via PropertyField, so I can pass in a SceneAsset - but PropertyField requires a SerializedProperty, and I'm not sure how to get that since I'm not storing this data on an actual object, but rather just locally in the window?
@surreal quest cant you use ObjectField?
ObjectField also takes a SerializedProperty
@spark zodiac there is a workaround on Windows to handle mouse and keyboard
@surreal quest there is a lot of overloads
Some without requiring SerializedProperty
@surreal quest there is one overload that doesn't requires a SerializedProperty
string, Object, Type, bool, params GUILayoutOption[]
It depends, if it works and you are not willing to update or support, yep
generally avoid deprecated apis - it means it will be removed in a recent update
is it an Editor or a Drawer?
EditorWindow
and also clogs up your compile time w/ warnings
Well yeah, so thats the issue
PropertyField doesnt hav ethat
Yes, but the concern now is about it being deprecated @regal jasper
Just pragma out the warnings if you don't really care
Bad practice, but for random stuff, who cares
it is not deprecated AFAIK, using it and no warning is poping up here
It's not deprecated
there are some that are deprecated, but not those 3
There is a ton of overloads, why do you focus on those deprecated
Ah okay, I just saw this at first
If one day a deprecated or warning annoys you.
Add at the top of your file:
#pragma warning disable XXX
the ones deprecated are the ones which doesn't have both SerializedProperty and the bool parameter only
Well it's not about bothering me, it's about it being stable enough to use lol
Those have been deprecated for years, and I don't know when they will be removed
But yeah this seems to work great - thanks!
Any idea on how I could essentially draw a picture in the editor of varied size? So it could be 100 pixels wide, 10 pixels wide, or even 1000 pixels wide - so ideally it would go into a scrollview. I know theres the methods for drawing via GL., but that isn't naturally supported via the scrollview. So it won't scroll naturally. Anyone have any ideas on the best way to go about this?
GUI.DrawTexture
I assume you use GUILayout, just use GUILayoutUtility to reserve the texture space.
@surreal quest
@onyx harness Sighs I know, I know, I just really don't want to make platform-specific calls/mess with things beyond vanilla unity. Lol, thank you for putting up with all my questions though as I keep trying to wiggle around it...
All your questions? 🤔
@spark zodiac I think you are misunderstanding the purpose of MouseMove
(there were 2 times a few weeks back where you suggested the same)
(for different problems)
It is sent when the mouse moves over the window.
If it were sent whenever anywhere your mouse move, all the windows would trigger it and become way to costy on the rendering.
nods It would just be nice if I could request a similar behaviour as mouse drag for other situations. Trying to simulate blender transformation movement, where you can tap "g" and basically all mouse moves are treated like drags... but I gotta do more homework. But seriously, thank you
I didn't try, but perhaps a way to keep track of the mouse would be to repaint.
Oh, I could! Repaint does still fire. It's just I still can't get mouse jumping/raw data about movement.
For that I only know the workaround on Windows...
To keep the mouse still and keep track of its path.
Maybe I can give you other workarounds for Mac, but they are prototypes I tried, not final solution.
It's okay! I really appreciate what you've given me so far! I think if I wanted to stick to nothing platform specific, I might have to get into the EventSystems.BaseEventData API maybe? I'll keep exploring!
Nope, if I'm not wrong, this is for Canvas
Meaning UI, not GUI
On Mac, to get the mouse position, I tried to render on specific windows like Hierarchy or Project
But this is not solid, people might not have those 2 windows open.
I have another prototype but I need to start my computer, I don't have the code in mind
Dang. nods OK. No worries!
I'll keep trying to work around it on the side - I have a solution that's good enough for now, just not the perfect editor UX experience I was imagining!
Do you hold G?
No - I activate translation on the first tap, then deactivate on the second. This way, while translating, the user can type things like "z" to restrict movement to the z-axis only.
If I recall correctly my trick, I use this to intercept the input and get the mouse position, I wrote in the tip channel months ago:
'' Just discovered you could catch the Editor keyboard input from anywhere using the hidden EditorApplication.globalEventHandler...
Example here:
https://pastebin.com/RbG54qJw''
Ooh, cool! Bookmarking/will try to work around with it. Thanks!
I'm wondering, have you tried the force Repaint on G? Does it give you the proper mouse position?
yeah, I can get everything to work with just Repaint and by using mouse position instead of delta (since repaint zeros-out delta), except for the mouse-jumping/wrap-around. That's the one thing I'm really struggling with, I guess.
Oh cool, well sorry I got nothing on Mac. =X
No worries. Thanks a lot for trying to help/talking through it , and for the ideas/tips!
Hey there,
I read my serializedProperty array with this approach.
private static ScriptableObject[] Read(SerializedProperty property)
{
List<ScriptableObject> selectedScriptableObjects = new List<ScriptableObject>();
for (int i = 0; i < property.arraySize; i++)
{ selectedScriptableObjects.Add(property.GetArrayElementAtIndex(i).objectReferenceValue as ScriptableObject);
}
return selectedScriptableObjects.ToArray();
}```
When I select one object it works but when I select multiple objects which on of them has more `arraysize` than the other I receive this error.
```InvalidOperationException: The operation is not possible when moved past all properties (Next returned false)
This error is for this part : property.GetArrayElementAtIndex(i).objectReferenceValue
Any idea ?
Hum...
I just did a simple test
I selected 2 GameObjects with a MeshRenderer.
A has 3 Materials.
B has 1 Material.
No matter how I selected them. The Inspector only showed me an array of 1.
You need to check the array size
and cap it to the lowest
@smoky radish
Yup, it just shows array of one of them.
Hmmm, good idea but why Unity behaves like this ? It is weird
@onyx harness Thanks
I'd also like to understand how the multi-select serializedProperty stuff works, it's not very intuitive whenever I go out of the norm
I'd love to answer that, but all the code is behind C++ =X
Just noticed that SerializedProperty has been heavily modified in 2019.2
I hope that's the first step of an improved Serializer.
I don't know if you saw but they're using a custom YAML serialiser now
which is a massive speedup
Yeah I was supa happy when I read this in the changelog
@onyx harness For this suggestion: "You need to check the array size
and cap it to the lowest"
What should I do ? I try to break the for loop when property.GetArrayElementAtIndex(i) is null but still I receive that error.
If you call it and it returns null, it means you already passed the limit X)
Or something like that
Hmmm, yup. you are right
I have 2 ideas in mind:
1/ Iterate over the SerializedProperty (SP) and manually fetch the elements.
2/ Manually extract every single array from their real Component (using targets). (This choice is much much more heavy to implement)
Do you know how to iterate over a SP?
it.Next(true);
SerializedProperty end = it.GetEndProperty();
while (SerializedProperty.EqualContents(it, end) == false && it.Next(true) == true)
{
Debug.Log(it.propertyPath);
}
Run this code.
Replace it with your SP
If you replace it with your SP, remove the first it.Next(true);
Or run this code from the beginning of your drawer.
weird to have these bool comparisons to booleans 😛
My code convention is very explicit and kind of verbose... I understand lots of people don't like it :p
But with it, I don't make my brain thinks, I understand automatically.
it's the opposite to me, I look at it and am like... oh, that's redundant
Very redundant I understand, because here we are dealing with booleans.
I use this. everywhere.
@smoky radish So, how is it?
Still thinking how to use your code :D
I should use Array.data[1] instead of GetArrayElementAtIndex(1) ?
No no
The code is just to show you how SP works behind, how it is iterating over all the Object's paths.
Oh
If it works correctly, it will show you all the paths that it is going through
Including your target array
And... if I am not wrong, the array should only output 1 element?
Yup, 1 element
😃
I think I'm idiot 😄 because I've not figured out how to fix this issue yet 😄
Awesome. Thanks
Just asking, is there a path in your array output that explicitly gives you 1?
private static ScriptableObject[] Read(SerializedProperty property)
{
List<ScriptableObject> selectedScriptableObjects = new List<ScriptableObject>();
SerializedProperty it = property.Copy();
SerializedProperty end = it.GetEndProperty();
while (SerializedProperty.EqualContents(it, end) == false && it.Next(true) == true)
{
Debug.Log(it.propertyPath);
if (it.propertyType == SerializedPropertyType.ObjectReference)
selectedScriptableObjects.Add(it.objectReferenceValue as ScriptableObject);
}
return selectedScriptableObjects.ToArray();
}
Paste me the result please.
Because whenever you iterate over an array, it gives many informations.
And if I recall, the size is one of them
I don't know what happens 😄 but I don't receive that error
And seems it just iterates through the first one
Log for multi edit or single one ?
The whole output
multi
The one where you were receiving an error
What console are you using?
I know the native one is shit
Native one
And it is shit 😄
If I want to put the note log here it has too many lines 😄
That image show all the logs. By too many I mean in Editor.log
This is my code if you want to know what it is about
It has 3 classes
I see it output 3 elements in your array
What is the size that you are expecting?
That's why I asked you to reduce to 1 line, I don't want to clean the stack trace myself 😅
For one of them is 3 another one is 6
By one you mean one output ?
you said "no error. And seems it just iterates through the first one"
By first one I meant between 2 objects which were selected just it worked for the one of them
I don't even see what you are expecting in the result
You want Read() to return all the distinct SO from many Objects?
No I don't want to receive an error when I select multiple object. Like these 2 when I read their serializedProperty array
Which by your code I don't receive that error
No error is a basic, but having the right result is a must.
Yup, right result here should be (-) sign in the dropdown
Because as you see Grass 1 Generative Categories are 3 elements but Grass 2 are 6
And tell me what are you expecting from Read by selecting these 2?
By selecting Grass 1 and 2, the values in dropdown are these
Wait what?
Do you realize a Dropdown is binary. It's selected or not.
When you multi select, it will be selected or not or mixed.
Dropdown can not fundamentally handle your case.
It is wrong 😄 I know but first I wanted not to receive that error.
Now I want to know how to compare selected objects dropdown selected elements to show (-) sign or if they are same show the result.
I've written that dropdown by myself by GenericMenu
Did you see my codes ?
When values are different between 2 or more dropdown
😄
So I think your code is good enough for not receiving that error 😄
What do you think ?
I think... you completely took the wrong path XD
SerializedProperty is already "merging" the data.
Which means you won't know the real data used behind
You just have another reality of it
You mean when I select multi objects ?
Yep
You want to know if array is the same for everyone or not.
SP is not giving you this information.
So how can I have this information ?
You need to take the 2nd choice I suggested earlier.
Let me ask you something first :D
Is it a good way to implement this kind of dropdown by GenericMenu ?
So Unity itself does this by your second suggestion ?
If you look how Unity handles multi-targets with popup mask
It unselect everything in its GenericMenu
I have no idea how Unity is doing it
It unselects everything IF masks are different
To be honest, the way they are handling it is shit.
Simply because GenericMenu can not handle this case.
When I talk about masks, Unity is just comparing integers, you are dealing with array of Objects. Which is heavier by few orders of magnitude.
And if you want my opinion, go the easy way 😃
Hmmm
It is bad 😄
The easy way is Unity PopupMask ?
My problem with it is when objects sorts automatically (Like scriptableObjects) selected elements are shifted so I was thinking to use GenericMenu is the better way
It can work, the same way as Unity's
By it you mean Unity PopupMask ?
Yep
Then you need to check if all arrays are the same, by digging into "targets"
And display your dash.
I just get confused :D
You say `EditorGUILayout.MaskField compares masks and then show that dash and By GenericMenu you say I should compare them according by target to show dash ?
Sorry if I'm idiot 😄
I dont know which GUI Unity is using, perhaps its MaskField.
MaskField works on integers
You work on Array[Object]
Unity just has to compare value of A, to B, then C, etc.
You have to do the same
But with Object A, B ,C...
Sorry I wrote a mistake
You work on Array[Array[Object]]
While Unity is dealing with Array[Int]
Very well, Thanks.
And if you want to implement multi select dropdown for scriptable objects, do you use GenericMenu or MaskField + Storing pre data and stuff ?
Me? If I wanted to handle multi-select dropdown? I would implement my own GenericMenu 😃
Nice 😄 so I chose the correct way 😄
But I'm used to create tool (toying with GUI), so it's not a big deal for me.
No no
By own GenericMenu, it would be my own custom GenericMenu clone.
Oh, I just figured out
Look how Odin Inspector deals with dropdown
Yup, you are awesome and you can do it but I can't 😄
That's why, stay with GM if you feel safer with it
Hey, I was where you were.
And I learned by trying hard
I do it in my spare time, it's my hobby, I don't have any pressure, so I can learn at my pace, which is everyday
I like to know more about serialization stuff and writing custom one if you have any useful links to check because Unity one is really pain in the ass 😄 My first problem is with PropertyDrawer for arrays as you see I used another extra class to have array in PropertyDrawer.
And thanks for your great responses. I appreciate and sorry if I wasted your time
I just implemented tools
More and more and more
It ended up in NG Tools:
https://assetstore.unity.com/packages/tools/utilities/ng-tools-free-80093
Wow, awesome
No time wasted, I never refuse to help a programmer willing to learn.
It doesnt mean I'm going to help everybody, but I like toying with the editor, and I knew I could help you.
About your extra class, it's not an evil thing, you needed to wrap it, if it is necessary, it's okay, no shame 😃
Thank you very much. I really like to learn more. I appreciate.
Hahaha welcome 😃
@onyx harness
Could you help me ?
private static void GetScriptableObjects(ScriptableObjectMultiSelectDropdownAttribute attribute)
{
Type genericClassType = typeof(Resources);
MethodInfo[] methodsInfo = genericClassType.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
MethodInfo methodInfo = methodsInfo.Where(_ => _.IsGenericMethod && _.Name.Equals("LoadAll") && _.GetParameters().FirstOrDefault().ParameterType == typeof(string))
.FirstOrDefault();
Type[] genericArguments = new Type[] { attribute.BaseType };
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);
_scriptableObjects = genericMethodInfo.Invoke(null, new object[] { "" }) as ScriptableObject[];
}```
By this function I get scriptable Objects in Resources folder. Right now I call this function in `OnGUI`but I think it's not optimize. Any idea ?
Whenever you post code, it is a good habit to remove the indents X)
Because in front of me, it's a mess
(My Discord is not fullscreened)
Are you calling it in every frame?
First scope indents, not inner scope XD
It's fine it's fine 😃
You are calling LoadAll() in every Repaint()? O_O
Yup, I know 😄 It is shit
First of all, you will need to cache it.
And ... why using Reflection? O_o
Reflection.LoadAll takes a path and a Type.
And what is giving attribute.BaseType?
The type of those scriptable objects which I show in the dropdown
But I can't use variable for generic method so I should make it by reflection
I think
I use _scriptableObjects in Repaint Event because I want the length for showing "Everything" in dropdown title but I don't know what is the best way to cache this array.
Just test it and confirm please.
Let me check
Keep in mind Unity often offers a generic way and a non-generic way.
I'm not sure, but I think UnityScript was a reason.
Can I cast Object[] to ScriptableObject[] ?
Seems that function works but I can't cast it. Casting to ScriptableObjects[] works in that reflection method but doesn't work on this 😄
How do you cast?
_scriptableObjects = Resources.LoadAll("", attribute.BaseType) as ScriptableObject[];
Test (ScriptableObject[]) instead of as.
It's not valid.
Hmmm, I think I cast from object(C#) to ScriptableObject[] in that reflection method.
Nope you don't
I don't know what you mean by not valid
Resources.LoadAll() do the cast for you
var list = new List<ScriptableObject>();
var result = Resources.LoadAll("");
for (int i = 0; i < result.Length; i++)
{
list.Add(result[i] as ScriptableObject);
}
list.ToArray();```
Show me the code
not the error
ScriptableObject[] a = (ScriptableObject[])Resources.LoadAll("");
ScriptableObject[] b = Resources.LoadAll("") as ScriptableObject[];
Both compile.
Yup, it compiles but it can't cast 😕
By "as ScriptableObject[]" it returns null and by "(ScriptableObject[])" there is an error.
InvalidCastException: Specified cast is not valid.
Oh
I see
Yay, it is fixed. I've used the 3rd way many times but it is really weird there isn't this kind of casting 😄
Thanks
What about caching ?
There is reasons behind that, but at the moment I don't have a precise idea.
Maybe C# contravariance.
For caching? Very easy, use a Dictionary<string, ScriptableObject[]>
And whenever the project is changing, you clear this cache.
End of the game.
How can I notice when the project is changed ?
Like when new scriptable object is created
You can replace the 3rd way by a 4th (which is the 3rd in a more compact way)
new List<Object>(Resources.LoadAll("")).ConvertAll<ScriptableObject>(o => (ScriptableObject)o);
Awesome
Everything that you have done today, next year you will be able to reproduce it in less than 20 minutes 😃
Think about it!
How ? 😄
Today you were looking for solution, tomorrow you will know the solution.
You learned a "lot" today, I am happy for you :]
Oh, you mean that :D
And I appreciate you help me to find the solutions. (Actually you tell me the solutions :D)
As long as you understand how I did them, it is okay.
This is what I tell my students, as long as you understand and you can reproduce it, you can copy whatever you want.
Yup, it is the purpose of learning. When you don't understand you can't learn too.
Then I hope you understood my code today 😃
Yup, I did although I'm reading a little about serializedProperty iteration.
About SP, it might take some time to grasp the whole concept, but it's okay
Hum... if I'm not wrong, yes.
Editor I'm not sure
PropertyDrawer I did use its constructor
I never implement any Editor
Sorry to ask many questions.
Is there any event for PropertyDrawer when the object is selected ?
Okay. Thanks
What you can do is to register to it in your PropertyDrawer
Well, it's all up to you
@onyx harness I registered to EditorApplication.projectChanged in constructor. Did I do it wrong ?
Now you need to understand how PropertyDrawer is instantiated by Unity
(More precisely, the Inspector)
But this might be a big topic
or not
Put a Debug.log in the constructor
And you will see how often drawers are created
You might be surprised
Yup, I put it there. It is like creating new class (non-MonoBehaviour). It is called when it is created.
Something which is weird (or not) is constructor of the object which is created before, will be never called by editing the code.
I didnt get what you just wrote
I mean I had written some codes before adding constructor then this constructor will be never called in the objects which were created before.
Am I right ?
It is called when I create new instance of it
Possibly
😄
So for fixing I should put whatever I want to put in constructor in for example OnGUI then remove it after first compile ?
After first compile?
I don't understand when you say "before adding constructor"
And what do you mean by putting OnGUI in a constructor?
I'm sorry, none of your sentences make sense to me X)
A new instance of what?
The object which uses that PropertyDrawer
Hehehe
😄
This is where I warned you about "this is a big topic"
It's not about creating a GameObject and adding Component to it
It's about who is being selected by the Inspector
There is a lot of stuff going on under the hood
When you select an asset, Inspector has an ActiveEditorTracker.
This tracker posses a list of all the Editors required to render the Objects.
Those Editor will generate some stuff and PropertyDrawer when requested.
I don't remember exactly when a drawer is generated, but if I am correct, they are kind of shared
There is a reason, because SP contains data, enough to render many set of data with just a single drawer.
Right now, we are in a blurry area, I don't remember exactly
I should read about it. Do you have any link ?
BTW where should I register to EditorApplication.projectChanged ?
I did
Use a Dictionary<string, Dictionary<Type, ScriptableObject[]>>
But it doesn't called sometimes.
your callback is not invoked you mean?
Yup
Like when I create new object in Project.
Really? O_o
Are you sure the static constructor is initialized at the beginning?
Hum... That's strange
you must have done something wrong
static ScriptableObjectMultiSelectionDropdownDrawer()
{
EditorApplication.projectChanged += GetScriptableObjects;
}```
I just added this
Remind me what is in GetScriptableObjects()?
private static void GetScriptableObjects()
{
UnityEngine.Object[] loadedObject = Resources.LoadAll("", _attribute.BaseType);
for (int i = 0; i < loadedObject.Length; i++)
{
_scriptableObjects.Add(loadedObject[i] as ScriptableObject);
}
}```
You forgot to clear _scriptableObjects, no?
Oh shit
You misunderstood me
You don't reload all the projects resources whenever you change it
You just clear the dictionary cache.
This cache is fed whenever you are running the drawers
"Lazy caching"
It's funny, I explained this concept earlier today to another dude in this Discord.
Anyway, this was the last question, I have to leave this reality realm to join the sleepy realm
I'm confused 😄
Thanks
night night
I think I should read about it.
Can I find what you explained about this concept somewhere ?
1/ Clear the dictionary cache on Project changed.
2/ When the drawer is asking for resources of a given Type at your path, it asks the cache. If not, it feeds it.
I don't have any link unfortunately, I learn a lot of things by myself by testing/try harding
2/ Your Read() remember
Okay, Thanks. I need time to think about these things 😄 and you should sleep 😄
Thanks
I appreciate.
I'm writing some sort of complex timeline behavior, and I need to know when a clip is selected so I can display some relevant stuff.
Anyone has an idea as to how know if a timeline clip is selected?
@unreal lotus just check the Selection.activeObject's Type
i need help
@onyx harness but there is no "update" function on the playable clips
Where should I start if I want to create a window like the one for the Animator? A window where you can create nodes and connect them.
@unreal lotus is there any enter?
Hello, i noticed one thing. Seems like scriptable object can't hold dictionary. Well it can but it loose the value when I load another scene. Maybe it's because dictionary don't serialize ?
Yes, that is entirely the reason
Tip: If something doesn't appear in the inspector then it is not serializable
There are multiple serializable dictionary implementations out there using ISerializationCallbackReceivers
Okay thanks !
@onyx harness Not that I know of... ?
These are the known functions that the playable script has:
https://docs.unity3d.com/ScriptReference/Playables.PlayableBehaviour.html
Considering that I need to know to change stuff depending if the playable clip is selected or not, I don't see a way to go about it from inside of the clip
Try this one: OnPlayableCreate
Am trying to make a floatfield appear based on what enum item was selected. The floatfield doesn't seem to appear whenever i select the enum item of "CUSTOM". If i do decide to move the floatfield outside the statement it will appear so atm i'm not too sure how to get around this. Any suggestions will be appreciated!
serializedObject.FindProperty("m_EnemyJumpMidAttackApexXPositionMode").enumValueIndex = (int)(EnemyHighJumpAttackApexXPositionMode)EditorGUILayout.EnumPopup("MID Jump Attack Apex X Position: ", lEnemyCombatScript.m_EnemyJumpMidAttackApexXPositionMode);
switch (lEnemyCombatScript.m_EnemyJumpHighAttackApexXPositionMode) {
case EnemyHighJumpAttackApexXPositionMode.PRESET:
break;
case EnemyHighJumpAttackApexXPositionMode.CUSTOM:
EditorGUILayout.BeginHorizontal();
GUILayout.Space(20);
EditorGUILayout.BeginVertical();
lEnemyCombatScript.m_JumpMidAttackVertexXPoint = EditorGUILayout.FloatField("Custom MID Jump Attack Apex X Pos:", lEnemyCombatScript.m_JumpMidAttackVertexXPoint);
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
break;
}
Hey @onyx harness :D
I've found out why my callback to EditorApplication.projectChanged was not invoked. I unregistered it in my PropertyDrawer destructor, I just removed it and it works now. Although I don't have any idea when objects are destroyed by Unity. Seems it stores them then after some seconds destroy them.
So where should I unregister my callback to EditorApplication.projectChanged ?
It's better than that X)
Your callback? Put it in your static constructor.
No need to destroy it.
Show me your actual code.
No unregister. It's magic.
I don't advise keeping such a habit, but in this case we don't mind.
Cause editor world.
Great
@wintry aspen Your lEnemyCombatScript.m_EnemyJumpHighAttackApexXPositionMode is not up to date if I'm not wrong.
Use serializedObject.FindProperty("m_EnemyJumpMidAttackApexXPositionMode").enumValueIndex instead. Cast it to your enum if needed.
O_O
What would be the best way to replicate the projec tview in an editor window? (list of assets)
Iterate over AssetDatabase.GetAllAssetPaths()
@onyx harness what field or UI element would be best to use to display each asset identically to the project view?
would i basically be recreated it from scratch?
I would say a lot of EditorGUI.Foldout
Kind of yes.
Isn't it what you were going to do?
Or have a look at :
https://docs.unity3d.com/Manual/TreeViewAPI.html
@south pawn
Just the first example.
@onyx harness this might be useful THANK YOU
@onyx harness ideally my list of assets would mimic the editor closely so users would be able to right click on them, or delete them etc
I'd have to code up that behaviour myself right? I don't get it for "free"
I'm sure the TreeView must provides some callback to handle contextual menu.
cool thanks
Just check it, I don't have a 100% sure answer about that
@onyx harness How you write new things into SP array ? Is it possible to use something like that Read function which you suggested to use ? Right now I use this function:
private static void Write(SerializedProperty property, ScriptableObject[] scriptableObjects)
{
property.arraySize = 0;
for (int i = 0; i < scriptableObjects.Length; i++)
{
property.arraySize++;
property.GetArrayElementAtIndex(i).objectReferenceValue = scriptableObjects[i];
}
}```
is it working?
Yup
Just change line 3.
Instead of arraySize = 0, write arraySize = scriptableObjects.Length
Then should I remove property.arraySize++ ?
Yep
I read GetArrayElementAtIndex is heavy. Is it ?
You have no choice.
Either you set through GetArrayElementAtIndex, or you need to set the real array behind this mascarade 😃
But the second way implies other stuff to implement.
Oh well. Thanks for the help. You are awesome 😄
You're welcome XD
@onyx harness Sorry to ask another question :D
private static void Write(SerializedProperty property, ScriptableObject[] scriptableObjects)
{
int i = 0;
SerializedProperty iterator = property.Copy();
iterator.arraySize = scriptableObjects.Length;
SerializedProperty end = iterator.GetEndProperty();
while (!SerializedProperty.EqualContents(iterator, end) && iterator.Next(true))
{
if (iterator.propertyType == SerializedPropertyType.ObjectReference)
{
iterator.objectReferenceValue = scriptableObjects[i];
i++;
}
}
}```
What about this ?
To be honest, I have no idea which one is the fastest
And I am curious to know
Can you bench it?
does the iterator actually go over all the elements in the array?
Yep
I don't know exactly how to bench it :D. Should I do it like 1000 times and then check the profiler ?
( @smoky radish In this case I would replace Next(true) by Next(false) )
Can you wrap your code with that :
private static void Write(SerializedProperty property, ScriptableObject[] scriptableObjects)
{
var w = new System.Diagnostics.Stopwatch();
w.Start();
int i = 0;
SerializedProperty iterator = property.Copy();
iterator.arraySize = scriptableObjects.Length;
SerializedProperty end = iterator.GetEndProperty();
while (!SerializedProperty.EqualContents(iterator, end) && iterator.Next(true))
{
if (iterator.propertyType == SerializedPropertyType.ObjectReference)
{
iterator.objectReferenceValue = scriptableObjects[i];
i++;
}
}
w.Stop();
long milliseconds = w.ElapsedMilliseconds;
Debug.Log(w.Elapsed.TotalMilliseconds + " ms");
}```
@onyx harness Hmm, I think the Next function input should be true, because the property is a class which has array in it.
Great. Let me test it
Oh
Then set it to true
since you are only dealing with ScriptableObject I guess it's fine in this case
But in other more complex scenario, this will impact the result.
Thanks
The second one is by that iteration method
From zero size to 9 in size 😄
And I don't have any idea 😄
really need to run it 1000 times to really compare times properly as that's kinda nonsense, there's a 0.19 in there
Shit... it's pretty hard to tell which one is faster XD
Yup, I think so
Yeah I guess so
Let me see 😄
What you can do instead of while 1000x the whole code.
Just multiply your array of SO by 1000x.
Even by 10000 if the numbers are too small
It's not the same.
But I'm more eager to know which one is faster in big array then just repeating the same small array.
EVEN if I know your situation will never involve >10 elements
funny results to be honest
It is by running 10000x
No, I'm checking it in array size too 😄 Let me check it out
By 10000x size
The first one is by that iteration method.
I guess GetArrayElementAtIndex is heavier
wait, the second one is GetArrayElementAtIndex ?
Hum well... it's pretty explicit here
Good to know
In your case, you should not worry about that, scale issues are not yours to worry
But still it's good to know
Yup
I have a class which one of its fields is System.Type. Is there any way to access to its value in SP ?
Yup, I know. But I like to assign a value to it 😄
You'd like?
I need actually 😄
Through SP?
Yup
Okay. Thanks. I need to think about it
Can I control how deep SerializedProperty.Next(true) can go ?
Assume there is a string field in a class and I use Next(true) but I don't want iteration enters that string field. If it makes sense in your opinion.
Yep
You can control of course
You have propertyType & propertyPath
If you know specifically what you need to skip
Oh, great. Thanks
If I want to access to one of the fields I should specify it by propertyPath ? It is like FindRelativeProperty() ?
So could you tell me what is FindRelativeProperty() in iteration ?
activitiesBoredom.Array.data[0].activityName
Like how I can find out which property is activityName ?
lol
You have the name already
just do propertyPath.EndsWith("activityName")
The name FindRelativeProperty is very explicit.
It looks relatively to the current SP.
Yup, I know. FindRelativeProperty does the same thing ?
Oh well
Hey gang. Is there a way to run scripts in Unity that modify the scene / assets permanents? Looking for something similar to the way you can run python code in blender. Basically not script that runs during gameplay but something that can be triggered as a one off (i.e. to create a bunch of objects in a programmatic way quickly.)
Yes
What is it called? I can't seem to find anything that does not refer to the regular game scripts.
You can build custom inspectors, you can build custom editor windows, you can run code on OnValidate, run code using [ExecuteInEditMode] or [ExecuteAlways], you can run things in the context menus, as Menu Items. You can run code using [InitialiseOnLoad], you can make custom EditorTools. There are so many ways to do this
What's the difference between ExecuteInEditMode and ExecuteAlways?
https://docs.unity3d.com/ScriptReference/ExecuteAlways.html documentatiooooon
Might actually only be referred to on this one https://docs.unity3d.com/ScriptReference/ExecuteInEditMode.html
I guess what I'm looking for is a very simple way to execute arbitrary code and "commit" it. As a very basic example: let's say I have a 3D Object and I want to make 5 copies of it placed equidistantly from each other. I can create a script and attach it to the main object and then run it in Start() but even using [ExecuteInEditMode] it's still not making actual copies but rather running it continuously.
I'd advise just making a MenuItem
Ah I see, thanks
Cool, I think that's the easiest way. Thanks!
Does simply having a script with [MenuItem("MyMenu/Do Something")] in the project add it to the menu?
Yup, you just have to remember that it's in the UnityEditor namespace, so you probably want it in an Editor folder
Makes sense. Thanks @visual stag
Also it's probably important to mention the Undo class. If you're creating objects register them with Undo.RegisterCreatedObjectUndo so they're deleted if you undo
The docs actually have some pretty short examples on the entry page https://docs.unity3d.com/ScriptReference/Undo.html
so that's handy
nice, was just looking at that. perfect.
How can i make the right click menu that appears when i click an asset in the project view appear in my own editor window?
With a MenuItem that starts with "Assets/
@visual stag thank you, i will look into this
@visual stag I think you misunderstood my question, i don't want to add a menu item to an existing menu, I want to use the existing project windows Contextual Menu in a custom editor window.
Oooooh
Let me know if EditorUtility.DisplayPopupMenu(rect, "Assets/", null); works
@visual stag bingo! It works perfectly
Sweet 😃
@visual stag thank you so much, you likely saved me a ton of time!
I've never used the function before, I just found it through decompilation by going to ProjectBrowser.OnGUI, seeing HandleContextClickInListArea and looking in there for a moment
the docs have the same code as an example though so I didn't need to ask whether it worked 😛
@visual stag any ideas how i might capture events from EditorUtility.DisplayPopupMenu? Im specifically trying to know when the user clicks "rename".
@south pawn as far as I know you'd have to reflect into ProjectBrowser.m_AssetTree.state.renameOverlay.IsRenaming()
and poll that
@visual stag ahh, cool, where you get this info btw? you using a decompiler?
do you use that instead of the doc btw?
im trying to make good use of the doc but its hard to find stuff sometimes
and its like a mystery what is available or not
I use the docs all the time, it's just often what I'm looking for already exists in a place in the editor so it's fairly quick to look directly at the implementation
is this stuff not in the reference source?
It is, but navigating via a decompiler is faster for me at least
I'm curious how
can you like, target elements in the editor view to figure out classes or something like that?
Yes
I use Resharper/Rider to decompile while I'm coding
oh that is quite useful indeed
So I can just browse to definition to get to the decompiled source
The decompiler doesn't have the editor browsing, that's the GUI debuggers:
Window/Analysis/UIElements Debugger and the GUI View Debugger
Rider doesn't have good search with the decompiler so it's useless for anything other than inspecting things you already have an access point to, for me at least
can't you already access the UI Elements debugger?
Yes, comment that out if your version has it
so you're using the built in view debuggers, to get you information on where to go in the decompiler?
Yup
okay then, I guess I don't see how that is better vs the raw source, but ok
I also search terms a lot
I found the CS ref source to be easier because I can use Visual studio which has great search features
Not everything is exposed to the UI
You could get the same speed out of a local version of the source, though Rider (and definitely VS) takes a while to launch, and I often don't have it open for various reasons. Not everything is on the source repo is it?
as far as I know the repo is complete for all C# code
and VS 2019 takes a few seconds to launch, and you just leave it open?
repeatedly decompiling the source code will always be slower in the long run
I think the UI Source is elsewhere, but perhaps I'm mistaken
you're mistaken
I learned UI Elements by using the CS Reference because the documentation was incomplete
UIElements isn't the UI I'm talking about
I mean, in pre-2019.3 there is a LOT of Imgui, but I'm sure thats all in there
oh yeah
its all there
the reference source is invaluable
and it doesn't lose things like comments (not that there are a lot) like decompiling does
I know, I do use both, I just don't bother with the source half the time because the decompiler takes less than a second to open and has extremely fast search with very little overhead
Also I don't mean IMGUI either! I mean UI, normal, UI.
@visual stag Most of the time I don't need anything else than looking at the source of a method I'm calling, or the class it is in
Game UI, the one that we all call "UI" without attaching any other clarifiers to
Yeah, I know about this too
Can I add both to one project and search them together using an IDE?
I see no reason why not
🤷
both are pretty simple solutions
no project name conflicts
and vs 2019 also supports just opening folders
@visual stag game gui is UGUI
Ehhhhhh, I wouldn't use that term
@waxen sandal I find for whatever reason Rider's search results for decompiling don't appear so I just use CTRL-B and defer to other things when I want to search
Also that earlier UI link is incorrect, it's https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/src/master/, that's the old mercurial one. Though seeing as it's a package now I suppose that's a non-issue! Source being so easy with packages is so damn nice
Yeah, I think it's been that way for a while now, I forget sometimes. They've moved Timeline over now, amongst other things
Hah, how could I forget, I definitely used Everything Search to find some UI code earlier this week 😆
I want my editor script to be notified whenever a field has been changed in the inspector for any asset and to be able to identify the GUID of that asset. What is the best approach or event to listen for?
I don't know any easy way to achieve that.
You'll have to monitor that yourself unfortunately
I would look into the Undo class and attempt to see whether there's a callback to subscribe to
(internally)
otherwise you could probably poll the internal state of it
Not sure how well that would work out but that's the only thing I can think of
on a previous project i had to poll the internal state of fields and stuff
i was just wondering because this seems like an ineffecient way to do stuff
is it common for people making editor extensions to be constantly polling for user input in this way?
people don't generally need a callback monitoring every change to every asset
but yeah, regularly polling internal state through reflection is common
I wouldnt day user input, but yeah globally a lot of stuff are hidden or not implemented for outside devs.
sad, but common
no wonder so many unity extensions end up breaking lol
How real-time must be your solution?
I'm showing the user a list of assets they have recently modified
Asset, meaning not scene object, right?
By real-time, it can be on the moment you set an object in the editor, or save it to disk.
Kind of 2 'realtimes'
What I would do
Monitor Selection.selectionChanged.
Save the list of assets in there.
Whenever it changes again, check if your previous selection has anything modified.
It's pretty light compare to a on-update check.
Yeah I would just track selection
I'm allready using that, so how do i know if the user has changed a field?
Do you know how to list the assets in an object?
generally, yes
Whenever the selection changes, you just compare the before & after.
so maintain a record of the state of each asset and check for changes after a selectionChanged event?
can you just create a SerializedObject out of the current selection and then go if(serializedObject.UpdateIfRequiredOrScript()) //has changed ?
Or does that just always update if it's a script
Ah, nah, that'd be difficult to track across all the objects anyway, ignore my speculation 😛
public static bool IsDirty(Object target);
i might be able to use this 😄
That's an idea, I don't know if it is going to work outside the Inspector's area
(EditorUtility.IsDirty)
That's an other cool idea, keep us in touch, I would like to know the final solution :)
Yeah, that's probably a good way of doing it, never used it before 😃
oh nevermind, isDirty just tells you if an asset needs saving, not if it has actually been changed here and now
Yeah but if you click on an object that hasn't been changed, then click away, that will get pushed to the top of their stack, which I assume isn't what they want
He won't do that, since he has to check with its 'previous assets referenced list'
What he needs right now is just a way to know if 'do I need to check this selection'
And being dirty is one way to check
it's a good way to reduce the objects you need to check for changes, if that's what you mean?
Yep
yes, is dirty narrows it down for sure, doubt there is a more elegant solution but ill keep looking
SelectionChanged and isDirty is a pretty good combo out there.
Is there a correct way of doing something like TSubclassOf<BaseClass> in Unity so designers (in inspector) can create a list of subclasses? I currently have the subclasses displaying fine on their own but the List<Baseclass> doesn't show subclasses.... I do understand that Unity isn't a big fan of this
[System.Serializable]
public class ComponentEditorWrapperV2
{
// So we know what IComponentType to cast to
public virtual EComponentType GetComponentType() { return EComponentType.NotImplemented; }
// Get the IComponentData
public virtual IComponentData GetComponentData() { return null; }
}
^Baseclass
Derived classes implement the methods and have a single value of different types if it matters
Work aroud is using plugins handling it.
Or coding your own editor and serializer
Yep, I was hoping it was just something I didn't read as I was researching but here I go
@south pawn hey, how did it work?
Workaround is using Object types like Components or ScriptableObjects imo. Though you could create instances of those plain classes dynamically. You just can't serialize them in a list of the base type
I actually just switched to a struct which contained a ComponentType enum, float value, and int value. I used a PropertyDrawer to display either an int or the float in inspector based on the enum. Then cast to the correct IComponentData type to add it to the entity. It isn't super clean under the hood but it works for designers and gives me time to do a few other things that are higher priority so it seems like a win. The original solution is way cleaner but I couldn't get it to fully work (not a solution in that case). Good learning moment though
You should have told us it was for unique data.
You're kind of mimicking how a Shader stores its data in the editor.
Yeah I've done this UI trick before, it's just usually not as applicable as the other advice 😃
Oh, well I am still all ears for a better solution. I would love to simplify/clean it up
There is always Odin 😃 I haven't tested it with every variation of generics but it works most of the time.
I'm using a script to dynamically change the render queue of a transparent material based on a height integer set in that script.
I'm accesing the material through the renderer and destroy the instance as should be done according to this page
However. I get an error that says "Destroy may not be called form edit mode! Use DestroyImmediate instead." Is the Unity documentation outdated? or am I doing somthing wrong?
If you are destroying it from edit mode you need to use DestroyImmediate
the example isn't in edit mode so they use Destroy
so i'll have to encapsulate that bit in "if UNITY_EDITOR" then ig?
You must be destroying in Edit mode, what function are you destroying from?
OnDestroy
just like the documentation shows
#if UNITY_EDITOR
DestroyImmediate(m_Material);
#else
Destroy(m_Material);
#endif
would this work?
you should probably actually do:
#if UNITY_EDITOR
if(!Application.isPlaying){ DestroyImmediate(m_Material); } else { Destroy(m_Material); }
#else
Destroy(m_Material);
#endif
(I had it slightly wrong, edited to reverse)
you can do without the #if and just use the top, but basically this'll make it so it'll only destroys immediately if it's in edit mode
and it strips out the redundant if statement if it's a build
Application.isPlaying return true if you pressed the big ol' play button?
Yup
There's no universal icon one can use for "apply changes" is there?
Want to have a small button in the inspector with this meaning
Nevermind, a save icon (floppy disk) would work
@harsh hull google Unity editor style viewer
It will show you styles and icons, just pick one
this is amazing! ty
Hey guys,
Is it possible to use PropertyDrawer and another Editor layer on it ?
You're gonna have to explain what you mean a bit more
Short answer: yes.
But curious as well, why doing it this way?
@visual stag , @onyx harness Sorry, I didn't notice your messages.
I have a dropdown which can select type from it. This one : https://bitbucket.org/rotorz/classtypereference-for-unity/src/master/
Then I want to make it conditional. When the type is selected, show some fields to fill them.
I'd make a custom editor
it gets a bit out of hand if you want to do more than a few fields hiding using property drawers
possible, but having a custom editor's much easier
Unless the things you want to hide are in the same class that the dropdown is and you can make a property drawer that encapsulates all of it
Forget the Editor solution then.
An Editor requires an Object as target. You just have a Type.
@smoky radish
According to the type, I use reflection and find its fields in its class then show them in inspector.
I don't want to use PropertyDrawer but I want to use another property drawer in my editor code.
@visual stag , @onyx harness It doesn't make sense ?
I don't understand your last sentence 🤔
I mean I want to use that PropertyDrawer which I sent its link in my editor. Select item from dropdown (It returns type of selected item) and then use that type in the editor by SP.
Although I've tried it before but I can't get the type in editor and it is weird. I may miss something.
Type is not serializable. You won't have it easily from SP
Oh, shit. You are right. I forgot that.
Do you have any idea ?
@onyx harness
Right now I try to use that PropertyDrawer and don't write a new one.
May I right a new one and just store a path and use that path for reflection ?
2 choices, either you play with the target and work directly from the real object.
Or I'm sure your Type-stringed version must be stored somewhere, this string you can fetch from SP.
What do you mean by "work directly from the real object." ?
About this part "I'm sure your Type-stringed version must be stored somewhere, this string you can fetch from SP." Is it done by using that PropertyDrawer ?
I'm not sure, maybe '_classRef' is the field where ClassTypeReference is storing the Type signature.
Working on real object, I meant using Target to fetch the object ClassTypeReference and not its SP.
I have this script that's supposed to add a game object from my project to every scene in my project. Here's the code: https://pastebin.com/WtxYLgyq It "works." The problem is it instantiates the prefab as a clone instead of as a variant. How do I make it instantiate it as a variant? The questMachine go is a variant in my project
it does this:
I want this:
you are looking for https://docs.unity3d.com/ScriptReference/PrefabUtility.InstantiatePrefab.html probably
sigh, I really wanted to figure this out on my own but...
at the end of my script I have this: EditorSceneManager.SaveOpenScenes();
and yet, when I go back into the scenes, they're unmodified
is there a different method I should be calling?
full script: https://pastebin.com/QfTCd7Fd
ok so after that then the save will work, or I don't need the save?
You need to mark the scene as dirty, then save it
k thanks again
how do I "get scene from path"? Googling that does not return the answer to the question
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
jesus. I don't know wtf is wrong with Unity SEO, but that was so hard to find
yes that would have worked, too
literally the name of the method in my google search and I didn't see it pop up?
Take a look on the EditorSceneManager api page, it seems that you are new to that api: https://docs.unity3d.com/ScriptReference/SceneManagement.EditorSceneManager.html
hi all, I'm curious about a non essential but fun visual effect for a IMGUI node editor.
Moving a Rect along a bezier curve over time. Do you know how this is done or know where I can find examples of such.
You got your bezier function, you got your Rect.
Just set the X and Y in an editor coroutine and job done.
lol really, if it's that simple I'll slap myself 😂 . i was thinking that it HAS to be difficult so i never even tried that haha thank you , I'll try that out 😂
Don't overthink :)
Does UIElements work with property drawers? All the tutorials and examples derive from Editor
i'm getting a nullreferenceexception when using getcomponent on a terrain component to set height :/
Have you tried setting the height manually? Sorry newbie here
i'm trying to learn procedural
I see
woops I had my Terrain named Terrain (in script)
dropped the capital t and I think it works sorta now lol
For future reference this channel is for extending the Editor. General scripting is #💻┃code-beginner
oops, sorry