pimdewitte / unitymainthreaddispatcher Goto Github PK
View Code? Open in Web Editor NEWA simple, thread-safe way of executing actions (Such as UI manipulations) on the Unity Main Thread
License: Apache License 2.0
A simple, thread-safe way of executing actions (Such as UI manipulations) on the Unity Main Thread
License: Apache License 2.0
I love UnityMainThreadDispatcher
; it solves a very simple problem well. However, I strongly dislike the static singleton anti-pattern used throughout the Unity ecosystem, and unfortunately this library is one of the culprits. I suggest adding the following interface:
public interface IUnityMainThreadDispatcher
{
void Enqueue(IEnumerator action);
void Enqueue(Action action);
Task EnqueueAsync(Action action);
}
which the UnityMainThreadDispatcher
class would implement. That way, developers can inject IUnityMainThreadDispatcher
implementations (possibly their own) via dependency injection, mock it in unit tests, and generally avoid static cling in their code. This would not be a breaking change, as the static Instance
method would still be present on the implementing class.
You can see my own version of this for reference in my personal UnityUtil library.
I tried to add the package to OpenUPM registry: https://openupm.com/packages/com.pimdewitte.unitymainthreaddispatcher/
It requires to have tags. Can we add some?
Hello, great project and i love using it for UI testing. I noticed, however, that when i run my tests on standalone android and iOS, that the following error shows up
Error Message: System.Exception : UnityMainThreadDispatcher could not find the UnityMainThreadDispatcher object. Please ensure you have added the MainThreadExecutor Prefab to your scene.
Was wondering if its something in my configuration or if this is not meant to be used in android/ios
I got this error: The type or namespace name 'Task' could not be found (are you missing a using directive or an assembly reference?)
I'm using Unity 2019.3, .NET 4.x. Adding "using System.Threading.Tasks;" seems to fix this
It would be great if we could use the dispatcher without implementing it in the scene. It seems logical to me because it's a singleton.
Here's the small change who can add this possibility:
public static UnityMainThreadDispatcher Instance()
{
if (!Exists())
{
var container = Instantiate<GameObject>(new GameObject("UnityMainThreadDispatcher",typeof(UnityMainThreadDispatcher)));
_instance = container.GetComponent<UnityMainThreadDispatcher>();
}
return _instance;
}
Hi,
I came across this when I searched for some sort of Singleton gameobject pattern which is persistent across scenes. I implemented it just the way you did, but had the problem that my object was created several times when I switched back and forth between scenes. After reading this I ended up removing the OnDestroyed()-method which clears the _instance field and added this to the Awake-method:
`void Awake () {
if (_instance == null) {
_instance = this;
DontDestroyOnLoad (this.gameObject);
//...
} else {
Destroy (this.gameObject);
}
}`
Maybe this is an issue for you, too (frankly, I don't know why the OnDestroy()-method was called on my gameobject)
Hello, How can I return from dispatcher...
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
return somefunction(); // Like this
});
First great work , and its awesome.
But today i was trying to use this for ios platform, and its not working for me.
i tried it for UWP before and its perfect. But suddenly its not working now, even if i try to switch the platform for same project.
i think i always get null instance though i'm making a instance of it, also tried to pass prefab from unity editor layout.
Please help me , is it related to platform ?
I have two scenes in my game. If I keep the UnityMainThreadDispatcher
GameObject in the one scene where I (currently) require it, the scene will successfully load. If I switch scenes (via UnityEngine.SceneManagement.SceneManager.LoadScene(...)
to my other scene, and then return to the dispatcher-driven scene, every alternating time I return to the scene I get the following error:
System.Exception: UnityMainThreadDispatcher could not find the UnityMainThreadDispatcher object. Please ensure you have added the MainThreadExecutor Prefab to your scene.
I can see the dispatcher in my hierarchy, even on these erroneous scene loads.
Note that, toggling scenes again will load successfully, until the next change. I have also tried to include the dispatcher in both scenes, which causes neither to work correctly.
Removing Destroy (this.gameObject);
in the Awake
conditional will resolve this, but afraid I might not understand the need for this and it may have side-effects (GC?)
private void OnDisconnected()
{
LogUtils.log("OnDisconnected");
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
InternetChecker.instance.InternetIsNotAvailable();
});
}
I have the above code, but in the logs "OnDisconnected" log is not seen. But the function "InternetIsNotAvailable" is called every frame in Update. Is there anything that I am missing in the usage of UnityMainThreadDispatcher
I have a script file which talks to the Android Java file but not connected directly with the scene. So is it possible to use this? If yes can you provide an example? as I am new to Unity and C#
I want use this in my custom plugin. However it need a prefab awaked in scene. Is there a way to dispatch in editor.
The April changes break compilation on some platforms (such as standalone windows) when building the application, instead of just running in the editor. The entire UnityEditor package is not included in an actual executable, and can't be used in non-editor scripts.
As mentioned in the readme, I use this class by creating an empty game object in a particular scene and attaching UnityMainThreadDispatcher.cs to it.
it doesn't matter if you go over to another scene and never come back to that scene.
but If you go to another scene and then return to that scene, there is a problem : UnityMainThreadDispatcher is duplicated.
Therefore, I modified Awake and onDestroy as below to fix the problem.
I'll leave a source code for those who are experiencing problems like me.
void Awake() {
if (_instance == null)
{
_instance = this;
DontDestroyOnLoad(this.gameObject);
}
else if(this != _instance) //Preserves only the first object created.
Destroy(this);
}
void OnDestroy() {
if(this == _instance) // If a duplicate object is destroyed, it does not free the first instance created.
_instance = null;
}
Place the empty gameobject with UnityMainThreadDispatcher.cs attached to scene A.
Play the game in scene A.
Awake () from UnityMainThreadDispatcher.cs is called.
Since _instance == null is true, The '_instance' stores the object.
Also, the DontDestroyOnLoad (this.gameObject); is called, so the object does not disappear when we load the scene B.
Now, if you go to scene B and then you come back to scene A,
not only the UnityMainThreadDispatcher object previously maintained by the DontDestroyOnLoad, another UnityMainThreadDispatcher object is created.
Therefore, Awake is executed, but in this case, the _instance is not null so that DontDestroyOnLoad(this.gameObject) is not called.
Moving on to thin B again, the existing UnityMainThreadDispatcher object survives, but the second generation UnityMainThreadDispatcher object that did not run DontDestroyOnLoad is destroyed.
At this time, the second UnityMainThreadDispatcher object was destroyed and OnDestroy was called.
This causes problems when the static variable _instance is initialized to null.
Because if you move back to thin A again, now the '_instance' value is null, so the DontDestroyOnLoad (this.gameObject) is called and two UnityMainThreadDispatchers exist.
If you go back and forth repeatedly like this, you will continue to have a memory leak.
And Even worse, when you are at scene B, then the _instance is null because of OnDestroy() So that you cannot actually call Instance(). it throws error.
Hey there,
I have a Windows console server application that uses things like ThreadPool, message Fibers, etc and I am trying to get it to work with Unity properly. It uses this fiber framework and is quite complex, with a fairly large amount of interfaces and files associated with it that use things like Enqueue, IExecutor, Execute, toExecute, DispatchAdapter. Unfortunately, I am just not familiar enough with threading to be able to figure out exactly how to accomplish what I am after.
I was able to get a test working using your UMTD. There was a place that used the call of "this.requestFiber.Enqueue(Method);" to, of course, queue up a method to run but when I would run the server within Unity it would not do anything once it ran it, so I took UMTD and just swapped it out for UnityMainThreadDispatcher.Instance().Enqueue(Method); and it worked. The only issue is, that was one single thing out of many, many places in which call Enqueue and I think that it kind of defeated the purpose of the whole fiber and enqueue system, to begin with by simply sending that one particular thing out to be processed. What I am trying to figure out / find information on is, in a system that uses Execute and things of that nature, is there a specific place I can / should put the UMTD to handle anything that is sent to be Enqueued so that I am not trying to go through the code and find everything that uses the Enqueue method and changing it to use the UMTD's Enqueue, or is that actually what I should do? I could technically just do a Find / Replace to anything using Enqueue, but that seems like it would not work well because of the "this.requestFiber" part of the call not being there anymore.
I am hoping that perhaps you might be able to give me an opinion or any info you might have? This is the very last part I need to get working in my game framework to finally be able to move on with my development, I have spent 2 months straight working on it and I am so close, yet I can't find any info on how to make this work the way I need. : (
Any assistance would be extremely appreciated!
Thanks,
-MH
Just be curious, what if an action is (computationally) heavy, does other thread wait for a long time for the lock to be released?
// UnityMainThreadDispatcher.cs
public void Update() {
lock(_executionQueue) {
while (_executionQueue.Count > 0) {
_executionQueue.Dequeue().Invoke();
}
}
}
โฆ to make it easier for people who only copy the .prefab and the .cs into their project so they don't lose the reference to this repo in case of issues.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.