234 lines
7.6 KiB
C#
234 lines
7.6 KiB
C#
using System;
|
|
using System.Threading.Tasks;
|
|
using UnityEngine;
|
|
using UnityEngine.Networking;
|
|
|
|
public static class Cupid
|
|
{
|
|
private static string serverAddress;
|
|
public static string ServerAddress => serverAddress;
|
|
private static string cupidBaseUri;
|
|
public static string CupidURI => cupidBaseUri;
|
|
|
|
private static int port;
|
|
public static int Port => port;
|
|
|
|
private static string bearerToken;
|
|
public static string BearerToken => bearerToken;
|
|
private static string settingsPassword = "";
|
|
public static string SettingsPassword => settingsPassword;
|
|
|
|
private static CupidSettings settings = null;
|
|
public static CupidSettings Settings => settings;
|
|
|
|
public static bool isInitialized => settings != null;
|
|
|
|
|
|
public static int RoomPort = -1;
|
|
|
|
|
|
public static async Task Init(string _serverAddress, int _port, string _bearerToken, string _settingsPassword)
|
|
{
|
|
if (!TryBuildEndpoints(_serverAddress, _port, out serverAddress, out cupidBaseUri, out port))
|
|
{
|
|
Logger.Log("Cupid: invalid or empty server address.");
|
|
bearerToken = _bearerToken ?? "";
|
|
settings = null;
|
|
return;
|
|
}
|
|
|
|
bearerToken = _bearerToken ?? "";
|
|
|
|
if (string.IsNullOrEmpty(bearerToken))
|
|
{
|
|
Logger.Log("Cupid: no bearer token; configure auth before matchmaking.");
|
|
settings = null;
|
|
return;
|
|
}
|
|
|
|
settingsPassword = _settingsPassword ?? "";
|
|
string settingsUrl = CupidURI + "/settings?password=" + UnityWebRequest.EscapeURL(settingsPassword);
|
|
using (UnityWebRequest www = UnityWebRequest.Get(settingsUrl))
|
|
{
|
|
www.SetRequestHeader("Authorization", "Bearer " + bearerToken);
|
|
var operation = www.SendWebRequest();
|
|
while (!operation.isDone)
|
|
{
|
|
await Task.Yield();
|
|
}
|
|
|
|
try
|
|
{
|
|
if (www.result != UnityWebRequest.Result.Success)
|
|
{
|
|
Logger.Log("Cupid settings request failed: " + www.error);
|
|
Logger.Log(www.downloadHandler != null ? www.downloadHandler.text : "");
|
|
settings = null;
|
|
return;
|
|
}
|
|
|
|
string body = www.downloadHandler != null ? www.downloadHandler.text : "";
|
|
if (string.IsNullOrWhiteSpace(body))
|
|
{
|
|
settings = null;
|
|
return;
|
|
}
|
|
|
|
if (body.Trim() == "403 Unauthorized")
|
|
{
|
|
Logger.Log("Cupid settings: wrong or missing password query (server rejected /settings).");
|
|
settings = null;
|
|
return;
|
|
}
|
|
|
|
settings = JsonUtility.FromJson<CupidSettings>(body);
|
|
if (settings == null) { throw new NullReferenceException(); }
|
|
Logger.Log("Cupid init success");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.Log("Error retreiving settings from server " + e.Message);
|
|
Logger.Log(www.downloadHandler != null ? www.downloadHandler.text : "");
|
|
settings = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Plain host/IP + HTTP port, or an absolute URL (https://host with no port uses 443).
|
|
/// Sets <paramref name="hostOnly"/> for game client transport; <paramref name="baseUri"/> has no trailing slash.
|
|
/// </summary>
|
|
static bool TryBuildEndpoints(string input, int fallbackHttpPort, out string hostOnly, out string baseUri, out int resolvedPort)
|
|
{
|
|
hostOnly = "";
|
|
baseUri = "";
|
|
resolvedPort = fallbackHttpPort;
|
|
input = (input ?? "").Trim();
|
|
if (string.IsNullOrEmpty(input))
|
|
return false;
|
|
|
|
if (input.IndexOf("://", StringComparison.Ordinal) >= 0
|
|
&& Uri.TryCreate(input, UriKind.Absolute, out Uri uri)
|
|
&& (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps))
|
|
{
|
|
hostOnly = uri.Host;
|
|
string authority = uri.GetLeftPart(UriPartial.Authority);
|
|
string path = uri.AbsolutePath;
|
|
if (!string.IsNullOrEmpty(path) && path != "/")
|
|
baseUri = authority.TrimEnd('/') + path.TrimEnd('/');
|
|
else
|
|
baseUri = authority;
|
|
resolvedPort = uri.Port;
|
|
return true;
|
|
}
|
|
|
|
hostOnly = input;
|
|
baseUri = "http://" + input + ":" + fallbackHttpPort;
|
|
resolvedPort = fallbackHttpPort;
|
|
return true;
|
|
}
|
|
|
|
|
|
public static string RandomUsername{
|
|
get{
|
|
string pool="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
string output ="";
|
|
for(int i=0; i < 5; i++){
|
|
output += pool.ToCharArray()[UnityEngine.Random.Range(0,pool.Length)];
|
|
}
|
|
|
|
return output;
|
|
}
|
|
}
|
|
|
|
/// <summary>Matchmaker GET / body: <c>"0"</c> while waiting; otherwise a JSON room object.</summary>
|
|
public static CupidRoom? ParseRoom(string data) => ParseRoom(data, 0, null);
|
|
|
|
/// <inheritdoc cref="ParseRoom(string)"/>
|
|
/// <param name="currentUserId">Used to pick <c>for_red</c> vs <c>for_blue</c> when both list the same players.</param>
|
|
/// <param name="teamDisambiguation">Optional hint (e.g. <see cref="GameManager.MyTeam"/>) when the roster is duplicated on both sides.</param>
|
|
public static CupidRoom? ParseRoom(string data, int currentUserId, Team? teamDisambiguation)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(data))
|
|
return null;
|
|
string t = data.Trim();
|
|
if (t == "0")
|
|
return null;
|
|
|
|
if (t.IndexOf("\"for_red\"", StringComparison.Ordinal) >= 0)
|
|
{
|
|
MatchmadeResponse env = JsonUtility.FromJson<MatchmadeResponse>(t);
|
|
if (env == null || !env.ok || !MatchmadeResponse.IsMatchReady(env))
|
|
return null;
|
|
MatchmadeTeamPayload branch = MatchmadeResponse.SelectTeamPayload(env, currentUserId, teamDisambiguation);
|
|
if (branch == null || branch.Port <= 0)
|
|
return null;
|
|
return ToCupidRoom(branch);
|
|
}
|
|
|
|
try
|
|
{
|
|
CupidRoom room = JsonUtility.FromJson<CupidRoom>(t);
|
|
if (room.Port <= 0)
|
|
return null;
|
|
return room;
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static CupidRoom ToCupidRoom(MatchmadeTeamPayload p)
|
|
{
|
|
var room = new CupidRoom
|
|
{
|
|
GameName = p.GameName ?? "",
|
|
Port = p.Port,
|
|
InitTime = p.InitTime,
|
|
match_id = p.match_id,
|
|
your_team = p.your_team ?? ""
|
|
};
|
|
if (p.Players != null)
|
|
{
|
|
room.Players = new CupidQueueEntry[p.Players.Length];
|
|
for (int i = 0; i < p.Players.Length; i++)
|
|
{
|
|
room.Players[i] = new CupidQueueEntry
|
|
{
|
|
Name = p.Players[i].Name,
|
|
LastSeen = p.Players[i].LastSeen,
|
|
UserId = p.Players[i].UserId
|
|
};
|
|
}
|
|
}
|
|
return room;
|
|
}
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class CupidSettings
|
|
{
|
|
public int minimum_players;
|
|
public int maximum_players;
|
|
public int waiting_time;
|
|
}
|
|
|
|
[System.Serializable]
|
|
public struct CupidRoom
|
|
{
|
|
public CupidQueueEntry[] Players;
|
|
public string GameName;
|
|
public int Port;
|
|
public long InitTime;
|
|
public int match_id;
|
|
public string your_team;
|
|
}
|
|
|
|
[System.Serializable]
|
|
public struct CupidQueueEntry
|
|
{
|
|
public string Name;
|
|
public long LastSeen;
|
|
public int UserId;
|
|
} |