Search Unity

"SendMessage cannot be called during Awake, CheckConsistency, or OnValidate" - can we suppress?

Discussion in 'Editor & General Support' started by Dreamback, Jun 22, 2018.

  1. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,912
    Not quite true. You can surround the editor code with
    #if UNITY_EDITOR
    pre-processor directives, and you can call the method by its namespace as well:
    Code (CSharp):
    1. private void OnValidate()
    2. {
    3. #if UNITY_EDITOR
    4.     UnityEditor.EditorApplication.delayCall += ()
    5.     {
    6.     };
    7. #endif
    8. }
    I guarantee you the error is due to a bug in your code.
     
    Deadcow_ likes this.
  2. mat108

    mat108

    Joined:
    Aug 24, 2018
    Posts:
    131
    Well my script looks like this (except the null check I just added but it seems to do the trick)

    Code (CSharp):
    1. #if UNITY_EDITOR
    2.     protected virtual void OnValidate()
    3.     {
    4.         UnityEditor.EditorApplication.delayCall += () =>
    5.         {
    6.             if (gameObject == null) return;
    7.  
    8.             int size = transform.childCount;
    9.             if (size > 0)
    10.             {
    11.                 for (int i = 0; i < size; i++)
    12.                 {
    13.                     transform.GetChild(i).transform.name = "EXIT_" + i.ToString();
    14.                 }
    15.             }
    16.         };
    17.     }
    18. #endif
    And it still spams warnings. So why bother delaying the call ?
    Also the null check does in fact not prevent the error. It's still happening in play mode.
     
  3. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,912
    This isn't directly aimed at you, but the whole thread really, but...

    Long story short this error is called because OnValidate seems to be called during serialisation - a threaded process - where jumping between the boundaries of Unity objects causes lots of instability issues (This warning is noted in the docs of ISerializationCallbackReciever).

    OnValidate should only be used for very basic validatation of values within the same instance. Anything beyond that, you should be making a custom inspector.
     
  4. mat108

    mat108

    Joined:
    Aug 24, 2018
    Posts:
    131
    What would a script look like that enforces certain object properties and parameters within the editor?
    For instance if I want fool-proof that doors are in the 'door' layer and all instances which inherit from my eatable class are properly tagged 'eatable', my approach now is to set these parameters as desired in OnValidate. What would be a way to do this that doesn't break Unity ?
     
  5. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,912
    Sorry but I'm not going to write all that code for you. Like I said, for extensive project automation and validation, use custom inspectors and custom editor tools. If you don't know how, learn how.

    If don't want to learn, buy an addon off the asset store to do it for you.
     
  6. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    I don't know what you're doing, but I use this method and works great for me.

    LOL not really no.
    Just use OnValidate and delayCall and it works wonders.
     
  7. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,912
    I mean yeah it does, most of the time at least. It's not fool-proof though. Again, OnValidate should really only validate within the same instance.
    .delayCall
    is mostly a hack.

    Besides, you go a lot further learning how to customise the editor. OnValidate will only get you so far.
     
  8. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Of course, but it's a pain in the ass to make a custom inspector for internal tools. I mean, if you're doing a tool to sell on the store then it's ok, but even then, I prefer plugins that don't use custom inspectors because they are a pain to customize. I much prefer to use custom attributes + OnValidate, but I guess it's just a matter of taste.
     
  9. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,912
    Yes, and my taste is to just use Odin because it's the best, fastest option. ;P
     
  10. Jen42

    Jen42

    Joined:
    Sep 20, 2017
    Posts:
    4
    I've never had this problem until just the other day when we updated to 2022.1.20 and now Unity's own UI is spamming itself. It's from a few places but mostly here when resizing the rect's in LayoutGroup, which are numerous in the project. We have a separate debug console it doesn't affect but I prefer the unity one. Anyone got any idea how to stop the spam? I get this warning hundreds of times along with a few others:

    'SendMessage cannot be called during Awake, CheckConsistency, or OnValidate (Template: OnRectTransformDimensionsChange) UnityEngine.UI.InputField:OnValidate ()'

    No callstack but clicking on it takes me to line 310 in UnityEngine.UI.LayoutGroup.cs


    upload_2022-11-2_12-49-24.png
     
  11. vecima

    vecima

    Joined:
    Jun 6, 2017
    Posts:
    16
    In 2 versions of 2021.3 (9f1 and 12f1) I have this same message being spammed in the console by basic UI components such as Canvas, Image, and even from an object that only has a RectTransform. None of the objects contain any code that calls OnValidate - at least none added by me. If I go into the Project Settings > Editor section and uncheck "Enter Play Mode Options" this error goes away, but then I'm stuck with Unity reloading the domain and scene every single time I press Play, which is honestly atrocious. Every time I set this checkbox to true and press play in the editor I get 108 of this warning message.

    upload_2022-11-30_11-50-3.png
     
    Whatever560 likes this.
  12. Ledii

    Ledii

    Joined:
    May 30, 2013
    Posts:
    9
    I was not able to find a solution I'm happy with here. But I did manage to find a dirty alternative.

    Code (CSharp):
    1.     private void OnValidate()
    2.     {
    3.         //Prevents attempts to run while initializing
    4.         if (!gameObject.activeInHierarchy) { return; }
    5.         StartCoroutine(DelayedValidate());
    6.     }
    7.  
    8.     private IEnumerator DelayedValidate()
    9.     {
    10.         //Waits for first available frame
    11.         yield return null;
    12.         //Execute unsafe code here...
    13.     }
     
  13. L0tan

    L0tan

    Joined:
    Jul 16, 2017
    Posts:
    75
    Same script, test your solution, didn't work :( warnings still appear with this 2 lines of code added v.v
     
  14. andyz

    andyz

    Joined:
    Jan 5, 2010
    Posts:
    2,273
    This does seem sensible as EditorApplication.delayCall awaits for all inspector changes and does not get triggered excessively (although that makes scene updates more sluggish so...)
    But this is missing from the documentation which should tell you the suggested way of handling "tasks such as create objects or call other non-thread-safe Unity API".
     
  15. andyz

    andyz

    Joined:
    Jan 5, 2010
    Posts:
    2,273
    UnityEditor.EditorApplication.delayCall is actually a problem if you do a standalone build as I think you get into a situation where the delayed call is run but this object is now dead (null!). So if you do not add a "this != null" check then any code inside the delayed call will likely throw a console error every time you run a build :rolleyes:

    Doesn't Unity have a pattern for this?!
    You can use Update() & runInEditMode but would rather not...
     
    Last edited: Jan 24, 2023
  16. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,912
    EditorApplication.delayCall is nulled every time after it's run.

    It's also an editor-only part of the API so it won't ever make it into a build.
     
  17. andyz

    andyz

    Joined:
    Jan 5, 2010
    Posts:
    2,273
    Sorry I was not too clear, I found a situation where I needed to do this to avoid an error in console when building to standalone, much to my surprise/annoyance:

    Code (CSharp):
    1. //update after all inspector checks
    2.         UnityEditor.EditorApplication.delayCall += () =>
    3.         {
    4.             if (this != null)
    5.             {
    6.                     //object is still valid so do something, may not be straight after build...
    7.             }
    8.         };
     
  18. Whatever560

    Whatever560

    Joined:
    Jan 5, 2016
    Posts:
    516
    I'm on 2021.3.19 and I have gazillions of them poluting the whole log and build (and probably just hiting performances hard)
    From what is logged, they trigger on "OnSpriteTilingPropertyChange" and "OnMeshFilterChanged". Not touching this at all and I have very few OnValidate (and none that temper with this as I recall)

    It would be great to have some insights on this.

    upload_2023-3-21_19-32-42.png
     
  19. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Maybe fill a bug report?
     
  20. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Wish SendMessage was removed ages ago. Its unrobust, slow, and causes issues.
    Or at least an option to disable the warning would be nice since no side-effects are produced for our cases anyway.
     
  21. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    You can disable warnings on a specific script using
    Code (CSharp):
    1. #pragma warning disable
    at the beginning of your code. You can even only disable specific warnings if you know their warning number.
    More info here, in the PRAGMA section: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives
     
  22. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Its not a CSharp warning though. Can't do that.
    Its a spam message via debug pipeline from the engine itself.
     
  23. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Oh right, I remember now... super annoying. I had to refactor my code to avoid it. It can make the builds crash too, it's not harmless.
     
  24. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    It doesn't.
    If it does for you then it was crashing for the different cause.

    Our case is specifically OnValidate. Wrapping into delayCall would work, but it pollutes codebase and slows down editor. Doing so for hundreds of scripts would be nasty.


    Also, who uses SendMessage in 2023 anyway and for what?
    When events exist, actions exist, Rx exist.

    That's like legacy garbage that should've been removed in version 5.
     
    Last edited: Mar 22, 2023
  25. Tiritto

    Tiritto

    Joined:
    Apr 19, 2019
    Posts:
    2
    Still an issue as of Unity 2022.2.15
     
  26. Whatever560

    Whatever560

    Joined:
    Jan 5, 2016
    Posts:
    516
    I found that calls to UnityEditor.PrefabUtility.IsPartOfPrefabInstance(this) in OnValidate was also logging this message. The other messages still remains ("OnSpriteTilingPropertyChange" and "OnMeshFilterChanged")
     
  27. el_Guero

    el_Guero

    Joined:
    Sep 15, 2017
    Posts:
    185
    I get this warnings now in Unity 2022 for tons of UI gameobjects. They do not have any custom scripts attached. Canvas Renderer, Image and Rect Transform. That's it. Why would this trigger any warnings?
     
  28. el_Guero

    el_Guero

    Joined:
    Sep 15, 2017
    Posts:
    185
    So actually the problem is the Canvas Scaler component. When I disable it I get no more of these warnings. And I realize that indeed, I have all my canvases as childrens of a normal gameobject so I can easily hide them in the hierarchy... so exactly the same problem as you had. What did you do to solve it?
     
  29. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Are your UI objects children of the canvas they belong to?
     
  30. el_Guero

    el_Guero

    Joined:
    Sep 15, 2017
    Posts:
    185
    What do you mean by that?

    This is my hierarchy:
    Normal GameObject Parent
    ___Canvas 1
    ______Panel
    _________Images, Buttons, etc
    ___Canvas 1
    ______Panel
    _________Images, Buttons, etc
    etc.

    And I actually tested, it doesn't make any difference on my end if I get rid of the parent object or not. I even tried to add a Canvas component to that parent, still, same problem.

    Opened my own thread since it seems to be a different problem, related directly to the canvas scaler component: https://forum.unity.com/threads/uni...essage-cannot-be-called-during-awake.1454824/
     
  31. Neohun

    Neohun

    Joined:
    Oct 30, 2018
    Posts:
    77
    I have an elegant solution. Since it is a problem caused by OnValidate() func when it is called on start-up, just skip the first frame:

    Code (CSharp):
    1.  
    2.   void OnValidate() {
    3.           // If it is player then skip the first frame.
    4.           if (Application.isPlaying && Time.frameCount == 0) {
    5.               return;
    6.           }
    7.           // Run your code here!
    8.    }
    9.  
     
    Last edited: Jul 6, 2023
  32. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Day X++ of asking to deprecate SendMessage.

    We are living in 2023 where there is Burst, DOTS, insane C# to C++ conversions and for some reason - SendMessage.

    Yep, this thing is still there since 5.x. Pseudo javascript is gone. Boo is gone.
    And yet deprecated code lingers forever just to cause more issues along the line.

    Write once - legacy forever.

    Its funny cause I've been reading 2022.3 compressed release notes since 2021.3.
    And guess what - instead of removing legacy code - there's more workarounds to figure out what game objects trigger SendMessage.
    Wow. That's useful. Message spam is now a tiny bit slower.

    I wonder how much faster some calls would get if this thing gets removed.
    Stuff like UI, AddComponent and other packages use it as a workaround instead of actual events.
    Less native marshalling required to be done. Less warning garbage produced in console.

    Imagine a world where mobile native monetization guys would actually pay attention and do not write bad practice code that stalls for eternity due to extreme levels misuse of SendMessage.

    Imagine OnValidate without workarounds and hundreds LOC less per project.
    Imagine less bugs due to layout group issues due to incorrect execution order because of broadcast event nature.

    Glorious. A man can dream.
     
    Last edited: Jul 6, 2023
    Lurking-Ninja and cxode like this.
  33. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Wouldn't this cause issues with initialization?
    I mean, if it skips the first frame and OnValidate initializes references or things like that, aren't you going to have errors elsewhere?
     
  34. Neohun

    Neohun

    Joined:
    Oct 30, 2018
    Posts:
    77
    Well, "OnValidate" is for editor use only so you don't rely on it for player since it won't work for a build.
    See unity documentation for it: OnValidate

    So you use OnValidate for change detection of inspector only. As a good programmer for initialization use "Awake" instead. Since these warnings occur when you enter play mode, you can use this approach to prevent them.
     
    Last edited: Jul 7, 2023
  35. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Funny, cause that's exactly what good programmers shouldn't do.

    Don't push dependency resolution to Awake.
    That will slow down loading time as well as instantiation of new objects. (extremely in some cases)
    Discarding runtime changes is completely valid strategy for OnValidate.

    However, sometimes you don't want to do any changes in runtime, not just initial ones (frame check is pointless code smell). That is - if changes are not supported. Sometimes you actually want to catch inspector changes and run e.g. re-authoring of entity data. Which means you're doing something wrong if you need to check against first frame only. Leaving a potential UX issue for the designer or a potential bug.

    Note that warning spam is not the "invalid" case.
    Its just Unity being really old without applying proper refactoring.
    In extreme cases where you really try hard to break down logic & rely upon execution order of broadcast event that is extremely slow as well - it "may" matter. So pretty much - never.

    So here's the tricky part. Which solution to use?
    If you use delayed callback - you're reducing editor performance plus no immediate results can be returned.
    If you don't - you're reducing editor performance due to console spam.
    (Less if you use Undo.AddComponent - it works wonders to cherry-pick changes done to the assets, so it spams a bit less. Doesn't matter for the packages / UGUI changes though)

    If you move validation logic to Awake - you're extremely reducing performance in build for each user and hinder application scalability.

    TL;DR: A simple rule is - if you can do something outside of playmode - do it in OnValidate.
    Use Awake only if initialization cannot be done in editor. Valid example is event subscriptions (or respective equivalent).

    The less logic you've got in Awake - the faster and more scalable your game will be.
    Native callbacks aren't free. Extra logic execution per component is not free either.

    Unity documentation makes bad practice 101 for newcomers.
    Youtube tutorials and such content make things hundred times worse. And it just lingers forever.
     
    Last edited: Jul 7, 2023
  36. Neohun

    Neohun

    Joined:
    Oct 30, 2018
    Posts:
    77
    Yeah, I bet you know much better than unity documentation since you're the best programmer in the world. I'm a game programmer for over 5 years and didn't have any issues about awake or slow init time etc. I use awake and I'll continue to do so. If something is needed to be initialized gradually I can do it async with an optimal way which is a very extreme case and mostly not needed. When you write this kind of disinformation, it is not useful but harmful for new comers. We're not living in the age of Pentium computers anymore to micro optimize things since they have practically zero gains.

    Last but not least, your comments are neither helpful nor related with the topic. If you have a better, more elegant solution you can share so we can learn. I always keep things simple and I will continue to do so. Just complaining about unity, documentation etc. doesn't solve any problem besides it just obscures the useful information and solutions. These are minor issues and can be fixed with easy workarounds, they will fix them over time. If you have a better solution just share otherwise I don't argue with anyone about my design choices.
     
    Last edited: Jul 7, 2023
  37. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    I've seen juniors that has been juniors for over 8 years. Time means nothing if you're unwilling to learn.
    I mean no offence to you personally, but what you're posting is not a valid solution [to the most that will inevitabily google up this page of the forum].

    If you want a recent example. Here's that popular RootMotion's Puppetmaster.
    Its Awake takes an eternity to execute (literally milliseconds on Ryzen 3950x).
    I'm not sure if author did any optimizations later on, but reducing Awake (moving initialization logic to the OnValidate, and removing extra checks), cut ~50% overhead out of object / ragdoll instantiation.
    Which was good enough to break unplayable / playable threshold. In fact, it can be improved even further, but we didn't had enough time to spend on it.

    Sure. If you're not doing mobile and/or not pushing engine to the limits it won't matter.

    Elegant solution would be to join Unity team, make proper refactoring to the source and then leave to make actual games. Unfortunately, that's not something easy to do.
    Neither there is a workaround that will cover all cases.
    This time around its a pick between bad, bad, and the worst solutions respectively.

    Can't push a bug repo on something that isn't a bug -> it will be ignored.

    At least, making the reason public why this issue is an issue on the other hand - is more than doable.
    Maybe it will get some traction internally, who knows?

    If the threads sticks high long enough, someone at least notice that there is an issue.
    Support reads this forum more often, so the chances are higher than zero.
     
    Last edited: Jul 7, 2023
  38. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,912
    Day X++ of the best solution still just being making a custom editor if you require anything beyond bare-bones basic validation.

    It's not even that hard having a custom editor that adds in an extra button or two to automate work. Or just wrapping
    DrawDefaultInspector
    in
    EditorGUI.Begin/EndChangeCheck
    and doing the validation after that.

    This isn't directed at you, I should add. But I feel like I explained the reason why this happens multiple times in this thread, and learning how to do the correct solution will save peeps a lot more time in the long run.
     
  39. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Thing is, writing editor per each property or logic or script wastes infinite amount of time. And most of the time you don't actually need to tie logic to the UI, just execute it automatically for specific components in specific manner (which OnValidate does by default).

    Its much more simpler [and less time consuming to maintain] to keep such logic in the same file to ensure its not missed while changing anything.

    There is no pipeline for script editor logic only automatization that is unrelated to inspector UI. That's an issue. OnValidate does it. Sure its an overabuse of its funtionality. But alternatives are infinitely worse.

    Entities approach this by decoupling authoring data from runtime data completely.
    It does work, but there's MonoBehaviour world where calls never change, get refactored or improved.

    What can be done from Unity side:
    1. SendMessage can be soft phased out.
    2. UGUI package gets proper refactoring to switch to actual events.
    3. This warning will be gone as a result, and you would be able to do execute any logic out of Awake, OnValidate or whatever place without rellying on really unstable execution order of SendMessage.
    4. As a bonus, UGUI gets faster, less buggy.
     
    Last edited: Jul 7, 2023
  40. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,912
    Right but only the minority of your scripts will require this kind of custom editor work and extensive validation. In the long run you will need custom inspectors or editor windows to allow for comfortable and quick editing anyway, of which saves time in the long run.

    Reusable editor tools save you the most time in the long run. At this point I hardly actually have to set up some new editor tool as my reusable ones are usually already fit for purpose (thanks Odin Inspector), saving me substantial amounts of time in the long run.

    The same is true of making reusable tools in general.

    Having a bunch of script templates helps in the long run too.

    Not sure what you're on about in that second paragraph. You can automate tons of editor only stuff.
     
  41. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Pretty much all scripts need some kind of dependency fetching.
    Half would require hard dependencies that should be present (or may not be present, so [RequireComponent] won't work on them).
    Initialization references between them, reading / writing initial state etc. Extra checks could be put there.

    Inspect your Awake's. If you see stuff like [Try]GetComponent, or any other equivalent of it - custom editors won't fix that.

    What you want is specific implementation per script.
    Generic solution won't work because context of each specific script being specific.

    Here's an example of validation logic I've mentioned for the Puppetmaster
    (I've cut parts as well since its a payed asset):
    Code (CSharp):
    1.         private void OnValidate() {
    2.             _transform = transform;
    3.             _hierarchyIsFlat = HierarchyIsFlat();
    4.    
    5.             // Find the target root
    6.             if (targetRoot == null && muscles.Length > 0 && muscles[0].target != null)
    7.                 targetRoot = FindTargetRootRecursive(muscles[0].target);
    8.  
    9.             if (targetRoot != null && targetAnimator == null) {
    10.                 targetAnimator = targetRoot.GetComponentInChildren<Animator>();
    11.             }
    12.  
    13.             foreach (Muscle muscle in muscles) {
    14.                 InitMuscle_Editor(muscle, muscles);
    15.             }
    16.    
    17.             UpdateHierarchies_Internal();
    18.             _defaultMuscles = (Muscle[]) muscles.Clone();
    19.  
    20.             // Find the SolverManagers on the Target hierarchy
    21.             if (targetRoot != null) {
    22.                 targetRoot.GetComponentsInChildren(solvers);
    23.             }
    24.         }
    25.  
    26.         private void InitMuscle_Editor(Muscle muscle, Muscle[] colleagues) {
    27.             ConfigurableJoint joint = muscle.joint;
    28.             if (joint == null) return;
    29.    
    30.             joint.anchor = Vector3.zero;
    31.             Transform jointTrm = joint.transform;
    32.            
    33.             muscle.transform = jointTrm;
    34.  
    35.             var connectedBody = joint.connectedBody;
    36.             if (connectedBody != null) {
    37.                 for (int i = 0; i < colleagues.Length; i++) {
    38.                     Muscle colleague = colleagues[i];
    39.  
    40.                     colleague.joint.TryGetComponent(out Rigidbody rgb);
    41.                     if (rgb == connectedBody) {
    42.                         muscle.connectedBodyTarget = colleague.target;
    43.                     }
    44.                 }
    45.             }
    46.            
    47.             jointTrm.TryGetComponent(out Rigidbody jointRGB);
    48.             muscle.rigidbody = jointRGB;
    49.    
    50.             muscle.InitiateAdditionalPin();
    51.    
    52.             muscle.UpdateColliders();
    53.             if (muscle.colliders.Count == 0)
    54.             {
    55.                 Vector3 size = Vector3.one * 0.1f;
    56.                 if (transform.TryGetComponent(out Renderer rend))
    57.                     size = rend.bounds.size;
    58.  
    59.                 jointRGB.inertiaTensor = PhysXTools.CalculateInertiaTensorCuboid(size, jointRGB.mass);
    60.             }
    61.    
    62.             muscle.SetKinematic(false);
    63.    
    64.             muscle.targetParent = muscle.connectedBodyTarget != null ? muscle.connectedBodyTarget : muscle.target.parent;
    65.    
    66.             if (!joint.gameObject.activeSelf)
    67.                 Debug.LogError("Can not initiate a puppet that has deactivated muscles. Make sure to enable it", joint.transform);
    68.    
    69.             // Set necessary joint params
    70.             ....
    71.             // Loads of stuff
    72.    
    73.             // Anchoring
    74.             bool hasJointConnectedBody = joint.connectedBody;
    75.    
    76.             if (hasJointConnectedBody)
    77.             {
    78.                 // more setup
    79.             }
    80.  
    81.             // Mapping
    82.             if (!hasJointConnectedBody) // extra stuff
    83.  
    84.             // Resetting
    85.             if (!hasJointConnectedBody)
    86.             {
    87.                 // extra stuff
    88.             }
    89.             else {
    90.                 // math
    91.             }
    92.  
    93.             Transform muscleTarget = muscle.target;
    94.             // Fix target Transforms
    95.             muscle.defaultTargetLocalPosition = muscleTarget.localPosition;
    96.             muscle.defaultTargetLocalRotation = muscleTarget.localRotation;
    97.         }
    It can get complex. Really complex. Generic editors are good for UI. Not so much for custom automatization or preventing designers from shooting themselves in the foot.

    And no, dependency injection is not the solution for the game dev. There's 20 page on general subforum as to why not. Short answer - it will make things even slower (both performance and iteration speed wise).

    Sure. But its definitely not easy as it could be.

    TL;DR: OnValidate is that replacement for the automatization pipeline. Some legacy code has to be removed in order to prevent at least console spam.

    It works. Its fine. But spam is annoying.
     
    Last edited: Jul 7, 2023
  42. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,912
    You're saying all these things you apparently can't do, but I do no problem on a daily basis.

    Like I said, most of my editor tools are generic and reusable. My most used one is my sub-class selector extension for Odin: https://github.com/spiney199/Subclass-Selector

    And I don't see how any of that code example would be any worse off being in an editor script.
     
  43. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    It will not be executed [always] before running the game automatically (or building). That's how.
    Unless you write a specific implementation that ties to the editor callbacks which is extra LOC's, more pain to maintain.

    Again, if you've missed the edit:
    As well as writing workarounds is.
     
    Last edited: Jul 7, 2023
  44. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,912
    No more painful than having all this non-runtime code clogging up your runtime scripts. I like my editor code in an entirely different assembly to my runtime code. Keeps things organised, neat, and, would you believe, maintainable too.

    Anyway, you do you. I'll be here writing editor code to automate things.
     
    xVergilx likes this.
  45. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Its more of an organization question. Not every script needs this.

    For something massive - sure it can be moved away in different assembly (or even split in partials).
    But for the most things - its just a waste of time. E.g. here's a more subtle example of automatization:
    Code (CSharp):
    1. #if UNITY_EDITOR
    2.       public override int UnpackingOrder_Editor => UnpackingOrder.AfterDefault;
    3.  
    4.       public void GatherEntityTypes(HashSet<Type> types) {
    5.          types.Add<SpellCircleFX>();
    6.       }
    7.  
    8.       protected override void OnValidate() {
    9.          base.OnValidate();
    10.  
    11.          _transform = transform;
    12.  
    13.          this.GetFromChildrenIfNull(ref _rotator);
    14.          TryGetComponent(out _circleText);
    15.  
    16.          _gameObject.SetupEntityBehaviour(ref _entityBehaviour);
    17.  
    18.          if (_circleVFXTarget != null)
    19.             _circleVFXRenderer = _circleVFXTarget.GetComponentInChildren<Renderer>();
    20.  
    21.          this.SetupDestroyTrigger(ref _ltt);
    22.       }
    23. #endif
    Wrapping small OnValidates in #if UNITY_EDITOR and arranging them always at the bottom is good enough for me. Pushes completely transparent intent that it is an editor only code. And does not get in the way visually of data authoring (or any potential MonoBehaviour logic).

    Would I want to switch back and forth in multiple files to see where dependencies come from? Probably not.
    Also, this editor related code may be altered or completely removed rapidly during iteration.

    Time spent on maintaining editor(s) is time wasted. Because you're not making an actual game.
    Tools has to have their purpose. If the goal can be achieved with more simple and easier tools - keep it simple.

    Editor tools are great. Don't get me wrong. They are really good at improving iteration speed.
    But they aren't designed to be automating processes behind the scenes. Inspector UI is UI.
    Data preparation logic (authoring) most of the time do not relate to the UI at all (or require to add more complexity to modify it).


    There are two major issues that's caused this thread:
    1. Lack of generalized approach to the editor automation that do not rely upon MonoBehaviour callbacks (or multiple editor callbacks / entry points);

    2. Legacy code that haven't been deprecated since ever;
    I can safely bet there still be .renderer, .light, .collider and SendMessage in UGUI packages 10 years later.
    [That is unless UI Toolkit becomes a standard, who knows]

    Both can be addressed. Or worked around. Personally, I'd prefer engine based solution.
    Authoring is great. Baking is decent (even if subscenes are still buggy);
    MonoBehaviour automation - not so much. It can be better and be faster for the editor.
    Finally removing legacy code would make runtime faster as well. Its a win / win.
     
    Last edited: Jul 7, 2023
  46. el_Guero

    el_Guero

    Joined:
    Sep 15, 2017
    Posts:
    185
    So how can I get rid of them if I don't even use onValidate?
     
  47. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Short answer - you can't.

    Long answer - not using UI is not an option. You could look through the code in an attempt to figure out what triggers for the related objects and move logic to other execution points. If its not the UI that triggers it - its probably AddComponent. Using Undo.AddComponent instead of runtime gameObject one will reduce number of spam warnings. Although, will not remove them completely. See through the thread and pick whatever case is most obviously could be yours.

    Best solution - ignore the warnings and don't waste your time.
    Unfortunately there is no embedded console functionality to ignore those warnings.
    And its not a C# one so can't ignore them via nowarn either.

    Basically, this is lightmapping spam v2.0.
    Which in the end was solved once its got known by the Unity Team.

    Alternatively grab some kind of custom console window re-implementation from store and filter them out.
     
  48. emredesu

    emredesu

    Joined:
    Aug 12, 2021
    Posts:
    55
    Upon upgrading from 2021 LTS to 2022 LTS, I've started randomly getting 20 instances of this warning on script recompilation and entering play mode, it's really annoying to be spammed with this even though my code has 0 references to SendMessage...

    It looks like this:
    SendMessage cannot be called during Awake, CheckConsistency, or OnValidate (SelectedObjectButton: OnRectTransformDimensionsChange)
    UnityEngine.UI.Text:OnValidate ()


    Seems like the issue goes back to either LayoutGroup or CanvasScaler calling SendMessage while adjusting sizeDelta of a RectTransform. What do?
     
    Last edited: Jul 8, 2023
  49. el_Guero

    el_Guero

    Joined:
    Sep 15, 2017
    Posts:
    185
    Yeah, on my end the funny thing is I don't use any of those methods in my code at all. But literally all UI elements give this warning. 999+ warnings for all my UI elements in the hierarchy. None of those have even scripts attached.
     
  50. SoftwareGeezers

    SoftwareGeezers

    Joined:
    Jun 22, 2013
    Posts:
    902
    Testing flocking algorithms, I was getting this from an OnValidate called from sliders. Spamming this SendMessage error from Init() called on a single controller GO from within OnValidate(). Suggests OnValidate() calls SendMessage??

    Replaced it with simple previous value tests and it works perfectly.

    Code (CSharp):
    1. public class FlockController : MonoBehaviour {
    2.     public GameObject prefab_flocker;
    3.     [Range(10, 500)]
    4.     public int flockerCount = 25;
    5.     int prevflockCount;
    6.  
    7.     [Range(15f, 100f)]
    8.     public float radius = 50;
    9.     float prevRadius;
    10.  
    11.     public Camera cam;
    12.     List<GameObject> littleFlockers;
    13.  
    14.     private void Start() {
    15.         prevflockCount = flockerCount;
    16.         prevRadius = radius;
    17.         Init();
    18.     }
    19.  
    20.     private void Init() {
    21.         littleFlockers = new List<GameObject>();
    22.         for (int n = 0; n < flockerCount; n++) {
    23.             GameObject go = Instantiate(prefab_flocker);
    24.             go.transform.position = Random.insideUnitCircle * radius;
    25.             littleFlockers.Add(go);
    26.         }
    27.     }
    28.  
    29.     private void Update() {
    30.         if (prevflockCount != flockerCount || prevRadius != radius) {
    31.             int count = littleFlockers.Count - 1;
    32.             while (count >= 0) {
    33.                 Destroy(littleFlockers[count]);
    34.                 count--;
    35.             }
    36.             littleFlockers = null;
    37.             Init();
    38.             cam.orthographicSize = radius;
    39.             prevflockCount = flockerCount;
    40.             prevRadius = radius;
    41.         }
    42.     }
    43. }
    So Update() here was OnValidate() { if(Application.isPlaying){} }
    Now it's "if previous value is different to current value".

    In short, OnValidate() is arse.