我使用Unity3D,我想在主线程中运行任务并等待它完成。
这是我的代码:
public override Task<Vibranium.Protobuffers.ACSpawnData> WorldObjectSpawned(Vibranium.Protobuffers.WorldObjectData request, ServerCallContext context)
{
ACSpawnData acSpawnData = new ACSpawnData();
IEnumerator SpawnGo(ACSpawnData acSpawnData)
{
int spawnId = WorldObjectManager.Instance.GetWorldObjects.Count + 1;
GameObject spawnedGO = GameObject.CreatePrimitive(PrimitiveType.Cube);
spawnedGO.name = spawnId.ToString();
spawnedGO.transform.SetParent(WorldObjectManager.Instance.transform);
if (request.WorldObjectType == WorldObjectType.Player)
{
spawnedGO.GetComponent<Renderer>().material.color = Color.red;
}
WorldObjectManager.Instance.GetWorldObjects.Add(spawnedGO);
acSpawnData.SpawnId = (uint)spawnId;
acSpawnData.WorldObjectType = request.WorldObjectType;
yield return null;
}
MainThreadDispatcher.Instance().Enqueue(SpawnGo(acSpawnData));
return Task.FromResult(acSpawnData);
}
要在主线程中执行IEnumerator,我使用以下命令:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading.Tasks;
/// Author: Pim de Witte (pimdewitte.com) and contributors, https://github.com/PimDeWitte/UnityMainThreadDispatcher
/// <summary>
/// A thread-safe class which holds a queue with actions to execute on the next Update() method. It can be used to make calls to the main thread for
/// things such as UI Manipulation in Unity. It was developed for use in combination with the Firebase Unity plugin, which uses separate threads for event handling
/// </summary>
public class MainThreadDispatcher : MonoBehaviour {
private static readonly Queue<Action> _executionQueue = new Queue<Action>();
public void Update() {
lock(_executionQueue) {
while (_executionQueue.Count > 0) {
_executionQueue.Dequeue().Invoke();
}
}
}
/// <summary>
/// Locks the queue and adds the IEnumerator to the queue
/// </summary>
/// <param name="action">IEnumerator function that will be executed from the main thread.</param>
public void Enqueue(IEnumerator action) {
lock (_executionQueue) {
_executionQueue.Enqueue (() => {
StartCoroutine (action);
});
}
}
/// <summary>
/// Locks the queue and adds the Action to the queue
/// </summary>
/// <param name="action">function that will be executed from the main thread.</param>
public void Enqueue(Action action)
{
Enqueue(ActionWrapper(action));
}
/// <summary>
/// Locks the queue and adds the Action to the queue, returning a Task which is completed when the action completes
/// </summary>
/// <param name="action">function that will be executed from the main thread.</param>
/// <returns>A Task that can be awaited until the action completes</returns>
public Task EnqueueAsync(Action action)
{
var tcs = new TaskCompletionSource<bool>();
void WrappedAction() {
try
{
action();
tcs.TrySetResult(true);
} catch (Exception ex)
{
tcs.TrySetException(ex);
}
}
Enqueue(ActionWrapper(WrappedAction));
return tcs.Task;
}
IEnumerator ActionWrapper(Action a)
{
a();
yield return null;
}
private static MainThreadDispatcher _instance = null;
public static bool Exists() {
return _instance != null;
}
public static MainThreadDispatcher Instance() {
if (!Exists ()) {
throw new Exception ("UnityMainThreadDispatcher could not find the UnityMainThreadDispatcher object. Please ensure you have added the MainThreadExecutor Prefab to your scene.");
}
return _instance;
}
void Awake() {
if (_instance == null) {
_instance = this;
DontDestroyOnLoad(this.gameObject);
}
}
void OnDestroy() {
_instance = null;
}
}
一切都很好。创建游戏对象时,Task.FromResult
不会等待SpawnGo
填充acSpawnData
,因此acSpawnData
总是空的。
如何阻止任务WorldObjectSpawned
的执行,直到IEnumerator SpawnGo
完成任务并填充acSpawnData
以便返回为止?
发布于 2022-05-17 14:49:18
https://stackoverflow.com/questions/72275646
复制相似问题