Editor GUI Fixes - #15
Conversation
Before changing a variable would not be detected and so not saved/serialized in some cases.
This would not work with the `upm-support` branch mcpiroman#14 as the attributes are not searched for in the attribute that these scripts are in by default.
mcpiroman
left a comment
There was a problem hiding this comment.
Note: The attributes [NativeDllLoadedTrigger] etc are not searched for in the source code of this tool itself
Yeah, I just search for them in the same assemblies as for native function declarations. I guess I should just search every assembly and maybe exclude standard unity ones for perf, because searching in every assembly doesn't sound the quickest thing.
The scene is automatically set as dirty when the gui target is
Admittedly this should have been in mcpiroman#12. However, here are the fixes anyways. GUI buttons to un/load show in edit mode if enableInEditMode is true. Disabling and re-enabling the DllManipulatorScript works now.
Previously triggers would not be cleared properly and so be duplicated. (Static variables seem to persist between entering/exiting playmode)
Allow custom triggers to be executed on the main thread in a queue. We need this internally to repaint the editor GUI as it uses the Unity API.
| if (EditorApplication.isPlaying) | ||
| Destroy(gameObject); | ||
| else | ||
| else if(_singletonInstance != this) |
There was a problem hiding this comment.
Allows the user to properly toggle enabled in edit mode.
|
Ready for review @mcpiroman. You will probably want to review 39c4fce separately. (side note: #14 should already be compatible with these changes) |
Initialize() is not always called so we should not always reset.
mcpiroman
left a comment
There was a problem hiding this comment.
Sorry this took me this long to have a look at this.
I'm somewhat scared about that option cloning, comparing (mainly bout forgetting to update that), but (partly because I'm not quite in the problem it tries to solve), I don't see a better way.
| /// <summary> | ||
| /// Should the method always be executed on the main thread, to allow use of the Unity API. | ||
| /// Note: this means the method is not immediately executed but put in a queue. | ||
| /// For consistent behaviour, the method is put in the queue even if it is triggered from the main thread. |
There was a problem hiding this comment.
Just about the line 39 - I don't think this behavior is really beneficial, I imagine usually one would want main thread events to stay in order. And as of consistency, dispatching frameworks which I recall tend to invoke calls from target ("main") thread right away. For events though, while it doesn't prevent dead-locks as much as with direct calls, I think this also makes sense.
There was a problem hiding this comment.
Ok I've changed it. I wasn't quite sure either which is why I left it commented out:
https://github.com/rogerbarton/UnityNativeTool/blob/a0dc185babf73065dad5935be87e2de2f8d5811a/scripts/DllManipulator.cs#L547-L548
|
|
||
| // Execute now or queue to the main thread | ||
| if (useMainThreadQueue /*&& Thread.CurrentThread.ManagedThreadId != _unityMainThreadId*/) | ||
| _mainThreadTriggerQueue.Enqueue(new Tuple<MethodInfo, object[]>(methodInfo, args)); |
There was a problem hiding this comment.
Instead of using tuple to wrap arguments, it could be simpler to just store an Action created with lambda, like so:
_mainThreadTriggerQueue.Enqueue(() => methodInfo.Invoke(null, args)); (You could also make e.g. Action<int> to provide an argument at call side, JIC you didn't know).
There was a problem hiding this comment.
Yes makes sense
| else | ||
| { | ||
| Debug.LogError($"Trigger method must either take no parameters or one parameter of type {nameof(NativeDll)}. Violation on method {method.Name} in {method.DeclaringType.FullName}"); | ||
| Debug.LogError($"Trigger method must either take no parameters or one parameter of type {nameof(NativeDll)} or two of type {nameof(NativeDll)} and int. Violation on method {method.Name} in {method.DeclaringType.FullName}"); |
There was a problem hiding this comment.
or two of type {nameof(NativeDll)} and int at first reading this sounded like two NativeDll parameters and one int parameter, don't know if that's just me though.
Also why do you assume the main thread id information would be useful? And when it turns out to be, it should be documented somehow (or I just missed that, in which case I'm sorry)
There was a problem hiding this comment.
I've changed it to be clearer and given examples of the possible functions in the TriggerAttribute doc.
The mainThreadId can be used to tell if we are on the main thread and are allowed to call unity functions. I guess this is partially obsolete now that we have the MainThreadTriggerQueue.
| /// Executes queued methods. | ||
| /// Should be called from the main thread in Update. | ||
| /// </summary> | ||
| public static void InvokeMainThreadQueue() |
There was a problem hiding this comment.
Don't wanna be fussy, but I'd move the dispatcher stuff to DllManipulatorScript, as it is closer to Unity, whilst this is intended to do 'the stuff', if you will.
There was a problem hiding this comment.
I assume you only mean to move this function, not the queue itself
There was a problem hiding this comment.
I mean the queue itself. I don't quite imagine how would you move just this method, so that might be interesting too.
There was a problem hiding this comment.
I mean the queue itself. I don't quite imagine how you would move just the method, so I don't disagree with that now.
There was a problem hiding this comment.
By making the queue public (its static already)
There was a problem hiding this comment.
Ah yes, but no, I see this whole in the Script as it is the interface with Unity.
| Initialize(); | ||
|
|
||
| if(!EditorApplication.isPlaying && Options.enableInEditMode) | ||
| EditorApplication.update += Update; |
There was a problem hiding this comment.
Doens't just having [ExecuteInEditMode] make the Update be invoke in editor? Or do I misunderstand sth.
There was a problem hiding this comment.
For ExecuteInEditMode "Update is only called when something in the Scene changed" - Docs. So we need to manually add this to cover all cases.
| [NativeDllAfterUnloadTrigger(UseMainThreadQueue = true)] | ||
| public static void RepaintAll() | ||
| { | ||
| RepaintAllEditors.Invoke(); |
There was a problem hiding this comment.
It's usually safer to handle null case with events (which can be done simply by putting ? before the dot). In this case you initialize the event, however I'm not sure if adding and removing an listener doesn't reset it back to null. Either or, it's better to be safe.
There was a problem hiding this comment.
Agreed however as the event is initialized with the default delegate it will never be null. https://stackoverflow.com/q/170907/9295437
Ill add it anyways...
Also RegisterTriggerMethod receives attribute instead of bool, Fix naming in DllManipulatorOptions
|
Regarding cloning the Options, its just that we need a separate copy for detecting changes. This copy is never changed directly only update when changes are made. Its pretty safe in my opinion. I've actually found this quite a good solution. |
|
I'm fine with that, thanks! |
Note: The attributes
[NativeDllLoadedTrigger]etc are not searched for in the source code of this tool itself. So by creating an.asmdefin #14 these attributes may not work, do you maybe know of an easy fix for this @mcpiroman?.