Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save yoshikischmitz/34a7cd476ce53b5e24fc1561520340f0 to your computer and use it in GitHub Desktop.
Save yoshikischmitz/34a7cd476ce53b5e24fc1561520340f0 to your computer and use it in GitHub Desktop.
Implementation of ISynchronizeInvoke for Unity3D game engine. Can be used to invoke anything on main Unity thread. ISynchronizeInvoke is used extensively in .NET forms, it's is elegant and quite useful in Unity as well. I implemented it so i can use it with System.IO.FileSystemWatcher.SynchronizingObject.
/*
Implementation of ISynchronizeInvoke for Unity3D game engine.
Can be used to invoke anything on main Unity thread.
ISynchronizeInvoke is used extensively in .NET forms, it's is elegant and quite useful in Unity as well.
I implemented it so i can use it with System.IO.FileSystemWatcher.SynchronizingObject.
help from: http://www.codeproject.com/Articles/12082/A-DelegateQueue-Class
example usage: https://gist.github.com/aeroson/90bf21be3fdc4829e631
license: WTFPL (http://www.wtfpl.net/)
contact: aeroson (theaeroson @gmail.com)
*/
using System.Collections;
using System.Threading;
using System.ComponentModel;
using System.Collections.Generic;
using System.Reflection;
using System;
public class UnitySynchronizeInvoke : ISynchronizeInvoke
{
Queue<UnityAsyncResult> fifoToExecute = new Queue<UnityAsyncResult>();
Thread mainThread;
public bool InvokeRequired { get { return mainThread.ManagedThreadId != Thread.CurrentThread.ManagedThreadId; } }
public UnitySynchronizeInvoke()
{
mainThread = Thread.CurrentThread;
}
public IAsyncResult BeginInvoke(Delegate method, object[] args)
{
var asyncResult = new UnityAsyncResult()
{
method = method,
args = args,
IsCompleted = false,
AsyncWaitHandle = new ManualResetEvent(false),
};
lock (fifoToExecute)
{
fifoToExecute.Enqueue(asyncResult);
}
return asyncResult;
}
public object EndInvoke(IAsyncResult result)
{
if (!result.IsCompleted)
{
result.AsyncWaitHandle.WaitOne();
}
return result.AsyncState;
}
public object Invoke(Delegate method, object[] args) {
if (InvokeRequired)
{
var asyncResult = BeginInvoke(method, args);
return EndInvoke(asyncResult);
}
else
{
return method.DynamicInvoke(args);
}
}
public void ProcessQueue()
{
if (Thread.CurrentThread != mainThread)
{
throw new Exception("Must be called from the same thread it was created on");
}
bool loop = true;
UnityAsyncResult data = null;
while (loop)
{
lock (fifoToExecute)
{
loop = fifoToExecute.Count > 0;
if (!loop) break;
data = fifoToExecute.Dequeue();
}
data.AsyncState = Invoke(data.method, data.args);
data.IsCompleted = true;
}
}
class UnityAsyncResult : IAsyncResult
{
public Delegate method;
public object[] args;
public bool IsCompleted { get; set; }
public WaitHandle AsyncWaitHandle { get; internal set; }
public object AsyncState { get; set; }
public bool CompletedSynchronously { get { return IsCompleted; } }
}
}
using UnityEngine;
using System.Threading;
public class UnitySynchronizeInvokeExample : MonoBehaviour
{
UnitySynchronizeInvoke synchronizeInvoke;
void Start()
{
synchronizeInvoke = new UnitySynchronizeInvoke();
(new Thread(ThreadMain)).Start();
}
void ThreadMain()
{
while (true)
{
var retObj = synchronizeInvoke.Invoke((System.Func<string>)(() =>
{
this.transform.localScale = Vector3.one * Random.Range(1.0f, 10.0f);
return this.gameObject.name;
}), null);
Debug.Log("Waited for the end of synchronizeInvoke and it synchronously returned me: " + (retObj as string));
Thread.Sleep(1 * 1000);
}
}
void Update()
{
synchronizeInvoke.ProcessQueue();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment