using System; using System.Collections; using UnityEngine; using UnityEngine.Networking; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace SmartBowSDK { public class SmartBowNetwork : MonoBehaviour { public SmartBowHelper smartBowHelper; // 本地 IP 地址(只在本地环境下生效) static string localIPAddress = "192.168.0.108"; //是否使用本地环境 static bool isLocal = false; // 服务器路径 static string serverPath = "/SmartBowBusinessServer"; // 最终服务器地址 static string serverURL => isLocal ? $"http://{localIPAddress}:11432{serverPath}" : $"https://xmjssvr.cn{serverPath}"; //private string serverURL = "https://xmjssvr.cn/SmartBowBusinessServer"; //private const string serverURL = "http://127.0.0.1:11332/SmartBowBusinessServer"; private string loginToken; /// /// 运行时设置本地 IP 并启用本地环境 /// public static void SetLocal(string ip) { isLocal = true; localIPAddress = ip; Debug.Log($"[SmartBowNetwork] 设置IP: {ip}"); } /// /// 发送手机验证码 /// public void SendPhoneValidateCode(string phone, int language, Action callback) { string url = $"{serverURL}/phoneValidate/sendPhoneValidateCode" + $"?phone={UnityWebRequest.EscapeURL(phone)}&language={language}"; StartCoroutine(Post(url, new WWWForm(), callback)); } /// /// 验证手机验证码 /// public void ValidatePhoneCode(string phone, int code, Action callback) { string url = $"{serverURL}/phoneValidate/validatePhone" + $"?phone={UnityWebRequest.EscapeURL(phone)}&code={code}"; StartCoroutine(Post(url, new WWWForm(), callback)); } /// /// 发送邮箱验证码 /// public void SendEmailValidateCode(string email, int language, Action callback) { string url = $"{serverURL}/emailValidate/sendEmailValidateCode" + $"?email={UnityWebRequest.EscapeURL(email)}&language={language}"; StartCoroutine(Post(url, new WWWForm(), callback)); } /// /// 验证邮箱验证码 /// public void ValidateEmailCode(string email, int code, Action callback) { string url = $"{serverURL}/emailValidate/validateEmail" + $"?email={UnityWebRequest.EscapeURL(email)}&code={code}"; StartCoroutine(Post(url, new WWWForm(), callback)); } /// /// 用户注册 /// /// 服务器索引 /// 用户名 /// 密码 /// 邮箱 /// 手机号 /// 当前接收的code,海外用邮箱 serverIndex = 1,国内 serverIndex = 0用手机号 /// 回调 public void RegisterByCode(int serverIndex, string username, string password, string email, string phone,int code, Action callback) { string url = $"{serverURL}/gameLogin/registerByCode" + $"?serverIndex={serverIndex}" + $"&username={UnityWebRequest.EscapeURL(username)}" + $"&password={UnityWebRequest.EscapeURL(password)}" + $"&email={UnityWebRequest.EscapeURL(email)}" + $"&phone={UnityWebRequest.EscapeURL(phone)}" + $"&code={code}"; StartCoroutine(Post(url, new WWWForm(), callback)); } //public IEnumerator ListUsernamesByEmail(string email, long timestamp, string sign, Action callback) //{ // string url = serverURL + "/gameLogin/listUsernamesByEmail"; // WWWForm form = new WWWForm(); // form.AddField("email", email); // form.AddField("timestamp", timestamp.ToString()); // form.AddField("sign", sign); // using (UnityWebRequest request = UnityWebRequest.Post(url, form)) // { // yield return request.SendWebRequest(); // RequestResult requestResult = JsonConvert.DeserializeObject(request.downloadHandler.text); // if (callback != null) callback(requestResult); // } //} //public IEnumerator ListUsernamesByPhone(string phone, long timestamp, string sign, Action callback) //{ // string url = serverURL + "/gameLogin/listUsernamesByPhone"; // WWWForm form = new WWWForm(); // form.AddField("phone", phone); // form.AddField("timestamp", timestamp.ToString()); // form.AddField("sign", sign); // using (UnityWebRequest request = UnityWebRequest.Post(url, form)) // { // yield return request.SendWebRequest(); // RequestResult requestResult = JsonConvert.DeserializeObject(request.downloadHandler.text); // if (callback != null) callback(requestResult); // } //} //public IEnumerator ResetPassword(string sign, long timestamp, string username, string password, Action callback) //{ // string url = serverURL + "/gameLogin/resetPassword"; // WWWForm form = new WWWForm(); // form.AddField("sign", sign); // form.AddField("timestamp", timestamp.ToString()); // form.AddField("username", username); // form.AddField("password", password); // using (UnityWebRequest request = UnityWebRequest.Post(url, form)) // { // yield return request.SendWebRequest(); // RequestResult requestResult = JsonConvert.DeserializeObject(request.downloadHandler.text); // if (callback != null) callback(requestResult); // } //} //重置密码 public void ResetPasswordByAccount(int serverIndex,string account, string codeAccount, int code, string newPassword, Action callback) { StartCoroutine(ResetPasswordByAccountCoroutine(serverIndex,account, codeAccount, code, newPassword, callback)); } /// /// 重置密码流程,先验证Code,在获取list,再重置对应的账号。 /// 基本和弓箭app流程一样 /// /// /// /// /// /// /// /// private IEnumerator ResetPasswordByAccountCoroutine(int serverIndex,string account,string codeAccount, int code, string newPassword, Action callback) { RequestResult validateResult = null; if (!(serverIndex >= 0 && serverIndex <= 2)) { callback?.Invoke(new RequestResult { code = -10, msg = "serverIndex 错误!", }); yield break; } bool isPhone = serverIndex == 0 ? true : false; // 1. 验证验证码 string validateUrl = isPhone ? $"{serverURL}/phoneValidate/validatePhone?phone={UnityWebRequest.EscapeURL(codeAccount)}&code={code}" : $"{serverURL}/emailValidate/validateEmail?email={UnityWebRequest.EscapeURL(codeAccount)}&code={code}"; yield return Post(validateUrl, new WWWForm(), result => validateResult = result); if (validateResult == null || validateResult.code != 0) { callback?.Invoke(new RequestResult { code = -10, msg = isPhone ? "手机号验证码验证失败" : "邮箱验证码验证失败" }); yield break; } // 2. 提取验证信息 JObject data = validateResult.data as JObject; string verifiedAccount = data.Value(isPhone ? "phone" : "email"); long timestamp = data.Value("timestamp"); string sign = data.Value("sign"); // 3. 查询用户名 RequestResult listResult = null; string listUrl = isPhone ? $"{serverURL}/gameLogin/listUsernamesByPhone" : $"{serverURL}/gameLogin/listUsernamesByEmail"; WWWForm listForm = new WWWForm(); listForm.AddField(isPhone ? "phone" : "email", verifiedAccount); listForm.AddField("timestamp", timestamp.ToString()); listForm.AddField("sign", sign); yield return Post(listUrl, listForm, result => listResult = result); if (listResult == null || listResult.code != 0) { callback?.Invoke(new RequestResult { code = -11, msg = "未找到绑定的账号" }); yield break; } // 4. 精确匹配账号名再重置密码 JArray users = listResult.data as JArray; bool matched = false; foreach (var item in users) { string username = item.Value("username"); long ts = item.Value("timestamp"); string sgn = item.Value("sign"); SmartBowLogger.Log(this,$"server: {username} vs account: {account}"); if (account.ToLower() == username.ToLower()) { matched = true; SmartBowLogger.Log(this,"匹配成功:" + username.ToLower()); // 5. 请求重置密码 string resetUrl = $"{serverURL}/gameLogin/resetPassword"; WWWForm resetForm = new WWWForm(); resetForm.AddField("sign", sgn); resetForm.AddField("timestamp", ts.ToString()); resetForm.AddField("username", username); resetForm.AddField("password", newPassword); yield return Post(resetUrl, resetForm, callback); break; } } // 6. 如果没有匹配账号,提示 if (!matched) { callback?.Invoke(new RequestResult { code = -12, msg = "未找到对应账号绑定" }); } } /// /// 登录 /// gameID和channelID请询问插件给予者给予 /// /// /// /// /// /// public void Login(string gameID, string channelID, string username, string password, Action callback) { WWWForm form = new WWWForm(); form.AddField("gameID", gameID); form.AddField("channelID", channelID); form.AddField("username", username); form.AddField("password", password); StartCoroutine(Post(serverURL + "/SmartBowSDK/login", form, (res) => { bool loginSuccess = res.code == 0; if (loginSuccess) loginToken = res.data as string; LoginResult loginResult = new LoginResult(); loginResult.success = loginSuccess; loginResult.message = res.msg; callback?.Invoke(loginResult); })); } /// /// 登出 /// /// public void Logout(Action callback) { loginToken = null; callback?.Invoke(true); } /// /// 获取用户信息 /// /// public void GetUserInfo(Action callback) { GetUserInfoResult getUserInfoResult = new GetUserInfoResult(); if (loginToken == null) { getUserInfoResult.message = "尚未登录"; callback?.Invoke(getUserInfoResult); return; } WWWForm form = new WWWForm(); form.AddField("token", loginToken); StartCoroutine(Post(serverURL + "/SmartBowSDK/getUserInfo", form, (res) => { if (res.code == 0) { UserInfo userInfo = (res.data as JObject).ToObject(); getUserInfoResult.success = true; getUserInfoResult.userInfo = userInfo; } getUserInfoResult.message = res.msg; callback?.Invoke(getUserInfoResult); })); } /// /// 设置用户名 /// /// 用户名字 /// public void SaveUserName(string nickname, Action callback) { if (loginToken == null) { callback?.Invoke(new RequestResult { msg = "尚未登录" }); return; } string url = $"{serverURL}/SmartBowSDK/saveUserName?token={loginToken}&nickname={UnityWebRequest.EscapeURL(nickname)}"; StartCoroutine(Post(url, new WWWForm(), callback)); } /// /// 设置用户的多个信息 /// /// 用户信息对象 /// public void SaveUserInfo(UserInfoExtended userInfo, Action callback) { if (loginToken == null) { callback?.Invoke(new RequestResult { msg = "尚未登录" }); return; } string json = JsonConvert.SerializeObject(userInfo); UnityWebRequest request = new UnityWebRequest($"{serverURL}/SmartBowSDK/saveUserInfo?token={loginToken}", "POST"); byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(json); request.uploadHandler = new UploadHandlerRaw(bodyRaw); request.downloadHandler = new DownloadHandlerBuffer(); request.SetRequestHeader("Content-Type", "application/json"); StartCoroutine(SendRequest(request, callback)); } /// /// 根据密钥上传分数 /// /// /// /// public void UploadSeasonSinglePlayerGameRes(string secret, int score, Action callback) { if (loginToken == null) { callback?.Invoke(new RequestResult { msg = "尚未登录" }); return; } string url = $"{serverURL}/SmartBowSDK/UploadSeasonSinglePlayerGameRes?token={loginToken}&secret={UnityWebRequest.EscapeURL(secret)}&score={score}"; StartCoroutine(Post(url, new WWWForm(), callback)); } /// /// 上传赛季PK分数 /// /// PK房间ID /// 密钥,游戏类型(解析得到) /// 对手ID /// 结果(0:我赢;1:他赢;2:平局) /// 回调 public void UploadSeasonPKGameRes(string roomKey, string secret, int p2ID, int gameRes, Action callback) { if (loginToken == null) { callback?.Invoke(new RequestResult { msg = "尚未登录" }); return; } string url = $"{serverURL}/SmartBowSDK/UploadSeasonPKGameRes" + $"?token={loginToken}" + $"&roomKey={UnityWebRequest.EscapeURL(roomKey)}" + $"&secret={UnityWebRequest.EscapeURL(secret)}" + $"&p2ID={p2ID}" + $"&gameRes={gameRes}"; StartCoroutine(Post(url, new WWWForm(), callback)); } /// /// 根据密钥获取排行榜 /// /// 密钥 /// 排行区域 3:国,1:省,2市,其他:全球 /// 国家 /// 省 /// 城市 /// public void GetSeasonRankListByGameType(string secret, int rankArea, string country, string state, string city, Action callback) { if (loginToken == null) { callback?.Invoke(new RequestResult { msg = "尚未登录" }); return; } string url = $"{serverURL}/SmartBowSDK/GetSeasonRankListByGameType?" + $"token={loginToken}" + $"&rankArea={rankArea}" + $"&secret={UnityWebRequest.EscapeURL(secret)}" + $"&countryCode={UnityWebRequest.EscapeURL(country)}" + $"&stateCode={UnityWebRequest.EscapeURL(state)}" + $"&cityCode={UnityWebRequest.EscapeURL(city)}"; StartCoroutine(Post(url, new WWWForm(), callback)); } /// /// 根据密钥获取自定义排行榜 /// /// 密钥 /// 排行区域 3:国,1:省,2市,其他:全球 /// 国家 /// 省 /// 市 /// 1是降序,其他是升序(不能小于0) /// 数量:不能小于0 /// public void GetSeasonRankListByCustom(string secret, int rankArea, string country, string state, string city, int rankType, int count, Action callback) { if (loginToken == null) { callback?.Invoke(new RequestResult { msg = "尚未登录" }); return; } string url = $"{serverURL}/SmartBowSDK/GetSeasonRankListByCustom?" + $"token={loginToken}" + $"&rankArea={rankArea}" + $"&secret={UnityWebRequest.EscapeURL(secret)}" + $"&countryCode={UnityWebRequest.EscapeURL(country)}" + $"&stateCode={UnityWebRequest.EscapeURL(state)}" + $"&cityCode={UnityWebRequest.EscapeURL(city)}" + $"&rankType={rankType}" + $"&count={count}"; StartCoroutine(Post(url, new WWWForm(), callback)); } /// /// 获取自己的用户信息 /// /// 密钥 /// 排行区域 3:国,1:省,2市,其他:全球 /// 国家 /// 省 /// 市 /// 1是降序,其他是升序(不能小于0) /// 数量:不能小于0 /// public void GetUserRankByGameType(string secret, int rankArea, string country, string state, string city, int rankType, int count, Action callback) { if (loginToken == null) { callback?.Invoke(new RequestResult { msg = "尚未登录" }); return; } string url = $"{serverURL}/SmartBowSDK/getUserRankByGameType?" + $"token={loginToken}" + $"&rankArea={rankArea}" + $"&secret={UnityWebRequest.EscapeURL(secret)}" + $"&countryCode={UnityWebRequest.EscapeURL(country)}" + $"&stateCode={UnityWebRequest.EscapeURL(state)}" + $"&cityCode={UnityWebRequest.EscapeURL(city)}" + $"&rankType={rankType}" + $"&count={count}"; StartCoroutine(Post(url, new WWWForm(), callback)); } /// /// 上传排行榜分数(定制) /// /// 密钥 /// 任务类型 /// 难度 /// 模式 /// 设备类型 /// 分数(>=0) /// 回调 public void UploadCustomLeaderboardScore(string secret, int taskId, int difficultType, int modeType, int deviceType, int score, Action callback) { if (loginToken == null) { callback?.Invoke(new RequestResult { msg = "尚未登录" }); return; } if (score < 0) { callback?.Invoke(new RequestResult { msg = "分数不能小于0" }); return; } string url = $"{serverURL}/SmartBowSDK/UploadCustomLeaderboardScore"; WWWForm form = new WWWForm(); form.AddField("token", loginToken); form.AddField("secret", secret); form.AddField("taskId", taskId); form.AddField("difficultType", difficultType); form.AddField("modeType", modeType); form.AddField("deviceType", deviceType); form.AddField("score", score); StartCoroutine(Post(url, form, callback)); } /// /// 获取排行榜(自定义) /// /// 密钥 /// 任务类型 /// 难度 /// 模式 /// 设备类型 /// 时间维度 /// 回调 public void GetCustomLeaderboard(string secret, int taskId, int difficultType, int modeType, int deviceType, int timeType, Action callback) { if (loginToken == null) { callback?.Invoke(new RequestResult { msg = "尚未登录" }); return; } string url = $"{serverURL}/SmartBowSDK/GetCustomLeaderboard"; WWWForm form = new WWWForm(); form.AddField("token", loginToken); form.AddField("secret", secret); form.AddField("taskId", taskId); form.AddField("difficultType", difficultType); form.AddField("modeType", modeType); form.AddField("deviceType", deviceType); form.AddField("timeType", timeType); StartCoroutine(Post(url, form, callback)); } private string GetCalibrateDataStorageLocalKey(string mac) { string key = "CalibrateDataStorage"; string version = "1.0.0"; return key + "_" + mac + "_" + version; } internal void SaveCalibrateRecord(string mac, string record) { if (smartBowHelper.calibrateDataStorageMode == CalibrateDataStorageMode.Local) { PlayerPrefs.SetString(GetCalibrateDataStorageLocalKey(mac), record == null ? "" : record); } else if (smartBowHelper.calibrateDataStorageMode == CalibrateDataStorageMode.Remote) { WWWForm form = new WWWForm(); form.AddField("mac", mac); form.AddField("record", record); StartCoroutine(Post(serverURL + "/SmartBowSDK/saveCalibrateRecord", form, null)); } } internal void GetCalibrateRecord(string mac, Action callback) { if (smartBowHelper.calibrateDataStorageMode == CalibrateDataStorageMode.Local) { callback?.Invoke(PlayerPrefs.GetString(GetCalibrateDataStorageLocalKey(mac), "")); } else if (smartBowHelper.calibrateDataStorageMode == CalibrateDataStorageMode.Remote) { WWWForm form = new WWWForm(); form.AddField("mac", mac); StartCoroutine(Post(serverURL + "/SmartBowSDK/getCalibrateRecord", form, (res) => { if (res.code == 0) callback?.Invoke(res.data as string); })); } } public static IEnumerator Post(string url, WWWForm form, Action callback) { using (UnityWebRequest request = UnityWebRequest.Post(url, form)) { yield return request.SendWebRequest(); if (request.result == UnityWebRequest.Result.Success) callback?.Invoke(JsonConvert.DeserializeObject(request.downloadHandler.text)); else callback?.Invoke(new RequestResult()); } } public static IEnumerator LoadSprite(string url, Action callback) { using (UnityWebRequest uwr = new UnityWebRequest(url, UnityWebRequest.kHttpVerbGET)) { uwr.downloadHandler = new DownloadHandlerTexture(); yield return uwr.SendWebRequest(); if (uwr.result != UnityWebRequest.Result.Success) yield break; Texture2D texture = DownloadHandlerTexture.GetContent(uwr); Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f)); callback?.Invoke(sprite); } } private IEnumerator SendRequest(UnityWebRequest request, Action callback) { yield return request.SendWebRequest(); if (request.result == UnityWebRequest.Result.Success) callback?.Invoke(JsonConvert.DeserializeObject(request.downloadHandler.text)); else callback?.Invoke(new RequestResult()); } } public class RequestResult { public int code = -9999; public object data; public string msg = "网络出错"; } public class LoginResult { /// /// 是否登录成功 /// public bool success; /// /// 消息描述 /// public string message; } public class GetUserInfoResult { /// /// 是否获取成功 /// public bool success; /// /// 消息描述 /// public string message; /// /// 用户信息 /// public UserInfo userInfo; } public class UserInfo { /// /// 昵称 /// public string nickname; /// /// 头像地址 /// public string avatarUrl; /// /// 性别(1表示男,2表示女) /// public int gender; } /// /// 用户数据 /// public class UserInfoExtended { /// /// //头像url /// public string avatarUrl; /// /// //名字 /// public string nickname; /// /// //性别 1 男,2女 /// public int gender; /// /// 生日 /// public string birthday; /// /// 国家 /// public string country; /// /// 省 /// public string state; /// /// 城市 /// public string city; } }