aha
This commit is contained in:
@ -0,0 +1,345 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Threading;
|
||||
using Mirror;
|
||||
using UnityEngine;
|
||||
using Random = UnityEngine.Random;
|
||||
namespace Edgegap
|
||||
{
|
||||
[HelpURL("https://mirror-networking.gitbook.io/docs/manual/transports/edgegap-transports/edgegap-relay")]
|
||||
public class EdgegapLobbyKcpTransport : EdgegapKcpTransport
|
||||
{
|
||||
[Header("Lobby Settings")]
|
||||
[Tooltip("URL to the Edgegap lobby service, automatically filled in after completing the creation process via button below (or enter manually)")]
|
||||
public string lobbyUrl;
|
||||
[Tooltip("How long to wait for the relay to be assigned after starting a lobby")]
|
||||
public float lobbyWaitTimeout = 60;
|
||||
|
||||
public LobbyApi Api;
|
||||
private LobbyCreateRequest? _request;
|
||||
private string _lobbyId;
|
||||
private string _playerId;
|
||||
private TransportStatus _status = TransportStatus.Offline;
|
||||
public enum TransportStatus
|
||||
{
|
||||
Offline,
|
||||
CreatingLobby,
|
||||
StartingLobby,
|
||||
JoiningLobby,
|
||||
WaitingRelay,
|
||||
Connecting,
|
||||
Connected,
|
||||
Error,
|
||||
}
|
||||
public TransportStatus Status
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!NetworkClient.active && !NetworkServer.active)
|
||||
{
|
||||
return TransportStatus.Offline;
|
||||
}
|
||||
if (_status == TransportStatus.Connecting)
|
||||
{
|
||||
if (NetworkServer.active)
|
||||
{
|
||||
switch (((EdgegapKcpServer)this.server).state)
|
||||
{
|
||||
case ConnectionState.Valid:
|
||||
return TransportStatus.Connected;
|
||||
case ConnectionState.Invalid:
|
||||
case ConnectionState.SessionTimeout:
|
||||
case ConnectionState.Error:
|
||||
return TransportStatus.Error;
|
||||
}
|
||||
}
|
||||
else if (NetworkClient.active)
|
||||
{
|
||||
switch (((EdgegapKcpClient)this.client).connectionState)
|
||||
{
|
||||
case ConnectionState.Valid:
|
||||
return TransportStatus.Connected;
|
||||
case ConnectionState.Invalid:
|
||||
case ConnectionState.SessionTimeout:
|
||||
case ConnectionState.Error:
|
||||
return TransportStatus.Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _status;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
Api = new LobbyApi(lobbyUrl);
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
this.relayGUI = false;
|
||||
}
|
||||
|
||||
public override void ServerStart()
|
||||
{
|
||||
if (!_request.HasValue)
|
||||
{
|
||||
throw new Exception("No lobby request set. Call SetServerLobbyParams");
|
||||
}
|
||||
_status = TransportStatus.CreatingLobby;
|
||||
Api.CreateLobby(_request.Value, lobby =>
|
||||
{
|
||||
_lobbyId = lobby.lobby_id;
|
||||
_status = TransportStatus.StartingLobby;
|
||||
Api.StartLobby(new LobbyIdRequest(_lobbyId), () =>
|
||||
{
|
||||
StartCoroutine(WaitForLobbyRelay(_lobbyId, true));
|
||||
}, error =>
|
||||
{
|
||||
_status = TransportStatus.Error;
|
||||
string errorMsg = $"Could not start lobby: {error}";
|
||||
Debug.LogError(errorMsg);
|
||||
OnServerError?.Invoke(0, TransportError.Unexpected, errorMsg);
|
||||
ServerStop();
|
||||
});
|
||||
},
|
||||
error =>
|
||||
{
|
||||
_status = TransportStatus.Error;
|
||||
string errorMsg = $"Couldn't create lobby: {error}";
|
||||
Debug.LogError(errorMsg);
|
||||
OnServerError?.Invoke(0, TransportError.Unexpected, errorMsg);
|
||||
});
|
||||
}
|
||||
|
||||
public override void ServerStop()
|
||||
{
|
||||
base.ServerStop();
|
||||
|
||||
Api.DeleteLobby(_lobbyId, () =>
|
||||
{
|
||||
// yay
|
||||
}, error =>
|
||||
{
|
||||
OnServerError?.Invoke(0, TransportError.Unexpected, $"Failed to delete lobby: {error}");
|
||||
});
|
||||
}
|
||||
|
||||
public override void ClientDisconnect()
|
||||
{
|
||||
base.ClientDisconnect();
|
||||
// this gets called for host mode as well
|
||||
if (!NetworkServer.active)
|
||||
{
|
||||
Api.LeaveLobby(new LobbyJoinOrLeaveRequest
|
||||
{
|
||||
player = new LobbyJoinOrLeaveRequest.Player
|
||||
{
|
||||
id = _playerId
|
||||
},
|
||||
lobby_id = _lobbyId
|
||||
}, () =>
|
||||
{
|
||||
// yay
|
||||
}, error =>
|
||||
{
|
||||
string errorMsg = $"Failed to leave lobby: {error}";
|
||||
OnClientError?.Invoke(TransportError.Unexpected, errorMsg);
|
||||
Debug.LogError(errorMsg);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void ClientConnect(string address)
|
||||
{
|
||||
_lobbyId = address;
|
||||
_playerId = RandomPlayerId();
|
||||
_status = TransportStatus.JoiningLobby;
|
||||
Api.JoinLobby(new LobbyJoinOrLeaveRequest
|
||||
{
|
||||
player = new LobbyJoinOrLeaveRequest.Player
|
||||
{
|
||||
id = _playerId,
|
||||
},
|
||||
lobby_id = address
|
||||
}, () =>
|
||||
{
|
||||
StartCoroutine(WaitForLobbyRelay(_lobbyId, false));
|
||||
}, error =>
|
||||
{
|
||||
_status = TransportStatus.Offline;
|
||||
string errorMsg = $"Failed to join lobby: {error}";
|
||||
OnClientError?.Invoke(TransportError.Unexpected, errorMsg);
|
||||
Debug.LogError(errorMsg);
|
||||
OnClientDisconnected?.Invoke();
|
||||
});
|
||||
}
|
||||
|
||||
private IEnumerator WaitForLobbyRelay(string lobbyId, bool forServer)
|
||||
{
|
||||
_status = TransportStatus.WaitingRelay;
|
||||
double startTime = NetworkTime.localTime;
|
||||
bool running = true;
|
||||
while (running)
|
||||
{
|
||||
if (NetworkTime.localTime - startTime >= lobbyWaitTimeout)
|
||||
{
|
||||
_status = TransportStatus.Error;
|
||||
string errorMsg = "Timed out waiting for lobby.";
|
||||
Debug.LogError(errorMsg);
|
||||
if (forServer)
|
||||
{
|
||||
_status = TransportStatus.Error;
|
||||
OnServerError?.Invoke(0, TransportError.Unexpected, errorMsg);
|
||||
ServerStop();
|
||||
}
|
||||
else
|
||||
{
|
||||
_status = TransportStatus.Error;
|
||||
OnClientError?.Invoke(TransportError.Unexpected, errorMsg);
|
||||
ClientDisconnect();
|
||||
}
|
||||
yield break;
|
||||
}
|
||||
bool waitingForResponse = true;
|
||||
Api.GetLobby(lobbyId, lobby =>
|
||||
{
|
||||
waitingForResponse = false;
|
||||
if (string.IsNullOrEmpty(lobby.assignment.ip))
|
||||
{
|
||||
// no lobby deployed yet, have the outer loop retry
|
||||
return;
|
||||
}
|
||||
relayAddress = lobby.assignment.ip;
|
||||
foreach (Lobby.Port aport in lobby.assignment.ports)
|
||||
{
|
||||
if (aport.protocol == "UDP")
|
||||
{
|
||||
if (aport.name == "server")
|
||||
{
|
||||
relayGameServerPort = (ushort)aport.port;
|
||||
|
||||
}
|
||||
else if (aport.name == "client")
|
||||
{
|
||||
relayGameClientPort = (ushort)aport.port;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool found = false;
|
||||
foreach (Lobby.Player player in lobby.players)
|
||||
{
|
||||
if (player.id == _playerId)
|
||||
{
|
||||
userId = player.authorization_token;
|
||||
sessionId = lobby.assignment.authorization_token;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
running = false;
|
||||
if (!found)
|
||||
{
|
||||
string errorMsg = $"Couldn't find my player ({_playerId})";
|
||||
Debug.LogError(errorMsg);
|
||||
|
||||
if (forServer)
|
||||
{
|
||||
_status = TransportStatus.Error;
|
||||
OnServerError?.Invoke(0, TransportError.Unexpected, errorMsg);
|
||||
ServerStop();
|
||||
}
|
||||
else
|
||||
{
|
||||
_status = TransportStatus.Error;
|
||||
OnClientError?.Invoke(TransportError.Unexpected, errorMsg);
|
||||
ClientDisconnect();
|
||||
}
|
||||
return;
|
||||
}
|
||||
_status = TransportStatus.Connecting;
|
||||
if (forServer)
|
||||
{
|
||||
base.ServerStart();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.ClientConnect("");
|
||||
}
|
||||
}, error =>
|
||||
{
|
||||
running = false;
|
||||
waitingForResponse = false;
|
||||
_status = TransportStatus.Error;
|
||||
string errorMsg = $"Failed to get lobby info: {error}";
|
||||
Debug.LogError(errorMsg);
|
||||
if (forServer)
|
||||
{
|
||||
OnServerError?.Invoke(0, TransportError.Unexpected, errorMsg);
|
||||
ServerStop();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnClientError?.Invoke(TransportError.Unexpected, errorMsg);
|
||||
ClientDisconnect();
|
||||
}
|
||||
});
|
||||
while (waitingForResponse)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
}
|
||||
}
|
||||
private static string RandomPlayerId()
|
||||
{
|
||||
return $"mirror-player-{Random.Range(1, int.MaxValue)}";
|
||||
}
|
||||
|
||||
public void SetServerLobbyParams(string lobbyName, int capacity)
|
||||
{
|
||||
SetServerLobbyParams(new LobbyCreateRequest
|
||||
{
|
||||
player = new LobbyCreateRequest.Player
|
||||
{
|
||||
id = RandomPlayerId(),
|
||||
},
|
||||
annotations = new LobbyCreateRequest.Annotation[]
|
||||
{
|
||||
},
|
||||
capacity = capacity,
|
||||
is_joinable = true,
|
||||
name = lobbyName,
|
||||
tags = new string[]
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void SetServerLobbyParams(LobbyCreateRequest request)
|
||||
{
|
||||
_playerId = request.player.id;
|
||||
_request = request;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// attempt to clean up lobbies, if active
|
||||
if (NetworkServer.active)
|
||||
{
|
||||
ServerStop();
|
||||
// Absolutely make sure there's time for the network request to hit edgegap servers.
|
||||
// sorry. this can go once the lobby service can timeout lobbies itself
|
||||
Thread.Sleep(300);
|
||||
}
|
||||
else if (NetworkClient.active)
|
||||
{
|
||||
ClientDisconnect();
|
||||
// Absolutely make sure there's time for the network request to hit edgegap servers.
|
||||
// sorry. this can go once the lobby service can timeout lobbies itself
|
||||
Thread.Sleep(300);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user