#↕️┃editor-extensions
1 messages · Page 104 of 1
I have no idea what im doing, no one I've reached out to will help me or even reply, I'm trying more and more things with no idea what im doing, I'm stuck and frustrated
I hate being ignored, I hate tutorials that don't explain things well enough, I hate that im so fucking stupid I can't do anything myself
am trying to create tool to editor using the new Ui elements am having ObjectField the problem ObjectField doesn't persist the object after attaching it became empty again
I have a type X which contains a type Y. How can I make the inspector for type X just show the inspector for the contained type Y?
Please ping me if you respond :)
probably with this https://docs.unity3d.com/ScriptReference/Editor.CreateEditor.html
thanks!
@acoustic egret in that example they don't show how to draw the "header" (the title bar in the inspector)
but you can use myEditor.DrawHeader();
just before you draw the body of the inspector with myEditor.OnInspectorGUI();
however the header drawn with that is very thick, so I don't really like it
perfect, thanks!
hello I'm trying to make my own Settings in the Project Settings window using a separate UXML file.
Am I doing this right? nothing is showing up.
Does anyone here know what to do with the Localization system and Japanese?
nvm
Got it
This code block draws every property of a SerializedProperty. How would I refactor it to draw every property of a SerializedObject?
protected void DrawProperties(SerializedObject obj)
{
var iterator = obj.GetIterator();
iterator.Next(true);
foreach (SerializedProperty p in iterator)
{
DrawProperties(p, true);
}
}```
This was my attempt to refactor it to work on SerializedObjects instead of properties, but it doesnt work. There's no error redline blocking compile, but the code doesn't fill the EditorWindow with anything
I am not sure if this question is best asked here or in a different channel, but I trying to use the Facebook SDK in my app. Currently, I am just authenticating with it. My code works fine on my machine, but when I push to an Android device, the app dies right at startup and the error is: Error AndroidRuntime java.lang.RuntimeException: Unable to get provider com.facebook.FacebookContentProvider: java.lang.ClassNotFoundException: Didn't find class "com.facebook.FacebookContentProvider" on path: Does anyone have experience with FB SDK and know how to address this?
You need to set the value to a serializedField.
I'm having a weird issue I don't know exactly how to tackle: I'm trying to do some custom serialization for an array, its justa bunch of checkboxes and a field for its width. However, if I change the width value, on the OnAfterDeserialize call, I get an IndexOutOfRangeException, since the width value was changed, but at the time of that deserialization, the actual array itself still has its old Length. Am I going about this in a completely wrong way?
Most likely. If you look in #854851968446365696 there are links to code sharing sites if you want to use them to share your code I could take a look at it 🙂
Sure! One sec, let me trim to the relevant parts
thanks for offering!
this are the array transformation methods I made to move from 2d to single-dimension
https://paste.ofcode.org/MwwBaxRAHYCnsjwjtxqHSA
and yeah, the actual error happens on line 27 of this second paste, but the actual fault is not on that function: if I move from a 5x5 to a 6x5, To2D receives a 25-long array, but a "6" width
Well it looks okay, but something feels off, not sure what though. I normally just do a double for loop so that the logic looks the same both ways.
Sorry, where would you do a double for?
you mean you wouldn't flatten and then rehidrate?
I mean for the deserialiation the To2D https://stackoverflow.com/a/28113181
Ah, yeah, I guess it is a bit inconsistent
Btw, use the height that you save, don't get it from the length as that could be messing stuff up
Actually, why are you not saving the size of the 2D array
Well, I don't think it should make a difference. After some checking, I'm pretty sure that the issue is that I modify the Width value, that triggers a new serialization loop, and the DataGrid class has (for example) an updated Width, but an outdated _flatGrid, so the dimensions mismatch
Yeah, that sounds right
I think if I could say something like "Hey, if your height or width change, flush your current grid data and start from 0" it would be fine
(or something like that)
I see what the problem is
You are using the 2d array's width when flattening, but using the stored variable when deserializing
Ya gotta be consistent
ah
let me check
yeah man
right on the money
you a genius
makes total sense
sorry, in the end it really was a stupid mistake
I have a custom property drawer for a type I use a lot, and I'd like to use a foldout. What's the appropriate place to store the bool for whether it's expanded? If I use a field on the PropertyDrawer class, this happens: https://gfycat.com/PeskyBrownCrossbill
Oh I could have scrolled up to see property.isExpanded which works in my case. Still, if I were to have more than one foldout per property, what could I do?
Every property has a isExpanded state, idk what you would be doing where you would have more than one foldout per property. But there would be no way to store the state
Perhaps using the isExpanded state from an unrelated subproperty that doesn't expand if it ever came to that?
my fields generated from an list so i don't have specific amount of fields how can i solve that
Hello guys and ladies. I have custom Tile based on Tile class. But I need to visualize it depending which sprite I add. If will be ideal if it takes sprite from base Tile class so I can omit Preview property. Can you help me someone please? I prefer this order but will be grateful for any of it:
- Sprite drawn instead of universal asset icon.
- Sprite drawn in the inspector as preview (bottom) or as rectangle.
- Preview property in inspector like on material for example. So I can see it there instead of this row one.
is there any way to get the type of an asset from a GUID without having to load the object?
there's this method, but it uses instance IDs
InternalEditorUtility.GetTypeWithoutLoadingObject(int instanceID)
any alternative to that one?
Lol, kinda weird, instance Id means it is loaded isn't it?
no idea I just found it googling randomly, haven't tested it
I guess the metadata might be loaded since it needs to exist in the project view
hello, I've created a piece of code in custom Editor Window that changes value of variable based on colliders. And it changes accordingly, but changes even if they are visible in scene after starting the game they are reverted. And I don't know why. Video shows the problem. Can You help me?
Sorry for sound, didn't know that twitch sound was also recording ;p
You gotta use serializedproperties or dirty the object
Im looking at this now and I am confused.
Both this script and the script I am working with both use a SerializedProperty as their input point.
I need to start with a SerializedObject to the best of my understanding
I dont understand how people are using these scripts with SerializedProperties to loop through anything or get more children, like, fundamentally I am missing something vital here
I am not understanding the difference between these two things maybe?
A serializedProperty is a single field in a SerializedObject? Yes? No?
How can all these scripts that ask for a single serialized property somehow serialize every field in a serialized object?
I -really- need some help with this, I am getting no where reading doccumentation
@idle tree have you used EditorWindows before? Just asking for context
Not very extensively, no
This is me trying to learn them
I got to where I am by following a tutorial to learn EditorWindows, but the tutorial was not very comprehensive and explained very little, so now I have gotten stuck trying to use any of it or go anywhere from here
I think I have a decent understanding of things like if(button) and layout, its specifically ScriptableObject SerializedObject and~~ ScriptableProperty~~ SerializedProperty that is tripping me up
@idle tree
public class SomeEditorWindow : EditorWindow
{
// The actual data in this window class instance
[SerializeField] private string _someString;
[SerializeField] private float _someFloat;
// The serialized representation of our Window's class instance
private SerializedObject _serObj;
// The serialized representations of our Window's class data
private SerializedProperty _someStringProp;
private SerializedProperty _someFloatProp;
[MenuItem("Something/OpenWindow")]
public static void OpenWindow()
{
GetWindow<SomeEditorWindow>();
}
// This is called when the Window is opened
private void OnEnable()
{
_serObj = new SerializedObject(this); // Create a SerializedObject that represents the window instance
_someStringProp = _serObj.FindProperty("_someString");
_someFloatProp = _serObj.FindProperty("_someFloat");
}
private void OnGUI()
{
// Approach 1
_someString = EditorGUILayout.TextField("Some String", _someString);
_someFloat = EditorGUILayout.FloatField("Some Float", _someFloat);
_serObj.Update(); // Update the SerializedObject so we get the values that currently exist
// Approach 2
_someStringProp.stringValue = EditorGUILayout.TextField("Some String", _someStringProp.stringValue);
_someFloatProp.floatValue = EditorGUILayout.FloatField("Some Float", _someFloatProp.floatValue);
// Approach 3
EditorGUILayout.PropertyField(_someStringProp);
EditorGUILayout.PropertyField(_someFloatProp);
_serObj.ApplyModifiedProperties(); // Apply any changes that were made to the SerializedProperties
}
}
This is one of the most basic examples I can think of to explain how it works
it's easy to visualize because it's all self contained in one class
see how the fields _someString and _someFloat can be used interchangeable with their corresponding serialized properties?
in the OnGUI method you can see 3 ways of editing the values of the fields in the class
1- Using the fields directly
2- Using the properties' data values
3- Using the properties with a property field
all 3 change the data in the exact same way, but 2 and 3 provide extra benefits. Like undo support, automatic styling, etc
the docs for SerializedObject say this
SerializedObject and SerializedProperty are classes for editing serialized fields on Unity objects in a completely generic way.
with "in a completely generic way" they mean that you can just deal with SerializedProperties by using a PropertyField and forget about anything else
you don't need to know the data type, you don't need to know almost anything
except the name of the property and the SerializedObject to which they belong
(I'm reading all this carefully)
yeah take your time to internalize it all, it took me a while to get used to it the first time I tried to use them
I've lost context of your original conversation with MechWarrior so feel free to @ me and ask again whatever your questions are and I'll try to help
Will do. I am comparing your commented code example to the tutorials I followed and scripts I was shown.
SerializedProperty iterator = myProperty.Copy();
while (it.Next(true))
{
Debug.Log(it.name);
}```
I was linked this as an example of "Looping through every serialized property in a serialized object" but I am not understanding where or how to use it to achieve that. Where does the reference to serialized object go? How does the property know if it is the "first" property? Or what the "next" property is?
Next() will change the SerializedProperty that is being referenced by the SerializedProperty that .Next() is called on
I am understanding now that the EditorWindow itself is the SerializedObject. In the tutorial I followed, the tutorializer made another SerializedObject as a variable within the EditorWindow, then populated the EditorWindow with all the Inspector data of the ScriptableObject variable the window held reference to.
However the way they did it confuses me greatly. Their ScriptableObject's "entry point" was an Array variable within the ScriptableObject, and mine has all the variables at the root of the scriptable object, not within a property, and so far all the examples I have looked at seem to refer to only a single Serialized Property, and don't explain how I can use that to use a SerializedObject ever, it all seems to revolve around Serialized Properties?
(I also keep mixing up Scriptable Object with Serialized Object which isn't helping either)
You create a SerializedObject that references a UnityEngine.Object. EditorWindow, GameObject, ScriptableObject, Component and more all inherit from UnityEngine.Object so you can create a SerializedObject for them and access their serialized properties
a better way of debugging a SerializedPoperty is by doing
Debug.Log(someSerializedProperty.propertyPath);
a lot better to visualize the whole path of the property
Let me add that to my editor window script just to see what happens
@idle tree can you maybe share the tutorial you're following? so we can see some context
Sure, its extremely bare bones though, I followed it because its the first result when you google "EditorWindow Tutorial"
it may be that they are using a custom Editor for the scriptable object, or that they are doing it directly on an EditorWindow
Of course now that I said that, all my google results are different 🔥
also, EditorWindows and SerializedObjects/SerializedProperties are not related per se
an EditorWindow is just a way of displaying whatever data you give to it
https://www.youtube.com/watch?v=c_3DXBrH-Is
I even joined this person's discord and asked their community but did not get answers there
In this video we take a look at how to dynamically draw Editor Windows in Unity by harnessing the power of the SerializedObject and SerializedProperty classes.
We create a tool that will automatically draw an inspector-like editor window, for any object we pass into it.
Be sure to LIKE and SUBSCRIBE if you enjoyed this guide! Share the video ...
you can display a bunch of variables in an EditorWindow without ever using any SerializedObject or SerializedProperty
ah ye I remember that tutorial, was also a bit confusing for me
Yes, the specific use case I am learning Editor Windows for is that I am learning all the steps to write EditorWindows that can be used as tools to edit prefabs in my project
which is why I was lead towards the path of SerializedObject and SerializedProperty, because MechWarrior99 was telling me not to be sloppy and just do "SetDirty"
So I followed that above tutorial because for my own needs, I needed to first learn how to put SerializedProperties from prefabs in an EditorWindow to facilitate making Unity Editor window Tools to edit my project with 🙂
yeah
At this point I think Ive spent more time trying to learn a whole lot of new concepts all at once that I am unfamiliar with than if I had just done the work I need to do manually, but it is valuable knowledge to have, the ability to make your own tools to automate work
and I know Odin exists 🔥 But I don't want to use it, there are too many draw backs, like you can't use it in a project with any other person who doesn't have a license, which would make me incapable of using it in any kind of practical environment
in that tutorial you're getting confused by the array, because each element of that array represents an instance of the class he's using for the example
there's 3 different topics in that tutorial, and he just mashed them all together
EditorWindows
Custom Editors
SerializedObjects/SerializedProperties
Yes, the problem as far as I understand it, is his ScriptableObject contains a Class Array, which is a Serialized Property of the SerializedObject that is the ScriptableObject?
protected void DrawProperties(SerializedProperty prop, bool drawChildren)
{
string lastPropPath = string.Empty;
foreach(SerializedProperty p in prop)
{
if (p.isArray && p.propertyType == SerializedPropertyType.Generic)
{
EditorGUILayout.BeginHorizontal();
p.isExpanded = EditorGUILayout.Foldout(p.isExpanded, p.displayName);
EditorGUILayout.EndHorizontal();
if (p.isExpanded)
{
EditorGUI.indentLevel++;
DrawProperties(p, drawChildren);
EditorGUI.indentLevel--;
}
}
else
{
if (!string.IsNullOrEmpty(lastPropPath) && p.propertyPath.Contains(lastPropPath)) { continue; }
lastPropPath = p.propertyPath;
EditorGUILayout.PropertyField(p, drawChildren);
}
}
}```
This is the method he writes that loops through all the SerializedProperties from the root array, but it makes no mention of SerializedObject
I have been getting that sense, I have been trying to use his tutorial as a base and disentangle all the dependencies. Make it not based on an Array, make it based on a Scriptable Object, so fourth
Maybe it would be better if I just gave up entirely and tried to find some other tutorial to introduce me to EditorWindows, Custom Editors, and SerializedObjects/SerializedProperties?
No, he has two classes, a class called GameData and a ScriptableObject class called GameDataObject, which has a list of GameData
the initial SerializedProperty is the serialized representation of that list
that's why he's able to loop just using that SerializedProperty
I had no idea 👀 That would explain why I couldnt make any progress, I was labouring under false understanding
foreach(SerializedProperty p in prop)
{
···
}
this snippet you shared is looping through the elements of the GameData list in the GameDataObject
so each loop he has a SerializedProperty that represents a GameData instance
then he just recursively loops again in the children properties to draw all the variables he has in the GameData class
it's not a great tutorial, horrible naming scheme, mixes a lot of concepts without any real explanation of which is what
That makes me feel a lot better about "not getting it." I was doing my best to follow along
foreach(SerializedProperty p in prop) in this example the prop is the GameData[]
i'd just skip this tutorial
go learn about custom Editors, EditorWindows and SerializedProperties/SerializedObjects separately
it will be a lot less confusing
https://docs.unity3d.com/Manual/editor-CustomEditors.html is a good place to start
I will do that. I was kind of envious of this tutorial because he makes it sound very easy to set up Custom Editors / Editor Windows, because I know I have struggled with Custom Inspector type stuff with how much work it takes to write out a custom inspector
I put myself through a lot of anguish trying to "get it to work" from what little is in that video
once you get the hang of it, it's pretty easy
the thing that consumes the most time is designing the layout and all that stuff
for most custom Editors you'll just be using automatic layout and mostly using PropertyFields to automate everything
so you just need to learn how the SerializedProperties/SerializedObjects work, the quirks of the different types of properties, how to loop through them, etc
Do you have any link reccomendations to learn SerializedProperties / SerializedObjects? When I google tutorials for either, they all seem embedded in tutorials for other things, like this tutorial you pointed out is covering four different subjects not very well.
Have you tried the Unity Learn stuff?
to be honest, for this topic I just learned from the documentation examples and then fiddling around with them and trying out things and googling specific questions
and asking a lot on this channel, MechWarrior was specially helpful 😊
other folks too
Yes, Unity Learn has no tutorials for Serialized anything, zero results
I also find I learn much better from video tutorials or people stepping me through code rather than Unity's documentation pages, they always assume the reader knows a lot more than I do I find
the most basic examples of SerializedProperties usage will probably be in Custom Editor tutorials
i'd suggest doing those
One of Unity's most powerful features is its extensible editor. This recorded talk from Unity 2011 introduces the basics of custom editor windows and inspectors, showing how to automate certain tasks, create custom GUI, and integrate with the rest of the editor to support specific workflows.
Oh custom editor tutorials in general, I understand now
yeah the terminology is a bit borked, some people called them "Custom Inspectors", but the "official" name seems to be Custom Editors
I.. I am struggling to give up on this guy's tutorial. I don't want to lose, I don't want to fail. I think my ego is getting better of me, I want what he shows and it very nearly hurts to just give up on it, lose, be defeated
that video seems a bit old, but skimming through it it looks like they try to break down all the stuff into bite-sized chunks
I feel like I am so close to beating it but in reality that is very likely not the case
nah don't worry
once it "clicks" you'll see how easy it becomes
it took me a couple of weeks to understand it, initially I was like "wtf is this alien language" but then i was "ah, this is so simple lmao"
🙃
Yeah I feel that, lots of things I can do now I can look back on when I looked at them and thought they were black magic
I feel like the sollution to this problem is that I need to find some way to loop through every top level Serialized Property, ignoring their children, of my Serialized Object, set them to currentProperty and then run DrawProperties on it, one by one
Mech then linked me a link on doing exactly that, looping through serialized object, but I got stuck again immediately
This is where I posted that code snippet from that is supposed to do it
What is "myProperty" ? Is it ANY property in the Serialized Object? A specifc one? The first one?
How do I know if its first?
You want the 3th reply
Its not though, that's what I already -have-
"What I was looking for is to loop through all children of a property"
I dont need to loop through all the children of a property, I need to loop through all the scriptable properties of a scriptable object
Thjat is what I am not getting, none of these tutorials ever reference Scriptable Objects Serialzied Objects
serializedObject.GetIterator();
// An attempt of mine to make it work with a serialized Object that does not work.
protected void DrawProperties(SerializedObject obj)
{
var iterator = obj.GetIterator();
iterator.Next(true);
foreach (SerializedProperty p in iterator)
{
DrawProperties(p, true);
}
}```
I'm doing something wrong here, this is as far as I got with GetIterator and using the errors VSCode spat out to write it
I don't remember what the problem you are having is originally
I know, I will google a tutorial on how to use GetIterator maybe?
Currently I just want to loop through every SerializedProperty in a SerializedObject and draw them by default, DrawProperties draws them by default
I have banished thoughts of doing anything after that because I haven't been able to get that much done yet, even I dont remember where I was going at this point
And what is it doing now?
Nothing because the code is not written to accept a ScriptableObject
// An attempt of mine to make it work with a serialized Object that does not work.
protected void DrawProperties(SerializedObject obj)
{
var iterator = obj.GetIterator();
iterator.Next(true);
foreach (SerializedProperty p in iterator)
{
DrawProperties(p, true);
}
}
This was my attempt to write code to make it accept a ScriptableObject
fuck
Serialized Object
Do you mean Scriptable or Serialized Object?
Right, so what part of that code is not working?
Yes Serialized, sorry, my brain is convinced its Scriptable every time I write it
One second Ill get you that information, i have to re-write all the code to use my broken method again
I ran it, it skips over foreach entirely
No console errors, nothing is null
@idle tree you don't need to do a recursive call of your method inside itself, using .Next(true) or .NextVisible(true) will get EVERY property after the one you provide as the iterator
including children properties
Oh sorry the call is not recursive, that's my own bad naming.
protected void DrawProperties(SerializedProperty prop, bool drawChildren)
protected void DrawProperties(SerializedObject obj)```
i forget in what order the properties are iterated, but I think it enters children before moving to the next top level property
two different methods that take a different parameter, I guess its not actually an overload method so I shouldnt have done that? Or it is maybe? At this point I doubt everything I know or have done
Reading
What is GetEnumerator? Is this the same as GetIterator?
No, that is what the foreach is calling
I'm sorry I don't know what to do with this information
Should I edit GetEnumerator? I don't think I can do that
No
If you don't understand it then just ignore it. It isn't important, I just posted incase it did help. If it is just causing more confusion then don't worry about it.
for (int i = 0; i < iterator.arraySize; i++)
{
DrawProperties(iterator.GetArrayElementAtIndex(i), true);
}
foreach (SerializedProperty p in iterator)
{
DrawProperties(p, true);
}```
It is not, the equivalent would be literally the code that is there. There is no other way to write it to have the same effect
Its okay, yeah. Just ignore it like you never saw it
public static IEnumerable<SerializedProperty> GetChildren(SerializedObject so)
{
var property = so.GetIterator();
property.Next(true);
var nextElement = property.Copy();
bool hasNextElement = nextElement.NextVisible(false);
if (!hasNextElement)
{
nextElement = null;
}
property.NextVisible(true);
while (true)
{
if ((SerializedProperty.EqualContents(property, nextElement)))
{
yield break;
}
yield return property;
bool hasNext = property.NextVisible(false);
if (!hasNext)
{
break;
}
}
}
You're SURE these arent identical? equivalent? I almost never use Foreach but I did here because the tutorial guy did, but to the best of my understanding of for loops, those are identical
and if you tell me they arent identical, I feel like you are telling me that I literally know nothing about for loops, and every single for loop ive ever written is wrong
Which may very well be the case
Is this one of those cases where -technically- its not the same because programmers very deeply care about being semantically correct, but functionally it does the same thing in the end?
I'm sorry I'm being argumentatitive now. I'll read that post
that dude in the tutorial you linked earlier was using a foreach loop to just loop through the elements in the serialized property that represented an array
I don't think you can iterate through the other properties doing that, not sure, I alwaus just use Next or NextVisible
that will iterate through EVERY serialized property in your object
well, depending on if you tell it to go into the children
You can see the code for the foreach up a bit
ah, right
I saw this code block from the guy's post but it didn't work for me
I edited it
Oh okay let me replace my copy of it
Your version wont compile.
GetIterator is a method which is not valid in the given context
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
public static class EditorExtensionMethods
{
public static IEnumerable<SerializedProperty> GetChildren(SerializedObject so)
{
var property = so.GetIterator.Next(false);
var nextElement = property.Copy();
bool hasNextElement = nextElement.NextVisible(false);
if (!hasNextElement)
{
nextElement = null;
}
property.NextVisible(true);
while (true)
{
if ((SerializedProperty.EqualContents(property, nextElement)))
{
yield break;
}
yield return property;
bool hasNext = property.NextVisible(false);
if (!hasNext)
{
break;
}
}
}
}
Edited mine
i mean, if you want the most basic example of how to iterate through properties on an object:
private void IterateProperties(SerializedObject serObj)
{
SerializedProperty iterator = serObj.GetIterator();
while (iterator.NextVisible(true))
{
Debug.Log(iterator.propertyPath);
}
}
Okay I am reading through, attempting to come to comprehension of it. It returns an IEnumerable. It starts from the first property, and moves through them in some way that my understanding starts to get muddy.
I am also getting a VERY long error when I try to use the method, trying to screen capture it
I think its saying I cant convert a serialized Property to a serialized property?
I'm sorry I am not very bright, guys. You are doing a lot to help me and I feel like I am letting you both down
@patent pebble No idea if this will help or what it does, but I found UnityEditorInternal.InternalEditorUtility.ProjectWindowDrag(..) incase you are interested (The class has a tone of neat stuff)
yeah I've seen that method I think it's just used to perform drags, similar to the DragAndDrop class
thx for sharing anyways
Ah yeah, makes sense. Didn't look at it at all haha
that InternalEditorUtility class does have a grea deal of useful stuff tho, once in a while i go through it to see if there's anything interesting I can apply to my tools
Haha yeah. I think my favorite is the SaveToSerializedFileAndForget(..) method which lets you serialize objects to YAML and save them to anywhere in the project
My man, the GetChildren returns an IEnumerable<SerializedProperty>
This is why ya can't just go copy pasting code, it doesn't help you understand anything
I have no idea what that is or how it relates to all this, so far we have not covered that at all
Yes I know, I am not trying to copy paste code, I am trying to come to an understanding
that is why I am asking all these questions, here, now
Why did you link me that code block if you didnt want to help me come to an understanding?
That feels kind of cruel to link something, say this will solve all your problems, then refuse to elaborate further on how to use it
I guess you -didnt- say it would solve all my problems, that was just how it felt
I want to learn, I want to grow
I'm sorry I am not very bright or experienced
Right, you foreach over it.
var properties = EditorExtensionMethods.GetChildren(serializedObject);
foreach (SerializedProperty prop in properties)
{
DrawProperties(prop, false);
}
If it doesn't make sense I would try looking up some info on foreach and IEnumerable.
tenacity is just about the only good quality I have to rely on , sorry stuff about me personally doesnt matter, moving onto code again
professionals dont talk about themselves, we're in it for the code only 😣
I am trying here man, I never know how much or little experience some one has so that makes it more difficult to know how much they need help sometimes. Some of the questions at this point are just normal C# questions, which I don't mind to a point, but ya also gotta look this stuff up your self or ask in #archived-code-general.
I try to help where I can, I understand editor stuff can feel complex or hard to get. But I also work, and just help out because I know how it is to be that person who doesn't understand.
I appreciate it, immensely.
This block doesn't error, but also doesn't draw anything in the EditorWindow. I am now debug logging and debug hooking and stepping through line by line to see if I can determine the reason why myself
Idk what your draw code looks like, but try just the normal EditorGUILayout.PropertyField(..)
I'm having trouble determining what things "are", when I debug log a serialized object, I just get "serialized object"
Oh right that might be the issue, I might not be actually drawing anything, I will check to be sure thats not the issue
Thanks, that worked 👍 SO is the expected variable, stepping in further
Hmm, it gets to the yield break, but then outside of the method
it then bypasses foreach
when I step forward, it just ignores it
Im going to close and reopen VS code
make sure if you're using custom classes that the are marked as [Serializable] and that your variables are using the [SerializeField] attribute
I -think- they are, when it was the earlier incarnation from the tutorial, if I passed in by name one of my variables that WAS an array, it would show all the variables there, of just that array
the class is serializable
what do your DrawProperties methods do currently?
you may be trying to draw an array's properties when the size of the array is 0
havent touched them yet, right now the foreach is being skipped over, DrawProperties is never called
okay VS code is reopened, stepping through again
debug everything
Hmmm something weird is happening
Okay I can do that
right now when I hit F11 on the first line
it doesnt go into the function, it skips it
but then it goes into that function of line 16 on line 17
plugging in debugs of everything now
Ive never seen VS do this, ever
so is Shovel, that's expected Im testing this on a shovel
I don't know what Base is refering to
nothing im aware of is called Base
and I definitely have no idea what m_objectHideFlags and m_script are, those aren't things I wrote
those are properties that belong to the SerializedObject, which in your case I assume it's either a Monobehaviour or a ScriptableObject
ScriptableObject in this case, because that's what tutorial guy was using
SerializedProperties are not just your data, they are also a bunch of other things that the object has, like the scripts, the hide flags, the sizes of arrays, etc
So it sounds like its getting caught up in scriptable object stuff? Yeah what you just said
you can avoid that by getting yourself your top-level SerializedProperties and then doing something similar to that GetChildren method
but instead of passing a SerializedObject you pass each of the top-level SerializedProperties
you can always access those because you know their names (the names of the variables in your ScriptableObject)
Is there a way to loop all the top level serialized properties or would that involve me writing out line by line the variable name string?
The entire point of this was sort of to not need to write out line by line every string, at that point Im just writing a custom inspector with extra steps
which I mean, I guess, is what I am doing
I am not understanding why it stops on that one line and draws nothing though hrrmgh
Like, I would expect it to draw -something-, its supposed to be doing foreach every single serializedProperty
but its only doing the very first one, then never drawing it, and then just doing the very first one over and over?
DrawProperties draws the properties and DrawProperties never gets called
foreach (SerializedProperty prop in properties) never enters
I'm not drawing the properties because the method to draw the properties doesnt get called because I cant figure out why the foreach wont enter
have you debugged the size of the collection of properties?
if it has nothing to loop on... well, it won't loop on anything
Properties doesnt have a Size, Length, Count, or any other variable like that
properties is an IEnumerable<SerializedProperty>
I cant find a size to debug
I can only get 5 things Equals, Enumerator, HashCode,Type, and ToString
convert it into an array and debug the Length
If I debug property INSIDE the function, it says it has no size
I think I should just stop, just quit
only properties of type array have an array size
I have no comprehension at all what this script is doing anymore
I'm so far out of my depth and league its not even funny
this makes me incredibly unhappy to have to give up
i don't think you understand how the GetChildren method works, at this point it's better if you went and tried to elarn what all the pieces are and how they work
you don't know what an IEnumeable is or how to use it
that's one of the reasons you're struggling with this
You are right, I don't know anything
it hurts me enormously in the chest to lose so badly like this. Programmers don't get hurt because they don't understand something
and i'm a programmer, so I shouldnt be in pain for losing
Its not losing to not understand something
i mean you can just skip the looping and get the properties manually by their name, and draw them with PropertyField
that will iterate automatically through all their children and draw them
literally most of the time when someone does a custom editor or anything involving SerializedProperties, we just get them by name
specially if it's something simple
Something is happening that I don't understand
that is helping me see why I have no idea whats going on
I commented out ALL the new code
saved it
compiled it
Unity is still running all the code I just commented out
its spitting out all the debug logs from the method I am no longer running
Which is impossible if I saved the file and recompiled it like Unity and VS code both say I did
this is extremely frustrating
Nothing is working the way I am promised by the machines themselves that it will work. this. way.
How can I hope to debug anything when netiher Unity nor Vs Code will even show me the truth
the answer is because I'm stupid, as usual
I was running my stupid overload method with the same stupid name
and I didnt see it because i'm a fucking blind idiot
Great. So this is where I am at now. I wasted my entire day. @gloomy chasm I wasted your entire day. and @patent pebble I wasted your entire day.
I achieved absolutely nothing, and returned to the exact same position I started with, a complete failure
I'm sorry I'm so fucking worthless
im just going to leave now because my mental health has crumbled because of the utter failure that is myself and my attempts to achieve anything ever
I appreciate both of your help enormously
I'm sorry im a worthless failure
im sorry I wasted your time
you didn't waste our time, we help because we want to. We've been in the same situation asking something that we didn't know how to solve and people helped because they wanted to
it's fine
You learned a lot, so it wasn't a waste! You aren't a failure or worthless, just still learning. I once spent over 2 hours trying to debug something and it turns out I just forgot to clear a list haha
I came back because I shouldnt run away and sit on the pity pot
I'm sorry I struggle with my mental health publicly
Thank you for your kind words. I will try to be strong.
you just have to get used to this sort of stuff
last week I spent 3 days trying to implement something that in the end wasn't possible due to Unity's limitations
i just scrapped it and moved on to the next thing 👍
Tomorrow I will close all these files related to this tutorial that has caused me nothing but grief for 3-4 days now, and just google for more random custom editor tutorials I guess
it's fine to leave stuff aside and then come back some time later with a fresh mind
you'll get used to it
I feel slightly better that even with the help of both you two experts, together all three of us still not solve it (through me) so its clearly not a simple thing to achieve
It was an unreasonable expectation I placed on myself to achieve this from the tutorial
because the tutorial guy made it sound easy and simple and showed the immediate results
and showed every line of code, one by one
it was unreasonable of me to think I would also be able to achieve success despite having everything handed to me line by line, and with the direct help of two experts
No my mental health is poisoning everything I am saying
I'm just going to go and do something, anything, for a while, that isnt this
Right-o, I finally got "restoring" to work for my sidebars. You can put them back to the exact same position when you first added them to the sidebar 👌
The logic was a pain to figure out and cover all of the different layout scenarios. Now I just gotta make it work for tabs and floating windows haha
ayeee that looks pretty neat
I think Unity staff is working on something similar for future versions of the engine
I think it was publicly available for alpha testing, but i'm not sure
I don't think so? I know they are working on blender-like workspaces.
Thanks!
hmmm maybe it was that what I saw. I just saw it in passing while randomly skimming through a roadmap or a forum post
Cant remember tbh
Hello ! I was wondering : Is there a method like GUI.DrawTexture but where you specify the texture position in world coordinates and that would automatically scale the texture depending on where the camera is ? Like how the camera icon is rendered.
Ideally I would be able to draw some kind of floating texture that is always facing the camera next to a position handle
is that possible ?
Handles.BeginGUI();
if (equipmentPartItem.sprite)
{
Texture2D texture2D = equipmentPartItem.sprite.texture;
Vector3 texturePos = Camera.current.WorldToScreenPoint(Vector3.zero);
Vector3 textureScale = Camera.current.WorldToScreenPoint(Vector3.one) - texturePos;
textureScale /= equipmentPartItem.sprite.pixelsPerUnit;
GUI.DrawTexture(new Rect(texturePos.x, Camera.current.pixelHeight - texturePos.y, texture2D.width * textureScale.x, texture2D.height * textureScale.y), texture2D);
}
Handles.EndGUI();
I figured it out myself.
Hi, does anyone know the right way to add tabs to a custom inspector (the tabs open different groupings of settings)? Currently, the index of whichever tab I have selected is saved as an int value on the script, using SerializedObject/SerializedProperty. This is nice as I can leave the inspector (by selecting a different game object, opening a new scene, or closing the eidtor), and when I reopen that scripts inspector, I see the same tab.
However, this approach results in the Scene being marked dirty. I don't like this, as I think changing tabs should be a visual choice and not effect the scene the script is in. Has anyone else found a better approach? I've thought of using EditorPrefs, howerver then the tab indexes would be shared between components of the same type, and I can see potential issues when two inspectors are open for the script type.
I also know about SerializedObject.ApplyModifiedPropertiesWithoutUndo, however use of that approach would be a big hassle given my current code, and anyway, I am not sure it is the appropriate choice.
Honestly I would go with the EditorPrefs or SessionState (like EditorPrefs but the settings only last while the project is open).
I am always against saving editor values in runtime code if you can help it. If you really wanted to, you could use reflection to get the field and set it that way instead of using SerializedProperty. Only downside is that the value will not be saved unless something else is changed.
But that is the nature of it if you don't want the scene to be dirty.
i like SessionState for things like this
you don't have to be as careful, you can just shove data into it and forget about it
I've never heard of that. Thanks! I will take a look.
Do you save separate data for each script using this method? If so, what do you use as the key? I was thinking of using the instance ID of the MonoBehaviour object.
just save the tab index per-object
use the Instance ID for the targetObject of your custom Editor script
Awesome, thanks! I think this will be perfect.
iirc you get the ID with Object.GetInstanceID()
@wintry badger this is assuming you only have one component that uses a tab system, if you have multiple in the same object I guess you can just use the name of the component + instanceID
You can also just serialize things on the editor instance, it'll persist between play mode but not objects and restarts iirc
Also instance Id isn't persistent eithrr
does instanceID persist an entire editor session?
i forgot about it
Yeah, I was wondering that too. I guess it would be easy enough to test and find out.
I don't think it's guaranteed but it almost always does
Iirc it sometimes also survives restarts
even if it's not 100% stable, seems good enough for a non-critical thing such as a tab index
Just to be clear, what do you mean by serializing it on the editor istance? Make the tab index a field on the editor class?
in the custom inspector (it's an Editor class)
Hmm, I was under the impression that once you click on a different game object, the inspector "object" is destroyed. Is my understanding wrong? Because in that instance, the tab index value would be reset when switching between game objects.
That can get pretty annoying though
yeah I can see that
Oh yeah it makes more sense for editor windows, still worth a try though
Ok, I just wanted to make sure I understood your suggestion completely. Awesome, thanks for the help both of you! I think I have everything I need to implement a solution.
Okay, so after some testing it appears that the instance ID is changed if you close and reopen a scene, so using it as a key will not work if you want to save the tab index between opening/closing different scenes. It does survive an assembly reload though, so will most likely work for most use cases. However, I am making note of it here for others to find in case they need similar functionality.
I want to show a context menu item when right clicking a GameObject in the hierarchy, but not in the GameObject menu. How can I do that?
This is my code currently
[MenuItem("GameObject/Guardrails/Physics Check", false, 0)]
static void CollisionCheck(MenuCommand menuCommand) {
Debug.Log($"Hello {menuCommand.context}");
}```
@twin dawn oo... kinda tough actually. You can disable the guardrails element by making its validator use the "Selection.activeGameObject != null" check
but it will stilla ppear, just be grayed out.
GameObject/ MenuItem path is special
ah ok I was trying to use the menuCommand.context field for this. I'll try that.
Ok this works and is actually kind of ideal because I'm happy with the fact that you can run this from the GameObject menu as long as you've got a GameObject selected.
how's that work
MenuItem("GameObject/Guardrails/Physics Check %_F")
Ah ok, it all goes in that string
Looks promising, thanks!
@wintry badger you could also try to use the Local File Identifier of the GameObject within its Scene
public static class LocalFileIDUtility
{
public static int GetLocalFileID(Object obj)
{
PropertyInfo inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", BindingFlags.NonPublic | BindingFlags.Instance);
SerializedObject serializedObject = new SerializedObject(obj);
inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null);
SerializedProperty localIdProp = serializedObject.FindProperty("m_LocalIdentfierInFile"); //Note: The misspelling is correct
return localIdProp.intValue;
}
}
haven't extensively done stuff with GlobalObjectID and LocalFileID but I would assume they are persistent enough to satisfy your needs
i think LocalFileID can cause situations where two GameObjects in different scenes share the same identifier, so if you're gonna use LocalFIleID you should probably include the Scene's GUID or something like that in your identifier
here's an extension method to get the GUID
public static class GameObjectExtensions
{
public static string GetSceneGUID(this GameObject gameObject)
{
string scenePath = gameObject.scene.path;
return AssetDatabase.AssetPathToGUID(scenePath);
}
}
Hello. I have custom scriptable tile based on Tile class. It works but unfortunately it doesn't show preview of base's Tile class Sprite property preview. So I created drawer so I can draw it as texture at bottom of inspector view. But how exactly I can get this property from base class using property.serializedObject.FindProperty("sprite")? Is it possible or I have to create reference on this sprite in my custom scriptable tile script firts?
m_Sprite is the name probably
If you hold alt and click in the inspector it should show the serialized name
^ while in debug mode
Thank you guys. I'll try.
Is there a way to force Unity to close context menus on middle-mouse click?
currently it only registers left and right click
i have a small tool that changes selection and opens a GenericMenu when I middle click an asset
and it's kind of annoying having to click outside with left click to be able to do middle click again on another asset
i want to be able to do quick successive middle clicks like I can with right clicks
Hello there, I am working on an editor tool and recently I started getting constant errors after code compile.
In the custom tool I am creating, I use my own defined profile with custom shortcuts. The only thing I do is setup a profile if the profile doesn't exist and I set the active profile id to my custom profile. I do this in OnFocus method and I revert the changes back to the default profile after the focus is lost. So, I am confused as to what could be an issue with that.
The weird thing is that I haven't received any issues related to shortcuts manager. These errors only started to appear recently. So, confused as to what I've done that could have caused this to appear.
This is the code that does all that:
private void OnFocus()
{
if (ShortcutManager.instance.GetAvailableProfileIds().ToList().FindIndex(id => id == Utils.ShortcutProfileID) == -1)
{
ShortcutManager.instance.CreateProfile(Utils.ShortcutProfileID);
ShortcutManager.instance.activeProfileId = Utils.ShortcutProfileID;
var bindings = ShortcutManager.instance.GetAvailableShortcutIds();
foreach (var bind in bindings)
{
if (!bind.Contains(Utils.Title))
{
ShortcutManager.instance.RebindShortcut(bind, ShortcutBinding.empty);
}
}
}
ShortcutManager.instance.activeProfileId = Utils.ShortcutProfileID;
}
private void OnLostFocus()
{
ShortcutManager.instance.activeProfileId = "Default";
}
And then I have the other script file, where I define all the shortcut functions. I haven't really used the shortcuts manager up until this project, so I might be utilizing this feature in not so correct way, I am not sure.
Can someone please give some advice, as to what could be causing these errors to appear?
Also, these error messages do not disappear and keep spamming the console, until I cause Unity to recompile some script
With a custom inspector of a component, what is the syntax to write an IF statement based on a variable of the component I am custom inspecting?
I can't just do If(variableName) because no such variable exists in the customInspector class
How do I do an If statement based on the thing this is a CustomEditor of
this is maybe the answer? but I have no idea how to use it in mine
VS code hates every line of it
It looks like this is the sollution ^
how do we access the generated physics shape data for imported 2d sprites ?
found it
ui toolkit reset button doesn't work immediately unless i switch to another gameobject and back again
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(BallController))]
public class BallControllerEditor : Editor
{
SerializedProperty shootSpeed;
private void OnEnable()
{
shootSpeed = serializedObject.FindProperty("<ShootSpeed>.k__BackingField");
Debug.Log(shootSpeed.floatValue);
}
any reasons why shootSpeed is null? dont get confused by the name 😄
the property is [field: SerializeField] public float ShootSpeed { get; private set; }
the name in debug mode is :
check the name in the meta
in the meta?
oh the .meta file in the folder i guess
BallController.cs.meta
fileFormatVersion: 2
guid: bc008ace14cc5d3439a6e7f0155996ce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
no serialized fields?
.
wrong meta
I dont have a prefab with that script
I can probably setup one for testing purpose
fileFormatVersion: 2
guid: b9d387287738a724b9daed7b4d7e6496
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
^ the meta of the prefab with the script on it
change that field in inspector, so its serialized
i did
the meta refuses to change
i changed my property name to m_MaxScale which works
so the problem seems to be the name of the backing field of the auto property
your custom inspector is active while youre doing all that?
you are in debug mode?
the debug mode was only active for seeing the serialized name
nice, now it works
without anything changing
@eager shale you had an extra period in there
"<ShootSpeed>.k__BackingField" nope
"<ShootSpeed>k__BackingField" yes
SOFTWARE DEVELOPMENT PROCESS:
- I can't fix this
- Crisis of confidence
- Questions career
- Questions life
- Oh it was a typo, cool
🙃
😔
I have no idea why this doesnt work.
I have no idea why this works.
me writing shaders
https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnTransformChildrenChanged.html
https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnTransformParentChanged.html
There's these but probably don't work in editor
Will this get me the name of the serialized object? x/y how do I get the name of a serialized object?
name in this context being the name of the unity component that I know the serialized object is serializing
answer: that wont work, I needed to use SO.targetObject.name
Or "m_Name"
Does anyone know if it's possible to change the options available in "Max size" in the texture importer settings?
I'm hoping to be able to add a size between 4096 and 8192 if possible
thanks for any help
those sizes are all base 2 values, correct me if I am wrong but there is no base 2 value between those two options so it wouldn't be performant to use it
@idle tree Would that be not performant Ram-wise? Basically my issue is that I'm working with the quest 2, and it seems that the system hardware is using more ram in recent updates and pushing my app into crash territory, it's a very custom app so all that really matters is getting as much resolution as possible without crashing
Ideally if I could set a mid-point of 6144 max size somehow hopefully it'd bring the crashing under control
Way beyond my technical knowledge to answer. I'm an artist, my knowledge comes from texture resolution prefering to be at base2 sizes because texture memory gets wasted if its not
Yeah I think there isn't really space for in-between sizes here, I can work with 4096 for now, surprisingly a 4k render with max size set to 8k is better looking than a 6k render with max size set to 4k 🤷♂️
Hello! How can I make _inputActionAsset to show up in the window?
Sorry to just link docs, but I would basically be just be repeating the info that is there
np, thank you 😄
i tried something, but
In this case the EditorWindow is the UnityEngine.Object that contains the field, so you need to pass it to the SerializedObject constructor. You will also need to add the [SerializeField] attribute to the _inputActionAsset field so it will actually be serialized.
And then for getting it, .FindProperty(..) you need to pass the string name of the field that is serialized. So in this case _inputActionAsset is the field you are wanting.
You are still passing the InputAction to the SerializedObject constructor
you need to pass the EditorWindow
aka this
ty so much, and sorry, im 0 at all the things connected to the cutom editor
All good, did you get it working?
Nice! You will also want to cache the SerializedObject instance so it is not recreated every frame.
Nope that would defeat the purpose of using SerializedProperty 🙂
Are you familiar with reflection in C#? If so, then this is basically that. If not, then please don't worry about it.
where ?
OnEnable
ty again
nope
Then don't worry about. Was just going to use it as a thing to relate the SerializedProperty/SerializedObject to, but if you don't know it then it won't help so don't give it another thought 🙂
Good Morning, can somebody help me with this error? I'm using a linux system and already tried to run unityhub as admin, but the error still occurs
I was able to solve this. I changed the owner of Unity and UnityHub and all it contains data to my own account (some of the files are owned by root)
My selection outline stopped working for some reason. I have the Gizmo enabled but still wont show up. What could cause this?
maybe color in color settings?
Im getting these 2 errors when trying to create scriptable objects from a input action asset, and i dont understand why.
private bool IsAssetCreated(InputData[] inputDataList, InputAction inputAction)
{
return inputDataList != null && inputDataList.Any(data => data.InputAction == inputAction);
}```
_inputDataInstance = CreateInstance<InputData>();
The selection outline is gone from my main scene. It still works perfectly in my prototype scene. What is going on? I deleted library folder and rebuilt it still wont work
Hello, "EditorGUILayout.PropertyField(serializedProperty, new GUIContent(name), false" does not work properly when it comes to arrays/lists past 2019. I want a way to drag and drop into the array/list field but I want to turn off the ability to show children and if possible turn off the array/list size field. is there a way to do that? in 2020+
do i need to create an instance for every createasset? - answer: yes
is there a way to exclude a static class from domain reload?
I don't want to turn off Domain Reloading in the entire project, I just want a static class to retain its data
i wonder if there's any attribute or something to tell Unity "hey, leave this one alone"
how can i modify the scriptable object that i have just created?, because if write inputDataInstance.InputAction = inputAction; before the SO is created, it doesnt assign the input action. I tried also AssetDatabase.SaveAssets(); and AssetDatabase.Refresh();, but nothing
Asset creation
See thread
No, that would involve excluding the class from the domain. Iirc, you can think of domain reloading as 'destroying' the old domain and creating a new one.
hmmm, do you know if there's a way of hiding assets in the project?
i could maybe try to make a hidden scriptableobject and keep the data there
don't know if HideFlags works with assets, or just gameobjects
Why not just use a ScriptableSingleton? Or SessionState?
If you don't save the ScriptableSingleton it will act the same as a SessionState
SessionState is too simple to fit my needs
but ScriptableSingleton could work
never used it before, so I guess it's time to learn
I know that it works for subassets, and I think it works for main assets too, but don't remember
I'll try it too just in case
It is so easy
public class MyData : ScriptableSingleton<MyData>
{
public string SomeValue { get... set... }
// other serialized values and properties...
}
// In some method in another class...
MyData.instance.SomeValue = "Cool!";
@gloomy chasm thanks a bunch, as always! 😊
does anybody know where i can find the code on how Unity snaps a vertex to a surface on another mesh (V + Shift + Ctrl)? tried finding the code in the VertexSnapping.cs on github (https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/EditorHandles/VertexSnapping.cs) but it doesn't cover the vertex snap to a surface.
It is literally right there, no? https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/EditorHandles/VertexSnapping.cs#L85
doesn't that snap the object to a nearby vertex?
trying to find the code where it snaps to a surface instead
this is what i'm talking about
Oh, I think that is just a raycast
You can use HandleUtility.GUIPointToWorldRay(..) I think
Yup
Would probably need to filter through the returned colliders because the first one would be the object being moved.
I feel like there is a better way to handle this...
Ah, actually I bet you can use HandleUtility.PickGameObject() and get the collider on it if it has one and use the collider.ClosestPoint()
That assumes I remember what HandleUtility.PickGameObject() does...
Is it good if it is saved outside the project?
In my particular case it wouldn't be ideal. Since I'm handling per-session per-project data
So having an external file would require additional handling to check to what project it belongs, etc
I wonder where the singleton saves the data
Oh it's per session
So, no saving
I mean, I'm sure I will use the ScriptableSingleton for tools that require the data to survive multiple sessions
But for this particular one I just need it to survive assembly reloads
I mean, no saving for the process lifetime, I guess you persist after a Domain reloax
yeye
for saving as a file it lets you specify a path within your project or within the preferences folder
If you had the FilePath attribute it will be saved between sessions. But otherwise it will only be saved between domain reloads
Oh shit, now we can have sub-channel that archives automatically, nice shit
I'm even outdated about Discord xD
ya getting old there 👴
I'm still not used to opening threads in Discord, so I always forget 😅
but ideally, what Unity staff wants us to do is open threads for topics whenever possible
but the Discord UI for that stuff is still kinda half baked, so it's not great
How is your tutorial stuff doing mister Mad?
slow lmao
i still have a lot of stuff that I need to learn before having enough competency to make a tutorial for it
and working on my own projects comes first, that stuff I do in my spare time or when I need a break from my games
Well you just learned about ScriptableSingleton :D
added to the tutorial list! 😋
i wouldn't need to make tutorials for all these editor APIs if Unity had comprehensive documentation... 🙃
but I guess this stuff is low priority for them
I do need too a backbone, a plan for writing.
I'm sad I had this idea early on, but never committed T_T
I could have wrote so many discoveries
- Get idea for cool project
- Get idea for another cool project
- Forget about 1st idea
- Repeat ad infinitum
♻️
I've had an idea for a tool for taking notes in the editor that would let you attach notes to pretty much everything.
Put notes on components, put notes on exposed fields, attach notes to GameObjects, have top-level editor sticky notes, etc
but I just never got around to make it
I think it would be feasible with IMGUI but it would require a lot of handling and it wouldn't probably perform very well
but I'm not sure
Embedded tooltips/tutorials is nice.
But it comes with 1 big downfall and 1 big upfall :D
It is embedded in Unity, and it is embedded in Unity :D
I don't see how you can inject your code in IMGUI
(Might be good to make a thread for this 😉 )
Editor notes and Tooltips
@gloomy chasm hey I was also checking out SessionState out of curiosity
is there any way of checking if a key already exists?
all it has is Erase/Get/Set methods
Just use get with w/e you want for the default value
It's like editorprefs
Oh I guess playerprefs has a haskey
yeah
SessionState has a problem
for numeric and string values you can check with a default value of a very absurd number or string
but with bools there's not an option
you just get either true or false
Unity uses SessionState internally, so there's no way to know if you are overriding an internal key
it usually won't happen, but there's always edge cases
Just prefix it with your assets name then
Or your company name or w/e
It's not that big of a deal
oh lol, I'm so dumb
yeah, using a prefix solves any potential problem
silly me 😅
how to draw GUI inside UIElements? i have custom window using UIElements and want to draw inspector with serialized stuff there
create the uxml or create the ui elements per code and display them in the window
//DroneComponent Script
public class DroneComponent : MonoBehaviour
{
[HideInInspector] public DroneComponentManager manager;
public void LinkToManager(DroneComponentManager manager)
{
if(this.manager != null)
{
this.manager.components.Remove(this);
}
this.manager = manager;
if(manager != null)
{
manager.components.Add(this);
}
}
}
//DroneComponentManager Script
public class DroneComponentManager : MonoBehaviour
{
public List<DroneComponent> components = new List<DroneComponent>();
}
//DroneComponentEditor Script
[CustomEditor(typeof(DroneComponent), true)]
public class DroneComponentEditor : Editor
{
public DroneComponentManager manager;
public override void OnInspectorGUI()
DroneComponent myDroneComponent = (DroneComponent)target;
var manager = (DroneComponentManager)EditorGUILayout.ObjectField("Link Manager", myDroneComponent.manager, typeof(DroneComponentManager));
if (manager != myDroneComponent.manager)
{
this.manager = manager;
myDroneComponent.LinkToManager(manager);
}
EditorUtility.SetDirty(myDroneComponent);
base.OnInspectorGUI();
}
}
not sure where to put the serializable field thing so I tried it on all relevant variables and nothing worked
You use SetDirty after making changes
didnt work
let me update code
there the prev code is updated
You're also modifying manager, not myDroneComponent
oh so both>
or... maybe not, you're modifying both?
I am adding to the component list in manager
so yes
right?
it worked
i changed it to this:
EditorUtility.SetDirty(myDroneComponent);
if(this.manager != null)
{
EditorUtility.SetDirty(this.manager);
}
sweet thanks @visual stag and @wild edge
what a weird thing to have to do
You should really only be dirtying things when changes happen. The SerializedObject/Property and Undo systems are the proper way of handling it. SetDirty is the laziest and least used way
Can someone help me with this?
https://forum.unity.com/threads/transform-2d-array-losing-reference-on-play.1225464/
Unity can't serialize 2D arrays
The only collections that Unity can serialize is T[] and List<T> (T being the type you want, for example string or Transform, etc.)
I see... I thought if I used a custom editor it would be possible
Thanks!
Sure thing. You can look up something like "unity how to serialize 2d array" and it should come up with something on how to do it 🙂
I would also look in to SerializedObject and SerializedProperty for your editor scripting in the future and use them instead of setting values directly to ensure that changes are saved and support undo
where should i stick something in an editor script that i want to update based on the position of the gameobject when it's being moved around in the editor? like for example if i want a reference to the closest gameobject of type whatever and they won't move at runtime so i want it to be done when placing the objects in the editor
like first i just stuck my logic in Editor.OnSceneGUI but it complained when i tried to use multiple targets and i know that probably isn't the place but i just want something that updates often
i guess the "correct" approach would ideally be to hook into some kind of event from the move tool itself or something but i have no clue about that
or another thing, if i want to keep the default inspector but detect when a value in it was changed and do something based on it?
[ExecuteInEditMode]
that's just for executing MonoBehaviours out of play mode
i don't think it was what that person asked
@teal timber another way to get notified when the Scene View is interacted with is subscribing to these events
SceneView.beforeSceneGui and SceneView.duringSceneGui
your question is a little bit confusing, can you clarify what issues you're having?
Are you having trouble getting the GameObject that's being moved?
Are you havin problems when multiple GameObjects are selected?
but it complained when i tried to use multiple targets
are you getting the "Multi-object editing is not supported? when you select multiple GameObjects with a custom editor?
if that's the case you can use the [CanEditMultipleObjects] like so:
[CanEditMultipleObjects]
[CustomEditor(typeof(MyMonoBehaviour))]
public class MyCustomEditor : Editor
{
private void OnSceneGUI()
{
Debug.Log($"{GetType()} Calling: OnSceneGUI()");
}
}
am i getting Type mismatch because i assign a instance to a field of a created asset?
public void SetInputAction(InputActionReference newInputAction) => inputAction = newInputAction;```
inputAction = newInputAction.action; 😉
inputAction is a InputActionReference that is null when its created
Are you sure? And doesn't the type mismatch tell you the types?
1 sec to open unity, but i dont think so, if i press play it turns into null
if i hover over the type mismatch nothing shows up
Oh that type of type mismatch
Not sure what to tell you tbh. Time for some debug.logs I guess
the right InputActionReference are passed
Hi,
I have properties (Dark Square Prefab and Light Square Prefab) of type "Square". It works well but the Select window from the Inspector doesn't show the prefabs from my assets of type "Square". (but it show the gameobjects of type "Square" in the Scene Tab).
That is because Unity can't get prefabs by the type of component on them.
If you want to reference a prefab it has to be by GameObject
This I think changed in 2021.2 if you are using the new search window
I see. Thank you @gloomy chasm
I'm sorry I don't know what to tell you. You could try setting it the next update just in case it is because the Object reference has not been resolved?
oh, there is a object ref problem in unity ?
Uhh... its complicated
No, anyway that is fixed now.
There is an issue with SerializedProperties and copying values of UnityEngine.Object fields the same update that they were set.
i think the problem comes from the CreateInstance<InputActionReference>(); because when i created a serializefield InputActionReference and use it into the SetInputAction function, it worked
but i dont know any other way of creating an instance of a SO, because InputActionReference is a SO too
hi people, i'm implementing my own 2D Animator solution, and everything is working fine, but i wan't to be able to send events on certain frames, the problem is that i can use a sprite on EditorGUI.ObjectField but i can't use a UnityEvent, does anyone know how can i implement a UnityEvent on my editor ?
i wan't to somehow be able to show the events for certain frames, so i have a class called SpriteAnimationFrame that holds information about sprites and events, however i'm not being able to show the unityevent in the inspector just like i'm doing with my sprites
that's the spriteanimationframe class
and that's how i' drawing the properties
is there a way to get the Pixel Per Unity value from an Input Texture2D after that import settings were applied ?
nvm just realized i need to use sprites instead of texture2d references in the editor
textureSprite.pixelsPerUnit
Serialized Properties
Hey all. I have an editor question... I have a prefab and when I drop it into a scene, I'd like for the editor to prompt me with some sort of "fill in these required fields" or something so I can set the prefab up appropriately in the scene.
Is this a thing?
Or, conversely, when I change the name of the GameObject in the editor, can I make a macro/script run to adjust stuff?
Seems like Unity really wants me to use VS or VSCode. Setting up Emacs is a real pain
@viral nimbus there's these 2, which are almost the same.
https://docs.unity3d.com/ScriptReference/EditorApplication-hierarchyChanged.html
https://docs.unity3d.com/ScriptReference/EditorWindow.OnHierarchyChange.html
I don't know if there's anything similar to get filtered notifications for each separate thing (creation, rename, reparent, etc)
Hello
Hello I have a two scripts that create scriptable objects. One creates TileClass that is than stored in TileAtlas. Every time I wanna add new class such as public TileClass stone; I have to go to script editor and add the new class. Is it possible to create editor extension that would do do this "for me", so that I would click button in editor, write name of a new class and it would be added. Rather than having to do it manualy.
use arrays
I can't get Omnisharp to work at all, I've been at it for 3 hours, installing and uninstalling .NET versions, logging in and out, reinstalling Unity, Omnisharp, Mono, VSCode...
[fail]: OmniSharp.MSBuild.ProjectLoader
The reference assemblies for .NETFramework,Version=v4.7.1 were not found. To resolve this, install the Developer Pack (SDK/Targeting Pack) for this framework version or retarget your application. You can download .NET Framework Developer Packs at https://aka.ms/msbuild/developerpacks```
```log
[fail]: OmniSharp.MSBuild.ProjectManager
Attempted to update project that is not loaded: c:\Users\User\My project\Assembly-CSharp.csproj```
I've followed the instructions in [#854851968446365696](/guild/489222168727519232/channel/854851968446365696/) , on Microsoft's website, on Unity's website, and on VSCode's website, along with what the error said
I've read countless discussions with this exact error in the server and no one ever reached a conclusion or found a solution. In the rare occasions that someone managed to fix it, they don't specify clearly
I've never used Windows before and I'm genuinely confused
I've also tried to set all of this up with Emacs, with no avail
I've also tried with VSCodium
You have this developer pack? https://dotnet.microsoft.com/download/dotnet-framework/net471
Yes, but I get the error ".NET Framework 4.7.1 or a later update is already installed on this computer."
I verify the version with a Microsoft's recommended community tool, and I have version 4.8.1, or something of the kind
I've tried multiple tools to remove this version, but none of them solved the 4.7.1 installer's error
I have logged out and rebooted the computer multiple times
Omg it worked
You were right, I was using the runtime, not the dev pack
Auto-complete now works well!
It even works on Emacs! Hooray!
it doesn't work so well with arrays. I like that I can acess this as TileClass.stone instead of looping trough array looking for stuff
I could write a function right, that would go like Function(TileAtlas, name of what you are searching for)
but this still seems superior option
It's not easily scalable, you dont need the variable name to be different, only the exposed identifier, it requires a lot of writing.
That doesn't seem superior to me when arrays fix all the above
Sure, you can generate that class
Arrays have terrible UX for that usecase
You end up makign a GetTile method that takes a string which you cn then typo
Or you need to make constants that contain the name of the tile and then we're back to the same problem
I'd just do a super dumb writing to file by just adding a bunch of lines together for all elements you want and then just use File.WriteAllText or something like that
And trigger a recompile
you are making a singleton
No they're not
class TileWrapper
{
public enum TileType tileType;
public Tile tile;
}
consider array of these instead
They can easily have different TileAtlasses with different tiles for biomes
you have editor assigned tile type, where you can designate as much stone tiles as you want
I don't think so. You can even write a custom inspector if you have a some kind of problem with the default one
you can later query your collection and for example make random selection from all stone tiles you placed in
you can also validate it based on your criteria, i.e. each collection should have 1 of each tile type etc
Slooowness takes over
The only slowness is the compilation, considering this is probably not done very often it's fine
Now you're writing code to solve a problem that didn't even exist in the first place
It's not fine if there are better options
oh im sorry
I don't agree there are better options in this specific use case, sure arrays are an option with (imo) bigger downsides
They are fast
Yes, just adding one element is fast. Looking up an element is slower (arguably not much depending on how long that list is going to get and how often they are querying it)
Just index?
So each tile is a specific index..?
array[TileType.stone]
They're arrays after all
Back to the first problem, you need to change the code to add a new element for the stone index
We're making the UX worse, and still not solving the problem (we've actually introduced the problem!)
The ux is not under consideration
??
The whole point is that the UX of adding a new element is currently bad
It's cumbersome to edit code to add an extra element
ah right
Because how they do it is bad
so i solve the original problem simply with odin DropdownValue
you can supply enumerator which will locate anything you want, for example instances of TileClass assets
and display a dropdown which to select, acting as enum so you dont have to weave it
Pretty much, just write a nice simple custom editor
guess you can do something similar rather simply
That's a better solution but still, you have to end up dealing with an array at runtime to find the element you want
And you don't need Odin for that necessarily
what do you propose?
Index still
That's not a good solution, it's error prone unless you write code to validate that a certain index is always a certain tile in which case you'll end up having to change code again to set that up
And edit code to add the index property in the first place
What I've been proposing all along, code gen to add an extra property to the TileAtlas class
No you write code that caches where what is, a lookup table. That's super easy and efficient
Sure there's a (imo) small annoyance when adding a new property (compilation time)
But other than that, it's easy and fast to access
it also has to be a dll as not to break in case of compiler errors, should also be able to handle renaming/removal, probably should do it automatically on asset changes
thats a rather big amount of work
So you acces it by index through a caching system, that's generated for each instance of TileAtlas? How do you tell it which tile you want? Strings are not a solution unless it's a constant and then you're back to editing code which is what they're trying to avoid in the first place
You still have to write more code to adda property
If you need variable text, just parse the keywords from a text area or smth
You don't have to make it a dll in this case, that's only relevant when you're automatically generating code on (e.g.) startup and it is not included in source control
Renaming/removing is still an issue with an array, the index will change or the name will change that some other code relies on. You don't get compilation errors since you're probably manually passing a string or index somewhere, breaking the game at runtime rather than compilation time
I don't understand what you're saying here
And I'm going to lunch
? You're never manually passing strings or indexes
I don't understand how you want to codegen it without changing something of the code either
yeah thats why i propose to use wrapper with some data available for query, sure its slower in access, which can be cached with a lut once, the hardcoded refs are still a problem but it can be resolved with your method, or with a static class with const identifiers that can be passed to the atlas for lookup
Well I guess you could do some code gen, but you'd then also end up with potentially a lot of fields in a single script, which I wouldn't say is ideal
// codegen ?
static class TileTypes
{
public const int Stone = 931239;
...
}
class TileAtlas
{
[SerializeField]
List<TileData> tiles;
[Serializeable]
class TileData {
public Tile reference;
// any additional data for queries
}
}
tileAtlas.GetRandom(TileTypes.Stone);
tileAtlas.AllOfType(TileTypes.Grass);
Hello! I have a question about changing variable type based on an enumerator. The main concept is that if I changed the enum to Name, component's type should be set to TMPro and should i change the enum to Icon the component's type should be Sprite. I am very new to editing the inspector so I do not know if this is possible or not and if it is indeed not possible, just point me in the right direction. Thank You!
you need to write a custom editor for that
yes! I am aware. that is why i stated that "I am very new to editing the inspector".
you need to hide / show different fields based on the enum. there's lots of examples for that out there
just do a switch statement on the enum and do the ObjectField with the desired type based on that
did you make that inspector? or do you know nothing about implementing custom Editors?
that is the default inspector. Its just a class in an array. To make it designer friendly I decided to try and swap types or hide/show relevant fields to the enum
ok start here
instead of making a custom Editor you could also use a PropertyDrawer, but it's a little bit more complicated
doing a PropertyDrawer would be better since it draws on every element of an array
if you make a custom Editor you are making the entire inspector, so you have to implement the array yourself and all that
@shrewd parrot lets assume the class you use in that array is named Display,
you can make a PropertyDrawer that targets the type Display,
and every time Unity needs to draw that it will use the logic in your PropertyDrawer
instead of using the default UI, which is what you're getting now
hmm okay
so i could just perhaps use a switch statement and check if the enum Display Type is of a certain type (like Name) and then display the relevant feilds (like TextMeshProGUI)?
in your PropertyDrawer you can get the fields of the instance of the target type
so you access your DisplayType enum, and based on that draw a different version of the ObjectField (the field that lets you drag objects into it)
it takes a Type as a parameter, which will make the field only accept objects of that type
oh shit thats a good one
and this one for drawing the enum selection popup
https://docs.unity3d.com/ScriptReference/EditorGUILayout.EnumPopup.html
@shrewd parrot on the PropertyDrawer documentation page scroll down to see the xamples that use IMGUI, instead of the UI Elements
yep i see it
I'm learning how to make these for a project and i was just wondering what are some simple yet effective things i can make to show off what i've learned
I needed to make a serializable version of a Dictionary for one of my tools
the tool only ever has to deal with the following types:
Bool, Float, Int, String, Vector3, Int[]
Because Unity doesn't serialize nested collections, I ended up having to use a wrapper for the int[] type like this:
[Serializable]
public class IntArrayWrapper : IConvertible
{
[SerializeField] public int[] Array;
public IntArrayWrapper(int[] intArray)
{
Array = intArray;
}
public object ToType(Type conversionType, IFormatProvider provider)
{
return Convert.ChangeType(Array, conversionType);
}
}
And use it in my manual serialization like so:
[Serializable]
public class SerializableDict<TKey, TValue> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver
{
[SerializeField] private List<TKey> keys = new List<TKey>();
[SerializeField] private List<TValue> values = new List<TValue>();
[SerializeField] private List<IntArrayWrapper> intArrayWrappers = new List<IntArrayWrapper>();
public void OnBeforeSerialize() // Save the dictionary to lists
{
keys.Clear();
values.Clear();
intArrayWrappers.Clear();
foreach (KeyValuePair<TKey, TValue> pair in this)
{
keys.Add(pair.Key);
if (pair.Value is int[])
SerializeValuesAsArrays(pair);
else
SerializeValues(pair);
}
}
public void OnAfterDeserialize() // Load dictionary from lists
{
this.Clear();
if (intArrayWrappers.Count != 0)
DeserializeValuesAsArrays();
else
DeserializeValues();
}
private void SerializeValues(KeyValuePair<TKey, TValue> pair) // bool, float, int, string, Vector3
{
values.Add(pair.Value);
}
private void SerializeValuesAsArrays(KeyValuePair<TKey, TValue> pair) // int[]
{
int[] array = (int[])Convert.ChangeType(pair.Value, typeof(int[]));
intArrayWrappers.Add(new IntArrayWrapper(array));
}
private void DeserializeValues() // bool, float, int, string, Vector3
{
for (int i = 0; i < keys.Count; i++)
this.Add(keys[i], values[i]);
}
private void DeserializeValuesAsArrays() // int[]
{
for (int i = 0; i < keys.Count; i++)
this.Add(keys[i], (TValue)Convert.ChangeType(intArrayWrappers[i], typeof(TValue)));
}
}
I wonder if there's a better solution
this one seems to be too cumbersome, even though it appears to work
I've never done any custom serialization in Unity, other than the very basics, so I don't really know if this is a good approach or not 😅
this is what I'm making, a way of displaying SessionState data
Looks fine to me, wonder how it behaves in high scale.
Also at if (pair.Value is int[])
I would prefer typeof(TValue) == typeof(int[])
Or maybe even move it out to its own foreach for performance reason
you did it already when deserializing
Look at #854851968446365696
idk if this is late but i have the exact same issue right now and i think i found a working solution but i cant get it to work properly yet -
https://github.com/github-for-unity/Unity/blob/master/src/UnityExtension/Assets/Editor/GitHub.Unity/SerializableDictionary.cs
ah, thanks for the tip! I missed that one 🙏
also looking at your issue now it might not be what you are looking for but whatever i guess 🤷♂️
maybe it helps a little
Looks fine to me, wonder how it behaves in high scale.
In what sense? adding big amounts of values?
or displaying large amounts of values in the UI?
also seeing as your one is basically an improved version if this, it probably isnt much use
@oak belfry yeah I've looked at a couple of serializable dictionary implementations
but they seemed too bloated, because they want to support all use cases
I wanted to implement mine as light as possible, because I know the data I need to serialize will never change type
it's gonna be always the same
Bool, Float, Int, String, Vector3, Int[] is all I will ever need to serialize
also since you know a bit about this, why does my editor give this error
SerializationException: there are 1 keys and 0 values after deserialization. Make sure that both key and value types are serializable.
SerializableDictionary`2[TKey,TValue].OnAfterDeserialize () (at Assets/Scripts/GenericDictionary.cs:40)
@oak belfry i have a similar safety check in mine too. It's usually caused by having types that are non-serializable
i tried with int + string, still didnt work
like nested collections, classes without the [Serializable], etc
for some reason it kinda works when i remove this
public void OnBeforeSerialize()
{
keys.Clear();
values.Clear();
foreach (var pair in this)
{
keys.Add(pair.Key);
values.Add(pair.Value);
}
}
well the keys.clear and values.clear
@oak belfry what types do your dictionaries contain?
well i want to have gameObject + KeyCode, but i tried string + int too just to check
still didnt work tho ._.
I have no idea, but have you checked if you values are null?
maybe that borks the serialization?
your error is telling you you have a key that doesn't have a value associated to it
debug everything and see what's happening
A lot of data, a lot of dictionary to serialize/deserialize
ah, tbh I don't know
i can try to feed it a couple thousand dictionaries and see how it reacts
brb
Just a thought, no need for justification 🙂
@onyx harness it took 10 seconds to serialize 10k dictionaries with 5 elements in each dictionary
so around 1 ms per dictionary
and generated 456 bytes of garbage per dictionary
i have no clue if that's good or bad, because I have no perspective on this topic 😅
Sounds like a lot X)
You should precalculate the length, an use array instead of List
@patent pebble I implemented one myself. If you don't need to use it in the inspector you can remove all the editor specific code and it will be as light as it is possible to be https://github.com/MechWarrior99/Bewildered-Core/blob/main/Runtime/UDictionary.cs
There is no way to make it lighter as far as I know.
ah, thanks for sharing! I'll take a look at it 😊
cut the time in half by using precomputed length and arrays
i also produce no garbage on deserialization, but still a little bit on serialization
112 bytes per dictionary
Hehehe
@gloomy chasm your Dictionary had a little bit more of a performance hit
probably due to all the checks and stuff you do
With or without the editor stuff?
with
Yeah I would expect as much. It is required in order to support duplicate values nicely in the property drawer
I was thinking of adding a 'editor only' dictionary which is just the serialization part without property drawer support
@gloomy chasm after trimming down your implementation I ended up with this
[Serializable]
public class UDictionary<TKey, TValue> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver
{
[SerializeField] private SerializableKeyValuePair[] _serializedPairs;
[Serializable]
private struct SerializableKeyValuePair
{
public TKey key;
public TValue value;
public SerializableKeyValuePair(KeyValuePair<TKey, TValue> pair)
{
key = pair.Key;
value = pair.Value;
}
}
public void OnBeforeSerialize()
{
_serializedPairs = new SerializableKeyValuePair[this.Count];
int index = 0;
foreach (var pair in this)
{
_serializedPairs[index] = (new SerializableKeyValuePair(pair));
index++;
}
}
public void OnAfterDeserialize()
{
this.Clear();
foreach (var pair in _serializedPairs)
{
this[pair.key] = pair.value;
}
}
}
Yup, seems right. Using an array will have worse performance I think if it is used in the inspector.
I'll keep that in mind. In this particular case I just need it for a very specific purpose, so I don't need to worry about anything else
your example works a lot better because you wrap the TKey and TValue in the SerializableKeyValuePair
in my original approach I was struggling because i kept the list of TKey and TValue on the top level class
so I was having problems with nested collections
i had to implement a Wrapper class with the IConvertible interface to be able to cast to generic types
[Serializable]
public class IntArrayWrapper : IConvertible
{
[SerializeField] public int[] Array;
public IntArrayWrapper(int[] intArray)
{
Array = intArray;
}
public object ToType(Type conversionType, IFormatProvider provider)
{
return Convert.ChangeType(Array, conversionType);
}
//... a bazillion more conversion methods required by the interface
}
it was a pretty annoying and ugly solution
Yeah, I am surprised most implementations on github don't do this. It allows it to support any collection, even nested dictionaries.
yeah I knew I had to do a wrapper class in order to make it work.
I didn't know exactly what I had to wrap lol
i've seen a lot of examples online and I don't think a lot of them use your approach
I've seen serializable dictionary implementations WAY more bloated than yours
Yeah, and a lot of them don't. Some go the approach of copy-pasting the dictionary source code and make the relevant fields serializable
(I checked, it isn't legal as far as I can tell)
Yeah, normally where a lot of them go wrong is with the PropertyDrawer, some of them do some really bad things like re-add the duplicated values each draw
It is literally why I made my own, not a single one had a good way of handling it all, and I looked at every single one I could find on github lol
nice
seems like most of your stuff works great and is lightweight
@gloomy chasm thanks for all the help 💙
Thanks, I try! Sure thing! Always happy to help! I also have a script for getting/setting the value of SerializedProperties if ya want (supports collections and SerializeReference)
i'm already using it 😋
you shared it a while back
💪 so nice
Oh yeah, well glad you are liking it 😄
all your SerializedProperty/SerializedObject stuff was of great help and served as a great example to start writing my own extension methods for some use cases
how could i add this derived class in there
im open to switching the way i do things but id rather avoid having tons of ScriptableObjects or storing it in a c# script / text file
I've thought of having every property on the base class and then an enum for the type, hiding certain properties depending on the type however i dont know if thats even possible
ok turns out it is possible, using https://github.com/Deadcows/MyBox
initially i tend to avoid using external libraries like this especially smaller ones but this one seems quite popular and has a lot of interesting features, hopefully it works well
Ups
Okay need some help with this.
I use a custom render pipeline to support a specific Oculus tech (SpaceWarp) and my current shaders don't support it.
If I build for android I want to change the shaders of all materials in my game to the simple lit shader. At runtime I just do .shader = simpleLitShader, but that gives graphical glitches because of spacewarp.
Now I am trying to do it in the build process, using the code below, but the materials stick with the old custom shader and not simple lit.
I also tried .material instead of sharedMaterial
Does anyone know if me or my code does something wrong?
public class ShaderSwitch : IProcessSceneWithReport
{
public int callbackOrder => 0;
public void OnProcessScene(Scene scene, BuildReport report)
{
foreach(GameObject go in scene.GetRootGameObjects())
{
var renderer = go.GetComponent<Renderer>();
if (renderer)
{
var tex = renderer.sharedMaterial.GetTexture("_Diffuse");
if (tex)
{
Debug.Log("did it for " + renderer.material.shader.name);
renderer.sharedMaterial.shader = Shader.Find("Universal Render Pipeline/Lit");
renderer.sharedMaterial.mainTexture = tex;
}
}
}
}
}
Probably need to Undo.RecordObject before changing it
Since you're changing the asset and not just the scene
I do change the scene, right?
I get all renderes in the scene and change the material
sharedMaterial probably references an asset
If it doesn't then you're doing something unusual
.material also did not work and I am not sure how recordobject works
Try Undo.Recordobject(renderer.sharedMaterial) before changing it
Yeah but I gotta give it a new name as well
Just do "Change material" or somethin
Didn't change it. Just seems to not apply
I'm not sure if that callback is intended to change assets/scenes but rather validate that things are correct
I am not sure either that's why I ask here haha
So if anyone else knows it for sure please let me know (:
It works using callbacks: https://forum.unity.com/threads/replace-shader-of-material-at-build-time.1226121/#post-7819149
No, but maybe post in this thread to remind the devs that users would like features for upgrading data: https://forum.unity.com/threads/script-data-upgrade.427767/
The only way is to manually keep track of your references. In this case it would probably mean you would have to rename references directly in the YAML (we've built some basic internal tools for this sort of thing) or fix the references via some other editor process like finding them in code etc.
hey guys, can anyone explain why the toggles are all joined as rows (.gif image after code)?
this is the property drawer code:
[CustomPropertyDrawer(typeof(StructureLayout))]
public class StructureLayoutDrawer : PropertyDrawer
{
const int maxStructureLength = 5;
const float checkboxSize = 16.0f;
const float lineSize = 20.0f;
bool foldout;
// test
bool[,] toggleValues = new bool[maxStructureLength, maxStructureLength];
public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label)
{
label = EditorGUI.BeginProperty(pos, label, prop);
pos.height = lineSize;
foldout = EditorGUI.Foldout(pos, foldout, label);
pos.y += lineSize;
if (foldout)
{
for (int i = 0; i < maxStructureLength; i++)
{
for (int j = 0; j < maxStructureLength; j++)
{
toggleValues[i, j] = EditorGUI.Toggle(pos, toggleValues[i, j]);
pos.x += checkboxSize;
}
pos.x -= checkboxSize * maxStructureLength;
pos.y += checkboxSize;
}
}
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return base.GetPropertyHeight(property, label) + checkboxSize * maxStructureLength;
}
}
I wonder if toggles reserve more space in that row to make it easier to use
Best to check with the imgui debugger
This is what I would do and it seems to not have your issue (I'll think about why that may be caused by your code):
toggleRect.width = 16;
toggleRect.height = 16;
for (int row = 0; row < 5; row++)
{
for (int column = 0; column < 5; column++)
{
toggleValues[column, row] = EditorGUI.Toggle(toggleRect, toggleValues[column, row]);
toggleRect.x += toggleRect.width;
}
toggleRect.y += toggleRect.height;
toggleRect.x = pos.x;
}```
Ah well, you forgot to set the width of the rect for the toggle. It seems to render correctly because there is some min size within the control, but you need to set the width to a valid value for the layouting/mouse check code to work.
For example, just do: pos.width = checkboxSize;
And probably I should have pinged you.
@waxen sandal @bitter barn Thank you! You guys were right, I just had to adjust the Rect width :)
Hello! Has anyone used Firebase Analytics in their Unity projects? I'm trying to find an alternative to Unity Analytics and would like to see if Firebase has any cons
This is an array of BuildObject (not a scriptable object). I'm attempting to override the inspector inside each element to add a button to the Action Data field.
I have added a script:
[CustomEditor(typeof(BuildObject)]
[CanEditMultipleObjects]
public class BuildObjectEditor : Editor {
public override void OnInspectorGUI() {
GUILayout.Label("Hello");
}
}
However, this isn't working
How can I do this without completely reimplementing the reorderable list implementation?
@shadow moss a custom Editor draws the entire inspector for a component
if you want to affect individual fields you can use a PropertyDrawer
yeye
on a list, the PropertyDrawer will target each element of the list, instead of the list itself
If I completely override OnGUI, I was expecting the inside of the foldout to be blank. However, I see that the entire element is blank.
I'm looking at ReorderableList.cs, but I don't see much in terms of foldout
yeah because Unity is still drawing an empty rect with the height of your property drawer
That makes sense
you can override PropertyDrawer.GetPropertyHeight and return a height of 0, but I think the list's drag handles will still draw for each element
what are you trying to do? why do you need the list to be empty?
I'll try returning a height of zero
I'm trying to just add a button to ActionData field (bottom)
Each element is of type BuildObject, and so I have a property drawer for BuildObject
I hope that makes sense
yes
just draw all the properties with PropertyFields and then add a button at the end
or maybe you can just call the base OnGUI and then do the button after that
I tried the latter, but if I call base.OnGUI, then I get a message stating that the GUI is not implemented
then just use a PropertyField for each of your child properties
Doing that now
@shadow moss ah sorry I just realized you can just use one PropertyField for the target property of the drawer
you don't need to do it for every single child property
just pass a bool to let the field know it has to include children
EditorGUI.PropertyField(position, property, label, true);
Oh, interesting
@shadow moss here's an example
[CustomPropertyDrawer(typeof(SomeClassForPropertyDrawer))]
public class SomePropertyDrawer : PropertyDrawer
{
private readonly float buttonHeight = EditorGUIUtility.singleLineHeight;
private readonly float spacing = EditorGUIUtility.standardVerticalSpacing;
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
float defaultHeight = EditorGUI.GetPropertyHeight(property, label, true);
return defaultHeight + spacing + buttonHeight;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position, property, label, true); //Draw property with children
Rect buttonRect = new Rect
{
x = position.x,
y = position.yMax - buttonHeight,
width = position.width,
height = buttonHeight
};
// Intend the rect to match with the property's intentation
EditorGUI.indentLevel++;
buttonRect = EditorGUI.IndentedRect(buttonRect);
EditorGUI.indentLevel--;
if (GUI.Button(buttonRect, "Some button"))
{
// Button logic
}
}
}
dealing with the height is a little bit annoying because you have to manually account for the extra stuff you add
I'm not an expert on custom drawers so there's probably cleaner ways of doing this, but for basic stuff this seems to be fine

