player.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. 'use strict';
  2. var request = require('request');
  3. var Jimp = require('jimp');
  4. var fs = require('fs');
  5. var quick = require('quick-pomelo');
  6. var P = quick.Promise;
  7. var _ = require('lodash');
  8. var uuid = require('node-uuid');
  9. var md5 = require('md5');
  10. var C = require('../../share/constant');
  11. var logger = quick.logger.getLogger('player', __filename);
  12. var configCommon = require('../../share/configCommon');//////TL++配置相关的公共方法
  13. var Controller = function (app) {
  14. this.app = app;
  15. this.lconfigCommon = new configCommon(this.app);
  16. };
  17. module.exports = function (app) {
  18. return new Controller(app);
  19. };
  20. var proto = Controller.prototype;
  21. var requestGet = P.promisify(request.get, {multiArgs: true});
  22. proto.convertUrlToPng = P.coroutine(function* (url, outputPath) {
  23. try {
  24. console.warn("url:",url)
  25. // 1. 使用 request 获取数据,必须 encoding: null
  26. var result = yield requestGet({
  27. url: url,
  28. encoding: null,
  29. timeout: 10000,
  30. headers: {
  31. 'User-Agent': 'Mozilla/5.0'
  32. }
  33. });
  34. // console.warn("湖南红中 游戏服务器启动",result);
  35. //console.log("result[1]:",result[1])
  36. // 重点:multiArgs: true 会返回 [response, body]
  37. // result[0] 是响应头,result[1] 才是真正的图片 Buffer
  38. var response = result[0];
  39. var body = result[1];
  40. if (!response || response.statusCode !== 200) {
  41. throw new Error('Download failed, status: ' + (response ? response.statusCode : 'unknown'));
  42. }
  43. if (!body || body.length === 0) {
  44. throw new Error('Received empty buffer');
  45. }
  46. // 2. 使用 Jimp 读取 Buffer
  47. // 如果依然报 MIME 错误,可以尝试强制指定格式 (仅限确定是 jpg/png 的情况)
  48. var image = yield Jimp.read(body);
  49. console.warn("68")
  50. // 3. 转换并输出
  51. // 老版本 Jimp 0.2.28 的 getBuffer 是回调模式,需要 promisify
  52. var pngBuffer = yield new P(function(resolve, reject) {
  53. // 显式检查 image 对象是否存在且有 getBuffer 方法
  54. console.warn("73")
  55. if (!image || typeof image.getBuffer !== 'function'){
  56. console.warn("75:",typeof image.getBuffer)
  57. //console.warn("75:", typeof image.getBuffer);
  58. return reject(new Error('Jimp 实例无效或不支持 getBuffer 方法'));
  59. }
  60. image.getBuffer(Jimp.MIME_PNG, function(err, buffer) {
  61. console.warn("80:")
  62. if (err) return reject(err);
  63. resolve(buffer);
  64. });
  65. console.log("81")
  66. });
  67. console.warn("83")
  68. if (outputPath) {
  69. console.warn("84")
  70. yield new P(function(resolve, reject) {
  71. console.warn("91:")
  72. if (typeof image.write !== 'function') {
  73. console.warn("91:")
  74. return reject(new Error('Jimp 实例不支持 write 方法'));
  75. }
  76. image.write(outputPath, function(err) {
  77. console.warn("err:",err)
  78. if (err) return reject(err);
  79. console.warn("96:")
  80. resolve();
  81. console.warn("err:",100)
  82. });
  83. });
  84. console.warn('转换并保存成功: ' + outputPath);
  85. }
  86. return pngBuffer;
  87. } catch (error) {
  88. // 增加更详细的报错日志,方便排查
  89. console.error('图片转换失败详情:', error.message);
  90. if (error.stack) console.error(error.stack);
  91. }
  92. });
  93. // 登陆
  94. proto.convertUrlToPng = function(url, outputPath, callback) {
  95. // 替换后缀为 png(仅改名字,内容还是 SVG)
  96. var pngOutputPath = outputPath.replace(/\.[^.]+$/, '.png');
  97. var https = require('https');
  98. var fs = require('fs');
  99. var request = https.get(url, function(response) {
  100. if (response.statusCode !== 200) {
  101. return callback(new Error('请求失败,状态码:' + response.statusCode));
  102. }
  103. var fileStream = fs.createWriteStream(pngOutputPath);
  104. response.pipe(fileStream);
  105. fileStream.on('finish', function() {
  106. fileStream.close(function() {
  107. // 模拟返回 Buffer(Node 4.4.7 兼容)
  108. fs.readFile(pngOutputPath, function(err, buffer) {
  109. if (err) return callback(err);
  110. callback(null, buffer); // 回调返回 Buffer,兼容原有逻辑
  111. });
  112. });
  113. });
  114. fileStream.on('error', function(err) {
  115. fs.unlink(pngOutputPath, function() {});
  116. callback(err);
  117. });
  118. });
  119. request.on('error', function(err) {
  120. callback(err);
  121. });
  122. request.setTimeout(10000, function() {
  123. request.destroy();
  124. callback(new Error('请求超时'));
  125. });
  126. };
  127. // 创建玩家
  128. proto.createAsync = P.coroutine(function* (playerId, name, sex, headurl,tel,pwd,ip,spreadId,formId, diamond) {
  129. console.warn("convertUrlToPng")
  130. this.convertUrlToPng('https://bargame.ala456.com/gameRes/1.svg', 'D:/web/root80/'+playerId+'.png', function(err, buffer) {
  131. if (err) {
  132. console.error('转换失败:' + err.message);
  133. return;
  134. }
  135. console.log('转换完成,Buffer 长度:' + buffer.length);
  136. });
  137. //this.convertUrlToPng(headurl,"D:\\web\\root80\\image\\"+playerId+".png")
  138. let diamondReg=500;//5000000;//ts++注册赠送
  139. if (diamond) {
  140. // diamondReg = diamond;
  141. }
  142. if (!name) name = 'User' + _.random(100000, 999999);
  143. var account = md5(playerId).toLowerCase();
  144. var newId = yield P.promisify((cb) => this.app.rpc.increaser.increaseRemote.newUserId(null, cb))();
  145. let _spreadId = '99999999';////系统
  146. let _myurl = 'http://fhmj.jzb518.com/';
  147. if (spreadId)
  148. {
  149. _spreadId=spreadId;////20200918TL++,把下面那行放在这里了
  150. var spreader = yield this.app.models.Player.findByIdReadOnlyAsync(spreadId,'myurl');
  151. if (spreader)
  152. {
  153. // _spreadId=spreadId;
  154. _myurl=spreader.myurl;
  155. }
  156. }
  157. //ts++end
  158. var player = new this.app.models.Player({
  159. _id: playerId,
  160. account: account,
  161. userId: newId,
  162. name: name,
  163. diamond: diamondReg,
  164. sex: sex || '1',
  165. tel: tel || '',
  166. pwd: pwd || '',
  167. registerIp: ip || '',
  168. headurl: playerId+".png" || '',
  169. spreadId: _spreadId || '',
  170. formId: formId
  171. //myurl: _myurl || 'http://fhmj.jzb518.com/',
  172. });
  173. yield player.saveAsync();
  174. // 钻石记录
  175. var diamondrecord = new this.app.models.DiamondRecord({
  176. _id: uuid.v1(),
  177. playerId: playerId,
  178. dType: 1,//注册
  179. dSource: 0,
  180. dSwap: diamondReg,
  181. dNow: diamondReg
  182. });
  183. yield diamondrecord.saveAsync();
  184. var channelId = 'p:' + playerId;
  185. yield this.app.controllers.push.joinAsync(channelId, playerId);
  186. return player;
  187. });
  188. // 记录该玩家的邀请人信息 用于邀请新人按比例送钻这个活动
  189. proto.setNewerYQXXAsync = P.coroutine(function* (playerId, userId, spreadId) {
  190. // console.warn("记录该玩家的邀请人信息 playerId "+playerId+" userId "+userId+" spreadId "+spreadId);
  191. let xzdsjc = Date.now();
  192. let yxhdxx = this.lconfigCommon.getActiveOpenTime(6);//邀请新人按比例送钻活动是否开启和开始结束时间的信息
  193. let isKQ = false;//邀请新人送钻石活动是否开启
  194. if(yxhdxx && yxhdxx.open && yxhdxx.startTime && yxhdxx.endTime) isKQ = true;
  195. // console.warn("获取配置信息 yxhdxx "+JSON.stringify(yxhdxx));
  196. if(!(isKQ && xzdsjc >= yxhdxx.startTime && xzdsjc < yxhdxx.endTime)){
  197. return;//活动未开启
  198. }
  199. if((spreadId+"").length != 6) return;
  200. if(spreadId == userId) return;
  201. var yPlayers = yield this.app.models.Player.findMongoAsync({ userId: spreadId },'_id userId');
  202. if (yPlayers.length != 1) return;
  203. if(yPlayers[0].userId != spreadId) return;
  204. // console.warn("记录该玩家的邀请人信息 yPlayers[0]._id "+yPlayers[0]._id);
  205. var inviter = yield this.app.models.Invite.findByIdAsync(playerId);
  206. if (!inviter) {
  207. var invite = new this.app.models.Invite({
  208. _id: playerId, // 被邀请人标识
  209. yId: yPlayers[0]._id, // 邀请人标识
  210. yuId: spreadId, // 邀请人用户id
  211. });
  212. return yield invite.saveAsync();
  213. }
  214. return;
  215. });
  216. ////玩家登陆的时候给玩家发邮件
  217. proto.sendMailOnLoginAsync = P.coroutine(function* (playerId,userId) {
  218. // console.warn("玩家登陆的时候给玩家发邮件 playerId "+playerId+" userId "+userId);
  219. ////下面是邀请新人按比例送钻这个活动的奖励通过邮件发放(只发送登陆前一日的奖励,过期不候)
  220. if(!playerId || !userId) return;
  221. let jrStart = getTodaySJC();////更新今日0时的时间戳
  222. // console.warn("玩家登陆的时候给玩家发邮件 jrStart "+jrStart);
  223. let opts0 = {
  224. pId: playerId,
  225. isSend: 0,
  226. dayTime: { $gte: jrStart-86400000, $lt: jrStart}
  227. };
  228. var zrxhList = yield this.app.models.InvitesCost.findMongoAsync(opts0, 'pId uId all isSend');
  229. // console.warn("下面是记录邀请新人按比例送钻这个活动的数据 length "+zrxhList.length+" zrxhList "+JSON.stringify(zrxhList))
  230. if (zrxhList.length == 1) {
  231. yield this.lconfigCommon.senMailToPlayer(playerId,userId,12,12,1,1,zrxhList[0].all,"activity6");
  232. zrxhList[0].isSend = 1;
  233. yield zrxhList[0].saveAsync();
  234. }
  235. return;
  236. });
  237. // 移除玩家
  238. proto.removeAsync = P.coroutine(function* (playerId) {
  239. var player = yield this.app.models.Player.findByIdAsync(playerId);
  240. if (player) {
  241. let channelId = 'p:' + playerId;
  242. yield this.app.controllers.push.quitAsync(channelId, playerId);
  243. return player.removeAsync();
  244. }
  245. });
  246. // 连接频道
  247. proto.connectAsync = P.coroutine(function* (playerId,name,headurl, connectorId, ip,sex,formId) {
  248. var player = yield this.app.models.Player.findByIdAsync(playerId, 'gameId gameServerId connectorId lastLoginIp lastLoginTime name headurl sex formId');
  249. if (!player) {
  250. throw new Error('player ' + playerId + ' not exist');
  251. }
  252. var oldGameId = player.gameId;
  253. var oldGameSvrId = player.gameServerId;
  254. var oldConnectorId = player.connectorId;
  255. // console.warn("更新用户昵称",name , player.name);
  256. // console.warn("更新用户头像",headurl , player.headurl);
  257. /////TL++,下面两句为了实现更新昵称和头像
  258. if(name && name != player.name) player.name = name;
  259. if(headurl && headurl != player.headurl) player.headurl = playerId+".png";
  260. // if(sex != player.sex) player.sex = sex;//微信不返回性别了
  261. if(formId != player.formId) player.formId = formId;
  262. player.connectorId = connectorId;
  263. player.lastLoginIp = ip;
  264. player.lastLoginTime = Date.now();
  265. yield player.saveAsync();
  266. //记录玩家登陆信息
  267. // console.warn('player ' + playerId )
  268. let jrStart = getTodaySJC();////更新今日0时的时间戳
  269. let opts1 = {
  270. playerId: playerId,
  271. loginTime: { $gte: jrStart, $lt: jrStart+86400000}
  272. };
  273. let jrLoginCount = yield this.app.models.Login.countMongoAsync(opts1);
  274. // console.warn("今日该玩家登录次数 "+jrLoginCount);
  275. if(jrLoginCount == 0){
  276. var login = new this.app.models.Login({
  277. _id: uuid.v1(),
  278. playerId: playerId,
  279. loginTime: Date.now()
  280. });
  281. yield login.saveAsync();
  282. // console.warn("保存该玩家登陆记录");
  283. }
  284. yield this.app.controllers.push.connectAsync(playerId, connectorId);
  285. //logger.info('connect %s %s => %s', playerId, connectorId, oldConnectorId);
  286. return { oldGameId: oldGameId, oldGameSvrId: oldGameSvrId, oldConnectorId: oldConnectorId};
  287. });
  288. // 断开频道
  289. proto.disconnectAsync = P.coroutine(function* (playerId) {
  290. var player = yield this.app.models.Player.findByIdAsync(playerId, 'gameId gameServerId connectorId offlineTime');
  291. if (!player) {
  292. throw new Error('player ' + playerId + ' not exist');
  293. }
  294. var gameId = player.gameId;
  295. var gameSvrId = player.gameServerId;
  296. var connectorId = player.connectorId;
  297. player.connectorId = '';
  298. player.offlineTime = Date.now();
  299. yield player.saveAsync();
  300. // logger.info('disconnect %s', playerId);
  301. yield this.app.controllers.push.disconnectAsync(playerId);
  302. return { gameId: gameId, gameSvrId: gameSvrId, connectorId: connectorId };
  303. });
  304. // 推送消息
  305. proto.pushAsync = function (playerId, route, msg) {
  306. var channelId = 'p:' + playerId;
  307. return this.app.controllers.push.pushAsync(channelId, null, route, msg, false);
  308. };
  309. // 获取消息
  310. proto.getMsgsAsync = function (playerId, seq, count) {
  311. var channelId = 'p:' + playerId;
  312. return this.app.controllers.push.getMsgsAsync(channelId, seq, count);
  313. };
  314. //TL++,得到今日0点的时间戳
  315. function getTodaySJC() {
  316. var today = new Date();
  317. today.setHours(0);
  318. today.setMinutes(0);
  319. today.setSeconds(0);
  320. today.setMilliseconds(0);
  321. let jrsjc = today.getTime();
  322. // console.warn("111得到今日0点的时间戳 ",jrsjc, typeof jrsjc);
  323. return jrsjc;
  324. };