#↕️┃editor-extensions

1 messages · Page 42 of 1

onyx harness
#

Or TextAsset

summer oyster
#

@onyx harness Thanks, I'll check that out, the fileFolder thing works but the object field would be better!

onyx harness
#

You can not exactly force the object picker to filter only JSON. But you can post check if it is a JSON file

ionic valley
#

How you guys accomplish that OnValidate doesn't trigger from Enable/Disable of a script?

twilit lance
#

hello everyone! i can seek for help here right?

orchid pelican
#

Is there a way to do rich text in new UI Elements using Label?

zealous ice
#

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

visual stag
#

@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

zealous ice
#

I there a list of GUI icons?

orchid pelican
#

@visual stag thanks.

zealous ice
#

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?
onyx harness
#

@zealous ice Oh yeah you can do better XD

zealous ice
#

How? This is only way I was able to achieve this

marsh tusk
#

Hi! Is it possible to add a field in a custom editor by type alone? (as long as the type is serializable?)

onyx harness
#

@marsh tusk I'm not sure I understand

marsh tusk
#

Hm , how do i prettily paste code? 😃

regal jasper
marsh tusk
#

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.

onyx harness
zealous ice
#

@onyx harness // I used this, for some reason, "IN lock" (or something like that) was not working with EditorGUIUtility.FindTexture

onyx harness
#

@zealous ice Because you are not using the right style

#

Use "IN LockButton"

#

this.isLock = GUI.Toggle(r, this.isLock, GUIContent.none, "IN LockButton");

zealous ice
#

Oh.... you can make locks like that...

onyx harness
#

Well being locked is a boolean, toggle was made for boolean.

zealous ice
#

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?

onyx harness
#

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);
        }
zealous ice
#

GeneralStyles is something built in or your own shortcut for strings?

onyx harness
#

Yeah sorry, it is my own code.

#

I just wanted to show you a "result"

zealous ice
#

Don't worry :v

#

I would probably do the same but It's only one editor window

onyx harness
#

What do you mean?

zealous ice
#

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?

onyx harness
#

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.

zealous ice
#

Also, In Unity's documentation I can't find (Rect, bool, GUIContent, string) overload

onyx harness
#

GUI

#

Not EditorGUI

zealous ice
onyx harness
#

GUIStyle has a cast operator for string

#

It should work

#

Or cast it explicitly

zealous ice
#

Oh, that's handy. Anyway, as I said, I will try it tomorrow

onyx harness
#

Hey @visual stag, did you have a chance to try dnSpy?

visual stag
#

nah sorry, I'll download it now if my internet will let me

toxic prism
#

lol you scrubbed that but i totes agree 😂

#

scary election coming up in canada 😛

visual stag
#

I can't talk politics, sorry 😛

toxic prism
#

hehe

visual stag
#

@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

onyx harness
#

Hehehe I knew it

#

The most powerful feature I see is modifying an assembly on the fly

visual stag
#

Yeah, it's not something I plan on ever needing personally 😛

onyx harness
#

And the dark theme, it is just the cherry on the cake

visual stag
#

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 ):

onyx harness
#

yeah I see

waxen sandal
#

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

visual stag
#

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

hardy locust
#

@visual stag dnSpy is much better than ilSpy

visual stag
#

@hardy locust thanks for that input 🙃

hardy locust
#

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)

smoky radish
#

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 ?

https://pastebin.com/v3MXjtEc

zealous ice
#

@onyx harness // Thanks, it works like a charm :D

zealous ice
#

@onyx harness // Do you maybe know what name eye visibility icon has?

#

If any even exist in 2018.4...

waxen sandal
#

Download the guistyle viewr from the assetstore

onyx harness
#

@zealous ice Use the script I gave you.
Yes I know it, but I'm not in front of my computer.

zealous ice
#

I used "CircularToggle" (or something like that, switches between line and circle) at the end

onyx harness
#

Good pick

onyx harness
#

@zealous ice You asked for an eye visibility:
EditorGUIUtility.FindTexture("d_ViewToolOrbit")
EditorGUIUtility.FindTexture("d_ViewToolOrbit On")

placid viper
visual stag
#

@placid viper the editor scripting channel is about extending the editor. General code questions are in #💻┃code-beginner

hazy basalt
#

Is there a way in the editor to select all of the children of a gameobject that contain a SpriteRenderer?

visual stag
#

@hazy basalt just set Selection.objects to your gameobjects

onyx harness
#

@visual stag Hey man, do you remember when I talked about doing overlay menus?

visual stag
#

You mean the pie menu thing?

onyx harness
#

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

visual stag
#

Yeah alright, I probably can't go too deep in it but I can give initial feedback

