我不知道如何正确发出异步Get请求。我有要求的协程。它返回给我录制播放器时所需的房间ID,但问题是所有这些操作都是在一个函数中完成的,在创建房间时,因此,协程没有时间写入数据。然后,此Get请求被实时使用,以获取更改的必要ID,并且存在相同的问题。 我的获取请求:
IEnumerator GetRequest(string uri)
{
using (UnityWebRequest webRequest = UnityWebRequest.Get(Host + uri))
{
yield return webRequest.SendWebRequest();
response = webRequest.downloadHandler.text;
}
}
方法:
public int GetID(string entity, string identify, string ID)
{
StartCoroutine(GetRequest(entity + identify));
var json = ParseJson(response);
return int.Parse(json[ID]);
}
我给他打电话的地方
public void CreateRoom()
{
TypedLobby sqlLobby = new TypedLobby("myLobby", LobbyType.SqlLobby);
string sqlLobbyFilter = "C0";
SetNickName(userName.text);
RoomOptions roomOptions = new RoomOptions
{
MaxPlayers = 5,
CustomRoomProperties = new ExitGames.Client.Photon.Hashtable() { { sqlLobbyFilter, "0" } },
CustomRoomPropertiesForLobby = new string[] { sqlLobbyFilter }
};
if (roomName.text.Length != 0)
{
client.PostRoom(roomName.text);
var roomID =client.GetID("Rooms/", roomName.text, "IDRoom");
client.PostPlayer(PhotonNetwork.NickName, roomID);
PhotonNetwork.CreateRoom(roomName.text, roomOptions, sqlLobby);
}
else notice.EmptyRoomName();
}
答案 0 :(得分:3)
您似乎正在尝试线性化协程。 “ StartCoroutine”的功能不像等待。
让我们首先探讨一下GetRequest协程的工作原理。
IEnumerator GetRequest(string uri)
{
using (UnityWebRequest webRequest = UnityWebRequest.Get(Host + uri))
{
yield return webRequest.SendWebRequest();
response = webRequest.downloadHandler.text;
}
}
上面的代码创建一个新的Web请求,并将控制权每帧返回给Unity 直到该Web请求完成。
像这样思考yield return webRequest.SendWebRequest();
:
while(!webRequest.isDone)
{
//suspend the coroutine until next frame
yield return null;
}
它只是在每一帧中暂停协程,直到有响应为止。
现在让我们逐步检查代码,看看发生了什么:
var roomID =client.GetID("Rooms/", roomName.text, "IDRoom");
哪个调用:
public int GetID(string entity, string identify, string ID)
{
StartCoroutine(GetRequest(entity + identify));
var json = ParseJson(response);
return int.Parse(json[ID]);
}
由于您的 GetRequest 方法中的 webRequest.SendWebRequest()不是即时的,因此至少在下一个响应中,响应将不包含可解析的JSON数据。框架。
由于在框架上调用了 GetID (它本身不是协程),因此它在被调用的框架中执行所有逻辑。它尝试对未设置的响应进行 ParseJson(response),这就是您的协程没有时间写的原因。
我们如何解决这个问题?
不幸的是,还没有一种万能的解决方案。您需要使逻辑去线性化,以便它可以出现在多个帧中。巧妙地使用 Queue 可以在这里很好地工作,或者在CoRoutine中添加更多逻辑也可以解决它。
这是使用CoRoutines的示例,因为队列可能需要更多代码来监视/处理它们:
将您的房间配置逻辑移动到一个协程中(而不是嵌套协程,只需在此内调用webrequest即可):
public IEnumerator ConfigureRoom(string roomNameText, RoomOptions roomOptions, TypedLobby sqlLobby)
{
client.PostRoom(roomNameText)
using (UnityWebRequest webRequest = UnityWebRequest.Get("Rooms/" + roomNameText))
{
yield return webRequest.SendWebRequest();
response = webRequest.downloadHandler.text;
}
var json = ParseJson(response);
var roomId = int.Parse(json["IDRoom"]);
client.PostPlayer(PhotonNetwork.NickName, roomID);
PhotonNetwork.CreateRoom(roomNameText, roomOptions, sqlLobby);
}
//Inside of your CreateRoom() method
if (roomName.text.Length != 0)
{
StartCoroutine(ConfigureRoom(roomName.text, roomOptions, sqlLobby));
}
这允许您在多个帧的过程中创建房间并更新数据。
免责声明:我已经在浏览器中输入了所有这些信息。可能存在较小的语法错误。请让我知道,以便我纠正它们。
答案 1 :(得分:2)
将GetID
更改为协程,给它Action
以使用int
,然后使用yield return GetRequest(...);
代替StartCoroutine(GetRequest(...));
。
IEnumerator GetRequest(string uri)
{
using (UnityWebRequest webRequest = UnityWebRequest.Get(Host + uri))
{
yield return webRequest.SendWebRequest();
response = webRequest.downloadHandler.text;
}
}
方法:
public IEnumerator GetID(string entity, string identify, string ID, Action<int> onComplete)
{
yield return GetRequest(entity + identify);
var json = ParseJson(response);
onComplete(int.Parse(json[ID]));
}
打给他
public void CreateRoom()
{
TypedLobby sqlLobby = new TypedLobby("myLobby", LobbyType.SqlLobby);
string sqlLobbyFilter = "C0";
SetNickName(userName.text);
RoomOptions roomOptions = new RoomOptions
{
MaxPlayers = 5,
CustomRoomProperties = new ExitGames.Client.Photon.Hashtable() { { sqlLobbyFilter, "0" } },
CustomRoomPropertiesForLobby = new string[] { sqlLobbyFilter }
};
if (roomName.text.Length != 0)
{
client.PostRoom(roomName.text);
StartCoroutine(
client.GetID("Rooms/", roomName.text, "IDRoom",
delegate(int roomID) {
client.PostPlayer(PhotonNetwork.NickName, roomID);
PhotonNetwork.CreateRoom(roomName.text, roomOptions, sqlLobby);
}));
}
else notice.EmptyRoomName();
}