SmartBowDemoUI.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. using System.Collections.Generic;
  4. using SmartBowSDK;
  5. using Newtonsoft.Json;
  6. using System.Linq;
  7. using System.Collections;
  8. namespace SmartBowDemoUI
  9. {
  10. public class SmartBowDemoUI : MonoBehaviour
  11. {
  12. public Transform contentRoot; // ScrollView Content
  13. public GameObject rowPrefab;
  14. [SerializeField] Image _imgAvatar;
  15. [SerializeField] Text _textNickname;
  16. [SerializeField] Text _textGender;
  17. string account;//账号
  18. string phoneNumber; //手机号
  19. string email; //邮箱
  20. string secret2 = "GF5qw/p0TF+qs9ByFBtMXnlExuU9YFe0XhHG5TDmnNM=";//游戏密钥2
  21. string password;//密码
  22. string channelId = "Android";//渠道ID
  23. string gameId = "SmartBowSDK";//游戏ID
  24. public int serverIndex = 0; //国内的用0,国外的用1
  25. private List<string> inputs = new List<string>();
  26. SmartBowHelper BowSmartBowHelper;
  27. public SmartBowHelper MyBowSmartBowHelper => BowSmartBowHelper;
  28. void Start()
  29. {
  30. SmartBowLogger.isDebug = true;
  31. //SmartBowNetwork.SetLocal("192.168.0.108");
  32. SmartBowNetwork.SetLocal("8.155.53.54");
  33. BowSmartBowHelper = SmartBowHelper.NewInstance();
  34. CreateRow("登录", "登录获取用户数据", new[] { "GameID", "ChannelID", "用户名", "密码" }, (values) =>
  35. {
  36. BowSmartBowHelper.Login(values[0], values[1], values[2], values[3], (res) =>
  37. {
  38. if (res.success)
  39. {
  40. Debug.Log("登录成功: " + res.message);
  41. TipText.Show(res.message);
  42. account = values[2];
  43. BowSmartBowHelper.GetUserInfo((res) =>
  44. {
  45. UserInfo userInfo = res.userInfo;
  46. Debug.Log("用户信息: " + JsonConvert.SerializeObject(userInfo));
  47. //渲染UI
  48. StartCoroutine(SmartBowNetwork.LoadSprite(userInfo.avatarUrl, (sprite) =>
  49. {
  50. _imgAvatar.sprite = sprite;
  51. }));
  52. _textNickname.text = userInfo.nickname;
  53. _textGender.text = userInfo.gender == 1 ? "男" : "女";
  54. });
  55. }
  56. else
  57. {
  58. Debug.LogError("登录失败: " + res.message);
  59. TipText.Show(res.message);
  60. return;
  61. }
  62. });
  63. });
  64. CreateRow("登出", "退出用户登录", null, (_) =>
  65. {
  66. BowSmartBowHelper.Logout((success) =>
  67. {
  68. TipText.Show(success ? "登出成功" : "登出失败");
  69. if (success)
  70. {
  71. _imgAvatar.sprite = null;
  72. _textNickname.text = "未登录";
  73. _textGender.text = "";
  74. }
  75. });
  76. });
  77. if (serverIndex == 0)
  78. {
  79. CreateRow("发送验证码", "注册修改密码等需要先发送对应的验证码", new[] { "手机号" }, (values) =>
  80. {
  81. Debug.Log(values + " = " + values[0]);
  82. phoneNumber = values[0];
  83. BowSmartBowHelper.SendPhoneValidateCode(values[0], 0, TipText.Show);
  84. });
  85. // CreateRow("单纯验证", new[] { "手机号", "Code" }, (values) =>
  86. // {
  87. // Debug.Log(values[0]);
  88. // if (int.TryParse(values[1], out int code))
  89. // {
  90. // BowSmartBowHelper.ValidatePhone(values[0], code, TipText.Show);
  91. // }
  92. // else
  93. // {
  94. // TipText.Show("Invalid code format");
  95. // }
  96. // });
  97. }
  98. else if (serverIndex == 1)
  99. {
  100. CreateRow("发送验证码", "注册修改密码等需要先发送对应的验证码", new[] { "邮箱" }, (values) =>
  101. {
  102. email = values[0];
  103. BowSmartBowHelper.SendEmailValidateCode(values[0], 0, TipText.Show);
  104. });
  105. // CreateRow("单纯验证", new[] { "邮箱", "Code" }, (values) =>
  106. // {
  107. // Debug.Log(values[0]);
  108. // if (int.TryParse(values[1], out int code))
  109. // {
  110. // BowSmartBowHelper.ValidatePhone(values[0], code, TipText.Show);
  111. // }
  112. // else
  113. // {
  114. // TipText.Show("Invalid code format");
  115. // }
  116. // });
  117. }
  118. else
  119. {
  120. Debug.LogError("Invalid server index: " + serverIndex);
  121. }
  122. CreateRow("注册", "注册新账号,以用户名注册,可以和手机邮箱一致", new[] { "用户名", serverIndex == 1 ? "邮箱" : "手机号", "Code1", "密码" }, (values) =>
  123. {
  124. if (!int.TryParse(values[2], out int code))
  125. {
  126. TipText.Show("Invalid code format");
  127. return;
  128. }
  129. //国内
  130. if (serverIndex == 0)
  131. {
  132. BowSmartBowHelper.Register(0, values[0], values[3], "", values[1], code, TipText.Show);
  133. }
  134. //国外
  135. else if (serverIndex == 1)
  136. {
  137. BowSmartBowHelper.Register(1, values[0], values[3], values[1], "", code, TipText.Show);
  138. }
  139. else
  140. {
  141. Debug.LogError("Invalid server index: " + serverIndex);
  142. }
  143. });
  144. CreateRow("修改密码", "修改用户名对应的密码", new[] { "用户名", serverIndex == 1 ? "邮箱" : "手机号", "Code2", "新密码" }, (values) =>
  145. {
  146. if (!int.TryParse(values[2], out int code))
  147. {
  148. TipText.Show("Invalid code format");
  149. return;
  150. }
  151. BowSmartBowHelper.ResetPassword(serverIndex, values[0], values[1], code, values[3], TipText.Show);
  152. });
  153. // CreateRow("修改用户名", "修改用户昵称", new[] { "昵称" }, (values) =>
  154. // {
  155. // BowSmartBowHelper.SaveUserName(values[0], TipText.Show);
  156. // });
  157. CreateRow("用户数据", "", new[] { "昵称", "头像url","生日","性别","国家", "省", "市" }, (values) =>
  158. {
  159. UserInfoExtended userInfoExtended = new UserInfoExtended();
  160. userInfoExtended.nickname = values[0];
  161. userInfoExtended.avatarUrl = values[1];//"https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTIWjCZKDf26TYib0Cia8vribsmQChxCkfibXYaPCVW69B7G2f5LUGYly2R6vEib9ic11L9zYBC350D93NZg/132";
  162. userInfoExtended.birthday = values[2];//"1995-01-01";
  163. userInfoExtended.gender = int.TryParse(values[3], out int gender) ? gender : 1;
  164. userInfoExtended.country = values[4];
  165. userInfoExtended.state = values[5];
  166. userInfoExtended.city = values[6];
  167. BowSmartBowHelper.SaveUserInfo(userInfoExtended, TipText.Show);
  168. });
  169. //提示使用
  170. CreateRow("用户注册事项", "修改用户数据,注册后要录入国省市,不然影响排行榜", null, null);
  171. //上传普通的排行榜成绩
  172. CreateRow("上传成绩", "密钥游戏排行记录", new[] { "密钥", "得分" }, (values) =>
  173. {
  174. int score = int.TryParse(values[1], out var s) ? s : 0;
  175. BowSmartBowHelper.UploadSeasonSinglePlayerGameRes(values[0], score, TipText.Show);
  176. });
  177. /**
  178. * 上传赛季pk分数
  179. * @param roomKey pk时候房间id
  180. * @param secret 解析 pk游戏类型密钥
  181. * @param p2ID 对战用户2 ID
  182. * @param gameRes PK游戏结果,0:玩家1胜利;1:玩家2胜利;2:双方平局
  183. */
  184. CreateRow("上传pk成绩", "", new[] { "房间id", "密钥", "对战用户2 ID", "PK游戏结果" }, (values) =>
  185. {
  186. string roomKey = values[0].Trim();
  187. string secret = values[1].Trim();
  188. string p2Str = values[2].Trim();
  189. string gameResStr = values[3].Trim();
  190. int userId2 = int.TryParse(p2Str, out var id2) ? id2 : 0;
  191. int gameRes = int.TryParse(gameResStr, out var res) ? res : 0;
  192. BowSmartBowHelper.UploadSeasonPKGameRes(roomKey, secret, userId2, gameRes, TipText.Show);
  193. });
  194. /**
  195. * 获取用户排行榜
  196. * @param secret 密钥
  197. * @param rankArea 排行区域 3:国,1:省,2市,其他:全球
  198. * @param countryCode
  199. * @param stateCode
  200. * @param cityCode
  201. * @return
  202. */
  203. CreateRow("获取排行榜", "", new[] { "密钥", "排行区域", "国家", "省", "市" }, (values) =>
  204. {
  205. int rankArea = int.TryParse(values[1], out var r) ? r : 0;
  206. BowSmartBowHelper.GetSeasonRankListByGameType(values[0], rankArea, values[2], values[3], values[4], TipText.Show);
  207. });
  208. /**
  209. * 获取用户排行榜以及自定义
  210. * @param secret 密钥
  211. * @param rankArea 排行区域 3:国,1:省,2市,其他:全球
  212. * @param countryCode
  213. * @param stateCode
  214. * @param cityCode
  215. * @param rankType 1是降序,其他是升序(不能小于0)
  216. * @param count 数量:不能小于0
  217. * @return
  218. */
  219. CreateRow("获取我的排名", "", new[] { "密钥", "排行区域", "国家", "省", "市", "排序", "数量" }, (values) =>
  220. {
  221. int rankArea = int.Parse(values[1]);
  222. int rankType = int.Parse(values[5]);
  223. int count = int.Parse(values[6]);
  224. BowSmartBowHelper.GetUserRankByGameType(values[0], rankArea, values[2], values[3], values[4], rankType, count, TipText.Show);
  225. });
  226. // 上传定制字段的排行榜成绩
  227. // userID为账号唯一标识码
  228. // taskID为任务对应id,比如判断射击是0,记忆射击是1
  229. // difficultType为任务难度类型,比如标准是0,进阶是1,专业是2
  230. // modeType为模式类型,比如无任何模式是0,战术模式是1
  231. // deviceType为设备类型,比如M9电子手枪为0
  232. // score为上述userID账户在判断射击标准难度下无任何模式使用M9电子手枪的分数3889
  233. CreateRow("上传成绩", "定制字段游戏数据排行记录", new[] { "密钥2", "任务ID", "难度", "模式", "设备", "得分" }, (values) =>
  234. {
  235. string secret = values[0];
  236. int taskId = int.TryParse(values[1], out var v1) ? v1 : 0;
  237. int difficultType = int.TryParse(values[2], out var v2) ? v2 : 0;
  238. int modeType = int.TryParse(values[3], out var v3) ? v3 : 0;
  239. int deviceType = int.TryParse(values[4], out var v4) ? v4 : 0;
  240. int score = int.TryParse(values[5], out var v5) ? v5 : 0;
  241. BowSmartBowHelper.UploadCustomLeaderboardScore(
  242. secret, taskId, difficultType, modeType, deviceType, score, TipText.Show);
  243. });
  244. //获取定制字段的排行榜
  245. // userID为账号唯一标识码
  246. // taskID为任务对应id,比如判断射击是0,记忆射击是1
  247. // difficultType为任务难度类型,比如标准是0,进阶是1,专业是2
  248. // modeType为模式类型,比如无任何模式是0,战术模式是1
  249. // deviceType为设备类型,比如M9电子手枪为0
  250. // deta排行榜日期类型,比如0是按周筛选下的排名,1为按月,2为按年,-1为不筛选日期
  251. CreateRow("获取排行榜", "定制字段游戏数据排行记录", new[] { "密钥2", "任务ID", "难度", "模式", "设备", "日期" }, (values) =>
  252. {
  253. string secret = values[0];
  254. int taskId = int.TryParse(values[1], out var v1) ? v1 : 0;
  255. int difficultType = int.TryParse(values[2], out var v2) ? v2 : 0;
  256. int modeType = int.TryParse(values[3], out var v3) ? v3 : 0;
  257. int deviceType = int.TryParse(values[4], out var v4) ? v4 : 0;
  258. int deta = int.TryParse(values[5], out var v5) ? v5 : -1;
  259. BowSmartBowHelper.GetCustomLeaderboard(
  260. secret, taskId, difficultType, modeType, deviceType, deta, TipText.Show);
  261. });
  262. }
  263. // 👇 新增:用于同步相同 placeholder 的输入框
  264. private Dictionary<string, List<InputField>> sharedInputs = new Dictionary<string, List<InputField>>();
  265. void CreateRow(string title, string describe, string[] placeholders, System.Action<string[]> onClick)
  266. {
  267. if (placeholders == null) placeholders = new string[0];
  268. GameObject row = Instantiate(rowPrefab, contentRoot);
  269. row.SetActive(true);
  270. Text titleText = row.transform.Find("TitleText").GetComponent<Text>();
  271. Text describeText = row.transform.Find("Describe").GetComponent<Text>();
  272. describeText.text = describe;
  273. Transform contentGroup = row.transform;
  274. Button execButton = contentGroup.Find("ExecButton").GetComponent<Button>();
  275. if(placeholders.Length == 0 && onClick == null)
  276. {
  277. execButton.gameObject.SetActive(false);
  278. }
  279. else
  280. {
  281. execButton.gameObject.SetActive(true);
  282. }
  283. Transform inputTemplate = contentGroup.Find("Input");
  284. inputTemplate.gameObject.SetActive(false);
  285. List<InputField> inputFields = new List<InputField>();
  286. int execIndex = execButton.transform.GetSiblingIndex();
  287. for (int i = placeholders.Length - 1; i >= 0; i--)
  288. {
  289. string placeholder = placeholders[i];
  290. Transform inputTf = Instantiate(inputTemplate, contentGroup);
  291. inputTf.name = "Input" + i;
  292. inputTf.SetSiblingIndex(execIndex);
  293. inputTf.gameObject.SetActive(true);
  294. LayoutElement _layoutElement = inputTf.gameObject.AddComponent<LayoutElement>();
  295. _layoutElement.preferredWidth = 230;
  296. _layoutElement.preferredHeight = 60;
  297. InputField input = inputTf.GetComponent<InputField>();
  298. input.placeholder.GetComponent<Text>().text = placeholder;
  299. // 从本地读取覆盖默认值
  300. string savedValue = PlayerPrefs.GetString($"SmartBowInput_{placeholder}", "");
  301. if (!string.IsNullOrEmpty(savedValue))
  302. {
  303. // input.text = savedValue;
  304. StartCoroutine(SetInputTextNextFrame(input, savedValue));
  305. }
  306. else
  307. {
  308. //默认值
  309. if (placeholder == "GameID")
  310. input.text = gameId;
  311. else if (placeholder == "ChannelID")
  312. input.text = channelId;
  313. else if (placeholder == "密钥2")
  314. StartCoroutine(SetInputTextNextFrame(input, secret2));
  315. }
  316. inputFields.Insert(0, input); // 保持顺序
  317. // 👇 注册同步逻辑
  318. if (!sharedInputs.ContainsKey(placeholder))
  319. sharedInputs[placeholder] = new List<InputField>();
  320. sharedInputs[placeholder].Add(input);
  321. bool isSyncing = false;
  322. input.onValueChanged.AddListener((newValue) =>
  323. {
  324. if (isSyncing) return;
  325. isSyncing = true;
  326. foreach (var otherInput in sharedInputs[placeholder])
  327. {
  328. if (otherInput != input && otherInput.text != newValue)
  329. otherInput.text = newValue;
  330. }
  331. isSyncing = false;
  332. });
  333. input.onEndEdit.AddListener((newValue) =>
  334. {
  335. // 存储到本地
  336. PlayerPrefs.SetString($"SmartBowInput_{placeholder}", newValue);
  337. PlayerPrefs.Save();
  338. });
  339. }
  340. titleText.text = title;
  341. execButton.onClick.RemoveAllListeners();
  342. execButton.onClick.AddListener(() =>
  343. {
  344. var values = inputFields.Select(field => field.text).ToArray();
  345. onClick.Invoke(values);
  346. });
  347. StartCoroutine(RefreshLayoutNextFrame(row.transform));
  348. }
  349. IEnumerator RefreshLayoutNextFrame(Transform root)
  350. {
  351. yield return null; // 等待一帧
  352. LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)root);
  353. }
  354. IEnumerator SetInputTextNextFrame(InputField input, string text)
  355. {
  356. yield return new WaitForSeconds(1.0f);//new WaitForEndOfFrame(); // 等待布局初始化
  357. input.text = text;
  358. }
  359. }
  360. public static class TipText
  361. {
  362. public static void Show(string message)
  363. {
  364. Debug.Log("[提示] " + message);
  365. // 或者调用 UI 展示
  366. }
  367. public static void Show(RequestResult result)
  368. {
  369. //Show(result.code + " = " + result.msg);
  370. string dataStr = result.data != null ? JsonConvert.SerializeObject(result.data, Formatting.Indented) : "null";
  371. Show($"{result.code} = {result.msg} = Data:{dataStr}");
  372. }
  373. }
  374. }