onyx harness
#

By "soon", it can be few days, but thanks for the interest

gusty walrus
#

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.

waxen sandal
#

This channel is for extending the editor not asking gameplay code questions

limpid condor
#

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

lucid hedge
#

why can you not find the visual studio exe?

#

it's called devenv.exe

limpid condor
#

oooh

#

oh my god

#

Thank you so much @lucid hedge

#

You are a lifesaver.

lucid hedge
#

😃

limpid condor
#

errm, I have another problem.

#

I have 2 errors in my Unity debug log:
"The referenced script on this behaviour is missing!"

waxen sandal
#

You probably changed the name of a class or deleted it

limpid condor
#

Ooh

#

Oh wow

#

Thank you @waxen sandal

waxen sandal
#

No worries

limpid condor
#

I am still very new to all this stuff. My bad

smoky radish
#

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 ?

https://pastebin.com/v3MXjtEc

#

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;`
ionic valley
#

Any way to check value change in inspector other than OnValidate? Because it also being called with OnEnable and OnDisable.

onyx harness
#

Well it is part of it, it's not a bug.

spark zodiac
#

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?

regal jasper
#

@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)

smoky radish
#

@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.

regal jasper
#

@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!

humble remnant
#

@spark zodiac its because that uses the sceneview camera, u might have to use the mouse delta from current event

brittle cosmos
#

So just to be sure OnValidate also runs while playing, but only in the editor, not in standalone/production?

onyx harness
#

Yep

brittle cosmos
#

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.

onyx harness
#

Nope, unfortunately, we have no information at all

#

You need to monitor that yourself

brittle cosmos
#

That's too bad.

onyx harness
#

Hakuna matata

idle anvil
#

"Hakuna matata" is a Swahili phrase; translated, it roughly means "No problems"

#

😉

onyx harness
#

I think we all watched Lion King XD

hot crane
#

Anyone played around with the graphview, or is it documented anywhere outside of basic scripting docs?

visual stag
#

@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);
    }
}```
kind linden
#

noted but for now I'm keeping it the way it is

visual stag
#

👍 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

spark zodiac
#

@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:

  1. Keep the Unity editor focused so that mouse jumping (ie EditorGUIUtility.SetWantsMouseJumping(1);) works on a MouseMove like it does on MouseDrag
  2. As soon as the cursor leaves the Unity application window, no more MouseMove events fire (they do on MouseDrag

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 😦

surreal quest
#

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?

onyx harness
#

@surreal quest cant you use ObjectField?

surreal quest
#

ObjectField also takes a SerializedProperty

onyx harness
#

@spark zodiac there is a workaround on Windows to handle mouse and keyboard

surreal quest
#

oh no it doesnt

#

hm

#

it's deprecated

#

idk if I should care about that

onyx harness
#

@surreal quest there is a lot of overloads

#

Some without requiring SerializedProperty

regal jasper
#

@surreal quest there is one overload that doesn't requires a SerializedProperty

surreal quest
#

Should I worry that it's deprecated at all or?

#

Well who cares, that seems to work

regal jasper
#

string, Object, Type, bool, params GUILayoutOption[]

onyx harness
#

It depends, if it works and you are not willing to update or support, yep

prisma chasm
#

generally avoid deprecated apis - it means it will be removed in a recent update

regal jasper
#

is it an Editor or a Drawer?

surreal quest
#

EditorWindow

prisma chasm
#

and also clogs up your compile time w/ warnings

surreal quest
#

Well yeah, so thats the issue

regal jasper
surreal quest
#

PropertyField doesnt hav ethat

#

Yes, but the concern now is about it being deprecated @regal jasper

onyx harness
#

Just pragma out the warnings if you don't really care

#

Bad practice, but for random stuff, who cares

regal jasper
#

it is not deprecated AFAIK, using it and no warning is poping up here

onyx harness
#

It's not deprecated

regal jasper
#

there are some that are deprecated, but not those 3

onyx harness
#

There is a ton of overloads, why do you focus on those deprecated

surreal quest
onyx harness
#

If one day a deprecated or warning annoys you.
Add at the top of your file:
#pragma warning disable XXX

regal jasper
#

the ones deprecated are the ones which doesn't have both SerializedProperty and the bool parameter only

surreal quest
#

Well it's not about bothering me, it's about it being stable enough to use lol

onyx harness
#

Those have been deprecated for years, and I don't know when they will be removed

surreal quest
#

But yeah this seems to work great - thanks!

surreal quest
#

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?

onyx harness
#

GUI.DrawTexture

#

I assume you use GUILayout, just use GUILayoutUtility to reserve the texture space.

#

@surreal quest

surreal quest
#

Alright lemme try that now

#

That worked perfectly - thank you again @onyx harness

spark zodiac
#

@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...

onyx harness
#

All your questions? 🤔

#

@spark zodiac I think you are misunderstanding the purpose of MouseMove

spark zodiac
#

(there were 2 times a few weeks back where you suggested the same)

#

(for different problems)

onyx harness
#

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.

spark zodiac
#

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

onyx harness
#

I didn't try, but perhaps a way to keep track of the mouse would be to repaint.

spark zodiac
#

Oh, I could! Repaint does still fire. It's just I still can't get mouse jumping/raw data about movement.

onyx harness
#

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.

spark zodiac
#

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!

onyx harness
#

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

spark zodiac
#

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!

onyx harness
#

Do you hold G?

spark zodiac
#

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.

onyx harness
#

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''

spark zodiac
#

Ooh, cool! Bookmarking/will try to work around with it. Thanks!

onyx harness
#

I'm wondering, have you tried the force Repaint on G? Does it give you the proper mouse position?

spark zodiac
#

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.

onyx harness
#

Oh cool, well sorry I got nothing on Mac. =X

spark zodiac
#

No worries. Thanks a lot for trying to help/talking through it , and for the ideas/tips!

smoky radish
#

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 ?

onyx harness
#

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

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

visual stag
#

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

onyx harness
#

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.

visual stag
#

I don't know if you saw but they're using a custom YAML serialiser now

#

which is a massive speedup

onyx harness
#

Yeah I was supa happy when I read this in the changelog

smoky radish
#

@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.

onyx harness
#

If you call it and it returns null, it means you already passed the limit X)

