using System; using System.Collections; using System.Text; using UnityEngine; using UnityEngine.Networking; namespace HotUpdate.Net { /// /// 游戏服 HTTP 鉴权:POST /register、POST /login → {token,pid} /// public static class AuthApi { public const string DefaultHttpBase = "https://game.xworld.ren"; [Serializable] class AuthBody { public string username; public string password; } public static IEnumerator Register(string httpBase, string username, string password, Action onDone) { yield return PostJson(httpBase, "/register", username, password, onDone); } public static IEnumerator Login(string httpBase, string username, string password, Action onDone) { yield return PostJson(httpBase, "/login", username, password, onDone); } /// /// 优先登录;失败则注册再登录(编辑器/游客自动账号)。 /// public static IEnumerator EnsureAccount(string httpBase, string username, string password, Action onDone) { AuthResponse loginOk = null; string loginErr = null; yield return Login(httpBase, username, password, (r, e) => { loginOk = r; loginErr = e; }); if (loginOk != null && !string.IsNullOrEmpty(loginOk.token)) { onDone?.Invoke(loginOk, null); yield break; } AuthResponse regOk = null; string regErr = null; yield return Register(httpBase, username, password, (r, e) => { regOk = r; regErr = e; }); if (regOk != null && !string.IsNullOrEmpty(regOk.token)) { onDone?.Invoke(regOk, null); yield break; } // 注册失败(例如已存在)再登录一次 AuthResponse login2 = null; string login2Err = null; yield return Login(httpBase, username, password, (r, e) => { login2 = r; login2Err = e; }); if (login2 != null && !string.IsNullOrEmpty(login2.token)) { onDone?.Invoke(login2, null); yield break; } onDone?.Invoke(null, $"auth failed login={loginErr}|{login2Err} register={regErr}"); } static IEnumerator PostJson(string httpBase, string path, string username, string password, Action onDone) { var url = (httpBase ?? DefaultHttpBase).TrimEnd('/') + path; var body = JsonUtility.ToJson(new AuthBody { username = username, password = password }); var bytes = Encoding.UTF8.GetBytes(body); using (var req = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST)) { req.uploadHandler = new UploadHandlerRaw(bytes); req.downloadHandler = new DownloadHandlerBuffer(); req.SetRequestHeader("Content-Type", "application/json"); req.timeout = 15; yield return req.SendWebRequest(); #if UNITY_2020_2_OR_NEWER bool failed = req.result != UnityWebRequest.Result.Success; #else bool failed = req.isNetworkError || req.isHttpError; #endif var text = req.downloadHandler?.text; if (failed) { string err = req.error; if (!string.IsNullOrEmpty(text)) { try { var ae = JsonUtility.FromJson(text); if (!string.IsNullOrEmpty(ae?.error)) err = ae.error; } catch { /* ignore */ } } onDone?.Invoke(null, $"{(int)req.responseCode} {err}"); yield break; } AuthResponse resp = null; try { resp = JsonUtility.FromJson(text); } catch (Exception e) { onDone?.Invoke(null, $"parse auth: {e.Message}"); yield break; } if (resp == null || string.IsNullOrEmpty(resp.token)) { onDone?.Invoke(null, "auth response missing token"); yield break; } onDone?.Invoke(resp, null); } } } }