ch_pvp.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. import ch_util from "../ch_util";
  2. /**
  3. * pvp扩展玩法 基于 chsdk
  4. */
  5. export type pvp_player = { head: string, nickName: string, uid: number, hid: number, province: string, pvp: number, rank: number };
  6. export type pvp_own_data<T> = { extends: T, type: 0 | 1 | 2, time: number, own: pvp_player };
  7. export type pvp_data<T> = { extends: T, other: pvp_player, own: pvp_player, type?: 0 | 1 | 2, status?: 0 | 1 | 2, time?: number, reward?: number, pvpId?: string };
  8. export type pvp_result = { other: { curRank: number, rank: number, curScore: number, score: number }, own: { curRank: number, rank: number, curScore: number, score: number } };
  9. class ch_pvp {
  10. private readonly _set_url: string = '/user/setPvpSceneData';
  11. private readonly _match_url: string = '/user/startPvpMatch';
  12. private readonly _finish_url: string = '/user/pvpFinishAction';
  13. private readonly _record_url: string = '/user/pvpChallengeRecord';
  14. private static _instance: ch_pvp;
  15. public static getInstance(): ch_pvp {
  16. if (!this._instance) this._instance = new ch_pvp();
  17. return this._instance;
  18. }
  19. /**
  20. * 设置自己的 PVP 擂台数据
  21. * 该方法用于更新当前用户在 PVP 擂台上的数据。数据将根据传入的 extend 参数进行更新,
  22. * 并返回一个包含操作状态和可能错误信息的 Promise。
  23. * @param extend - 一个pvp擂台数据对象,包含要更新的具体数据。
  24. * @returns 一个 Promise,解析为一个包含以下属性的对象:
  25. * - code: 操作的结果状态。0 表示成功,其他值表示不同的错误类型。
  26. * - err: 可选字符串,指示错误信息(如果有)。
  27. */
  28. public async setSceneData<T extends { [key: string]: any }>(extend: T): Promise<{ code: number, err?: string }> {
  29. const check = chsdk.check_req_time('setSceneData');
  30. if (check) return check;
  31. const body = { extends: ch_util.stringify(extend) };
  32. const ret = await chsdk.makePostTokenRequest(chsdk.getUrl(this._set_url), body);
  33. if (ret.code != chsdk.code.success) {
  34. chsdk.log.warn(ret);
  35. } else {
  36. chsdk.log.log(`PVP擂台数据上报成功`);
  37. if (!this._own) {
  38. await this.getOwn<T>();
  39. } else {
  40. this._own.extends = extend;
  41. }
  42. }
  43. return ret;
  44. }
  45. /**
  46. * 开始匹配
  47. * @param uid (可选)具体好友的uid,默为空
  48. * @returns null 匹配失败
  49. *
  50. * pvp_data<T>
  51. extends PVP 擂台数据
  52. * other 台主信息
  53. * own 自己的信息
  54. * head:头像, nickName:名字, uid:id, hid:省id, province:省名, pvp:pvp排位分值, rank:pvp排行榜名次
  55. */
  56. public async startMatch<T extends { [key: string]: any }>(uid?: number | null): Promise<pvp_data<T> | null> {
  57. const check = chsdk.check_req_time('startMatch');
  58. if (check) return null;
  59. const ret = await chsdk.makePostTokenRequest(chsdk.getUrl(this._match_url), { uid: uid ? uid.toString() : '' });
  60. if (ret.code != chsdk.code.success) {
  61. chsdk.log.warn(ret);
  62. return null;
  63. } else {
  64. const data = ret.data.data;
  65. data.other.uid = Number.parseInt(data.other.uid);
  66. data.other.hid = Number.parseInt(data.other.hid);
  67. data.other.province = chsdk.provinceCode2Name(data.other.hid);
  68. data.own.uid = Number.parseInt(data.own.uid);
  69. data.own.hid = Number.parseInt(data.own.hid);
  70. data.own.province = chsdk.provinceCode2Name(data.own.hid);
  71. return { extends: ch_util.parse(data.extends) as T, other: data.other, own: data.own }
  72. }
  73. }
  74. /**从一条记录开始匹配,用于复仇*/
  75. public async startMatchRecord<T extends { [key: string]: any }>(pd: pvp_data<T>): Promise<pvp_data<T> | null> {
  76. const check = chsdk.check_req_time('startMatch');
  77. if (check) return null;
  78. let pp = await this.startMatch<T>(pd.other.uid);
  79. if (!pp) return null;
  80. pp.extends = pd.extends;
  81. pp.pvpId = pd.pvpId;
  82. return pp;
  83. }
  84. /**
  85. * 完成pvp上报
  86. * @param otherUid 对方uid
  87. * @param status 0:挑战失败 1:挑战胜利
  88. * @param ext PVP 擂台数据
  89. * @param serverData 服务器处理排行数据,订阅消息
  90. * ..ownValue 增减自己排位分值
  91. * ..otherValue 增减对方排位分值
  92. * ..msg 自定义的订阅消息
  93. * @param pvpId 复仇id
  94. * @returns 对战结果
  95. * other 对方的排名和分数变化
  96. * own 自己的排名和分数变化
  97. * curRank 当前排名(变动后)
  98. curScore 当前分数(变动后)
  99. rank 名数变动
  100. score 分数变动
  101. */
  102. public async finish<T extends { [key: string]: any }>(otherUid: number, status: 0 | 1, ext: T,
  103. serverData: { ownValue?: number, otherValue?: number, msg?: string }
  104. , pvpId?: string
  105. ): Promise<pvp_result> {
  106. const check = chsdk.check_req_time('finish');
  107. if (check) return null;
  108. const body = { otherUid: otherUid.toString(), status: status, extends: ch_util.stringify(ext), serverData: ch_util.stringify(serverData), pvpId: pvpId };
  109. const ret = await chsdk.makePostTokenRequest(chsdk.getUrl(this._finish_url), body);
  110. if (ret.code != chsdk.code.success) {
  111. chsdk.log.warn(ret);
  112. return null;
  113. } else {
  114. const data = ret.data.data;
  115. chsdk.log.log(`pvp结果数据上报成功,结算:`, data);
  116. return data;
  117. }
  118. }
  119. private _own: any;
  120. /**获取自己的pvp擂台数据*/
  121. public async getOwn<T extends { [key: string]: any }>(): Promise<pvp_own_data<T> | null> {
  122. if (!this._own) await this.getRecords<T>(3, false);
  123. return this._own;
  124. }
  125. //
  126. private _cache_records: any | null = null;
  127. private _cache_time: number;
  128. private get_cache_records(): any | null {
  129. if (chsdk.date.now() - this._cache_time > 6e4) return null;
  130. return this._cache_records;
  131. }
  132. /**
  133. * 获取pvp对战记录
  134. * @param type 0:全部纪录 1:被挑战的记录信息(默认) 2:挑战别人的记录 3:不需要纪录
  135. * @param cache 默认为true,优先缓存拿数据,缓存存在一分钟
  136. * @returns own:自己的PVP 擂台数据
  137. * list:交互纪录
  138. * extends PVP 擂台数据
  139. * reward 奖励惩罚排位分值,由于serverData中得来
  140. * type 0:自己的数据 1:被挑战的记录信息 2:挑战别人的记录
  141. * status 0:挑战失败 1:挑战胜利 2:复仇成功
  142. * time 时间
  143. * pvpId pvp复仇id
  144. * other 对方信息
  145. * own 自己信息
  146. */
  147. public async getRecords<T extends { [key: string]: any }>(typeId: 0 | 1 | 2 | 3 = 1, cache: boolean = true): Promise<{
  148. own: pvp_own_data<T>,
  149. list: pvp_data<T>[],
  150. }
  151. > {
  152. if (cache) {
  153. const data = this.get_cache_records();
  154. if (data) return data;
  155. }
  156. const check = chsdk.check_req_time('getRecords');
  157. if (check) return null;
  158. const ret = await chsdk.makePostTokenRequest(chsdk.getUrl(this._record_url), { typeId: typeId });
  159. if (ret.code != chsdk.code.success) {
  160. chsdk.log.warn(ret);
  161. return null;
  162. } else {
  163. let data = ret.data.data;
  164. if (data.own) {
  165. const d = data.own;
  166. d.extends = ch_util.parse(d.extends) as T;
  167. d.own.uid = Number.parseInt(d.own.uid);
  168. d.own.hid = Number.parseInt(d.own.hid);
  169. d.own.province = chsdk.provinceCode2Name(d.own.hid);
  170. } else {
  171. data.own = null;
  172. }
  173. data.list ||= [];
  174. for (let i = 0; i < data.list.length; i++) {
  175. const d = data.list[i];
  176. d.extends = ch_util.parse(d.extends) as T;
  177. d.own.uid = Number.parseInt(d.own.uid);
  178. d.own.hid = Number.parseInt(d.own.hid);
  179. d.own.province = chsdk.provinceCode2Name(d.own.hid);
  180. d.other.uid = Number.parseInt(d.other.uid);
  181. d.other.hid = Number.parseInt(d.other.hid);
  182. d.other.province = chsdk.provinceCode2Name(d.other.hid);
  183. }
  184. this._own = data.own;
  185. this._cache_records = data;
  186. this._cache_time = chsdk.date.now();
  187. return data;
  188. }
  189. }
  190. /**
  191. * 获取pvp排位分值榜单
  192. * @returns
  193. */
  194. public async getRank(): Promise<{
  195. list: {
  196. head: string;
  197. nickName: string;
  198. rank: number;
  199. score: number;
  200. userId: number;
  201. [key: string]: any;
  202. }[], ower: {
  203. head: string;
  204. nickName: string;
  205. rank: number;
  206. score: number;
  207. userId: number;
  208. [key: string]: any;
  209. }
  210. }> {
  211. const d = await chsdk.loadRankData('pvp', 1, 100, true);
  212. return { list: d.data.list, ower: d.data.own };
  213. }
  214. /**
  215. * 分享pvp数据,邀请对战
  216. * @param player 玩家自己信息
  217. * @param extend (可选)pvp关卡等数据
  218. * @param title 分享显示标题
  219. * @param imageUrl 分享显示图片
  220. */
  221. public async sharePvp<T extends { [key: string]: any }>(player: pvp_player, extend?: T, title?: string, imageUrl?: string) {
  222. chsdk.shareAppMessage(title, '', imageUrl, ch_util.stringify({ type: 'pvp', player: player, extends: extend }));
  223. }
  224. /**
  225. *获取从好友分享的pvp数据进入游戏的数据
  226. */
  227. public getSharePvpExtends<T extends { [key: string]: any }>(): { player: pvp_player, extend?: T } {
  228. const query = chsdk.getQuery();
  229. if (!query) return null;
  230. const message = query.message;
  231. if (!message) return null;
  232. const data = ch_util.parse(message);
  233. if (!data) return null;
  234. if (data.type != 'pvp') return null;
  235. query.message = null;
  236. return { player: data.player, extend: data.extends as T };
  237. }
  238. }
  239. //
  240. export default ch_pvp.getInstance();