#

Or something like that

smoky radish
#

Hmmm, yup. you are right

onyx harness
#

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?

smoky radish
#

No, I think I don't know or I don't understand what you mean 😄

#

Could you tell me ?

onyx harness
#

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.

visual stag
#

weird to have these bool comparisons to booleans 😛

onyx harness
#

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.

visual stag
#

it's the opposite to me, I look at it and am like... oh, that's redundant

onyx harness
#

Very redundant I understand, because here we are dealing with booleans.

#

I use this. everywhere.

#

@smoky radish So, how is it?

smoky radish
#

Still thinking how to use your code :D
I should use Array.data[1] instead of GetArrayElementAtIndex(1) ?

onyx harness
#

No no

#

The code is just to show you how SP works behind, how it is iterating over all the Object's paths.

smoky radish
#

Oh

onyx harness
#

At the very beginning of your Editor/PropertyDrawer.

#

Set it with the SP argument

smoky radish
#

Now I understand 😄

#

Thanks

onyx harness
#

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?

smoky radish
#

Yup, 1 element

onyx harness
#

😃

smoky radish
#

I think I'm idiot 😄 because I've not figured out how to fix this issue yet 😄

onyx harness
#

Wait

#

I'm gonna help ya

smoky radish
#

Awesome. Thanks

onyx harness
#

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.

smoky radish
#

I'm not sure if I understand your question.

#

Okay

onyx harness
#

Because whenever you iterate over an array, it gives many informations.

#

And if I recall, the size is one of them

smoky radish
#

I don't know what happens 😄 but I don't receive that error

#

And seems it just iterates through the first one

onyx harness
#

I know

#

but I need the logs

smoky radish
#

Log for multi edit or single one ?

onyx harness
#

The whole output

#

multi

#

The one where you were receiving an error

#

What console are you using?

#

I know the native one is shit

smoky radish
#

Native one

#

And it is shit 😄

#

If I want to put the note log here it has too many lines 😄

onyx harness
#

Just reduce the linesize to 1

#

Console top-right > Log Entry > 1 Lines

smoky radish
#

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

onyx harness
#

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 😅

smoky radish
#

For one of them is 3 another one is 6

onyx harness
#

So 3 elements should be the final result

#

and you are receiving only one?

smoky radish
#

By one you mean one output ?

onyx harness
#

you said "no error. And seems it just iterates through the first one"

smoky radish
#

By first one I meant between 2 objects which were selected just it worked for the one of them

onyx harness
#

I don't even see what you are expecting in the result

smoky radish
#

That PropertyDrawer is for these 2 scriptableObjects

onyx harness
#

You want Read() to return all the distinct SO from many Objects?

smoky radish
#

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

onyx harness
#

No error is a basic, but having the right result is a must.

smoky radish
#

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

onyx harness
#

And tell me what are you expecting from Read by selecting these 2?

smoky radish
#

By selecting Grass 1 and 2, the values in dropdown are these

onyx harness
#

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.

smoky radish
#

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 ?

onyx harness
#

You want to show a dash (-), where?

#

In the menu entries?

smoky radish
#

