Files
AIGame/AIClient/Assets/HotUpdate/Scripts/Net/AuthApi.cs
T
udxandCursor b7a0bbcb89 Add hot-update boot pipeline, UI bundles/atlas assets, and design docs.
Ignore AIClient/Library and AIClient/HybridCLRData permanently; include HybridCLR/YooAsset project setup and UI tooling.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 16:02:58 +08:00

125 lines
4.6 KiB
C#

using System;
using System.Collections;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
namespace HotUpdate.Net
{
/// <summary>
/// 游戏服 HTTP 鉴权:POST /register、POST /login → {token,pid}
/// </summary>
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<AuthResponse, string> onDone)
{
yield return PostJson(httpBase, "/register", username, password, onDone);
}
public static IEnumerator Login(string httpBase, string username, string password, Action<AuthResponse, string> onDone)
{
yield return PostJson(httpBase, "/login", username, password, onDone);
}
/// <summary>
/// 优先登录;失败则注册再登录(编辑器/游客自动账号)。
/// </summary>
public static IEnumerator EnsureAccount(string httpBase, string username, string password, Action<AuthResponse, string> 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<AuthResponse, string> 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<AuthError>(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<AuthResponse>(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);
}
}
}
}