├── .browserslistrc ├── .gitignore ├── README.md ├── babel.config.js ├── dist ├── favicon.ico ├── globle.js ├── globle.js.gz ├── index.html └── static │ ├── css │ ├── app.d07cd864.css │ ├── chunk-vendors.61510d44.css │ └── chunk-vendors.61510d44.css.gz │ ├── fonts │ ├── ionicons.143146fa.woff2 │ ├── ionicons.99ac3308.woff │ └── ionicons.d535a25a.ttf │ ├── img │ └── ionicons.a2c4a261.svg │ └── js │ ├── app.ae58f1dd.js │ ├── app.ae58f1dd.js.gz │ ├── app.ae58f1dd.js.map │ ├── chunk-vendors.6577b8b2.js │ ├── chunk-vendors.6577b8b2.js.gz │ └── chunk-vendors.6577b8b2.js.map ├── package.json ├── public ├── favicon.ico ├── globle.js └── index.html ├── src ├── App.vue ├── assets │ └── logo.png ├── components │ ├── bag.vue │ ├── eqs.vue │ ├── market.vue │ ├── monster-map.vue │ ├── pet-catch-ctrl.vue │ ├── pet.vue │ ├── screens.vue │ ├── shop.vue │ ├── skill-map.vue │ ├── skills.vue │ ├── tasks.vue │ └── userinfo.vue ├── config.js ├── libs │ ├── YunDingOnlineSDK.js │ ├── protocol.js │ ├── regHooks.js │ └── tools.js ├── main.js ├── mixins.js ├── router │ └── index.js ├── store │ └── index.js └── views │ ├── Home.vue │ └── User.vue └── vue.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | package-lock.json 4 | yarn.lock 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YunDingGameOnline 2 | 闲暇时间拿网页游戏SDK练手 3 | 4 | 基于 [云顶修仙摸鱼页游](http://yundingxx.com:8888/) 的后端服务 5 | 6 | [游玩](http://yundingxx.kidsongs.top) 7 | 8 | --- 9 | 10 | ##### 2020-10-11 机制更新 11 | ###### 加入自动获取刷新验证码,避免卡登陆 12 | ###### 修复一回合解决不了战斗会无限刷新的问题 13 | ###### 加入无限挂机开关 14 | --- 15 | ##### 2020-10-10 问题修复 16 | ###### 1.去掉自动升级,有的人要卡小号; 17 | ###### 2.每日计划问题多多,先去掉了; 18 | --- 19 | ##### 2020-09-30 重大更新 - 无限挂机 20 | ###### 1.掉线重新组队,支持按原操作的组队阵容、副本,一旦掉队自动重连,支持插队判断。使用此功能需要全队手动重新组队; 21 | ###### 2.加入每日计划打副本,按主页面访问时间每24小时自动切换勾选的副本打每日到没奖励。使用此功能需要队长手动切换挂机副本至少一次; 22 | ###### 3.加入小于49级自动升级; 23 | ###### 4.去掉了server酱; 24 | ###### 5.支持了隐藏队伍; 25 | --- 26 | ##### 2020-09-07 27 | ###### 加入宠物锁定,锁定的宠物不合成、不丢弃(合宠的时候记得去掉); 28 | --- 29 | ##### 2020-09-06 30 | ###### 修复自动合成的BUG 31 | --- 32 | ##### 2020-09-05 33 | ###### BUG修复;去掉了5毛钱特效;加入自动捕捉拥有指定技能的宠物然后合成,会一直循环直到宠物满(没钱合)。步骤:先退出队伍(最好再重新加载一下),然后选定需要的技能,再点击自动合成就开始了。全程隐藏队伍,自动切换副本,丢宠判定不丢神兽和5技能及以上的,但是合成只判定了不合成神兽,如果有除神兽之外不想被合成的宠请不要使用此功能 34 | --- 35 | ##### 2020-09-04 36 | ###### BUG修复;捕捉功能修改; 37 | --- 38 | ##### 2020-09-04 from yuanye Merge. 39 | ###### 背包里面的物品信息面板 添加 显示/隐藏 切换;删除多余代码;物品类型补充 40 | --- 41 | ##### 2020-09-03 from yuanye Merge. 42 | ###### 添加批量分解功能;添加系统商城; 43 | --- 44 | ##### 2020-09-03 45 | ###### 加入副本资料展示;优化部分交互;同步作者修改;更新地图数据;增加魔灵提示;延长掉线刷新重连时间; 46 | --- 47 | ##### 2020-09-02 48 | ###### 功能模块化;加入整理背包 49 | --- 50 | ##### 2020-09-01 51 | ###### 加入出售功能;加入玩家市场,智能物品分类、价格排序、按数量购买、商品检索;增加技能图鉴、怪物图鉴;怪物图鉴增加搜索功能 52 | --- 53 | ##### 2020-08-31 54 | ###### 优化UI;优化战斗信息显示;修复队伍任务数量错误问题;同步修复弹幕显示;优化抓宠/丢宠名称显示;加入所有技能升级;加入任务领取/完成;加入主副宠切换; 55 | --- 56 | ##### 2020-08-28 57 | ###### 增加抓宠;优化了战斗信息显示; 58 | --- 59 | ##### 2020-08-27 60 | ###### 增加弹幕开关;增加server酱推送掉队通知;增加了栅格化布局,移动端也可以看得舒服;修复其他问题; 61 | --- 62 | ##### 2020-08-26 63 | ###### 聊天室修改为弹幕 64 | --- 65 | ##### 2020-08-25 66 | ###### 增加修炼显示,增加自定义修炼技能次数;修复地图队伍过多包长度解析错误问题;增加了聊天室(目前会接收所有消息);加入简易登出实现 67 | --- 68 | ##### 2020-08-20 69 | ###### 增加自动挖宝功能 70 | --- 71 | ##### 2020-08-08 from yuanye Merge. 72 | ###### 添加物品合成功能;人物信息展示;宠物相关功能;修复装备属性显示错乱的错误;优化了搜索功能 73 | --- 74 | ##### 2020-07-24 from yuanye Merge. 75 | ###### 优化了背包功能,追加单个物体操作、批量使用分解(出售还没做);优化了战斗收益UI;修复了领取任务后没刷新任务的问题; 76 | --- 77 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flywor/YunDingGameOnline/0d25e5b1523d26156213f2495762814e6236f15d/dist/favicon.ico -------------------------------------------------------------------------------- /dist/globle.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flywor/YunDingGameOnline/0d25e5b1523d26156213f2495762814e6236f15d/dist/globle.js.gz -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 深入响应式原理 —— Vue.js
-------------------------------------------------------------------------------- /dist/static/css/app.d07cd864.css: -------------------------------------------------------------------------------- 1 | #app,body,html{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:#2c3e50;width:100%;height:100%;padding:0}.ivu-card-body{width:100%;height:calc(100% - 51px);padding:8px!important}.moling{position:fixed;top:10px;font-size:60px;z-index:999999999;color:#aa2121;transform:translate(-50%)}@-webkit-keyframes molingframe{0%{text-shadow:0 0 4px #fff,0 -5px 4px #ff3,2px -10px 6px #fd3,-2px -15px 11px #f80,2px -25px 36px #f20}25%{text-shadow:0 0 4px #fff,2px -7px 6px #ff3,2px -12px 8px #fd3,-3px -20px 11px #f80,4px -30px 22px #f20}50%{text-shadow:0 0 4px #fff,2px -10px 8px #ff3,2px -14px 10px #fd3,-4px -25px 11px #f80,4px -35px 25px #f20}75%{text-shadow:0 0 4px #fff,2px -7px 6px #ff3,2px -12px 8px #fd3,-3px -20px 11px #f80,4px -30px 22px #f20}to{text-shadow:0 0 4px #fff,0 -5px 4px #ff3,2px -10px 6px #fd3,-2px -15px 11px #f80,2px -25px 36px #f20}}@keyframes molingframe{0%{text-shadow:0 0 4px #fff,0 -5px 4px #ff3,2px -10px 6px #fd3,-2px -15px 11px #f80,2px -25px 36px #f20}25%{text-shadow:0 0 4px #fff,2px -7px 6px #ff3,2px -12px 8px #fd3,-3px -20px 11px #f80,4px -30px 22px #f20}50%{text-shadow:0 0 4px #fff,2px -10px 8px #ff3,2px -14px 10px #fd3,-4px -25px 11px #f80,4px -35px 25px #f20}75%{text-shadow:0 0 4px #fff,2px -7px 6px #ff3,2px -12px 8px #fd3,-3px -20px 11px #f80,4px -30px 22px #f20}to{text-shadow:0 0 4px #fff,0 -5px 4px #ff3,2px -10px 6px #fd3,-2px -15px 11px #f80,2px -25px 36px #f20}}.home[data-v-6a0e8444]{padding:16px;position:relative;overflow-x:hidden;height:100%}.home .formitem[data-v-6a0e8444]{width:100px}.home .dm[data-v-6a0e8444]{word-break:keep-all;position:fixed;z-index:9999;-webkit-animation:dmframe-data-v-6a0e8444 20s linear;animation:dmframe-data-v-6a0e8444 20s linear;top:0;left:100%}@-webkit-keyframes dmframe-data-v-6a0e8444{0%{left:100%}to{left:-100%}}@keyframes dmframe-data-v-6a0e8444{0%{left:100%}to{left:-100%}}.home .card-container[data-v-6a0e8444]{width:100%}.home .card-container .card[data-v-6a0e8444]{display:inline-block;width:100%;height:430px;margin:0 8px 8px 0;vertical-align:top}.home iframe[data-v-6a0e8444]{width:100%;height:100%;border:0}.good-header{display:flex;justify-content:space-between;align-items:center;padding-right:32px}.good-header .ivu-input-with-suffix,.good-info{font-size:12px}.good-info{box-shadow:0 3px 10px;background:#fff;opacity:.9;width:100%;display:flex;justify-content:space-between;padding:10px;position:fixed;z-index:99}.good-info .close-btn{position:absolute;left:0;top:0}.goods-box{padding-bottom:180px}.goods-box .ivu-badge{width:48%;margin:0 1%}.goods-box .ivu-badge .good-name{margin:0 .3% 5px 0;width:100%;font-size:12px!important}.goods-box .ivu-badge .ivu-badge-count{font-size:8px;top:2px;right:10px}.info-box{padding-right:20px;padding-top:20px}.info-box .basci-info,.info-box .eq-info{display:flex;flex-direction:column;align-items:flex-start}.button-box{display:flex;flex-direction:column}.button-box .ivu-btn{margin-top:2px!important}.pet-btn[data-v-90cf5b4e]{padding-top:5px;display:flex!important;justify-content:center}.pet-btn .ivu-btn[data-v-90cf5b4e]{padding:0 6px!important}.slelect-box[data-v-90cf5b4e],.slelect-box p[data-v-90cf5b4e]{padding:10px}.goods-box[data-v-5512574c]{padding-bottom:180px}.goods-box .good-name[data-v-5512574c]{margin:0 .5% 5px 0;width:49%;font-size:12px!important}.info-box[data-v-5512574c]{box-shadow:0 3px 10px;font-size:12px;background:#fff;opacity:.9;width:100%;display:flex;justify-content:space-between;padding:10px;position:fixed;z-index:99;bottom:0}.info-box .basci-info[data-v-5512574c]{display:flex;flex-direction:column;align-items:flex-start}.user[data-v-709aa2bc]{width:100%;height:100%}.fight-gains ul li[data-v-709aa2bc],.user p[data-v-709aa2bc]{display:flex;justify-content:space-between}.fight-gains ul li[data-v-709aa2bc]{padding:5px 0}.fight-gains ul .goods[data-v-709aa2bc]{flex-direction:column}.fight-gains ul .goods li[data-v-709aa2bc]{padding:2px 0 2px 10px;color:#42b983}.br{height:5px;width:100%}.ivu-modal-header{padding:8px 4px!important}.ivu-modal-close{top:0!important}.ivu-modal-footer{padding:4px!important}.ivu-modal-body{padding:0!important}.eq-img{width:20px;vertical-align:middle;margin-right:10px}.ivu-tabs-bar{margin-bottom:0!important}.ivu-tabs-bar .ivu-tabs-tab{padding:8px 5px!important}.ivu-table-tbody{font-size:12px}.ivu-table-tbody .ivu-table-column-center{height:36px}.ivu-table-tbody .ivu-table-column-center .ivu-table-cell{padding:0} -------------------------------------------------------------------------------- /dist/static/css/chunk-vendors.61510d44.css.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flywor/YunDingGameOnline/0d25e5b1523d26156213f2495762814e6236f15d/dist/static/css/chunk-vendors.61510d44.css.gz -------------------------------------------------------------------------------- /dist/static/fonts/ionicons.143146fa.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flywor/YunDingGameOnline/0d25e5b1523d26156213f2495762814e6236f15d/dist/static/fonts/ionicons.143146fa.woff2 -------------------------------------------------------------------------------- /dist/static/fonts/ionicons.99ac3308.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flywor/YunDingGameOnline/0d25e5b1523d26156213f2495762814e6236f15d/dist/static/fonts/ionicons.99ac3308.woff -------------------------------------------------------------------------------- /dist/static/fonts/ionicons.d535a25a.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flywor/YunDingGameOnline/0d25e5b1523d26156213f2495762814e6236f15d/dist/static/fonts/ionicons.d535a25a.ttf -------------------------------------------------------------------------------- /dist/static/js/app.ae58f1dd.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flywor/YunDingGameOnline/0d25e5b1523d26156213f2495762814e6236f15d/dist/static/js/app.ae58f1dd.js.gz -------------------------------------------------------------------------------- /dist/static/js/chunk-vendors.6577b8b2.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flywor/YunDingGameOnline/0d25e5b1523d26156213f2495762814e6236f15d/dist/static/js/chunk-vendors.6577b8b2.js.gz -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yundingonline", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build" 8 | }, 9 | "dependencies": { 10 | "compression-webpack-plugin": "^4.0.0", 11 | "core-js": "^3.6.5", 12 | "view-design": "^4.3.2", 13 | "vue": "^2.6.11", 14 | "vue-router": "^3.2.0", 15 | "vuex": "^3.4.0" 16 | }, 17 | "devDependencies": { 18 | "@vue/cli-plugin-babel": "^4.4.0", 19 | "@vue/cli-service": "^4.4.0", 20 | "less": "^3.0.4", 21 | "less-loader": "^5.0.0", 22 | "vue-template-compiler": "^2.6.11" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flywor/YunDingGameOnline/0d25e5b1523d26156213f2495762814e6236f15d/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 深入响应式原理 —— Vue.js 9 | 10 | 11 | 12 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 16 | 32 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flywor/YunDingGameOnline/0d25e5b1523d26156213f2495762814e6236f15d/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/bag.vue: -------------------------------------------------------------------------------- 1 | 165 | 304 | -------------------------------------------------------------------------------- /src/components/eqs.vue: -------------------------------------------------------------------------------- 1 | 27 | 56 | -------------------------------------------------------------------------------- /src/components/market.vue: -------------------------------------------------------------------------------- 1 | 69 | 108 | -------------------------------------------------------------------------------- /src/components/monster-map.vue: -------------------------------------------------------------------------------- 1 | 58 | 92 | -------------------------------------------------------------------------------- /src/components/pet-catch-ctrl.vue: -------------------------------------------------------------------------------- 1 | 57 | 338 | -------------------------------------------------------------------------------- /src/components/pet.vue: -------------------------------------------------------------------------------- 1 | 202 | 412 | -------------------------------------------------------------------------------- /src/components/screens.vue: -------------------------------------------------------------------------------- 1 | 23 | 42 | -------------------------------------------------------------------------------- /src/components/shop.vue: -------------------------------------------------------------------------------- 1 | 33 | 76 | -------------------------------------------------------------------------------- /src/components/skill-map.vue: -------------------------------------------------------------------------------- 1 | 55 | 88 | -------------------------------------------------------------------------------- /src/components/skills.vue: -------------------------------------------------------------------------------- 1 | 46 | 88 | -------------------------------------------------------------------------------- /src/components/tasks.vue: -------------------------------------------------------------------------------- 1 | 40 | 52 | -------------------------------------------------------------------------------- /src/components/userinfo.vue: -------------------------------------------------------------------------------- 1 | 13 | 60 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | "core": { 3 | "ext_url": "https://github.com/imdong/YunDingOnlineSDK/raw/master/auto_login.user.js", 4 | "official_login": "http://yundingxx.com:3366/login" 5 | }, 6 | "maps": window.globalMaps 7 | } -------------------------------------------------------------------------------- /src/libs/YunDingOnlineSDK.js: -------------------------------------------------------------------------------- 1 | import Protocol from './protocol' 2 | // 调试模式 3 | let DEBUG = false; 4 | 5 | /** 6 | * 一些常量 7 | */ 8 | const JS_WS_CLIENT_TYPE = 'js-websocket'; 9 | const JS_WS_CLIENT_VERSION = '0.0.1'; 10 | 11 | /** 12 | * 返回消息状态码 13 | */ 14 | const RES_OK = 200; // 成功 15 | const RES_FAIL = 500; // 失败 16 | const RES_OLD_CLIENT = 501; // 客户端版本不符 17 | 18 | const gapThreshold = 100; // heartbeat gap threashold 19 | 20 | /** 21 | * {object} 默认配置 22 | */ 23 | let default_config = { 24 | gameHost: 'yundingxx.com', 25 | gameProtocol: 'ws', 26 | loginPort: 3014, 27 | gamePort: 3052, 28 | loginServer: null, 29 | gameServer: null, 30 | socketPathTpl: '{protocol}://{host}:{port}/' 31 | }; 32 | 33 | let Package = Protocol.Package, 34 | Message = Protocol.Message; 35 | 36 | /** 37 | * 工具类 38 | */ 39 | let Tool = { 40 | /** 41 | * 替换字符串中的变量占位符 42 | * 43 | * @param {string} str 需要替换的字符串 44 | * @param {object} replaceMaps 替换关系 45 | */ 46 | replaceParams: function (str, replaceMaps) { 47 | return str.replace(/{([^}]+)}/g, function (full_match, key) { 48 | return replaceMaps[key] || full_match; 49 | }); 50 | } 51 | } 52 | 53 | /** 54 | * Hooks 默认的 55 | */ 56 | let CoreHooks = { 57 | /** 58 | * 登录游戏成功回调 59 | * @param {*} data 60 | */ 61 | onLoginGame: function (data) { 62 | if (data.code != RES_OK) { 63 | DEBUG && console.error('onLoginGame', data.msg); 64 | return; 65 | } 66 | 67 | this.user_info = Object.assign(this.user_info, data.data); 68 | }, 69 | /** 70 | * 主要是用于保存数据 71 | * @param {*} data 72 | */ 73 | onSaveData: function (data) { 74 | if (data.code != RES_OK) { 75 | DEBUG && console.error('onLoginGame', data.msg || data); 76 | return; 77 | } 78 | 79 | let datas = data.data || data, 80 | save_keys = ['map', 'myInfo', 'players', 'userTasks', 'wordLogds', 'team', 'teams', 'screens', 'initData']; 81 | save_keys.forEach((key) => { 82 | if (!datas[key]) { 83 | return; 84 | } 85 | this.user_info[key] = datas[key]; 86 | 87 | if (key == 'map') { 88 | this.user_info.mid = datas.map.id; 89 | } 90 | }) 91 | } 92 | } 93 | 94 | // 给Hook绑定 Mark 95 | Object.keys(CoreHooks).forEach((name) => { 96 | CoreHooks[name].hookMark = 'Core.' + name; 97 | }); 98 | 99 | /** 100 | * YunDingXX Online API 101 | * 102 | * @param {object} config 配置信息 103 | */ 104 | let GameApi = function (config) { 105 | // 加载配置 106 | if ('object' == typeof config || 'undefined' == typeof config) { 107 | this.config = Object.assign(default_config, config); 108 | } 109 | 110 | // 初始化配置 111 | this.initConfig(); 112 | }; 113 | 114 | // 设置调试模式 115 | GameApi.isDEBUG = function () { 116 | DEBUG = true; 117 | } 118 | 119 | /** 120 | * 初始化配置信息 121 | */ 122 | GameApi.prototype.initConfig = function () { 123 | // WebSocket 链接对象 124 | this.socket = null; 125 | 126 | // 用于标记自己要停止 127 | this.isStop = false; 128 | 129 | // 玩家信息都存在这里 渲染视图请读取这里 130 | this.email = ''; 131 | this.password = ''; // 用于自动重连 132 | this.user_info = {}; 133 | 134 | // 登录 Token 我猜你不会偷这个吧? 135 | this.token = null; 136 | 137 | // 生成服务器链接地址 138 | if (!this.config.loginServer) { 139 | this.config.loginServer = this.getSocketServer(this.config.loginPort); 140 | } 141 | 142 | // 消息处理分发 143 | this.messageHandlers = []; 144 | this.messageHandlers[Package.TYPE_HANDSHAKE] = this.onHandshake; 145 | this.messageHandlers[Package.TYPE_HEARTBEAT] = this.onHeartbeat; 146 | this.messageHandlers[Package.TYPE_DATA] = this.onData; 147 | this.messageHandlers[Package.TYPE_KICK] = this.onKick; 148 | 149 | // 维持心跳 150 | this.reqId = 1; 151 | this.heartbeatInterval = 0; 152 | this.heartbeatId = null; 153 | this.heartbeatTimeoutId = null; 154 | this.heartbeatTimeout = 0; 155 | this.xyUpdateIntervalId = 0; 156 | 157 | // 路由字典 158 | this.dict = {}; 159 | this.abbrs = {}; 160 | 161 | // 协议相关??? 162 | this.protoVersion = 0; 163 | this.serverProtos = {}; 164 | this.clientProtos = {}; 165 | 166 | // 一些无法命名的回调 167 | this.initCallback = null; // 初始化完毕的回调 168 | this.callbacks = []; // 根据 SeqId 来区分回调(如果有) 169 | this.callRoutes = []; // 和上面一样 只是区分 Route 170 | 171 | // 注册各路由的回调钩子 172 | this.hookHandlers = GameApi.regHookHandlers; 173 | } 174 | 175 | /** 176 | * 用于批量提前注册,避免每次创建都要注册一次 177 | */ 178 | GameApi.regHookHandlers = { 179 | "onAdd": [], //* 玩家上线? 180 | "onLeave": [], //* 玩家离开 181 | "onChatMsg": [], //* 收到消息 182 | "onMyTeamReload": [ // 重新载入队伍 183 | CoreHooks.onSaveData 184 | ], 185 | "onStartBat": [ // 战斗开始 186 | CoreHooks.onSaveData 187 | ], 188 | "onRoundBatEnd": [ // 战斗结束 189 | 190 | ], 191 | "chat.chatHandler.send": [], // 发送消息 192 | "connector.entryHandler.enter": [], 193 | "connector.fationHandler.applyForFation": [], // 申请工会 194 | "connector.fationHandler.closeUserTask": [], // 放弃任务 195 | "connector.fationHandler.createFation": [], // 创建工会 196 | "connector.fationHandler.donateFationFunds": [], // 捐赠 197 | "connector.fationHandler.doneFationApply": [], // 同意入会 198 | "connector.fationHandler.getFationApply": [], // 查看申请 199 | "connector.fationHandler.getFationList": [], // 打开工会列表 200 | "connector.fationHandler.getFationTask": [], // 领取任务 201 | "connector.fationHandler.initFation": [], // 初始聚仙阁楼页面 202 | "connector.fationHandler.leaveFation": [], // 脱离工会 203 | "connector.fationHandler.showFationUserList": [], // 查看工会人员 204 | "connector.fationHandler.upFation": [], // 升级工会 205 | "connector.fationHandler.upFationUserSkill": [console.log], // 点技能 206 | "connector.fationHandler.upUserFationLevel": [], // 升降职位 207 | "connector.loginHandler.login": [ // 登录 Token 208 | CoreHooks.onSaveData 209 | ], 210 | "connector.playerHandler.byGoodsToSystem": [], // 购买系统物品 211 | "connector.playerHandler.byPalyerGoods": [], // 购买玩家物品 212 | "connector.playerHandler.getCopyTask": [], 213 | "connector.playerHandler.getPlayerSellGoods": [], // 初始仙坊集市 214 | "connector.playerHandler.init": [], 215 | "connector.playerHandler.move": [], // 移动 216 | "connector.playerHandler.moveToNewMap": [ // 移动至新地图 217 | CoreHooks.onSaveData 218 | ], 219 | "connector.playerHandler.nextMap": [], // 切换地图 220 | "connector.playerHandler.payUserTask": [], // 完成任务 221 | "connector.playerHandler.sellGoods": [], 222 | "connector.playerHandler.sendMsg": [], 223 | "connector.playerHandler.wearUserEquipment": [], // 佩戴拆卸装备 224 | "connector.systemHandler.getRankList": [], // 排行榜 225 | "connector.systemHandler.getSystemSellGoods": [], // 初始系统中出售物品 226 | "connector.systemHandler.getSystemTask": [], // 初始任务中心 227 | "connector.systemHandler.subSystemMsg": [], // 初始任务中心 228 | "connector.teamHandler.addTeam": [], // 加入队伍 229 | "connector.teamHandler.createdTeam": [ // // 创建队伍 230 | CoreHooks.onSaveData 231 | ], 232 | "connector.teamHandler.getAllCombatScreen": [ // 获取战斗场景 233 | CoreHooks.onSaveData 234 | ], 235 | "connector.teamHandler.getTeamList": [ // 获取队伍列表 236 | CoreHooks.onSaveData 237 | ], 238 | "connector.teamHandler.leaveTeam": [], // 离开队伍 239 | "connector.teamHandler.roundOperating": [], // 回合操作 240 | "connector.teamHandler.showMyTeam": [], // 显示我的团队 241 | "connector.teamHandler.startCombat": [], 242 | "connector.teamHandler.startCombatBoss": [], 243 | "connector.teamHandler.switchCombatScreen": [], // 切换战斗场景 244 | "connector.userHandler.addUserPetSkill": [], // 添加用户宠物技能 245 | "connector.userHandler.allSellGoods": [], // 整理 246 | "connector.userHandler.allocationPoint": [], // 保存/分配属性点 247 | "connector.userHandler.fbProcess": [], // 法宝点击 248 | "connector.userHandler.fitPet": [], // 确认合成 249 | "connector.userHandler.forgingUserEq": [], // 进阶装备 250 | "connector.userHandler.getMyFb": [], // 获取我的法宝 251 | "connector.userHandler.getMyGoods": [], // 初始我得物品 252 | "connector.userHandler.getMyPet": [], // 初始我得宠物 253 | "connector.userHandler.getMyPetSkillGoods": [], // 获取我的宠物用品 254 | "connector.userHandler.getMySkill": [], // 初始我得技能 255 | "connector.userHandler.getMyTitle": [], // 称号弹框 256 | "connector.userHandler.getMylogs": [], // 查看我的日志 257 | "connector.userHandler.getUserEqs": [], // 获取我得装备列表 258 | "connector.userHandler.getUserTask": [], 259 | "connector.userHandler.makeGoods": [], // 合成物品 260 | "connector.userHandler.playUserPet": [], // 出战宠物 261 | "connector.userHandler.polyLin": [], // 聚灵 262 | "connector.userHandler.repairUserArms": [], // 修炼装备 263 | "connector.userHandler.resetAttribute": [], // 重置属性 264 | "connector.userHandler.selectMyTitle": [], // 选择我的称号 265 | "connector.userHandler.sellGoods": [], 266 | "connector.userHandler.shelfMyGoods": [], // 取回到背包 267 | "connector.userHandler.turnIntoPet": [], // 幻化宠物 268 | "connector.userHandler.upPlayerLevel": [], 269 | "connector.playerHandler.upLevelUserSkill": [], 270 | "connector.userHandler.upUserPetLevel": [], // 升级宠物 271 | "connector.userHandler.updateUserPrice": [], // 更新玩家货币 272 | "connector.userHandler.useGoods": [], // 使用物品 273 | "connector.userHandler.userInfo": [], 274 | "connector.userHandler.wbt": [], // 挖宝图 275 | "connector.userHandler.xyDuiHuan": [], 276 | "connector.userHandler.xyUpdate": [ // // 仙蕴提交 277 | CoreHooks.onSaveData 278 | ], 279 | "gate.gateHandler.queryEntry": [], // *登录游戏 280 | "connector.userHandler.getNewPet": [] // 预览合宠 281 | }; 282 | 283 | /** 284 | * 生成服务器链接地址 285 | * @param {*} port 286 | */ 287 | GameApi.prototype.getSocketServer = function (port, host, protocol) { 288 | if ('number' != typeof port) { 289 | return null; 290 | } 291 | 292 | return Tool.replaceParams(this.config.socketPathTpl, { 293 | protocol: protocol || this.config.gameProtocol, 294 | host: host || this.config.gameHost, 295 | port: port 296 | }); 297 | } 298 | 299 | /** 300 | * 注册路由回调钩子 301 | * @param {string} route 挂载的路由地址 302 | * @param {function} cb 回调 303 | * @param {string} position 用于 触发时机 暂不可用 304 | */ 305 | GameApi.prototype.regHookHandler = function (route, cb, position) { 306 | // 检查 route 和 cn 是否有效 307 | if (!this.hookHandlers[route] || 'function' != typeof cb) { 308 | return false; 309 | } 310 | 311 | // 如果有 Mark 就尝试去重 312 | let cbMark = cb.hookMark || null; 313 | if (cbMark && 'object' == typeof this.hookHandlers[route]) { 314 | for (let i = 0; i < this.hookHandlers[route].length; i++) { 315 | const cb_item = this.hookHandlers[route][i]; 316 | if (cb_item.hookMark && cbMark == cb_item.hookMark) { 317 | return cb_item; 318 | } 319 | } 320 | } 321 | 322 | // 追加到结果 323 | this.hookHandlers[route].push(cb); 324 | 325 | return true; 326 | } 327 | 328 | /** 329 | * 启动实例 330 | */ 331 | GameApi.prototype.start = function () { 332 | if (this.socket) { 333 | return; 334 | } 335 | // 建立 ws 链接 336 | this.createWebSocket(this.config.loginServer); 337 | } 338 | 339 | /** 340 | * 创建一个 WebSocket 连接并初始化 341 | * 342 | * @param {string} url 服务地址 ws://host:prot/path 343 | */ 344 | GameApi.prototype.createWebSocket = function (url) { 345 | // 创建对象 346 | let socket = new WebSocket(url); 347 | 348 | // 指定传输数据类型 349 | socket.binaryType = 'arraybuffer'; 350 | 351 | /** 352 | * 批量绑定相关回调事件 353 | */ 354 | let bindEvents = { 355 | open: this.onOpen, 356 | message: this.onMessage, 357 | error: this.onError, 358 | close: this.onClose 359 | }; 360 | 361 | // 遍历事件列表 添加 绑定 362 | Object.keys(bindEvents).map((enevtName) => { 363 | socket.addEventListener(enevtName, (event) => { 364 | bindEvents[enevtName].call(this, event); 365 | }); 366 | }); 367 | 368 | // 将 reqId 重置 369 | this.reqId = 1; 370 | this.socket = socket; 371 | 372 | return socket; 373 | } 374 | 375 | /** 376 | * WebSocket 建立连接的回调 377 | * 378 | * @param {object} event 379 | */ 380 | GameApi.prototype.onOpen = function (event) { 381 | // 发送握手包 382 | this.handShake(); 383 | }; 384 | 385 | /** 386 | * WebSocket 收到消息时的回调 387 | * @param {object} event 388 | */ 389 | GameApi.prototype.onMessage = function (event) { 390 | let messages = Package.decode(event.data); 391 | if (messages.type != 3) { 392 | // console.log('onMessage', messages); 393 | } 394 | 395 | // 根据事件类型分发到对应的处理程序 396 | if (Array.isArray(messages)) { 397 | for (let i = 0; i < messages.length; i++) { 398 | let msg = messages[i]; 399 | this.messageHandlers.call(this, [msg.type](msg.body)); 400 | } 401 | } else { 402 | this.messageHandlers[messages.type].call(this, messages.body); 403 | } 404 | 405 | // 重新计算心跳包时间 406 | if (this.heartbeatTimeout) { 407 | this.nextHeartbeatTimeout = Date.now() + this.heartbeatTimeout; 408 | } 409 | }; 410 | 411 | /** 412 | * WebSocket 报错时的回调 413 | * 414 | * @param {object} event 415 | */ 416 | GameApi.prototype.onError = function (event) { 417 | console.log('onError', event); 418 | setTimeout(() => { 419 | window.location.reload(); 420 | }, ~~(Math.random()*60*1000)+30000); 421 | }; 422 | 423 | /** 424 | * WebSocket 断开时的回调 425 | * 426 | * @param {object} event 427 | */ 428 | GameApi.prototype.onClose = function (event) { 429 | console.log('onClose', event, this.isStop); 430 | if (this.isStop) { 431 | return; 432 | } 433 | 434 | // 重连 435 | this.login(); 436 | }; 437 | 438 | /** 439 | * 发送消息到服务器(自动处理编码信息) 440 | * 441 | * @param {object} data 442 | * @param {string} type 443 | */ 444 | GameApi.prototype.sendMessage = function (data, route, cb) { 445 | // 分析参数 446 | if (arguments.length == 2 && 'function' == typeof route) { 447 | cb = route; 448 | route = null; 449 | } 450 | 451 | // 解包消息 452 | let bytes = Protocol.strencode(JSON.stringify(data)), 453 | pkg_type = Package.TYPE_HANDSHAKE, 454 | routeId = null; 455 | 456 | // 分析路由情况 457 | if ('string' == typeof route) { 458 | // 是否压缩路由 (存在 Dict 的就压缩) 459 | let compressRoute = 0; 460 | if (this.dict && this.dict[route]) { 461 | routeId = this.dict[route]; 462 | compressRoute = 1; 463 | } 464 | 465 | // 然后生成 Message 466 | let reqId = this.reqId++ % 255; 467 | let type = reqId ? Message.TYPE_REQUEST : Message.TYPE_NOTIFY; 468 | 469 | // 设置回调 470 | if ('function' == typeof cb || 'string' == typeof cb) { 471 | this.callbacks[reqId] = cb; 472 | } 473 | 474 | // 设置回调路由表 475 | this.callRoutes[reqId] = route; 476 | 477 | // 将消息打包 478 | bytes = Message.encode(reqId, type, compressRoute, compressRoute ? routeId : route, bytes); 479 | pkg_type = Package.TYPE_DATA; 480 | } 481 | 482 | // 封装到最终格式 483 | let packet = Package.encode(pkg_type, bytes); 484 | 485 | if (this.socket.readyState === this.socket.CLOSED) { 486 | setTimeout(() => { 487 | window.location.reload(); 488 | }, ~~(Math.random()*60*1000)+30000); 489 | } 490 | 491 | // 发出封包 这里应该有发送失败的处理 492 | this.socket.send(packet); 493 | } 494 | 495 | /** 496 | * 处理握手返回包 497 | * 498 | * @param {*} data 499 | */ 500 | GameApi.prototype.onHandshake = function (data) { 501 | // 解码数据 502 | data = JSON.parse(Protocol.strdecode(data)); 503 | DEBUG && console.log('onHandshake', data); 504 | 505 | // 报错的话 506 | if (data.code === RES_OLD_CLIENT) { 507 | throw new Error('client version not fullfill'); 508 | return; 509 | } 510 | 511 | // 其他错误 512 | if (data.code !== RES_OK) { 513 | throw new Error('handshake fail'); 514 | return; 515 | } 516 | 517 | // 要发送握手回复 518 | let packet = Package.encode(Package.TYPE_HANDSHAKE_ACK); 519 | this.socket.send(packet); 520 | 521 | // 保存心跳时间 522 | if (data.sys && data.sys.heartbeat) { 523 | // 超时信息 524 | this.heartbeatInterval = data.sys.heartbeat * 1000; // heartbeat interval 525 | this.heartbeatTimeout = this.heartbeatInterval * 2; // max heartbeat timeout 526 | 527 | // 保存字典 528 | let dict = data.sys.dict; 529 | 530 | // Init compress dict 531 | if (dict) { 532 | this.dict = dict; 533 | this.abbrs = {}; 534 | 535 | for (let route in dict) { 536 | this.abbrs[dict[route]] = route; 537 | } 538 | } 539 | } 540 | 541 | // 保存 protos 信息 542 | if (data.sys && data.sys.protos) { 543 | let protos = data.sys.protos; 544 | 545 | // Init protobuf protos 546 | if (protos) { 547 | this.protoVersion = protos.version || 0; 548 | this.serverProtos = protos.server || {}; 549 | this.clientProtos = protos.client || {}; 550 | } 551 | } 552 | 553 | // if (typeof handshakeCallback === 'function') { 554 | // handshakeCallback(data.user); 555 | // } 556 | 557 | // 握手成功有回调的话 558 | if (this.initCallback) { 559 | this.initCallback.call(this); 560 | this.initCallback = null; 561 | } 562 | }; 563 | 564 | /** 565 | * 保持心跳 566 | */ 567 | GameApi.prototype.onHeartbeat = function () { 568 | if (!this.heartbeatInterval) { 569 | // no heartbeat 570 | return; 571 | } 572 | 573 | let packet = Package.encode(Package.TYPE_HEARTBEAT); 574 | if (this.heartbeatTimeoutId) { 575 | clearTimeout(this.heartbeatTimeoutId); 576 | this.heartbeatTimeoutId = null; 577 | } 578 | 579 | if (this.heartbeatId) { 580 | // already in a heartbeat interval 581 | return; 582 | } 583 | this.heartbeatId = setTimeout(() => { 584 | this.heartbeatId = null; 585 | this.socket.send(packet); 586 | 587 | this.nextHeartbeatTimeout = Date.now() + this.heartbeatTimeout; 588 | this.heartbeatTimeoutId = setTimeout(this.heartbeatTimeoutCb, this.heartbeatTimeout); 589 | }, this.heartbeatInterval); 590 | }; 591 | 592 | /** 593 | * 心跳超时的回调 594 | */ 595 | GameApi.prototype.heartbeatTimeoutCb = function () { 596 | let gap = this.nextHeartbeatTimeout - Date.now(); 597 | if (gap > gapThreshold) { 598 | this.heartbeatTimeoutId = setTimeout(this.heartbeatTimeoutCb, gap); 599 | } else { 600 | DEBUG && console.error('server heartbeat timeout'); 601 | } 602 | }; 603 | 604 | /** 605 | * 收到数据回复 606 | * 607 | * @param {*} data 608 | */ 609 | GameApi.prototype.onData = function (data) { 610 | let msg = Message.decode(data); 611 | 612 | // 从发包请求中取回 Route 613 | if (!msg.route && msg.id && this.callRoutes[msg.id]) { 614 | msg.route = this.callRoutes[msg.id]; 615 | } 616 | 617 | // 解码 Body 618 | msg.body = JSON.parse(Protocol.strdecode(msg.body)); 619 | 620 | // 检查是否有回调 621 | let cbMark = [], is_call = false, is_bubble = true; 622 | if ('function' == typeof this.callbacks[msg.id]) { 623 | let cb = this.callbacks[msg.id]; 624 | delete this.callbacks[msg.id]; 625 | if ('string' == typeof cb.hookMark) { 626 | cbMark.push(cb.hookMark); 627 | } 628 | 629 | is_call = true; 630 | is_bubble = !(cb.call(this, msg.body) === false); 631 | } 632 | 633 | // 检查钩子 634 | if (is_bubble && msg.route && 'object' == typeof this.hookHandlers[msg.route]) { 635 | for (let i = 0; i < this.hookHandlers[msg.route].length; i++) { 636 | const cb = this.hookHandlers[msg.route][i]; 637 | if ('string' == typeof cb.hookMark) { 638 | if (cbMark.indexOf(cb.hookMark) >= 0) { 639 | continue; 640 | } 641 | cbMark.push(cb.hookMark); 642 | } 643 | 644 | is_call = true; 645 | is_bubble = !(cb.call(this, msg.body) === false); 646 | if (is_bubble) continue; 647 | } 648 | } 649 | 650 | // 如果没有人接收 就打印出来 651 | if (!is_call) { 652 | DEBUG && console.log('onData', msg.route, msg.body); 653 | } 654 | }; 655 | 656 | /** 657 | * 被踢么? 658 | * 659 | * @param {*} data 660 | */ 661 | GameApi.prototype.onKick = function (data) { 662 | DEBUG && console.log('onKick', data); 663 | }; 664 | 665 | /** 666 | * 停止进程 667 | */ 668 | GameApi.prototype.Stop = function () { 669 | // 标记自己要停止了 670 | this.isStop = true; 671 | 672 | // 如果都没建立 就不存在退出了 673 | if (!this.socket) { 674 | return; 675 | } 676 | 677 | // 断开 WS 链接 678 | this.socket.close(); 679 | 680 | // 停止心跳 681 | if (this.heartbeatId) { 682 | clearInterval(this.heartbeatId) 683 | } 684 | if (this.heartbeatTimeoutId) { 685 | clearTimeout(this.heartbeatTimeoutId); 686 | } 687 | if (this.xyUpdateIntervalId) { 688 | clearInterval(this.xyUpdateIntervalId) 689 | } 690 | } 691 | 692 | //======= 下面是游戏事件封装区 =======// 693 | 694 | /** 695 | * 发送握手包 696 | * 697 | * WebSocket 链接成功后自动发送 698 | */ 699 | GameApi.prototype.handShake = function () { 700 | let handshakeBuffer = { 701 | 'sys': { 702 | type: JS_WS_CLIENT_TYPE, 703 | version: JS_WS_CLIENT_VERSION, 704 | rsa: {}, 705 | protoVersion: this.protoVersion 706 | } 707 | }; 708 | 709 | this.sendMessage(handshakeBuffer); 710 | } 711 | 712 | /** 713 | * 登录游戏 714 | * 715 | * @param {*} email 716 | * @param {*} pwd 717 | * @param {*} code 718 | */ 719 | GameApi.prototype.login = function (_email, pwd, code, is_r) { 720 | let email = _email || this.email, 721 | password = pwd || this.password, 722 | route = 'gate.gateHandler.queryEntry', 723 | data = { 724 | login_email: email, 725 | login_pwd: password, 726 | code: '', 727 | is_r: true 728 | }; 729 | 730 | // 设置握手回调 731 | this.initCallback = function () { 732 | // 尝试保存账号 733 | this.email = email; 734 | this.password = pwd; 735 | this.user_info.email = email; 736 | 737 | // 设置消息回调 738 | this.sendMessage(data, route, this.onLogin); 739 | } 740 | this.start(); 741 | } 742 | 743 | /** 744 | * 登录成功的回调 745 | * 746 | * @param {*} data 747 | */ 748 | GameApi.prototype.onLogin = function (data) { 749 | if (data.code != RES_OK) { 750 | DEBUG && console.error('onLogin', data.msg); 751 | return true; 752 | } 753 | DEBUG && console.log('onLogin', data) 754 | 755 | // 保存端口等信息 756 | this.config.gamePort = data.port; 757 | this.user_info.mid = data.mid; 758 | this.token = data.token; 759 | 760 | // 断开登录链接 重新连接到游戏服务器 761 | this.isStop = true; // 先标记停止 然后等下再开起来 762 | this.socket.close(); 763 | this.gameServer = this.getSocketServer(data.port); 764 | this.initCallback = this.loginToken; 765 | this.createWebSocket(this.gameServer); 766 | } 767 | 768 | /** 769 | * 使用 Token 登录游戏服务器 770 | */ 771 | GameApi.prototype.loginToken = function () { 772 | let route = 'connector.loginHandler.login', 773 | data = { 774 | email: this.user_info.email, 775 | token: this.token 776 | }; 777 | 778 | // 标记自己开工了 779 | this.onClose = false; 780 | 781 | // 先清空工作台 782 | // DEBUG && console.clear(); 783 | 784 | // 如果登录成功 785 | this.sendMessage(data, route, (data) => { 786 | if (data.code != RES_OK) { 787 | DEBUG && console.error('登录到游戏服务器失败', data); 788 | this.Stop(); 789 | return; 790 | } 791 | 792 | DEBUG && console.log('登录到游戏服务器成功', this, data); 793 | 794 | // 开始定时提交仙蕴 795 | this.xyUpdateIntervalId = setInterval(() => { 796 | this.xyUpdate() 797 | }, 60000); 798 | }); 799 | } 800 | 801 | /** 802 | * 发送消息 803 | */ 804 | GameApi.prototype.chatSend = function (send_msg) { 805 | this.sendMessage({ 806 | send_channel: 3, 807 | send_msg 808 | }, "chat.chatHandler.send") 809 | } 810 | 811 | /** 812 | * 仙蕴提交 813 | */ 814 | GameApi.prototype.xyUpdate = function () { 815 | this.sendMessage({}, "connector.userHandler.xyUpdate"); 816 | } 817 | 818 | /** 819 | * 查看我的日志 820 | */ 821 | GameApi.prototype.getMylogs = function () { 822 | this.sendMessage({}, "connector.userHandler.getMylogs"); 823 | } 824 | 825 | /** 826 | * 获取我的法宝 827 | */ 828 | GameApi.prototype.getMyFb = function () { 829 | this.sendMessage({}, "connector.userHandler.getMyFb"); 830 | } 831 | 832 | /** 833 | * 获取我的法宝 834 | */ 835 | GameApi.prototype.upPlayerLevel = function () { 836 | this.sendMessage({}, "connector.userHandler.upPlayerLevel"); 837 | } 838 | 839 | /** 840 | * 升级技能 841 | */ 842 | GameApi.prototype.upLevelUserSkill = function (type, id) { 843 | this.sendMessage({ type, id }, "connector.playerHandler.upLevelUserSkill"); 844 | } 845 | 846 | /** 847 | * 法宝点击 848 | * @param type 1 升星 2共生 3养灵 4佩戴 849 | * @param id 850 | */ 851 | GameApi.prototype.fbProcess = function (type, id) { 852 | this.sendMessage({ 853 | type, id 854 | }, "connector.userHandler.fbProcess"); 855 | } 856 | 857 | /** 858 | * 移动 859 | * @param x 横坐标 860 | * @param mid 地图id 861 | */ 862 | GameApi.prototype.move = function (x, mid) { 863 | this.sendMessage({ 864 | x: x, 865 | mid: mid 866 | }, "connector.playerHandler.move"); 867 | } 868 | 869 | /** 870 | * 切换地图 871 | * @param type 0 | 1 872 | */ 873 | GameApi.prototype.nextMap = function (type) { 874 | this.sendMessage({ 875 | type 876 | }, "connector.playerHandler.nextMap"); 877 | } 878 | 879 | /** 880 | * 移动至新地图 881 | */ 882 | GameApi.prototype.moveToNewMap = function (mid) { 883 | this.sendMessage({ 884 | mid: mid 885 | }, "connector.playerHandler.moveToNewMap"); 886 | } 887 | 888 | /** 889 | * 获取战斗场景列表 890 | */ 891 | GameApi.prototype.getAllCombatScreen = function () { 892 | this.sendMessage({}, "connector.teamHandler.getAllCombatScreen"); 893 | } 894 | 895 | /** 896 | * 切换战斗场景 897 | * @param {*} cbatid 898 | */ 899 | GameApi.prototype.switchCombatScreen = function (cbatid) { 900 | this.sendMessage({ 901 | cbatid: cbatid 902 | }, "connector.teamHandler.switchCombatScreen"); 903 | } 904 | 905 | /** 906 | * 获取队伍列表 907 | */ 908 | GameApi.prototype.getTeamList = function (mid) { 909 | this.sendMessage({ 910 | mid: mid 911 | }, "connector.teamHandler.getTeamList"); 912 | } 913 | 914 | /** 915 | * 创建队伍 916 | */ 917 | GameApi.prototype.createdTeam = function (mid) { 918 | this.sendMessage({ 919 | mid: mid 920 | }, "connector.teamHandler.createdTeam"); 921 | } 922 | 923 | /** 924 | * 加入队伍 925 | */ 926 | GameApi.prototype.addTeam = function (tid) { 927 | this.sendMessage({ 928 | tid: tid 929 | }, "connector.teamHandler.addTeam"); 930 | } 931 | 932 | /** 933 | * 离开队伍 934 | */ 935 | GameApi.prototype.leaveTeam = function () { 936 | this.sendMessage({}, "connector.teamHandler.leaveTeam"); 937 | } 938 | 939 | /** 940 | * 开始战斗 941 | */ 942 | GameApi.prototype.startCombat = function (cbatid) { 943 | this.sendMessage({ cbatid: cbatid }, 'connector.teamHandler.startCombat'); 944 | } 945 | 946 | /** 947 | * 回合操作 948 | * 949 | * @param type 类型 捕捉 1001 技能 1 950 | * @param skill 操作 技能 951 | * @param attack_id 目标 952 | * @param tid 队伍ID? 953 | */ 954 | GameApi.prototype.roundOperating = function (type, skill, attack_id, mtid) { 955 | this.sendMessage({ 956 | type: type, 957 | parm: skill, 958 | attack_id: attack_id, 959 | tid: mtid 960 | }, "connector.teamHandler.roundOperating"); 961 | } 962 | 963 | /** 964 | * 初始我得物品 965 | */ 966 | GameApi.prototype.getMyGoods = function (page) { 967 | this.sendMessage({ 968 | page 969 | }, "connector.userHandler.getMyGoods"); 970 | } 971 | 972 | /** 973 | * 出售物品 974 | */ 975 | GameApi.prototype.playerSellGoods = function (ugid, price, count) { 976 | this.sendMessage({ 977 | ugid: ugid, 978 | game_gold: price, 979 | count 980 | }, "connector.playerHandler.sellGoods"); 981 | } 982 | 983 | /** 984 | * 选择我的称号 985 | */ 986 | GameApi.prototype.selectMyTitle = function (index) { 987 | this.sendMessage({ 988 | index 989 | }, "connector.userHandler.selectMyTitle"); 990 | } 991 | 992 | /** 993 | * 称号弹框 994 | */ 995 | GameApi.prototype.getMyTitle = function () { 996 | this.sendMessage({}, "connector.userHandler.getMyTitle"); 997 | } 998 | 999 | /** 1000 | * 初始我得宠物 1001 | */ 1002 | GameApi.prototype.getMyPet = function () { 1003 | this.sendMessage({}, "connector.userHandler.getMyPet"); 1004 | } 1005 | 1006 | /** 1007 | * 挖宝图 1008 | */ 1009 | GameApi.prototype.wbt = function (ugid) { 1010 | this.sendMessage({ 1011 | ugid 1012 | }, "connector.userHandler.wbt"); 1013 | } 1014 | 1015 | /** 1016 | * 领高级宝图任务 1017 | */ 1018 | GameApi.prototype.getCopyTask = function (tid) { 1019 | this.sendMessage({ 1020 | tid 1021 | }, "connector.playerHandler.getCopyTask"); 1022 | } 1023 | 1024 | /** 1025 | * 初始我得技能 1026 | */ 1027 | GameApi.prototype.getMySkill = function () { 1028 | this.sendMessage({}, "connector.userHandler.getMySkill"); 1029 | } 1030 | 1031 | /** 1032 | * 修炼装备 1033 | */ 1034 | GameApi.prototype.repairUserArms = function (type) { 1035 | this.sendMessage({ 1036 | type 1037 | }, "connector.userHandler.repairUserArms"); 1038 | } 1039 | 1040 | /** 1041 | * 获取任务列表 1042 | */ 1043 | GameApi.prototype.getUserTask = function () { 1044 | this.sendMessage({ 1045 | }, "connector.userHandler.getUserTask"); 1046 | } 1047 | 1048 | /** 1049 | * 使用物品 1050 | */ 1051 | GameApi.prototype.useGoods = function (gid) { 1052 | this.sendMessage({ 1053 | gid 1054 | }, "connector.userHandler.useGoods"); 1055 | } 1056 | 1057 | /** 1058 | * 更新角色信息 1059 | */ 1060 | GameApi.prototype.userInfo = function () { 1061 | this.sendMessage({ 1062 | }, "connector.userHandler.userInfo"); 1063 | } 1064 | 1065 | /** 1066 | * 佩戴拆卸装备 1067 | */ 1068 | GameApi.prototype.wearUserEquipment = function (ueid) { 1069 | this.sendMessage({ 1070 | ueid 1071 | }, "connector.playerHandler.wearUserEquipment"); 1072 | } 1073 | 1074 | /** 1075 | * 完成任务 1076 | */ 1077 | GameApi.prototype.payUserTask = function (utid) { 1078 | this.sendMessage({ 1079 | utid 1080 | }, "connector.playerHandler.payUserTask"); 1081 | } 1082 | 1083 | /** 1084 | * 幻化宠物 1085 | */ 1086 | GameApi.prototype.turnIntoPet = function (pid) { 1087 | this.sendMessage({ 1088 | pid 1089 | }, "connector.userHandler.turnIntoPet"); 1090 | } 1091 | 1092 | /** 1093 | * 初始系统中出售物品 1094 | */ 1095 | GameApi.prototype.getSystemSellGoods = function (pageIndex) { 1096 | this.sendMessage({ 1097 | pageIndex 1098 | }, "connector.systemHandler.getSystemSellGoods"); 1099 | } 1100 | 1101 | /** 1102 | * 取回到背包 1103 | */ 1104 | GameApi.prototype.shelfMyGoods = function (id) { 1105 | this.sendMessage({ 1106 | id: id 1107 | }, "connector.userHandler.shelfMyGoods"); 1108 | } 1109 | 1110 | /** 1111 | * 初始仙坊集市 1112 | */ 1113 | GameApi.prototype.getPlayerSellGoods = function (pageIndex, type) { 1114 | this.sendMessage({ 1115 | pageIndex: pageIndex ? pageIndex : 1, 1116 | select: type 1117 | }, "connector.playerHandler.getPlayerSellGoods"); 1118 | } 1119 | 1120 | /** 1121 | * 购买玩家物品 1122 | */ 1123 | GameApi.prototype.byPalyerGoods = function (id, type) { 1124 | this.sendMessage({ 1125 | usgid: id, type 1126 | }, "connector.playerHandler.byPalyerGoods"); 1127 | } 1128 | 1129 | /** 1130 | * 购买系统物品 1131 | */ 1132 | GameApi.prototype.byGoodsToSystem = function (type, id) { 1133 | this.sendMessage({ 1134 | id, type 1135 | }, "connector.playerHandler.byGoodsToSystem"); 1136 | } 1137 | 1138 | /** 1139 | * 初始任务中心 1140 | */ 1141 | GameApi.prototype.getSystemTask = function () { 1142 | this.sendMessage({}, "connector.systemHandler.getSystemTask"); 1143 | } 1144 | 1145 | // 开关系统广播 1146 | GameApi.prototype.subSystemMsg = function (status) { 1147 | this.sendMessage({ status }, "connector.systemHandler.subSystemMsg"); 1148 | } 1149 | 1150 | /** 1151 | * 合成物品 1152 | */ 1153 | GameApi.prototype.makeGoods = function (selectGoodsArr) { 1154 | this.sendMessage({ 1155 | arr: selectGoodsArr 1156 | }, "connector.userHandler.makeGoods"); 1157 | } 1158 | 1159 | /** 1160 | * 分解物品 1161 | */ 1162 | GameApi.prototype.sellGoods = function (selectGoodsArr) { 1163 | this.sendMessage({ 1164 | arr: selectGoodsArr 1165 | }, "connector.userHandler.sellGoods"); 1166 | } 1167 | 1168 | /** 1169 | * 出战宠物 1170 | */ 1171 | GameApi.prototype.playUserPet = function (id, status) { 1172 | this.sendMessage({ 1173 | pid: id, 1174 | status 1175 | }, "connector.userHandler.playUserPet"); 1176 | } 1177 | 1178 | /** 1179 | * 升级宠物 type==1升级 type==2分配潜力 type==3放生 1180 | */ 1181 | GameApi.prototype.upUserPetLevel = function (pid, type, point) { 1182 | let parms = { pid: pid, type }; 1183 | if (type == 2) { 1184 | point = point || {}; 1185 | Object.assign(parms, { 1186 | str: point.str || null, 1187 | int: point.int || null, 1188 | agi: point.agi || null, 1189 | vit: point.vit || null, 1190 | con: point.con || null 1191 | }); 1192 | } 1193 | this.sendMessage(parms, "connector.userHandler.upUserPetLevel"); 1194 | } 1195 | 1196 | /** 1197 | * 发送消息 1198 | */ 1199 | GameApi.prototype.send = function (send_channel, send_msg) { 1200 | this.sendMessage({ 1201 | send_channel, 1202 | send_msg 1203 | }, "chat.chatHandler.send"); 1204 | } 1205 | 1206 | /** 1207 | * 保存/分配属性点 1208 | */ 1209 | GameApi.prototype.allocationPoint = function (str, int, agi, vit, con) { 1210 | this.sendMessage({ 1211 | str: str, // 力量 1212 | int: int, // 智力 1213 | agi: agi, // 敏捷 1214 | vit: vit, // 耐力 1215 | con: con // 体质 1216 | }, "connector.userHandler.allocationPoint"); 1217 | } 1218 | 1219 | /** 1220 | * 获取我得装备列表 1221 | */ 1222 | GameApi.prototype.getUserEqs = function () { 1223 | this.sendMessage({}, "connector.userHandler.getUserEqs"); 1224 | } 1225 | 1226 | /** 1227 | * 更新玩家货币 1228 | */ 1229 | GameApi.prototype.updateUserPrice = function () { 1230 | this.sendMessage({}, "connector.userHandler.updateUserPrice"); 1231 | } 1232 | 1233 | /** 1234 | * 显示我的团队 1235 | */ 1236 | GameApi.prototype.showMyTeam = function (is_show) { 1237 | this.sendMessage({ is_show }, "connector.teamHandler.showMyTeam"); 1238 | } 1239 | 1240 | /** 1241 | * 排行榜? 1242 | * @param type 1=等级 2=兽宠 3=神兵 1243 | */ 1244 | GameApi.prototype.getRankList = function (type) { 1245 | this.sendMessage({ type }, "connector.systemHandler.getRankList"); 1246 | } 1247 | 1248 | /** 1249 | * 初始聚仙阁楼页面 1250 | */ 1251 | GameApi.prototype.initFation = function () { 1252 | this.sendMessage({}, "connector.fationHandler.initFation"); 1253 | } 1254 | 1255 | /** 1256 | * 创建工会 1257 | */ 1258 | GameApi.prototype.createFation = function (name) { 1259 | this.sendMessage({ 1260 | name 1261 | }, "connector.fationHandler.createFation"); 1262 | } 1263 | 1264 | /** 1265 | * 申请工会 1266 | */ 1267 | GameApi.prototype.applyForFation = function (fid) { 1268 | this.sendMessage({ 1269 | fid 1270 | }, "connector.fationHandler.applyForFation"); 1271 | } 1272 | 1273 | 1274 | /** 1275 | * 同意入会 1276 | * @param type 1=同意 2=拒绝 1277 | * @param fation_apply_id 1278 | */ 1279 | GameApi.prototype.doneFationApply = function (type, fation_apply_id) { 1280 | this.sendMessage({ 1281 | type, faid: fation_apply_id 1282 | }, "connector.fationHandler.doneFationApply"); 1283 | } 1284 | 1285 | /** 1286 | * 升降职位 1287 | */ 1288 | GameApi.prototype.upUserFationLevel = function (type, uid) { 1289 | this.sendMessage({ 1290 | type, uid 1291 | }, "connector.fationHandler.upUserFationLevel"); 1292 | } 1293 | 1294 | /** 1295 | * 打开工会列表 1296 | */ 1297 | GameApi.prototype.getFationList = function () { 1298 | this.sendMessage({}, "connector.fationHandler.getFationList"); 1299 | } 1300 | 1301 | /** 1302 | * 查看申请 1303 | */ 1304 | GameApi.prototype.getFationApply = function () { 1305 | this.sendMessage({}, "connector.fationHandler.getFationApply"); 1306 | } 1307 | 1308 | /** 1309 | * 查看工会人员 1310 | */ 1311 | GameApi.prototype.showFationUserList = function () { 1312 | this.sendMessage({}, "connector.fationHandler.showFationUserList"); 1313 | } 1314 | 1315 | /** 1316 | * 脱离工会 1317 | */ 1318 | GameApi.prototype.leaveFation = function () { 1319 | this.sendMessage({}, "connector.fationHandler.leaveFation"); 1320 | } 1321 | 1322 | /** 1323 | * 点技能 1324 | */ 1325 | GameApi.prototype.upFationUserSkill = function (type) { 1326 | this.sendMessage({ 1327 | type 1328 | }, "connector.fationHandler.upFationUserSkill"); 1329 | } 1330 | 1331 | /** 1332 | * 捐赠 1333 | */ 1334 | GameApi.prototype.donateFationFunds = function () { 1335 | this.sendMessage({}, "connector.fationHandler.donateFationFunds"); 1336 | } 1337 | 1338 | /** 1339 | * 领取任务 1340 | */ 1341 | GameApi.prototype.getFationTask = function () { 1342 | this.sendMessage({}, "connector.fationHandler.getFationTask"); 1343 | } 1344 | 1345 | /** 1346 | * 升级工会 1347 | */ 1348 | GameApi.prototype.upFation = function (type) { 1349 | this.sendMessage({ 1350 | type 1351 | }, "connector.fationHandler.upFation"); 1352 | } 1353 | 1354 | /** 1355 | * 聚灵 1356 | */ 1357 | GameApi.prototype.polyLin = function (type) { 1358 | this.sendMessage({ 1359 | type 1360 | }, "connector.userHandler.polyLin"); 1361 | } 1362 | 1363 | /** 1364 | * 放弃任务 1365 | */ 1366 | GameApi.prototype.closeUserTask = function (tid) { 1367 | this.sendMessage({ 1368 | tid: tid 1369 | }, "connector.fationHandler.closeUserTask"); 1370 | } 1371 | 1372 | /** 1373 | * 整理 1374 | */ 1375 | GameApi.prototype.allSellGoods = function () { 1376 | this.sendMessage({}, "connector.userHandler.allSellGoods"); 1377 | } 1378 | 1379 | /** 1380 | * 重置属性 1381 | */ 1382 | GameApi.prototype.resetAttribute = function () { 1383 | this.sendMessage({}, "connector.userHandler.resetAttribute"); 1384 | } 1385 | 1386 | /** 1387 | * 预览合宠 1388 | */ 1389 | GameApi.prototype.getNewPet = function (a_id, b_id) { 1390 | this.sendMessage({ 1391 | ids: a_id + "," + b_id 1392 | }, "connector.userHandler.getNewPet"); 1393 | } 1394 | 1395 | /** 1396 | * 确认合成 1397 | */ 1398 | GameApi.prototype.fitPet = function (a_id, b_id) { 1399 | this.sendMessage({ 1400 | ids: a_id + "," + b_id 1401 | }, "connector.userHandler.fitPet"); 1402 | } 1403 | 1404 | /** 1405 | * 添加用户宠物技能? 1406 | */ 1407 | GameApi.prototype.addUserPetSkill = function (ugid,upid) { 1408 | this.sendMessage({ 1409 | ugid, upid 1410 | }, "connector.userHandler.addUserPetSkill"); 1411 | } 1412 | 1413 | /** 1414 | * 获取我的宠物用品? 1415 | */ 1416 | GameApi.prototype.getMyPetSkillGoods = function () { 1417 | this.sendMessage({}, "connector.userHandler.getMyPetSkillGoods"); 1418 | } 1419 | 1420 | export default GameApi 1421 | -------------------------------------------------------------------------------- /src/libs/protocol.js: -------------------------------------------------------------------------------- 1 | define(function (exports, require, module) { 2 | (function (exports, ByteArray, global) { 3 | var Protocol = exports; 4 | 5 | var PKG_HEAD_BYTES = 4; 6 | var MSG_FLAG_BYTES = 1; 7 | var MSG_ROUTE_CODE_BYTES = 2; 8 | var MSG_ID_MAX_BYTES = 5; 9 | var MSG_ROUTE_LEN_BYTES = 1; 10 | 11 | var MSG_ROUTE_CODE_MAX = 0xffff; 12 | 13 | var MSG_COMPRESS_ROUTE_MASK = 0x1; 14 | var MSG_TYPE_MASK = 0x7; 15 | 16 | var Package = Protocol.Package = {}; 17 | var Message = Protocol.Message = {}; 18 | 19 | Package.TYPE_HANDSHAKE = 1; 20 | Package.TYPE_HANDSHAKE_ACK = 2; 21 | Package.TYPE_HEARTBEAT = 3; 22 | Package.TYPE_DATA = 4; 23 | Package.TYPE_KICK = 5; 24 | 25 | Message.TYPE_REQUEST = 0; 26 | Message.TYPE_NOTIFY = 1; 27 | Message.TYPE_RESPONSE = 2; 28 | Message.TYPE_PUSH = 3; 29 | 30 | /** 31 | * pomele client encode 32 | * id message id; 33 | * route message route 34 | * msg message body 35 | * socketio current support string 36 | */ 37 | Protocol.strencode = function (str) { 38 | var byteArray = new ByteArray(str.length * 3); 39 | var offset = 0; 40 | for (var i = 0; i < str.length; i++) { 41 | var charCode = str.charCodeAt(i); 42 | var codes = null; 43 | if (charCode <= 0x7f) { 44 | codes = [charCode]; 45 | } else if (charCode <= 0x7ff) { 46 | codes = [0xc0 | (charCode >> 6), 0x80 | (charCode & 0x3f)]; 47 | } else { 48 | codes = [0xe0 | (charCode >> 12), 0x80 | ((charCode & 0xfc0) >> 6), 0x80 | (charCode & 0x3f)]; 49 | } 50 | for (var j = 0; j < codes.length; j++) { 51 | byteArray[offset] = codes[j]; 52 | ++offset; 53 | } 54 | } 55 | var _buffer = new ByteArray(offset); 56 | copyArray(_buffer, 0, byteArray, 0, offset); 57 | return _buffer; 58 | } 59 | ; 60 | 61 | /** 62 | * client decode 63 | * msg String data 64 | * return Message Object 65 | */ 66 | Protocol.strdecode = function (buffer) { 67 | var bytes = new ByteArray(buffer); 68 | var array = []; 69 | var offset = 0; 70 | var charCode = 0; 71 | var end = bytes.length; 72 | while (offset < end) { 73 | if (bytes[offset] < 128) { 74 | charCode = bytes[offset]; 75 | offset += 1; 76 | } else if (bytes[offset] < 224) { 77 | charCode = ((bytes[offset] & 0x3f) << 6) + (bytes[offset + 1] & 0x3f); 78 | offset += 2; 79 | } else { 80 | charCode = ((bytes[offset] & 0x0f) << 12) + ((bytes[offset + 1] & 0x3f) << 6) + (bytes[offset + 2] & 0x3f); 81 | offset += 3; 82 | } 83 | array.push(charCode); 84 | } 85 | var res = ''; 86 | var chunk = 8 * 1024; 87 | var i; 88 | for (i = 0; i < array.length / chunk; i++) { 89 | res += String.fromCharCode.apply(null, array.slice(i * chunk, (i + 1) * chunk)); 90 | } 91 | res += String.fromCharCode.apply(null, array.slice(i * chunk)); 92 | return res; 93 | 94 | // return String.fromCharCode.apply(null, array); 95 | } 96 | ; 97 | 98 | /** 99 | * Package protocol encode. 100 | * 101 | * Pomelo package format: 102 | * +------+-------------+------------------+ 103 | * | type | body length | body | 104 | * +------+-------------+------------------+ 105 | * 106 | * Head: 4bytes 107 | * 0: package type, 108 | * 1 - handshake, 109 | * 2 - handshake ack, 110 | * 3 - heartbeat, 111 | * 4 - data 112 | * 5 - kick 113 | * 1 - 3: big-endian body length 114 | * Body: body length bytes 115 | * 116 | * @param {Number} type package type 117 | * @param {ByteArray} body body content in bytes 118 | * @return {ByteArray} new byte array that contains encode result 119 | */ 120 | Package.encode = function (type, body) { 121 | var length = body ? body.length : 0; 122 | var buffer = new ByteArray(PKG_HEAD_BYTES + length); 123 | var index = 0; 124 | buffer[index++] = type & 0xff; 125 | buffer[index++] = (length >> 16) & 0xff; 126 | buffer[index++] = (length >> 8) & 0xff; 127 | buffer[index++] = length & 0xff; 128 | if (body) { 129 | copyArray(buffer, index, body, 0, length); 130 | } 131 | return buffer; 132 | } 133 | ; 134 | 135 | /** 136 | * Package protocol decode. 137 | * See encode for package format. 138 | * 139 | * @param {ByteArray} buffer byte array containing package content 140 | * @return {Object} {type: package type, buffer: body byte array} 141 | */ 142 | Package.decode = function (buffer) { 143 | var offset = 0; 144 | var bytes = new ByteArray(buffer); 145 | var length = 0; 146 | var rs = []; 147 | while (offset < bytes.length) { 148 | var type = bytes[offset++]; 149 | length = ((bytes[offset++]) << 16 | (bytes[offset++]) << 8 | bytes[offset++]) >>> 0; 150 | var body = length ? new ByteArray(length) : null; 151 | copyArray(body, 0, bytes, offset, length); 152 | offset += length; 153 | rs.push({ 154 | 'type': type, 155 | 'body': body 156 | }); 157 | } 158 | return rs.length === 1 ? rs[0] : rs; 159 | } 160 | ; 161 | 162 | /** 163 | * Message protocol encode. 164 | * 165 | * @param {Number} id message id 166 | * @param {Number} type message type 167 | * @param {Number} compressRoute whether compress route 168 | * @param {Number|String} route route code or route string 169 | * @param {Buffer} msg message body bytes 170 | * @return {Buffer} encode result 171 | */ 172 | Message.encode = function (id, type, compressRoute, route, msg) { 173 | // caculate message max length 174 | var idBytes = msgHasId(type) ? caculateMsgIdBytes(id) : 0; 175 | var msgLen = MSG_FLAG_BYTES + idBytes; 176 | 177 | if (msgHasRoute(type)) { 178 | if (compressRoute) { 179 | if (typeof route !== 'number') { 180 | throw new Error('error flag for number route!'); 181 | } 182 | msgLen += MSG_ROUTE_CODE_BYTES; 183 | } else { 184 | msgLen += MSG_ROUTE_LEN_BYTES; 185 | if (route) { 186 | route = Protocol.strencode(route); 187 | if (route.length > 255) { 188 | throw new Error('route maxlength is overflow'); 189 | } 190 | msgLen += route.length; 191 | } 192 | } 193 | } 194 | 195 | if (msg) { 196 | msgLen += msg.length; 197 | } 198 | 199 | var buffer = new ByteArray(msgLen); 200 | var offset = 0; 201 | 202 | // add flag 203 | offset = encodeMsgFlag(type, compressRoute, buffer, offset); 204 | 205 | // add message id 206 | if (msgHasId(type)) { 207 | offset = encodeMsgId(id, buffer, offset); 208 | } 209 | 210 | // add route 211 | if (msgHasRoute(type)) { 212 | offset = encodeMsgRoute(compressRoute, route, buffer, offset); 213 | } 214 | 215 | // add body 216 | if (msg) { 217 | offset = encodeMsgBody(msg, buffer, offset); 218 | } 219 | 220 | return buffer; 221 | } 222 | ; 223 | 224 | /** 225 | * Message protocol decode. 226 | * 227 | * @param {Buffer|Uint8Array} buffer message bytes 228 | * @return {Object} message object 229 | */ 230 | Message.decode = function (buffer) { 231 | var bytes = new ByteArray(buffer); 232 | var bytesLen = bytes.length || bytes.byteLength; 233 | var offset = 0; 234 | var id = 0; 235 | var route = null; 236 | 237 | // parse flag 238 | var flag = bytes[offset++]; 239 | var compressRoute = flag & MSG_COMPRESS_ROUTE_MASK; 240 | var type = (flag >> 1) & MSG_TYPE_MASK; 241 | 242 | // parse id 243 | if (msgHasId(type)) { 244 | var m = parseInt(bytes[offset]); 245 | var i = 0; 246 | do { 247 | var m = parseInt(bytes[offset]); 248 | id = id + ((m & 0x7f) * Math.pow(2, (7 * i))); 249 | offset++; 250 | i++; 251 | } while (m >= 128); 252 | } 253 | 254 | // parse route 255 | if (msgHasRoute(type)) { 256 | if (compressRoute) { 257 | route = (bytes[offset++]) << 8 | bytes[offset++]; 258 | } else { 259 | var routeLen = bytes[offset++]; 260 | if (routeLen) { 261 | route = new ByteArray(routeLen); 262 | copyArray(route, 0, bytes, offset, routeLen); 263 | route = Protocol.strdecode(route); 264 | } else { 265 | route = ''; 266 | } 267 | offset += routeLen; 268 | } 269 | } 270 | 271 | // parse body 272 | var bodyLen = bytesLen - offset; 273 | var body = new ByteArray(bodyLen); 274 | 275 | copyArray(body, 0, bytes, offset, bodyLen); 276 | 277 | return { 278 | 'id': id, 279 | 'type': type, 280 | 'compressRoute': compressRoute, 281 | 'route': route, 282 | 'body': body 283 | }; 284 | } 285 | ; 286 | 287 | var copyArray = function (dest, doffset, src, soffset, length) { 288 | if ('function' === typeof src.copy) { 289 | // Buffer 290 | src.copy(dest, doffset, soffset, soffset + length); 291 | } else { 292 | // Uint8Array 293 | for (var index = 0; index < length; index++) { 294 | dest[doffset++] = src[soffset++]; 295 | } 296 | } 297 | }; 298 | 299 | var msgHasId = function (type) { 300 | return type === Message.TYPE_REQUEST || type === Message.TYPE_RESPONSE; 301 | }; 302 | 303 | var msgHasRoute = function (type) { 304 | return type === Message.TYPE_REQUEST || type === Message.TYPE_NOTIFY || type === Message.TYPE_PUSH; 305 | }; 306 | 307 | var caculateMsgIdBytes = function (id) { 308 | var len = 0; 309 | do { 310 | len += 1; 311 | id >>= 7; 312 | } while (id > 0); return len; 313 | }; 314 | 315 | var encodeMsgFlag = function (type, compressRoute, buffer, offset) { 316 | if (type !== Message.TYPE_REQUEST && type !== Message.TYPE_NOTIFY && type !== Message.TYPE_RESPONSE && type !== Message.TYPE_PUSH) { 317 | throw new Error('unkonw message type: ' + type); 318 | } 319 | 320 | buffer[offset] = (type << 1) | (compressRoute ? 1 : 0); 321 | 322 | return offset + MSG_FLAG_BYTES; 323 | }; 324 | 325 | var encodeMsgId = function (id, buffer, offset) { 326 | do { 327 | var tmp = id % 128; 328 | var next = Math.floor(id / 128); 329 | 330 | if (next !== 0) { 331 | tmp = tmp + 128; 332 | } 333 | buffer[offset++] = tmp; 334 | 335 | id = next; 336 | } while (id !== 0); 337 | return offset; 338 | }; 339 | 340 | var encodeMsgRoute = function (compressRoute, route, buffer, offset) { 341 | if (compressRoute) { 342 | if (route > MSG_ROUTE_CODE_MAX) { 343 | throw new Error('route number is overflow'); 344 | } 345 | 346 | buffer[offset++] = (route >> 8) & 0xff; 347 | buffer[offset++] = route & 0xff; 348 | } else { 349 | if (route) { 350 | buffer[offset++] = route.length & 0xff; 351 | copyArray(buffer, offset, route, 0, route.length); 352 | offset += route.length; 353 | } else { 354 | buffer[offset++] = 0; 355 | } 356 | } 357 | 358 | return offset; 359 | }; 360 | 361 | var encodeMsgBody = function (msg, buffer, offset) { 362 | copyArray(buffer, offset, msg, 0, msg.length); 363 | return offset + msg.length; 364 | }; 365 | 366 | module.exports = Protocol; 367 | if (typeof (window) != "undefined") { 368 | window.Protocol = Protocol; 369 | } 370 | } 371 | )(typeof (window) == "undefined" ? module.exports : (this.Protocol = {}), typeof (window) == "undefined" ? Buffer : Uint8Array, this); 372 | 373 | }); 374 | -------------------------------------------------------------------------------- /src/libs/regHooks.js: -------------------------------------------------------------------------------- 1 | import GameApi from './YunDingOnlineSDK' 2 | 3 | window.freshPackage = true 4 | window.chatMsg = [] 5 | window.screens = [] 6 | 7 | // 暴露一个接口 用来接收 app 对象 8 | export default function (_app) { 9 | const app = _app; 10 | 11 | function buildUserTasks (userTasks) { 12 | const taskList = [] 13 | userTasks.map(task => { 14 | const give = [] 15 | task.task.give_goods.map((gds, i) => { 16 | give.push(`${gds.name} x ${task.task.give_goods_num[i].count}`) 17 | }) 18 | if (task.task.contribution_num) { 19 | give.push(`帮贡 ${task.task.contribution_num}`) 20 | } 21 | 22 | const need = [] 23 | task.needGoods.map(gds => { 24 | need.push(`${gds.name} [${gds.have_count}/${gds.need_count}]`) 25 | }) 26 | 27 | taskList.push({ 28 | utid: task.utid, 29 | _id: task.task._id, 30 | title: task.task.name, 31 | info: task.task.info, 32 | give, 33 | need 34 | }) 35 | }) 36 | app.$set(app.user, 'userTasks', taskList); 37 | } 38 | 39 | // 创建空函数 屏蔽 onLeave onAdd 消息刷屏 40 | let emptyCb = () => {}; 41 | emptyCb.hookMark = 'regHooks.emptyCb'; 42 | GameApi.regHookHandlers['onLeave'].push(emptyCb); 43 | GameApi.regHookHandlers['onAdd'].push(emptyCb); 44 | 45 | function sendValidateCode (email) { 46 | fetch("http://yundingxx.com:3366/api/sendMailCode", { 47 | "headers": { 48 | "content-type": "application/x-www-form-urlencoded; charset=UTF-8" 49 | }, 50 | "body": `email=${email}`, 51 | "method": "POST", 52 | "mode": "cors", 53 | "credentials": "include" 54 | }).then(rs => rs.json()).then(rs => { 55 | if (rs.code == 304) { 56 | const next = rs.data + 1; 57 | app.$Message.info(`${next}秒后自动重新获取验证码然后刷新`); 58 | setTimeout(() => sendValidateCode(email), next * 1000); 59 | } else { 60 | location.reload(); 61 | } 62 | }); 63 | } 64 | 65 | // 接管登录成功的回调 66 | let loginCb = function (data) { 67 | console.log(data) 68 | let user = app.user; 69 | // 检查错误 70 | if (data.code == 500) { 71 | app.$set(user, 'status', "登录失败"); 72 | app.$set(user, 'status_msg', "账号已在他处登录"); 73 | return; 74 | } else if (data.code != 200) { 75 | if (data.code == 400) { 76 | sendValidateCode(user.email); 77 | } 78 | app.$set(user, 'status', "登录失败"); 79 | app.$set(user, 'status_msg', data.msg || '未知错误'); 80 | return; 81 | } 82 | 83 | // 登录成功 84 | if (data.token) { 85 | user.status = '鉴权成功'; 86 | return; 87 | } 88 | user.status = '登录成功'; 89 | 90 | // 没有数据就不在继续了 91 | if ('object' != typeof data.data) { 92 | return; 93 | } 94 | app.$set(user, 'userEqs', data.data.userEqs); 95 | app.$set(user, 'myInfo', data.data.myInfo); 96 | buildUserTasks(data.data.userTasks); 97 | // 记录地图位置 98 | app.$set(user, 'map', data.data.map); 99 | // 获取一些初始化的信息 100 | this.userInfo(); 101 | this.getSystemTask(); // 任务中心 102 | // 获取地图队伍列表 103 | this.getTeamList(app.user.map.id); 104 | // 获取物品信息 105 | app.$set(user, 'goods', []); 106 | app.$set(user, 'goodsPage', 1); 107 | this.getMyGoods(); 108 | // 获取技能信息 109 | this.getMySkill(); 110 | } 111 | loginCb.hookMark = "regHooks.loginCb"; 112 | GameApi.regHookHandlers['gate.gateHandler.queryEntry'].push(loginCb); 113 | GameApi.regHookHandlers['connector.loginHandler.login'].push(loginCb); 114 | 115 | // 移动地图的返回 116 | let moveToNewMapCb = function (data) { 117 | if (data.code != 200) { 118 | app.$Message.error(data.msg); 119 | return; 120 | } 121 | 122 | // 更新地图位置 123 | app.$set(app.user, 'map', data.map); 124 | }; 125 | moveToNewMapCb.hookMark = "regHooks.moveToNewMapCb"; 126 | GameApi.regHookHandlers['connector.playerHandler.moveToNewMap'].push(moveToNewMapCb); 127 | 128 | // 创建队伍回调 129 | let createdTeamCb = function (data) { 130 | if (data.code != 200) { 131 | app.$Message.error(data.msg); 132 | return; 133 | } 134 | 135 | // 保存队长信息 136 | app.$set(app.user, 'team', { 137 | leader: this.email, 138 | users: [] 139 | }); 140 | 141 | app.$Message.success('队伍创建成功'); 142 | } 143 | createdTeamCb.hookMark = "regHooks.createdTeamCb"; 144 | GameApi.regHookHandlers['connector.teamHandler.createdTeam'].push(createdTeamCb); 145 | 146 | // 离开队伍的回调 147 | let leaveTeamCb = function (data) { 148 | if (data.code != 200) { 149 | app.$Message.error(data.msg); 150 | return; 151 | } 152 | app.$delete(app.user, 'team'); 153 | app.$Message.info('已离开队伍'); 154 | 155 | this.getTeamList(app.user.map.id) 156 | } 157 | leaveTeamCb.hookMark = "regHooks.leaveTeamCb"; 158 | GameApi.regHookHandlers['connector.teamHandler.leaveTeam'].push(leaveTeamCb); 159 | 160 | // 加入队伍 161 | let addTeamCb = function (data) { 162 | if (data.code != 200) { 163 | app.$Message.error(data.msg); 164 | return; 165 | } 166 | 167 | // 整理结构 168 | let combat = data.data.combat || null, 169 | leader = data.data.users[0].nickname, 170 | users = data.data.users; 171 | 172 | for (let i = 0; i < this.user_info.screens.length; i++) { 173 | const screen = this.user_info.screens[i]; 174 | if (screen._id == combat) { 175 | combat = screen.name; 176 | } 177 | } 178 | 179 | app.$set(app.user, 'team', { 180 | combat: combat, 181 | leader: leader, 182 | users: users 183 | }); 184 | app.$Message.info('已加入队伍'); 185 | } 186 | addTeamCb.hookMark = "regHooks.addTeamCb"; 187 | GameApi.regHookHandlers['connector.teamHandler.addTeam'].push(addTeamCb); 188 | 189 | // 重新接收队伍信息 190 | let onMyTeamReloadCb = function (data) { 191 | if (data.code && data.code != 200) { 192 | app.$Message.error(data.msg); 193 | return; 194 | } 195 | 196 | let user = app.user; 197 | 198 | // 队员退出 199 | if (data.new_uid && !data.team && user.team) { 200 | // 移除队员 201 | user.team.users.forEach((item, index) => { 202 | if (item._id == data.new_uid) { 203 | user.team.users.splice(index, 1); 204 | } 205 | }); 206 | return; 207 | } 208 | if (data.data || !data.team) { 209 | if (data.data) { 210 | app.$set(user, 'fighting', false) 211 | } 212 | app.$delete(user, 'team') 213 | app.$delete(user, 'combatName') 214 | return; 215 | } 216 | 217 | // 获取队长信息 218 | let leader = data.team.leader, 219 | users = []; 220 | 221 | for (let i = 0; i < data.team.users.length; i++) { 222 | const user = data.team.users[i]; 223 | if (user._id == leader) { 224 | leader = user.email; 225 | } 226 | users.push({ 227 | _id: user._id, 228 | email: user.email, 229 | level: user.level 230 | }) 231 | } 232 | 233 | app.$set(user, 'team', { 234 | leader: leader, 235 | users: users, 236 | combat: data.team.combat 237 | }); 238 | 239 | if (user.email === leader && app.user.fighting) { 240 | this.startCombat(user.tempcombatid || user.combatId || data.team.combat); 241 | } 242 | } 243 | onMyTeamReloadCb.hookMark = "regHooks.onMyTeamReloadCb"; 244 | GameApi.regHookHandlers['onMyTeamReload'].push(onMyTeamReloadCb); 245 | 246 | // 获取队伍列表 247 | let getTeamListCb = function (data) { 248 | 249 | if (data.code != 200) { 250 | app.$Message.error(data.msg); 251 | return; 252 | } 253 | let user = app.user; 254 | 255 | if (window.screens.length === 0) { 256 | window.screens.push(...data.data.screens); 257 | } 258 | 259 | app.$set(user, 'screens', data.data.screens); 260 | app.$set(user, 'teams', data.data.teams.filter(ts => ts.users.length !== ((ts.combat || {}).player_num))); 261 | } 262 | getTeamListCb.hookMark = "regHooks.getTeamListCb"; 263 | GameApi.regHookHandlers['connector.teamHandler.getTeamList'].push(getTeamListCb); 264 | 265 | // 切换场景回调 266 | let switchCombatScreenCb = function (data) { 267 | if (data.code != 200) { 268 | app.$Message.error(data.msg); 269 | return; 270 | } 271 | 272 | app.$Message.success("切换副本成功"); 273 | this.getTeamList(app.user.map.id) 274 | } 275 | switchCombatScreenCb.hookMark = "regHooks.switchCombatScreenCb"; 276 | GameApi.regHookHandlers['connector.teamHandler.switchCombatScreen'].push(switchCombatScreenCb); 277 | 278 | // 战斗开始 279 | let onStartBatCb = function (data) { 280 | if (data.code != 200) { 281 | app.$Message.error(data.msg); 282 | return; 283 | } 284 | const user = app.user 285 | const battleUnit = data.data.initData 286 | 287 | let catchTarget 288 | const catchList = user.catchType ? user.catchPetBySkill: user.catchPet; 289 | // 匹配捕捉的宠物名称 290 | if (catchList && catchList.includes) { 291 | catchTarget = battleUnit.find(bu => bu.team === 2 && catchList.includes(bu.name.replace(/<[^>]+>/g, ''))); 292 | } 293 | if (catchTarget) { 294 | this.roundOperating( 295 | '1001', 296 | '', 297 | catchTarget.id, 298 | user.team ? user.team._id : '' 299 | ); 300 | } else { 301 | this.roundOperating( 302 | user.skilltype || '1', 303 | user.skillid || '1', 304 | '', 305 | user.team ? user.team._id : '' 306 | ); 307 | } 308 | } 309 | onStartBatCb.hookMark = "regHooks.onStartBatCb"; 310 | GameApi.regHookHandlers['onStartBat'].push(onStartBatCb); 311 | 312 | // 战斗结束 313 | let onRoundBatEndCb = function (data) { 314 | // 开启新的战斗 315 | // data.data.win 判断战斗结果 316 | const user = app.user 317 | if (user.myInfo.hp_store < 5000) { 318 | this.byGoodsToSystem(2, '5eef5b6e0faad0b123d709c5'); 319 | } 320 | if (user.myInfo.mp_store < 5000) { 321 | this.byGoodsToSystem(2, '5eef5d140faad0b123d709c6'); 322 | } 323 | if (user.fighting && user.team) { 324 | this.startCombat(user.tempcombatid || user.combatId || user.team.combat); 325 | } 326 | 327 | // 保存战斗消息 328 | app.setMessage(this.email, data.data); 329 | this.userInfo(); 330 | } 331 | onRoundBatEndCb.hookMark = "regHooks.onRoundBatEndCb"; 332 | GameApi.regHookHandlers['onRoundBatEnd'].push(onRoundBatEndCb); 333 | 334 | // 发送消息 335 | let chatSendCb = function (data) { 336 | if (data.code != 200) { 337 | app.$Message.error(data.msg); 338 | return; 339 | } 340 | } 341 | chatSendCb.hookMark = "regHooks.chatSendCb"; 342 | GameApi.regHookHandlers['chat.chatHandler.send'].push(chatSendCb); 343 | 344 | // 接收消息 345 | let onChatMsgCb = function (data) { 346 | data.key = Date.now(); 347 | window.chatMsg.push(data); 348 | } 349 | onChatMsgCb.hookMark = "regHooks.onChatMsgCb"; 350 | GameApi.regHookHandlers['onChatMsg'].push(onChatMsgCb); 351 | 352 | // 获取我的背包物品 353 | let getMyGoodsCb = function (data) { 354 | if (data.code != 200) { 355 | app.$Message.error(data.msg); 356 | return; 357 | } 358 | let flag = true; 359 | for (let i = 0; i < data.data.goods.length; i++) { 360 | const good = data.data.goods[i]; 361 | if (flag && good.goods && good.goods.info && good.goods.info.indexOf('储备值') > -1) { 362 | this.useGoods(good._id); 363 | flag = false; 364 | } else { 365 | let map, unusecbt, highcbt, goodsType 366 | // 转换物品类型 367 | switch (good.goods_type) { 368 | case '5eee25a1ba4d0b4c4ef605d0': 369 | goodsType = '蛋'; 370 | break; 371 | case '5ec63cc24947081a6cd8d3a6': 372 | goodsType = '未鉴定的装备'; 373 | break; 374 | case '5e77ee52b1012a6374d2bd1b': 375 | goodsType = '可装备的装备'; 376 | break; 377 | case '5f01e52c0f80941f56ecc1ae': 378 | goodsType = '藏宝图'; 379 | break; 380 | case '5ef04600544717379c820835': 381 | goodsType = '技能书'; 382 | break; 383 | case '5ec63cb54947081a6cd8d3a5': 384 | goodsType = '材料'; 385 | break; 386 | case '5f01e4990f80941f56ecc1ac': 387 | goodsType = '法宝材料'; 388 | break; 389 | case '5eedd0138822d61cf3d9548a': 390 | case '5eedd0178822d61cf3d9548b': 391 | goodsType = '兽决'; 392 | break; 393 | case '5eef5f0b0faad0b123d709d0': 394 | goodsType = '大补丹'; 395 | break; 396 | case '5eef5f0b0faad0b123d709d0': 397 | goodsType = '大补丹'; 398 | break; 399 | default: 400 | // console.log(`这个${good.name}俺不知道是什么类型`) 401 | break; 402 | } 403 | // 解析宝图位置 404 | if (good.name && good.expand) { 405 | map = JSON.parse(good.expand).map 406 | } else if ((good.name || good.goods.name).indexOf('藏宝图') > -1) { 407 | if ((good.name || good.goods.name).indexOf('高级藏宝图') > -1) { 408 | highcbt = true 409 | } 410 | unusecbt = true 411 | } 412 | 413 | app.user.goods.push({ 414 | id: good._id, 415 | num: good.count, 416 | map, 417 | unusecbt, 418 | highcbt, 419 | name: good.name || good.goods.name, 420 | goodsType, 421 | info: good.goods || good 422 | }); 423 | } 424 | } 425 | 426 | if (app.user.goods.length !== data.data.count) { 427 | this.getMyGoods(++app.user.goodsPage); 428 | } 429 | } 430 | getMyGoodsCb.hookMark = "regHooks.getMyGoodsCb"; 431 | GameApi.regHookHandlers['connector.userHandler.getMyGoods'].push(getMyGoodsCb); 432 | 433 | // 购买蓝药血药 434 | let byGoodsToSystemCb = function (data) { 435 | if (data.code != 200) { 436 | app.$Message.error(data.msg); 437 | return; 438 | } 439 | app.$Message.success(data.msg); 440 | 441 | // 重置背包 442 | app.user.goods = []; 443 | app.user.goodsPage = 1; 444 | this.getMyGoods(); 445 | } 446 | byGoodsToSystemCb.hookMark = "regHooks.byGoodsToSystemCb"; 447 | GameApi.regHookHandlers['connector.playerHandler.byGoodsToSystem'].push(byGoodsToSystemCb); 448 | 449 | // 使用物品回调 450 | let useGoodsCb = function (data) { 451 | if (data.code != 200) { 452 | app.$Message.error(data.msg); 453 | return; 454 | } 455 | if (!window.freshPackage) return; 456 | this.userInfo(); 457 | // 重置背包 458 | app.user.goods = []; 459 | app.user.goodsPage = 1; 460 | this.getMyGoods(); 461 | } 462 | useGoodsCb.hookMark = "regHooks.useGoodsCb"; 463 | GameApi.regHookHandlers['connector.userHandler.useGoods'].push(useGoodsCb); 464 | 465 | // 仙蕴聚灵 466 | let polyLinCb = function (data) { 467 | if (data.code != 200) { 468 | app.$Message.error(data.msg); 469 | return; 470 | } 471 | this.userInfo(); 472 | } 473 | polyLinCb.hookMark = "regHooks.polyLinCb"; 474 | GameApi.regHookHandlers['connector.userHandler.polyLin'].push(polyLinCb); 475 | 476 | // 整理回调 477 | let allSellGoodsCb = function (data) { 478 | if (data.code != 200) { 479 | app.$Message.error(data.msg); 480 | return; 481 | } 482 | // 重置背包 483 | app.user.goods = []; 484 | app.user.goodsPage = 1; 485 | this.getMyGoods(); 486 | } 487 | allSellGoodsCb.hookMark = "regHooks.allSellGoodsCb"; 488 | GameApi.regHookHandlers['connector.userHandler.allSellGoods'].push(allSellGoodsCb); 489 | 490 | // 分解物品回调 491 | let sellGoodsCb = function (data) { 492 | if (data.code != 200) { 493 | app.$Message.error(data.msg); 494 | return; 495 | } 496 | this.userInfo(); 497 | // 重置背包 498 | app.user.goods = []; 499 | app.user.goodsPage = 1; 500 | this.getMyGoods(); 501 | } 502 | useGoodsCb.hookMark = "regHooks.sellGoodsCb"; 503 | GameApi.regHookHandlers['connector.userHandler.sellGoods'].push(sellGoodsCb); 504 | 505 | // 佩戴拆卸装备 506 | let wearUserEquipmentCb = function (data) { 507 | if (data.code != 200) { 508 | app.$Message.error(data.msg); 509 | return; 510 | } 511 | this.userInfo(); 512 | // 重置背包 513 | app.user.goods = []; 514 | app.user.goodsPage = 1; 515 | this.getMyGoods(); 516 | } 517 | useGoodsCb.hookMark = "regHooks.wearUserEquipmentCb"; 518 | GameApi.regHookHandlers['connector.playerHandler.wearUserEquipment'].push(wearUserEquipmentCb); 519 | 520 | // 升级回调 521 | let upPlayerLevelCb = function (data) { 522 | if (data.code != 200) { 523 | app.$Message.error(data.msg); 524 | return; 525 | } 526 | this.userInfo(); 527 | } 528 | upPlayerLevelCb.hookMark = "regHooks.upPlayerLevelCb"; 529 | GameApi.regHookHandlers['connector.userHandler.upPlayerLevel'].push(upPlayerLevelCb); 530 | 531 | // 获取用户信息 532 | let userInfoCb = function (data) { 533 | if (data.code != 200) { 534 | app.$Message.error(data.msg); 535 | return; 536 | } 537 | data.user.nextExp = data.nextLevelGetExp 538 | let user = app.user; 539 | app.$set(user, 'myInfo', data.user); 540 | } 541 | userInfoCb.hookMark = "regHooks.userInfoCb"; 542 | GameApi.regHookHandlers['connector.userHandler.userInfo'].push(userInfoCb); 543 | 544 | // 获取用户技能 545 | let getMySkillCb = function (data) { 546 | if (data.code != 200) { 547 | app.$Message.error(data.msg); 548 | return; 549 | } 550 | app.$set(app.user, 'skills', data.data.skill); 551 | 552 | const arms = []; 553 | const typeMap = { 554 | 0: '剑', 1: '枪', 2: '锤', 3: '伞' 555 | }; 556 | const levelMap = { 557 | 0: { name: '入门', exp: 200 }, 558 | 1: { name: '精修', exp: 500 }, 559 | 2: { name: '意境', exp: 1500 }, 560 | 3: { name: '心境', exp: 3500 }, 561 | 4: { name: '解境', exp: 5000 }, 562 | 5: { name: '魂入体', exp: 30000 }, 563 | 6: { name: '灵出窍', exp: 100000 }, 564 | 7: { name: '神境', exp: 500000 } 565 | }; 566 | data.data.arms_exp.map((exp, index) => { 567 | const typeName = typeMap[index]; 568 | const level = levelMap[data.data.arms_level[index]]; 569 | arms.push({ exp, needExp: level.exp, name: `${typeName}${level.name}` }); 570 | }); 571 | app.$set(app.user, 'arms', arms); 572 | } 573 | getMySkillCb.hookMark = "regHooks.getMySkillCb"; 574 | GameApi.regHookHandlers['connector.userHandler.getMySkill'].push(getMySkillCb); 575 | 576 | // 升级主动技能 577 | let upLevelUserSkillCb = function (data) { 578 | if (data.code != 200) { 579 | app.$Message.error(data.msg || `${data.code}错误但是没有错误信息,不知道作者搞什么鬼`); 580 | return; 581 | } 582 | this.getMySkill(); 583 | } 584 | upLevelUserSkillCb.hookMark = "regHooks.upLevelUserSkillCb"; 585 | GameApi.regHookHandlers['connector.playerHandler.upLevelUserSkill'].push(upLevelUserSkillCb); 586 | 587 | // 分配属性点回调 588 | let allocationPointCb = function (data) { 589 | if (data.code != 200) { 590 | app.$Message.error(data.msg); 591 | return; 592 | } 593 | this.userInfo(); 594 | } 595 | allocationPointCb.hookMark = "regHooks.allocationPointCb"; 596 | GameApi.regHookHandlers['connector.userHandler.allocationPoint'].push(allocationPointCb); 597 | 598 | // 获取系统任务 599 | let getSystemTaskCb = function (data) { 600 | if (data.code != 200) { 601 | app.$Message.error(data.msg); 602 | return; 603 | } 604 | const taskList = [] 605 | data.data.list.map(task => { 606 | taskList.push({ 607 | _id: task._id, 608 | title: task.name, 609 | info: task.info 610 | }) 611 | }) 612 | app.$set(app.user, 'systemTask', taskList); 613 | } 614 | getSystemTaskCb.hookMark = "regHooks.getSystemTaskCb"; 615 | GameApi.regHookHandlers['connector.systemHandler.getSystemTask'].push(getSystemTaskCb); 616 | 617 | // 领取任务 618 | let getCopyTaskCb = function (data) { 619 | 620 | if (data.code != 200) { 621 | app.$Message.error(data.msg); 622 | return; 623 | } 624 | this.getUserTask(); 625 | } 626 | getCopyTaskCb.hookMark = "regHooks.getCopyTaskCb"; 627 | GameApi.regHookHandlers['connector.playerHandler.getCopyTask'].push(getCopyTaskCb); 628 | 629 | // 获取任务列表 630 | let getUserTaskCb = function (data) { 631 | if (data.code != 200) { 632 | app.$Message.error(data.msg); 633 | return; 634 | } 635 | buildUserTasks(data.data) 636 | } 637 | getUserTaskCb.hookMark = "regHooks.getUserTaskCb"; 638 | GameApi.regHookHandlers['connector.userHandler.getUserTask'].push(getUserTaskCb); 639 | 640 | // 完成任务回调 641 | let payUserTaskCb = function (data) { 642 | 643 | if (data.code != 200) { 644 | app.$Message.error(data.msg); 645 | return; 646 | } 647 | // 重置背包 648 | app.user.goods = []; 649 | app.user.goodsPage = 1; 650 | this.getMyGoods(); 651 | this.getUserTask(); 652 | } 653 | payUserTaskCb.hookMark = "regHooks.payUserTaskCb"; 654 | GameApi.regHookHandlers['connector.playerHandler.payUserTask'].push(payUserTaskCb); 655 | 656 | // 挖宝图回调 657 | let wbtCb = function (data) { 658 | if (!app.user.wbtResult) { 659 | app.user.wbtResult = [] 660 | } 661 | app.user.wbtResult.push(data.msg); 662 | if (data.code != 200) { 663 | app.$Message.error({ 664 | background: true, 665 | content: data.msg 666 | }); 667 | return; 668 | } 669 | app.$Message.success({ 670 | background: true, 671 | content: data.msg 672 | }); 673 | if (!window.freshPackage) return; 674 | // 重置背包 675 | app.user.goods = []; 676 | app.user.goodsPage = 1; 677 | this.getMyGoods(); 678 | } 679 | wbtCb.hookMark = "regHooks.wbtCb"; 680 | GameApi.regHookHandlers['connector.userHandler.wbt'].push(wbtCb); 681 | // 合成物品回调 682 | let makeGoodsCb = function (data) { 683 | if (data.code != 200) { 684 | app.$Message.error(data.msg); 685 | return; 686 | } 687 | app.$Message.success(data.msg); 688 | 689 | // 重置背包 690 | app.user.goods = []; 691 | app.user.goodsPage = 1; 692 | this.getMyGoods(); 693 | } 694 | makeGoodsCb.hookMark = "regHooks.makeGoodsCb"; 695 | GameApi.regHookHandlers['connector.userHandler.makeGoods'].push(makeGoodsCb); 696 | 697 | 698 | 699 | //获取宠物信息 700 | let getMyPetCb = function (data) { 701 | if (data.code != 200) { 702 | app.$Message.error(data.msg); 703 | return; 704 | } 705 | 706 | app.$set(app.user, 'myPets', data.data.data.sort((a, b) => (b.skill || []).length - (a.skill || []).length)); 707 | } 708 | getMyPetCb.hookMark = "regHooks.getMyPetCb"; 709 | GameApi.regHookHandlers['connector.userHandler.getMyPet'].push(getMyPetCb); 710 | 711 | //宠物升级、加点,放生 712 | let upUserPetLevelCb = function (data) { 713 | if (data.code != 200) { 714 | app.$Message.error(data.msg); 715 | return; 716 | } 717 | 718 | this.getMyPet() 719 | } 720 | upUserPetLevelCb.hookMark = "regHooks.upUserPetLevelCb"; 721 | GameApi.regHookHandlers['connector.userHandler.upUserPetLevel'].push(upUserPetLevelCb); 722 | 723 | //宠物出战 724 | let playUserPetCb = function (data) { 725 | if (data.code != 200) { 726 | app.$Message.error(data.msg); 727 | return; 728 | } 729 | if (data.data.name) { 730 | const msg = data.data.status ? `${data.data.name}参战成功` : `${data.data.name}休息成功` 731 | app.$Message.success(msg); 732 | } 733 | this.getMyPet() 734 | } 735 | playUserPetCb.hookMark = "regHooks.playUserPetCb"; 736 | GameApi.regHookHandlers['connector.userHandler.playUserPet'].push(playUserPetCb); 737 | 738 | 739 | //宠物幻化 740 | let turnIntoPetCb = function (data) { 741 | this.getMyPet(); 742 | if (data.code != 200) { 743 | app.$Message.error(data.msg); 744 | return; 745 | } 746 | app.$Message.success(data.msg); 747 | } 748 | turnIntoPetCb.hookMark = "regHooks.turnIntoPetCb"; 749 | GameApi.regHookHandlers['connector.userHandler.turnIntoPet'].push(turnIntoPetCb); 750 | 751 | //预览合宠 752 | let getNewPetCb = function (data) { 753 | if (data.code != 200) { 754 | app.$Message.error(data.msg); 755 | return; 756 | } 757 | app.$Message.success(data.msg); 758 | this.getMyPet() 759 | } 760 | getNewPetCb.hookMark = "regHooks.getNewPetCb"; 761 | GameApi.regHookHandlers['connector.userHandler.getNewPet'].push(getNewPetCb); 762 | 763 | //确认合宠 764 | let fitPetCb = function (data) { 765 | if (data.code != 200) { 766 | app.$Message.error(data.msg); 767 | return; 768 | } 769 | app.$Message.success(data.msg); 770 | this.getMyPet() 771 | } 772 | fitPetCb.hookMark = "regHooks.fitPetCb"; 773 | GameApi.regHookHandlers['connector.userHandler.fitPet'].push(fitPetCb); 774 | 775 | //打书 776 | let addUserPetSkillCb = function (data) { 777 | if (data.code != 200) { 778 | app.$Message.error(data.msg); 779 | return; 780 | } 781 | app.$Message.success(data.msg); 782 | this.getMyPet() 783 | } 784 | addUserPetSkillCb.hookMark = "regHooks.addUserPetSkillCb"; 785 | GameApi.regHookHandlers['connector.userHandler.addUserPetSkill'].push(addUserPetSkillCb); 786 | 787 | 788 | // 上架出售 789 | let playerSellGoodsCb = function (data) { 790 | if (data.code != 200) { 791 | app.$Message.error(data.msg); 792 | return; 793 | } 794 | app.$Message.success(`${data.data.name} x ${data.data.sell.count}上架成功`); 795 | // 重置背包 796 | app.user.goods = []; 797 | app.user.goodsPage = 1; 798 | this.getMyGoods(); 799 | } 800 | playerSellGoodsCb.hookMark = "regHooks.playerSellGoodsCb"; 801 | GameApi.regHookHandlers['connector.playerHandler.sellGoods'].push(playerSellGoodsCb); 802 | 803 | 804 | // 获取市场物品 805 | let getPlayerSellGoodsCb = function (data) { 806 | if (data.code != 200) { 807 | app.$Message.error(data.msg); 808 | return; 809 | } 810 | data.data.playerSellUser.map(sell => { 811 | app.user.market.list.push(sell); 812 | }) 813 | if (app.user.market.list.length !== data.data.count) { 814 | setTimeout(() => { 815 | user.market.pageIndex++; 816 | this.getPlayerSellGoods(user.market.pageIndex, user.market.type); 817 | }, 1100) 818 | } else { 819 | const good_map_type = {}; 820 | app.user.market.list.map(gds => { 821 | const name = gds.name || gds.goods.name; 822 | if (app.user.market.keyword && name.indexOf(app.user.market.keyword) === -1) { 823 | return 824 | } 825 | 826 | if (!good_map_type[name]) { 827 | good_map_type[name] = []; 828 | } 829 | 830 | good_map_type[name].push(gds); 831 | }); 832 | 833 | const sellGoods = []; 834 | Object.keys(good_map_type).map(name => { 835 | sellGoods.push({ 836 | name, 837 | count: good_map_type[name].length, 838 | list: good_map_type[name].sort((n, m) => (n.sell_game_gold / n.count) - (m.sell_game_gold / m.count)) 839 | }); 840 | }); 841 | app.$set(app.user.market, 'sellGoods', sellGoods); 842 | app.$Spin.hide(); 843 | } 844 | } 845 | getPlayerSellGoodsCb.hookMark = "regHooks.getPlayerSellGoodsCb"; 846 | GameApi.regHookHandlers['connector.playerHandler.getPlayerSellGoods'].push(getPlayerSellGoodsCb); 847 | 848 | //系统商城 849 | let getSystemSellGoodsCb = function (data) { 850 | if (data.code != 200) { 851 | app.$Message.error(data.msg); 852 | return; 853 | } 854 | const goods = data.data.goods; 855 | let shop = { 856 | shopPage: 0, 857 | goods: [] 858 | } 859 | if (app.user.shop) { 860 | shop.shopPage = goods.length > 0 ? app.user.shop.shopPage + 1 : app.user.shop.shopPage-1; 861 | shop.goods = app.user.shop.goods.concat(goods); 862 | } 863 | 864 | if (goods.length > 0) { 865 | this.getSystemSellGoods(shop.shopPage+1) 866 | } 867 | app.$set(app.user, 'shop', shop); 868 | } 869 | getSystemSellGoodsCb.hookMark = "regHooks.getSystemSellGoodsCb"; 870 | GameApi.regHookHandlers['connector.systemHandler.getSystemSellGoods'].push(getSystemSellGoodsCb); 871 | } -------------------------------------------------------------------------------- /src/libs/tools.js: -------------------------------------------------------------------------------- 1 | import configData from "@/config.js"; 2 | 3 | export const sleep = function (method) { 4 | const start = Number(Date.now()) 5 | return new Promise((resolve) => { 6 | (function selfRecursion () { 7 | setTimeout(() => { 8 | let flag 9 | if (typeof method === 'function') { 10 | flag = !method() 11 | } 12 | if (typeof method === 'number') { 13 | flag = Number(Date.now()) - start < method 14 | } 15 | if (flag) { 16 | selfRecursion() 17 | } else { 18 | resolve() 19 | } 20 | }, 10) 21 | })() 22 | }) 23 | } 24 | 25 | export const findMapPath = function (nowid, toid) { 26 | const maps = configData.maps 27 | const topath = [] 28 | 29 | function circleCalcle (nid, pre = []) { 30 | const { up, next } = maps.find(m => m.id === nid) 31 | const allId = up.concat(next) 32 | if (pre.length > 0 && !allId.some(id => id === pre[pre.length - 1])) return 33 | allId.filter(id => !pre.some(p => p === id)).map(id => { 34 | if (id === toid) { 35 | topath.push([...pre, nid, id]) 36 | return 37 | } 38 | circleCalcle(id, [...pre, nid]) 39 | }) 40 | } 41 | 42 | circleCalcle(nowid) 43 | const nicePath = topath.sort((n, m) => n.length - m.length)[0] 44 | nicePath.splice(0, 1) 45 | return nicePath.map(id => maps.find(m => m.id === id)) 46 | } 47 | 48 | export const randomNum = function (minNum , maxNum = Infinity, exclude = []) { 49 | let result = parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10) 50 | if (exclude.length >= (maxNum - minNum)) { 51 | return null 52 | } 53 | if (exclude.includes(result)) { 54 | result = randomNum(minNum, maxNum, exclude) 55 | } 56 | return result 57 | } -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store' 5 | import mixins from './mixins' 6 | import viewDesign from 'view-design' 7 | import 'view-design/dist/styles/iview.css' 8 | 9 | Vue.use(viewDesign) 10 | Vue.mixin(mixins) 11 | 12 | Vue.config.productionTip = false 13 | 14 | new Vue({ 15 | router, 16 | store, 17 | render: h => h(App) 18 | }).$mount('#app') 19 | -------------------------------------------------------------------------------- /src/mixins.js: -------------------------------------------------------------------------------- 1 | import { sleep } from "@libs/tools"; 2 | export default { 3 | data () { 4 | return { 5 | rareType: ["普通", "稀有", "传说", "PY"] 6 | } 7 | }, 8 | filters: { 9 | addStyle_mixin (val) { 10 | const arr1 = ["体质", "魔力", "力量", "耐力", "敏捷"]; 11 | const arr2 = ["物理暴击", "法术暴击", "特技"]; 12 | 13 | if (arr1.includes(val)) { 14 | return "color:green;font-weight: 600;"; 15 | } 16 | if (arr2.includes(val)) { 17 | return "color:orchid;"; 18 | } 19 | return ""; 20 | }, 21 | getIndex_mixin (val) { 22 | const index = val + 1; 23 | return index.toString(); 24 | } 25 | }, 26 | methods: { 27 | async useItem_mixin (readUse) { 28 | const { useNum, id, name } = readUse; 29 | if (!useNum || useNum < 0) return this.$Message.error('请输入正确的数量') 30 | window.freshPackage = false; 31 | this.$Spin.show({ 32 | render: () => ( 33 |

34 | 正在连续使用物品{name} 35 | {useNum} 36 | 个,为避免请求次数过多和程序错乱,在此窗口关闭后再进行其他操作 37 |

38 | ), 39 | }); 40 | for (let i = 0; i < useNum; i++) { 41 | this.game.useGoods(id); 42 | await sleep(1100); 43 | } 44 | window.freshPackage = true; 45 | this.game.userInfo(); 46 | // 重置背包 47 | this.user.goods = []; 48 | this.user.goodsPage = 1; 49 | this.game.getMyGoods(); 50 | this.readToUse = null; 51 | this.$Spin.hide(); 52 | }, 53 | //用于生成装备展示信息 54 | getEqsInfo_mixin (obj) { 55 | const eq_data = { 56 | 佩戴等级: obj.wear_level, 57 | 物理伤害: obj.physical_damage, 58 | 物理防御: obj.physical_defense, 59 | 魔法伤害: obj.magic_damage, 60 | 魔法防御: obj.magic_defense, 61 | 治疗能力: obj.restore_damage, 62 | 气血: obj.a, 63 | 速度: obj.speed, 64 | 体质: obj.con, 65 | 魔力: obj.int, 66 | 力量: obj.str, 67 | 耐力: obj.vit, 68 | 敏捷: obj.agi, 69 | 物理暴击: obj.physical_crit, 70 | 法术暴击: obj.magic_crit, 71 | 特技: obj.skill ? `${obj.skill.name}--${obj.skill.info}` : "", 72 | 评分: Math.round(obj.score), 73 | }; 74 | let eq_info = {}; 75 | for (const key in eq_data) { 76 | if (eq_data.hasOwnProperty(key)) { 77 | const element = eq_data[key]; 78 | if (element) { 79 | eq_info[key] = element; 80 | } 81 | } 82 | } 83 | return eq_info; 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import Home from '../views/Home.vue' 4 | import User from '../views/User.vue' 5 | 6 | Vue.use(VueRouter) 7 | 8 | const routes = [ 9 | { 10 | path: '/', 11 | name: 'Home', 12 | component: Home 13 | }, 14 | { 15 | path: '/user/:email', 16 | name: 'user', 17 | component: User 18 | } 19 | ] 20 | 21 | const router = new VueRouter({ 22 | routes 23 | }) 24 | 25 | export default router 26 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | }, 9 | mutations: { 10 | }, 11 | actions: { 12 | }, 13 | modules: { 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 |