Like this

onyx harness
#

Ah

#

That's really a pointy detail XD

smoky radish
#

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 ?

onyx harness
#

I think... you completely took the wrong path XD

smoky radish
#

😄

#

Why ?

onyx harness
#

SerializedProperty is already "merging" the data.

#

Which means you won't know the real data used behind

#

You just have another reality of it

smoky radish
#

You mean when I select multi objects ?

onyx harness
#

Yep

#

You want to know if array is the same for everyone or not.

#

SP is not giving you this information.

smoky radish
#

So how can I have this information ?

onyx harness
#

You need to take the 2nd choice I suggested earlier.

smoky radish
#

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 ?

onyx harness
#

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 😃

smoky radish
#

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

onyx harness
#

It can work, the same way as Unity's

smoky radish
#

By it you mean Unity PopupMask ?

onyx harness
#

Yep

#

Then you need to check if all arrays are the same, by digging into "targets"

#

And display your dash.

smoky radish
#

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 😄

onyx harness
#

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]

smoky radish
#

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 ?

onyx harness
#

Me? If I wanted to handle multi-select dropdown? I would implement my own GenericMenu 😃

smoky radish
#

Nice 😄 so I chose the correct way 😄

onyx harness
#

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.

smoky radish
#

Oh, I just figured out

onyx harness
#

Look how Odin Inspector deals with dropdown

smoky radish
#

Yup, you are awesome and you can do it but I can't 😄

onyx harness
#

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

smoky radish
#

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.

onyx harness
#

It took me a long time before "mastering" SP/SerializedObject

#

I have no link

smoky radish
#

And thanks for your great responses. I appreciate and sorry if I wasted your time

onyx harness
#

I just implemented tools

#

More and more and more

smoky radish
#

Wow, awesome

onyx harness
#

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 😃

smoky radish
#

Thank you very much. I really like to learn more. I appreciate.

onyx harness
#

Hahaha welcome 😃

smoky radish
#

@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 ?
onyx harness
#

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 😃

smoky radish
#

LOL

#

😄

#

Yup, every frame

onyx harness
#

You are calling LoadAll() in every Repaint()? O_O

smoky radish
#

Yup, I know 😄 It is shit

onyx harness
#

First of all, you will need to cache it.

#

And ... why using Reflection? O_o

#

Reflection.LoadAll takes a path and a Type.

smoky radish
#

Because the type is not specified

#

And I need it for LoadAll generic

onyx harness
#

And what is giving attribute.BaseType?

smoky radish
#

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.

onyx harness
#
Resources.LoadAll(path, typeof(Object));```
#

They are strickly equivalent

smoky radish
#

WTF

#

I've not known we have this function 😄

onyx harness
#

Just test it and confirm please.

smoky radish
#

Let me check

onyx harness
#

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.

smoky radish
#

Can I cast Object[] to ScriptableObject[] ?

onyx harness
#

Have you tried?

#

😃

smoky radish
#

Seems that function works but I can't cast it. Casting to ScriptableObjects[] works in that reflection method but doesn't work on this 😄

onyx harness
#

How do you cast?

smoky radish
#

_scriptableObjects = Resources.LoadAll("", attribute.BaseType) as ScriptableObject[];

onyx harness
#

Test (ScriptableObject[]) instead of as.

smoky radish
#

It's not valid.

#

Hmmm, I think I cast from object(C#) to ScriptableObject[] in that reflection method.

onyx harness
#

Nope you don't

#

I don't know what you mean by not valid

#

Resources.LoadAll() do the cast for you

smoky radish
onyx harness
#
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.

smoky radish
#

Yup, it compiles but it can't cast 😕

#

By "as ScriptableObject[]" it returns null and by "(ScriptableObject[])" there is an error.

onyx harness
#

I see

#

Use the 3rd way

smoky radish
#

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 ?

onyx harness
#

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.

smoky radish
#

How can I notice when the project is changed ?

#

Like when new scriptable object is created

onyx harness
#

You have a delegate for that purpose

#

EditorApplication.projectWindowChanged

smoky radish
#

Nice

#

Thanks

onyx harness
#

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);

smoky radish
#

Awesome

onyx harness
#

Everything that you have done today, next year you will be able to reproduce it in less than 20 minutes 😃

#

Think about it!

smoky radish
#

How ? 😄

onyx harness
#

Today you were looking for solution, tomorrow you will know the solution.

#

You learned a "lot" today, I am happy for you :]

smoky radish
#

Oh, you mean that :D
And I appreciate you help me to find the solutions. (Actually you tell me the solutions :D)

onyx harness
#

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.

smoky radish
#

Yup, it is the purpose of learning. When you don't understand you can't learn too.

onyx harness
#

Then I hope you understood my code today 😃

smoky radish
#

Yup, I did although I'm reading a little about serializedProperty iteration.

onyx harness
#

About SP, it might take some time to grasp the whole concept, but it's okay

smoky radish
#

Yup

#

Editor and PropertyDrawer derived class can have constructor ?

onyx harness
#

Hum... if I'm not wrong, yes.

smoky radish
#

Wow

#

I didn't know that

onyx harness
#

Editor I'm not sure

#

PropertyDrawer I did use its constructor

#

I never implement any Editor

smoky radish
#

Sorry to ask many questions.
Is there any event for PropertyDrawer when the object is selected ?

onyx harness
#

Nope

#

Selection.selectionChanged you got only

smoky radish
#

Okay. Thanks

onyx harness
#

What you can do is to register to it in your PropertyDrawer

#

Well, it's all up to you

smoky radish
#

@onyx harness I registered to EditorApplication.projectChanged in constructor. Did I do it wrong ?

onyx harness
#

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

smoky radish
#

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.

onyx harness
#

I didnt get what you just wrote

smoky radish
#

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

onyx harness
#

Possibly

smoky radish
#

😄

#

So for fixing I should put whatever I want to put in constructor in for example OnGUI then remove it after first compile ?

onyx harness
#

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)

smoky radish
#

LOL 😄

#

Constructor is just called when I create a new instance ?

onyx harness
#

A new instance of what?

smoky radish
#

The object which uses that PropertyDrawer

onyx harness
#

Hehehe

smoky radish
#

😄

onyx harness
#

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.

smoky radish
#

Wow

#

You are right

#

😐

#

It is weird in my opinion and I don't figure it out 😄

onyx harness
#

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

smoky radish
#

I should read about it. Do you have any link ?
BTW where should I register to EditorApplication.projectChanged ?

onyx harness
#

static constructor

#

Of your PropertyDrawer

smoky radish
#

I did

onyx harness
#

Use a Dictionary<string, Dictionary<Type, ScriptableObject[]>>

smoky radish
#

But it doesn't called sometimes.

onyx harness
#

your callback is not invoked you mean?

smoky radish
#

Yup

onyx harness
#

and sometimes mean?

#

What do you do to trigger it?

smoky radish
#

Like when I create new object in Project.

onyx harness
#

Really? O_o

#

Are you sure the static constructor is initialized at the beginning?

#

Hum... That's strange

#

you must have done something wrong

smoky radish
#
static ScriptableObjectMultiSelectionDropdownDrawer()
{
    EditorApplication.projectChanged += GetScriptableObjects;
}```
#

I just added this

onyx harness
#

Remind me what is in GetScriptableObjects()?

smoky radish
#
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);
    }
}```
onyx harness
#

You forgot to clear _scriptableObjects, no?

smoky radish
#

Oh shit

onyx harness
#

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

smoky radish
#

I'm confused 😄

#

Thanks

#

night night

#

I think I should read about it.
Can I find what you explained about this concept somewhere ?

onyx harness
#

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

smoky radish
#

Okay, Thanks. I need time to think about these things 😄 and you should sleep 😄

#

Thanks

#

I appreciate.

unreal lotus
#

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?

onyx harness
#

@unreal lotus just check the Selection.activeObject's Type

night solstice
#

i need help

unreal lotus
#

@onyx harness but there is no "update" function on the playable clips

coarse tree
#

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.

onyx harness
#

@unreal lotus is there any enter?

sinful marsh
#

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 ?

visual stag
#

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

sinful marsh
#

Okay thanks !

unreal lotus
onyx harness
#

Try this one: OnPlayableCreate

wintry aspen
#

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;
}

smoky radish
#

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 ?

onyx harness
#

It's better than that X)

#

Your callback? Put it in your static constructor.

#

No need to destroy it.

#

Show me your actual code.

smoky radish
#

So no unregister ?

#

My code ? 😄

onyx harness
#

No unregister. It's magic.

#

I don't advise keeping such a habit, but in this case we don't mind.

#

Cause editor world.

smoky radish
#

Great

onyx harness
#

@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.

wintry aspen
#

@onyx harness daaamn thanks for the fast reply. worked perfectly

#

you bloody legend

onyx harness
#

O_O

south pawn
#

What would be the best way to replicate the projec tview in an editor window? (list of assets)

onyx harness
#

Iterate over AssetDatabase.GetAllAssetPaths()

south pawn
#

@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?

onyx harness
#

I would say a lot of EditorGUI.Foldout

#

Kind of yes.

#

Isn't it what you were going to do?

#

@south pawn

#

Just the first example.

south pawn
#

@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"

onyx harness
#

I'm sure the TreeView must provides some callback to handle contextual menu.

south pawn
#

cool thanks

onyx harness
#

Just check it, I don't have a 100% sure answer about that

smoky radish
#

@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];
    }
}```
onyx harness
#

is it working?

smoky radish
#

Yup

onyx harness
#

Just change line 3.

#

Instead of arraySize = 0, write arraySize = scriptableObjects.Length

smoky radish
#

Then should I remove property.arraySize++ ?

onyx harness
#

Yep

smoky radish
#

I read GetArrayElementAtIndex is heavy. Is it ?

onyx harness
#

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.

smoky radish
#

Oh well. Thanks for the help. You are awesome 😄

onyx harness
#

You're welcome XD

smoky radish
#

@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 ?
onyx harness
#

To be honest, I have no idea which one is the fastest

#

And I am curious to know

#

Can you bench it?

visual stag
#

does the iterator actually go over all the elements in the array?

onyx harness
#

Yep

smoky radish
#

I don't know exactly how to bench it :D. Should I do it like 1000 times and then check the profiler ?

onyx harness
#

( @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");
}```
smoky radish
#

@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

onyx harness
#

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.

smoky radish
#

Thanks

#

The second one is by that iteration method

#

From zero size to 9 in size 😄

#

And I don't have any idea 😄

visual stag
#

really need to run it 1000 times to really compare times properly as that's kinda nonsense, there's a 0.19 in there

onyx harness
#

Shit... it's pretty hard to tell which one is faster XD

smoky radish
#

Yup, I think so

onyx harness
#

Yeah I guess so

smoky radish
#

Let me see 😄

onyx harness
#

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

smoky radish
#

Oh run it 1000x is same as set array size to 1000x ?

#

Or I get it wrong 😄

onyx harness
#

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

smoky radish
#

The second one is by that iteration method.
From zero in size to 9.

visual stag
#

funny results to be honest

smoky radish
#

It is by running 10000x

onyx harness
#

You mean, from 0 to 9000?

#

Oh ok

smoky radish
#

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

visual stag
#

wait, the second one is GetArrayElementAtIndex ?

smoky radish
#

Yup

#

Sorry

#

😄

onyx harness
#

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

smoky radish
#

Yup

smoky radish
#

I have a class which one of its fields is System.Type. Is there any way to access to its value in SP ?

onyx harness
#

Type is not serializable

#

I don't even think it will show up

smoky radish
#

Yup, I know. But I like to assign a value to it 😄

onyx harness
#

You'd like?

smoky radish
#

I need actually 😄

onyx harness
#

Through SP?

smoky radish
#

Yup

onyx harness
#

I don't think SP will have it

#

You need to toy directly with SO

#

Using the target

smoky radish
#

Okay. Thanks. I need to think about it

#

Can I control how deep SerializedProperty.Next(true) can go ?

onyx harness
#

Can you be more specific?

#

(Yes you can, but what do you want to do?)

smoky radish
#

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.

onyx harness
#

Yep

#

You can control of course

#

You have propertyType & propertyPath

#

If you know specifically what you need to skip

smoky radish
#

Oh, great. Thanks

#

If I want to access to one of the fields I should specify it by propertyPath ? It is like FindRelativeProperty() ?

onyx harness
#

Nope

#

propertyPath is absolute

smoky radish
#

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 ?

onyx harness
#

lol

#

You have the name already

#

just do propertyPath.EndsWith("activityName")

#

The name FindRelativeProperty is very explicit.

#

It looks relatively to the current SP.

smoky radish
#

Yup, I know. FindRelativeProperty does the same thing ?

onyx harness
#

What?

#

same thing as what?

smoky radish
#

propertyPath.EndsWith("activityName")

#

This

#

😄

onyx harness
#

no no

#

It looks exactly for the path you request

smoky radish
#

Oh well

thorny bobcat
#

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.)

visual stag
#

Yes

thorny bobcat
#

What is it called? I can't seem to find anything that does not refer to the regular game scripts.

visual stag
#

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

brittle cosmos
#

What's the difference between ExecuteInEditMode and ExecuteAlways?

visual stag
thorny bobcat
#

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.

visual stag
#

I'd advise just making a MenuItem

brittle cosmos
#

Ah I see, thanks

thorny bobcat
#

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?

visual stag
#

Yup, you just have to remember that it's in the UnityEditor namespace, so you probably want it in an Editor folder

thorny bobcat
#

Makes sense. Thanks @visual stag

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

#

so that's handy

thorny bobcat
#

nice, was just looking at that. perfect.

south pawn
#

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?

visual stag
#

With a MenuItem that starts with "Assets/

south pawn
#

@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.

visual stag
#

Oooooh

south pawn
#

menu*

visual stag
#

Let me know if EditorUtility.DisplayPopupMenu(rect, "Assets/", null); works

south pawn
#

@visual stag bingo! It works perfectly

visual stag
#

Sweet 😃

south pawn
#

@visual stag thank you so much, you likely saved me a ton of time!

visual stag
#

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 😛

south pawn
#

@visual stag any ideas how i might capture events from EditorUtility.DisplayPopupMenu? Im specifically trying to know when the user clicks "rename".

visual stag
#

@south pawn as far as I know you'd have to reflect into ProjectBrowser.m_AssetTree.state.renameOverlay.IsRenaming()

#

and poll that

south pawn
#

@visual stag ahh, cool, where you get this info btw? you using a decompiler?

visual stag
#

Yup

#

dnSpy or ILSpy

#

I'm trying out the former

south pawn
#

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

visual stag
#

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

severe python
#

is this stuff not in the reference source?

visual stag
#

It is, but navigating via a decompiler is faster for me at least

severe python
#

I'm curious how

#

can you like, target elements in the editor view to figure out classes or something like that?

visual stag
#

Yes

waxen sandal
#

I use Resharper/Rider to decompile while I'm coding

severe python
#

oh that is quite useful indeed

waxen sandal
#

So I can just browse to definition to get to the decompiled source

visual stag
#

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

severe python
#

can't you already access the UI Elements debugger?

visual stag
#

Yes, comment that out if your version has it

severe python
#

so you're using the built in view debuggers, to get you information on where to go in the decompiler?

visual stag
#

Yup

severe python
#

okay then, I guess I don't see how that is better vs the raw source, but ok

visual stag
#

I also search terms a lot

severe python
#

I found the CS ref source to be easier because I can use Visual studio which has great search features

visual stag
#

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?

severe python
#

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

visual stag
#

I think the UI Source is elsewhere, but perhaps I'm mistaken

severe python
#

you're mistaken

#

I learned UI Elements by using the CS Reference because the documentation was incomplete

visual stag
#

UIElements isn't the UI I'm talking about

severe python
#

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

visual stag
#

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.

severe python
#

in game ui, editor ui, imgui, ui elements

#

wtf are you talking about "Normal ui"

waxen sandal
#

@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

visual stag
#

Game UI, the one that we all call "UI" without attaching any other clarifiers to

severe python
#

why they also have stuff on bitbucket, I don't know

visual stag
#

Yeah, I know about this too

#

Can I add both to one project and search them together using an IDE?

severe python
#

I see no reason why not

visual stag
#

🤷

severe python
#

both are pretty simple solutions

#

no project name conflicts

#

and vs 2019 also supports just opening folders

hardy locust
#

@visual stag game gui is UGUI

visual stag
#

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

severe python
#

its a package in the manager?

#

I didn't evenr ealize

visual stag
#

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 😆

south pawn
#

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?

onyx harness
#

I don't know any easy way to achieve that.

#

You'll have to monitor that yourself unfortunately

visual stag
#

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

south pawn
#

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?

visual stag
#

people don't generally need a callback monitoring every change to every asset

#

but yeah, regularly polling internal state through reflection is common

onyx harness
#

I wouldnt day user input, but yeah globally a lot of stuff are hidden or not implemented for outside devs.

visual stag
#

sad, but common

south pawn
#

no wonder so many unity extensions end up breaking lol

onyx harness
#

How real-time must be your solution?

south pawn
#

I'm showing the user a list of assets they have recently modified

onyx harness
#

Asset, meaning not scene object, right?

south pawn
#

its an editor window, so pretty realtime

#

yes

onyx harness
#

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.

visual stag
#

Yeah I would just track selection

south pawn
#

I'm allready using that, so how do i know if the user has changed a field?

onyx harness
#

Do you know how to list the assets in an object?

south pawn
#

generally, yes

onyx harness
#

Whenever the selection changes, you just compare the before & after.

south pawn
#

so maintain a record of the state of each asset and check for changes after a selectionChanged event?

onyx harness
#

Not each, only the current.

#

And yes, that's it

south pawn
#

ah ok

#

makes sense

#

thanks @onyx harness @visual stag 😃

visual stag
#

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 😛

south pawn
#

public static bool IsDirty(Object target);

i might be able to use this 😄

onyx harness
#

That's an idea, I don't know if it is going to work outside the Inspector's area

south pawn
#

(EditorUtility.IsDirty)

onyx harness
#

That's an other cool idea, keep us in touch, I would like to know the final solution :)

visual stag
#

Yeah, that's probably a good way of doing it, never used it before 😃

south pawn
#

oh nevermind, isDirty just tells you if an asset needs saving, not if it has actually been changed here and now

onyx harness
#

Needs saving, implies having changed

#

Why doesn't it work for you?

visual stag
#

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

onyx harness
#

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

visual stag
#

it's a good way to reduce the objects you need to check for changes, if that's what you mean?

onyx harness
#

Yep

south pawn
#

yes, is dirty narrows it down for sure, doubt there is a more elegant solution but ill keep looking

onyx harness
#

SelectionChanged and isDirty is a pretty good combo out there.

drowsy shell
#

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

onyx harness
#

Won't work.

#

Serializer does not know how to deal with those Type.

drowsy shell
#

I assumed so

#

Workaround it is then

onyx harness
#

Work aroud is using plugins handling it.
Or coding your own editor and serializer

drowsy shell
#

Yep, I was hoping it was just something I didn't read as I was researching but here I go

onyx harness
#

@south pawn hey, how did it work?

visual stag
#

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

drowsy shell
#

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

onyx harness
#

You should have told us it was for unique data.
You're kind of mimicking how a Shader stores its data in the editor.

visual stag
#

Yeah I've done this UI trick before, it's just usually not as applicable as the other advice 😃

drowsy shell
#

Oh, well I am still all ears for a better solution. I would love to simplify/clean it up

hoary surge
#

There is always Odin 😃 I haven't tested it with every variation of generics but it works most of the time.

blazing trout
#

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?

visual stag
#

If you are destroying it from edit mode you need to use DestroyImmediate

#

the example isn't in edit mode so they use Destroy

blazing trout
#

so i'll have to encapsulate that bit in "if UNITY_EDITOR" then ig?

visual stag
#

You must be destroying in Edit mode, what function are you destroying from?

blazing trout
#

OnDestroy

#

just like the documentation shows

#
        #if UNITY_EDITOR
        DestroyImmediate(m_Material);
        #else
        Destroy(m_Material);
        #endif
#

would this work?

visual stag
#

Yes

#

I assume you have [ExecuteInEditMode] and that is causing the problem?

blazing trout
#

cool 👌

#

Yea I do

#

I have no more erros now though, so thanks! 😄

visual stag
#

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

blazing trout
#

Application.isPlaying return true if you pressed the big ol' play button?

visual stag
#

Yup

blazing trout
#

cool; thanks for the advice 😄

#

changed it accordingly 😄

harsh hull
#

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

onyx harness
#

@harsh hull google Unity editor style viewer

#

It will show you styles and icons, just pick one

harsh hull
#

this is amazing! ty

smoky radish
#

Hey guys,
Is it possible to use PropertyDrawer and another Editor layer on it ?

visual stag
#

You're gonna have to explain what you mean a bit more

onyx harness
#

Short answer: yes.
But curious as well, why doing it this way?

smoky radish
visual stag
#

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

onyx harness
#

Forget the Editor solution then.
An Editor requires an Object as target. You just have a Type.
@smoky radish

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 ?

onyx harness
#

I don't understand your last sentence 🤔

smoky radish
#

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.

onyx harness
#

Type is not serializable. You won't have it easily from SP

smoky radish
#

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 ?

onyx harness
#

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.

smoky radish
#

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 ?

onyx harness
#

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.

cloud wedge
regal jasper
cloud wedge
#

thank you

#

yep that did it

cloud wedge
#

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?

cloud wedge
#

ok so after that then the save will work, or I don't need the save?

regal jasper
#

You need to mark the scene as dirty, then save it

cloud wedge
#

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

cloud wedge
#

yes that would have worked, too

#

literally the name of the method in my google search and I didn't see it pop up?

regal jasper
cloud wedge
#

i guess the difference is instead of "from" it's "by"

#

thanks

ancient sable
#

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.

onyx harness
#

You got your bezier function, you got your Rect.
Just set the X and Y in an editor coroutine and job done.

ancient sable
#

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 😂

onyx harness
#

Don't overthink :)

harsh hull
#

Does UIElements work with property drawers? All the tutorials and examples derive from Editor

visual stag
#

Yes

thorn reef
#

i'm getting a nullreferenceexception when using getcomponent on a terrain component to set height :/

terse olive
#

Have you tried setting the height manually? Sorry newbie here

thorn reef
#

i'm trying to learn procedural

terse olive
#

I see

thorn reef
#

woops I had my Terrain named Terrain (in script)

#

dropped the capital t and I think it works sorta now lol

visual stag
thorn reef
#

oops, sorry

glass kiln
#

hey guys i got this code, and im firing the 2 voids at random times

#

public void xroom1()
{
attack1();
heal();
}
public void xroom2()
{
attack2();
heal();
}