gamesModel.class.php 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. <?php
  2. /**
  3. *
  4. */
  5. class gamesModel extends NewModel
  6. {
  7. /**
  8. * 花色字典
  9. * @var array
  10. */
  11. public static $colors = [
  12. 'spade' => 0,
  13. 'heart' => 1,
  14. 'club' => 2,
  15. 'diamond' => 3,
  16. ];
  17. /**
  18. * 牌点字典
  19. * @var array
  20. */
  21. public static $figures = [
  22. 'A' => 1,
  23. '2' => 2,
  24. '3' => 3,
  25. '4' => 4,
  26. '5' => 5,
  27. '6' => 6,
  28. '7' => 7,
  29. '8' => 8,
  30. '9' => 9,
  31. '10' => 10,
  32. 'J' => 11,
  33. 'Q' => 12,
  34. 'K' => 13,
  35. ];
  36. /**
  37. * redis对象实例
  38. * @var [type]
  39. */
  40. protected static $redis, $video_redis;
  41. /**
  42. * 根据投注总数排序发牌结果
  43. * @param array $sum 投注总数
  44. * @param array $res 发牌结果
  45. * @return array 发牌结果
  46. */
  47. protected static function sortGame($sum, $res)
  48. {
  49. $min = min($sum);
  50. asort($sum);
  51. $data = array();
  52. foreach ($sum as $k => $v) {
  53. if ($v == $min) {
  54. $data[] = array_shift($res);
  55. shuffle($data);
  56. shuffle($res);
  57. } else {
  58. $data[] = array_pop($res);
  59. }
  60. }
  61. $result = array();
  62. $i = 0;
  63. foreach ($sum as $k => $v) {
  64. $result[$k] = $data[$i];
  65. $i++;
  66. }
  67. ksort($result);
  68. return $result;
  69. }
  70. /**
  71. * 根据字典转换卡牌数据
  72. * @param [type] $cards [description]
  73. * @return [type] [description]
  74. */
  75. public static function parseCards($cards)
  76. {
  77. $new_cards = array();
  78. foreach ($cards as $v) {
  79. $new_cards[] = array(self::$colors[$v[0]], self::$figures[$v[1]]);
  80. }
  81. return $new_cards;
  82. }
  83. /**
  84. * 格式化卡片卡牌数据
  85. * @param [type] $cards_data [description]
  86. * @return [type] [description]
  87. */
  88. protected static function formatCardsData($cards_data)
  89. {
  90. $data = [];
  91. foreach ($cards_data as $key => $value) {
  92. $cards = self::parseCards($value['cards']);
  93. $data[] = array(
  94. 'win' => !$key,
  95. 'cards' => $cards,
  96. 'type' => $value['check']['type'],
  97. );
  98. }
  99. return $data;
  100. }
  101. /**
  102. * 游戏定时器
  103. * @return [type] [description]
  104. */
  105. public function crontab()
  106. {
  107. /**
  108. * 封装各方法
  109. * @return [type] [description]
  110. */
  111. $microtime = microtime(1);
  112. fanwe_require(APP_ROOT_PATH . 'mapi/lib/redis/BaseRedisService.php');
  113. fanwe_require(APP_ROOT_PATH . 'mapi/lib/redis/GamesRedisService.php');
  114. $redis = new GamesRedisService();
  115. if ($redis->isLock()) {
  116. return array('is_lock');
  117. }
  118. $redis->lock();
  119. fanwe_require(APP_ROOT_PATH . 'mapi/lib/redis/VideoRedisService.php');
  120. $video_redis = new VideoRedisService();
  121. $game_log_model = self::build('game_log');
  122. $time = NOW_TIME;
  123. $games = $game_log_model->field('id,game_id,create_time,long_time')->select(['status' => 1]);
  124. $game_types = array();
  125. $return_data = array('time' => 0);
  126. /**
  127. * 游戏处理
  128. */
  129. if ($games) {
  130. $m_config = load_auto_cache("m_config");
  131. $game_commission = +$m_config['game_commission'];
  132. $podcast_commission = intval(defined('PODCAST_COMMISSION') && PODCAST_COMMISSION);
  133. $bm_promoter = intval(defined('OPEN_BM') && OPEN_BM);
  134. if ($bm_promoter) {
  135. $bm_config = load_auto_cache("bm_config");
  136. $promoter_times = floatval($bm_config['promoter_center_game_stream_revenue']) / 100;
  137. $platform_times = floatval($bm_config['sites_game_stream_revenue']) / 100;
  138. }
  139. $user_model = self::build('user');
  140. $games_model = self::build('games');
  141. $coin_log_model = self::build('coin_log');
  142. $banker_log_model = self::build('banker_log');
  143. $user_game_log_model = self::build('user_game_log');
  144. fanwe_require(APP_ROOT_PATH . 'mapi/lib/tools/Poker.class.php');
  145. fanwe_require(APP_ROOT_PATH . 'mapi/lib/tools/NiuNiu.class.php');
  146. fanwe_require(APP_ROOT_PATH . 'mapi/lib/tools/DeZhou.class.php');
  147. fanwe_require(APP_ROOT_PATH . 'mapi/lib/tools/Dice.class.php');
  148. fanwe_require(APP_ROOT_PATH . 'mapi/lib/redis/UserRedisService.php');
  149. $user_redis = new UserRedisService();
  150. foreach ($games as $game) {
  151. $game_log_id = $game['id'];
  152. $game_id = $game['game_id'];
  153. $game_log = $redis->get($game_log_id, 'video_id,podcast_id,group_id,public_cards,banker_id');
  154. $video_id = $game_log['video_id'];
  155. $podcast_id = $game_log['podcast_id'];
  156. $banker_id = $game_log['banker_id'];
  157. if (!isset($game_types[$game_id])) {
  158. $game_types[$game_id] = $games_model->field('commission_rate,rate,option,class,principal,ticket_rate')->selectOne(['id' => $game_id]);
  159. }
  160. $game_type = $game_types[$game_id];
  161. $option = json_decode($game_type['option'], 1);
  162. if (!in_array($game_type['class'], ['Poker', 'NiuNiu', 'DeZhou', 'Dice'])) {
  163. break;
  164. }
  165. $game_object = new $game_type['class']();
  166. if ($game['create_time'] + $game['long_time'] <= $time) {
  167. $live_in = $video_redis->getOne_db($video_id, 'live_in');
  168. if ($redis->isVideoLock($video_id)) {
  169. break;
  170. }
  171. $redis->lockVideo($video_id);
  172. if ($live_in && $game['long_time']) {
  173. $sql_time = microtime(1);
  174. // 计算投注结果
  175. $sum = [];
  176. $sum_v = [];
  177. $table = DB_PREFIX . 'user_game_log';
  178. foreach ($option as $key => $value) {
  179. $res = intval($user_game_log_model->sum('money', ['game_log_id' => $game_log_id, 'bet' => $key]));
  180. $sum[] = $res;
  181. $sum_v[] = $res * $value;
  182. }
  183. $rate = $user_redis->getOne_db($podcast_id, 'rate');
  184. $rate = $rate ? $rate : (+$game_type['rate']);
  185. $cheat = rand(1, 100) < $rate && !$banker_id;
  186. $dices = [];
  187. $cards_data = [];
  188. switch ($game_id) {
  189. case 1:
  190. case 2:
  191. $cards_data = self::formatCardsData($game_object->play());
  192. if ($cheat) {
  193. $cards_data = self::sortGame($sum_v, $cards_data);
  194. } else {
  195. shuffle($cards_data);
  196. }
  197. break;
  198. case 3:
  199. $game_object->flop(json_decode($game_log['public_cards'], 1));
  200. $data = self::formatCardsData($game_object->play());
  201. $cards = self::parseCards($game_object->gp);
  202. $gp = array(
  203. 'win' => false,
  204. 'cards' => $cards,
  205. 'type' => 0,
  206. );
  207. if ($game_object->compare($res[0], $res[1]) == $game_object->compare($res[1], $res[0])) {
  208. $data[0]['win'] = false;
  209. $gp['win'] = true;
  210. shuffle($data);
  211. } else {
  212. if ($cheat && $sum_v[2] > $sum_v[0]) {
  213. $value = $data[0];
  214. $data[0] = $data[1];
  215. $data[1] = $value;
  216. } else {
  217. shuffle($data);
  218. }
  219. }
  220. $cards_data = array(
  221. $data[0],
  222. $gp,
  223. $data[1],
  224. );
  225. break;
  226. case 4:
  227. if ($cheat) {
  228. $key = [];
  229. $min = min($sum_v);
  230. foreach ($sum_v as $k => $v) {
  231. $key[] = $k;
  232. }
  233. $key = $key[array_rand($key)];
  234. $total = $key == 1 ? 7 : ($key ? rand(8, 12) : rand(2, 6));
  235. } else {
  236. $total = false;
  237. }
  238. $dices = $game_object->play(2, $total);
  239. break;
  240. default:
  241. break;
  242. }
  243. // 计算得胜结果
  244. $result = 0;
  245. $data = array('status' => 2);
  246. if ($cards_data) {
  247. foreach ($cards_data as $key => $value) {
  248. if ($value['win']) {
  249. $result = $key + 1;
  250. }
  251. unset($cards_data[$key]['win']);
  252. $data['option_win' . ($key + 1)] = intval($value['win']);
  253. $data['option_cards' . ($key + 1)] = json_encode($value['cards']);
  254. $data['option_type' . ($key + 1)] = $value['type'];
  255. }
  256. } else if ($dices) {
  257. $res = array_sum($dices);
  258. switch ($res) {
  259. case 7:
  260. $result = 2;
  261. break;
  262. default:
  263. $result = $res > 7 ? 1 : 3;
  264. break;
  265. }
  266. $data['dices'] = json_encode($dices);
  267. }
  268. $data['win'] = $result;
  269. $times = $option[$result];
  270. $redis->set($game_log_id, $data);
  271. // MySQL结束游戏
  272. // 计算主播收入
  273. $commission_rate = $game_type['commission_rate'];
  274. $income = array_sum($sum) - $times * $sum[$result - 1];
  275. $suit_patterns = json_encode($cards_data ? $cards_data : $dices);
  276. $bet = json_encode($sum);
  277. $podcast_income = $income > 0 ? intval($income * $commission_rate / 100) : 0;
  278. $final_income = $banker_id ? ($income > 0 ? intval($income * $game_commission / 100) : 0) : $income - $podcast_income;
  279. $commission = 0;
  280. Connect::beginTransaction();
  281. // 游戏记录结算
  282. if ($game_log_model->resultLog($game_log_id, $result, $bet, $suit_patterns, $podcast_income, $banker_id ? 0 : $final_income) === false) {
  283. Connect::rollback();
  284. $return_data[$game_log_id] = 'error:' . __LINE__ . ' sql:' . $game_log_model->getLastSql();
  285. break;
  286. }
  287. // 玩家收入
  288. if ($sum[$result - 1]) {
  289. // 获得下注总金额三倍返还
  290. if ($user_model->multiAddCoin($game_log_id, $result, $times) === false) {
  291. Connect::rollback();
  292. $return_data[$game_log_id] = 'error:' . __LINE__ . ' sql:' . $user_model->getLastSql();
  293. break;
  294. }
  295. // 批量插入金币记录
  296. if ($coin_log_model->multiAddLog($game_log_id, $result, $times) === false) {
  297. Connect::rollback();
  298. $return_data[$game_log_id] = 'error:' . __LINE__ . ' sql:' . $coin_log_model->getLastSql();
  299. break;
  300. }
  301. // 平台抽成
  302. if ($game_commission) {
  303. if ($user_model->multiAddCoin($game_log_id, $result, -$game_commission / 100 * $times) === false) {
  304. Connect::rollback();
  305. $return_data[$game_log_id] = 'error:' . __LINE__ . ' sql:' . $user_model->getLastSql();
  306. break;
  307. }
  308. // 批量插入金币记录
  309. if ($coin_log_model->multiAddLog($game_log_id, $result, -$game_commission / 100 * $times, '玩家收入平台抽成') === false) {
  310. Connect::rollback();
  311. $return_data[$game_log_id] = 'error:' . __LINE__ . ' sql:' . $coin_log_model->getLastSql();
  312. break;
  313. }
  314. }
  315. // 主播抽成
  316. if ($podcast_commission) {
  317. if ($user_model->multiAddCoin($game_log_id, $result, -$commission_rate / 100 * $times) === false) {
  318. Connect::rollback();
  319. $return_data[$game_log_id] = 'error:' . __LINE__ . ' sql:' . $user_model->getLastSql();
  320. break;
  321. }
  322. // 批量插入金币记录
  323. if ($coin_log_model->multiAddLog($game_log_id, $result, -$commission_rate / 100 * $times, '玩家收入主播抽成') === false) {
  324. Connect::rollback();
  325. $return_data[$game_log_id] = 'error:' . __LINE__ . ' sql:' . $coin_log_model->getLastSql();
  326. break;
  327. }
  328. $commission = $commission_rate / 100 * $times * $sum[$result - 1];
  329. if (defined('OPEN_DIAMOND_GAME_MODULE') && OPEN_DIAMOND_GAME_MODULE == 1) {
  330. $ticket = intval($commission * $game_type['ticket_rate'] / 100);
  331. $res = $user_model->update(['ticket' => ['ticket + ' . $ticket]], ['id' => $podcast_id]);
  332. $video_redis->inc_field($video_id, 'vote_number', $ticket);
  333. if ($res) {
  334. $log_data = [
  335. 'log_info' => '主播游戏赢家抽成',
  336. 'log_time' => NOW_TIME,
  337. 'log_admin_id' => 0,
  338. 'money' => 0,
  339. 'user_id' => 1,
  340. 'type' => 7,
  341. 'prop_id' => 0,
  342. 'score' => 0,
  343. 'point' => 0,
  344. 'podcast_id' => $podcast_id,
  345. 'diamonds' => 0,
  346. 'ticket' => $ticket,
  347. 'video_id' => $video_id,
  348. ];
  349. self::build('user_log')->insert($log_data);
  350. }
  351. if (defined('GAME_DISTRIBUTION') && GAME_DISTRIBUTION) {
  352. if (self::build('game_distribution')->addLog($podcast_id, $video_id, $game_log_id, $ticket, '游戏直播分销') === false) {
  353. Connect::rollback();
  354. $return_data[$game_log_id] = 'error:' . __LINE__ . ' sql:' . $user_game_log_model->getLastSql();
  355. break;
  356. }
  357. }
  358. } else {
  359. $res = $user_model->coin($podcast_id, $commission);
  360. $account_diamonds = $user_model->coin($podcast_id);
  361. if ($res) {
  362. //会员账户 金币变更日志表
  363. if ($coin_log_model->addLog($podcast_id, $game_log_id, $commission, $account_diamonds, '主播游戏赢家抽成') === false) {
  364. Connect::rollback();
  365. $return_data[$game_log_id] = 'error:' . __LINE__;
  366. break;
  367. }
  368. }
  369. if (defined('GAME_DISTRIBUTION') && GAME_DISTRIBUTION) {
  370. if (self::build('game_distribution')->addLog($podcast_id, $video_id, $game_log_id, $commission, '游戏直播分销') === false) {
  371. Connect::rollback();
  372. $return_data[$game_log_id] = 'error:' . __LINE__ . ' sql:' . $user_game_log_model->getLastSql();
  373. break;
  374. }
  375. }
  376. }
  377. }
  378. $win_rate = (1 - ($game_commission + $commission_rate * $podcast_commission) / 100);
  379. $win_times = $times * $win_rate;
  380. // 批量插入获胜记录
  381. if ($user_game_log_model->multiAddLog($game_log_id, $result, $win_times, $podcast_id) === false) {
  382. Connect::rollback();
  383. $return_data[$game_log_id] = 'error:' . __LINE__ . ' sql:' . $user_game_log_model->getLastSql();
  384. break;
  385. }
  386. if (defined('WEIXIN_DISTRIBUTION') && WEIXIN_DISTRIBUTION) {
  387. self::build('weixin_distribution_log')->muitAddLog($game_log_id, $win_rate, '直播游戏分销');
  388. }
  389. }
  390. // 主播收入增加
  391. if ($podcast_income) {
  392. if (defined('OPEN_DIAMOND_GAME_MODULE') && OPEN_DIAMOND_GAME_MODULE == 1) {
  393. $ticket = intval($podcast_income * $game_type['ticket_rate'] / 100);
  394. $res = $user_model->update(['ticket' => ['ticket + ' . $ticket]], ['id' => $podcast_id]);
  395. $video_redis->inc_field($video_id, 'vote_number', $ticket);
  396. if ($res) {
  397. $log_data = [
  398. 'log_info' => '游戏直播收入',
  399. 'log_time' => NOW_TIME,
  400. 'log_admin_id' => 0,
  401. 'money' => 0,
  402. 'user_id' => $podcast_id,
  403. 'type' => 7,
  404. 'prop_id' => 0,
  405. 'score' => 0,
  406. 'point' => 0,
  407. 'podcast_id' => $podcast_id,
  408. 'diamonds' => 0,
  409. 'ticket' => $ticket,
  410. 'video_id' => $video_id,
  411. ];
  412. self::build('user_log')->insert($log_data);
  413. }
  414. if (defined('GAME_DISTRIBUTION') && GAME_DISTRIBUTION) {
  415. if (self::build('game_distribution')->addLog($podcast_id, $video_id, $game_log_id, $ticket, '游戏直播分销') === false) {
  416. Connect::rollback();
  417. $return_data[$game_log_id] = 'error:' . __LINE__ . ' sql:' . $user_game_log_model->getLastSql();
  418. break;
  419. }
  420. }
  421. } else {
  422. $res = $user_model->coin($podcast_id, $podcast_income);
  423. $account_diamonds = $user_model->coin($podcast_id);
  424. if ($res) {
  425. //会员账户 金币变更日志表
  426. if ($coin_log_model->addLog($podcast_id, $game_log_id, $podcast_income, $account_diamonds, '游戏直播收入') === false) {
  427. Connect::rollback();
  428. $return_data[$game_log_id] = 'error:' . __LINE__;
  429. break;
  430. }
  431. }
  432. if (defined('GAME_DISTRIBUTION') && GAME_DISTRIBUTION) {
  433. if (self::build('game_distribution')->addLog($podcast_id, $video_id, $game_log_id, $podcast_income, '游戏直播分销') === false) {
  434. Connect::rollback();
  435. $return_data[$game_log_id] = 'error:' . __LINE__ . ' sql:' . $user_game_log_model->getLastSql();
  436. break;
  437. }
  438. }
  439. }
  440. }
  441. // 主播收入增加
  442. if ($podcast_income + $commission) {
  443. if ($user_game_log_model->addLog($game_log_id, $podcast_id, $podcast_income + $commission) === false) {
  444. Connect::rollback();
  445. $return_data[$game_log_id] = 'error:' . __LINE__;
  446. break;
  447. }
  448. }
  449. if ($bm_promoter) {
  450. $win_times = $win_times ? $win_times : 0;
  451. if (self::build('bm_promoter')->addGameLog($game_log_id, $result, $win_times, $promoter_times, $platform_times) === false) {
  452. Connect::rollback();
  453. $return_data[$game_log_id] = 'error:' . __LINE__ . ' sql:' . $game_log_model->getLastSql();
  454. break;
  455. }
  456. }
  457. $stop_banker = false;
  458. // 庄家收入
  459. if ($banker_id) {
  460. $banker_income = $income;
  461. if ($income > 0) {
  462. $banker_income = intval((100 - $game_commission - $commission_rate) / 100 * $income);
  463. }
  464. $res = $banker_log_model->update(['coin' => ["`coin`+$banker_income"]], ['user_id' => $banker_id, 'video_id' => $video_id, 'status' => 3]);
  465. $video_redis->inc_field($video_id, 'coin', $banker_income);
  466. $coin = $video_redis->getOne_db($video_id, 'coin');
  467. if ($res) {
  468. if ($user_game_log_model->addLog($game_log_id, $banker_id, $banker_income) === false) {
  469. Connect::rollback();
  470. $return_data[$game_log_id] = 'error:' . __LINE__;
  471. break;
  472. }
  473. }
  474. // 强制下庄
  475. if ($coin < $game_type['principal']) {
  476. $stop_banker = true;
  477. }
  478. }
  479. Connect::commit();
  480. $sql_time = microtime(1) - $sql_time;
  481. $ids = array();
  482. if ($sum[$result - 1]) {
  483. $res = $user_game_log_model->field('user_id')->group('user_id')->select(array('game_log_id' => $game_log_id));
  484. foreach ($res as $value) {
  485. $ids[] = $value['user_id'];
  486. }
  487. }
  488. if ($podcast_income) {
  489. $ids[] = $podcast_id;
  490. }
  491. if (!empty($ids)) {
  492. user_deal_to_reids($ids);
  493. }
  494. $banker = $video_redis->getRow_db($video_id, [
  495. 'banker_status',
  496. 'banker_id',
  497. 'banker_log_id',
  498. 'banker_name',
  499. 'banker_img',
  500. 'coin',
  501. ]);
  502. $tim_time = microtime(1);
  503. // 新推送
  504. $ext = array(
  505. 'type' => 39,
  506. 'desc' => '',
  507. 'room_id' => $video_id,
  508. 'time' => 0,
  509. 'game_id' => $game_id,
  510. 'game_log_id' => $game_log_id,
  511. 'game_status' => 2,
  512. 'game_action' => 4,
  513. 'podcast_income' => $podcast_income,
  514. 'game_data' => array(
  515. 'win' => $result,
  516. 'bet' => $sum,
  517. 'dices' => $dices,
  518. 'cards_data' => $cards_data,
  519. ),
  520. 'banker_status' => intval($banker['banker_status']),
  521. 'banker' => [
  522. 'banker_id' => intval($banker['banker_id']),
  523. 'banker_log_id' => intval($banker['banker_log_id']),
  524. 'banker_name' => $banker['banker_name'] ? $banker['banker_name'] : '',
  525. 'banker_img' => $banker['banker_img'] ? $banker['banker_img'] : '',
  526. 'coin' => intval($banker['coin']),
  527. 'max_bet' => $banker['coin'] / (max($option) - 1),
  528. ],
  529. );
  530. $res = timSystemNotify($game_log['group_id'], $ext);
  531. if ($stop_banker) {
  532. if ($banker_log_model->returnCoin(['video_id' => $video_id, 'status' => 3], '底金不足,玩家下庄') == false) {
  533. $return_data[$game_log_id] = 'error:' . __LINE__ . $banker_log_model->getLastSql();
  534. break;
  535. }
  536. $banker_ext = [
  537. 'type' => 43,
  538. 'desc' => '',
  539. 'room_id' => $video_id,
  540. 'action' => 4,
  541. 'banker_status' => 0,
  542. 'data' => [
  543. 'banker' => [
  544. 'banker_id' => intval($banker['banker_id']),
  545. 'banker_log_id' => intval($banker['banker_log_id']),
  546. 'banker_name' => $banker['banker_name'] ? $banker['banker_name'] : '',
  547. 'banker_img' => $banker['banker_img'] ? $banker['banker_img'] : '',
  548. 'coin' => intval($banker['coin']),
  549. ],
  550. ],
  551. ];
  552. $data = [
  553. 'banker_id' => 0,
  554. 'banker_status' => 0,
  555. "banker_log_id" => 0,
  556. "banker_name" => '',
  557. "banker_img" => '',
  558. 'coin' => 0,
  559. ];
  560. $video_redis->update_db($video_id, $data);
  561. $banker_res = timSystemNotify($game_log['group_id'], $banker_ext);
  562. }
  563. $tim_time = microtime(1) - $tim_time;
  564. $return_data[$game_log_id] = array(
  565. 'type' => 'result',
  566. 'id' => $game_log_id,
  567. 'data' => $ext,
  568. 'res' => $res,
  569. 'sql_time' => $sql_time,
  570. 'tim_time' => $tim_time,
  571. 'banker_ext' => $banker_ext,
  572. 'banker_res' => $banker_res,
  573. );
  574. if (defined('OPEN_MISSION') && OPEN_MISSION) {
  575. $gamers = $user_game_log_model->field('user_id')->select(['game_log_id' => $game_log_id, 'type' => 1]);
  576. if ($gamers) {
  577. $mission_model = self::build('mission');
  578. foreach ($gamers as $gamer) {
  579. $mission_model->incProgress($gamer['user_id'], 1);
  580. }
  581. }
  582. }
  583. } else {
  584. // 返还投注
  585. Connect::beginTransaction();
  586. if ($game_log_model->update(array('status' => 2), array('id' => $game_log_id)) === false) {
  587. Connect::rollback();
  588. $return_data[$game_log_id] = 'error:' . __LINE__;
  589. break;
  590. }
  591. $redis->set($game_log_id, array('status' => 2));
  592. if ($user_model->returnCoin($game_log_id) === false) {
  593. Connect::rollback();
  594. $return_data[$game_log_id] = 'error:' . __LINE__;
  595. break;
  596. }
  597. if ($coin_log_model->returnCoin($game_log_id) === false) {
  598. Connect::rollback();
  599. $return_data[$game_log_id] = 'error:' . __LINE__;
  600. break;
  601. }
  602. if ($GLOBALS['db']->affected_rows()) {
  603. $res = $user_game_log_model->field('user_id')->group('user_id')->select(array('game_log_id' => $game_log_id));
  604. $ids = array();
  605. foreach ($res as $value) {
  606. $ids[] = $value['user_id'];
  607. }
  608. user_deal_to_reids($ids);
  609. }
  610. Connect::commit();
  611. $data = [
  612. 'game_log_id' => 0,
  613. 'banker_id' => 0,
  614. 'banker_status' => 0,
  615. "banker_log_id" => 0,
  616. "banker_name" => '',
  617. "banker_img" => '',
  618. 'coin' => 0,
  619. ];
  620. $video_redis->update_db($video_id, $data);
  621. $ext = array(
  622. 'type' => 34,
  623. 'desc' => '',
  624. );
  625. $res = timSystemNotify($game_log['group_id'], $ext);
  626. $return_data[$game_log_id] = array(
  627. 'type' => 'end_return',
  628. 'id' => $game_log_id,
  629. 'res' => $res,
  630. );
  631. }
  632. $redis->unLockVideo($video_id);
  633. } else if ($game['create_time'] + $game['long_time'] > $time && !$banker_id) {
  634. // 机器人下注
  635. $robot_num = $video_redis->getOne_db($video_id, 'robot_num');
  636. if ($robot_num) {
  637. $rest = $game['create_time'] + $game['long_time'] - $time;
  638. if (rand(1, 300) < $game_type['rate'] && ($time - $game['create_time'] > 5)) {
  639. $option = json_decode($game_type['option'], 1);
  640. $data = array();
  641. $op = array_rand($option);
  642. for ($i = 0; $i < $robot_num; $i++) {
  643. if (isset($data[$op])) {
  644. $data[$op] += rand(0, 10) * 10;
  645. } else {
  646. $data[$op] = rand(0, 10) * 10;
  647. }
  648. }
  649. foreach ($data as $key => $value) {
  650. $redis->inc($game_log_id, 'option' . $key, $value);
  651. }
  652. $data = $redis->get($game_log_id, array('option1', 'option2', 'option3'));
  653. $bet = array();
  654. for ($i = 1; $i <= 3; $i++) {
  655. $bet[] = intval($data['option' . $i]);
  656. }
  657. $ext = array(
  658. 'type' => 39,
  659. 'room_id' => $video_id,
  660. 'desc' => '',
  661. 'time' => $rest,
  662. 'game_id' => $game_id,
  663. 'game_log_id' => $game_log_id,
  664. 'game_status' => 1,
  665. 'game_action' => 2,
  666. 'game_data' => array(
  667. 'bet' => $bet,
  668. ),
  669. );
  670. $res = timSystemNotify($game_log['group_id'], $ext);
  671. $return_data[$game_log_id] = array(
  672. 'type' => 'robot',
  673. 'id' => $game_log_id,
  674. 'ext' => $ext,
  675. 'res' => $res,
  676. );
  677. }
  678. }
  679. }
  680. }
  681. }
  682. $this->clearGameLog();
  683. if (defined('OPEN_BANKER_MODULE') && OPEN_BANKER_MODULE == 1) {
  684. $this->clearBankerLog($video_redis);
  685. }
  686. if ($bm_promoter) {
  687. self::build('bm_promoter')->payPromoter();
  688. }
  689. $return_data['time'] = microtime(1) - $microtime;
  690. $redis->unLock();
  691. return $return_data;
  692. }
  693. /**
  694. * 将关闭的直播游戏上庄记录移入历史记录
  695. * @return void
  696. */
  697. public function clearBankerLog($video_redis)
  698. {
  699. $video_table = DB_PREFIX . 'video';
  700. $table = DB_PREFIX . 'banker_log';
  701. $history = DB_PREFIX . 'banker_log_history';
  702. $res = $GLOBALS['db']->getOne("SELECT COUNT(1) FROM `$table` WHERE `video_id` NOT IN(SELECT id FROM `$video_table` WHERE live_in = 1)");
  703. if ($res) {
  704. $res = $GLOBALS['db']->getAll("SELECT `video_id` FROM `$table` WHERE `video_id` NOT IN(SELECT id FROM `$video_table` WHERE live_in = 1) AND `status` IN (1,3) GROUP BY `video_id`");
  705. $model = self::build('banker_log');
  706. foreach ($res as $key => $value) {
  707. $data = [
  708. 'banker_id' => 0,
  709. 'banker_status' => 0,
  710. "banker_log_id" => 0,
  711. "banker_name" => '',
  712. "banker_img" => '',
  713. 'coin' => 0,
  714. ];
  715. $video_redis->update_db($value['video_id'], $data);
  716. $res = $model->returnCoin(['video_id' => $value['video_id'], 'status' => ['in', [1, 3]]], '主播退出,退还上庄金额');
  717. if ($res === false) {
  718. Connect::rollback();
  719. $return_data['clear_log'] = array('error:' . __LINE__ . ':' . $model->getLastSql());
  720. }
  721. }
  722. Connect::beginTransaction();
  723. $res = Connect::exec("INSERT INTO `$history`(SELECT * FROM `$table` WHERE `video_id` NOT IN(SELECT id FROM `$video_table` WHERE live_in = 1) AND `status` IN (2,4))");
  724. if ($res === false) {
  725. Connect::rollback();
  726. $return_data['clear_log'] = array('error:' . __LINE__);
  727. }
  728. $res = Connect::exec("DELETE FROM `$table` WHERE `video_id` NOT IN(SELECT id FROM `$video_table` WHERE live_in = 1) AND `status` IN (2,4)");
  729. if ($res === false) {
  730. Connect::rollback();
  731. $return_data['clear_log'] = array('error:' . __LINE__);
  732. }
  733. Connect::commit();
  734. }
  735. }
  736. /**
  737. * 将关闭的直播游戏记录移入历史记录
  738. * @return void
  739. */
  740. public function clearGameLog()
  741. {
  742. $table = DB_PREFIX . 'game_log';
  743. $video_table = DB_PREFIX . 'video';
  744. $res = $GLOBALS['db']->getOne("SELECT COUNT(1) FROM `$table` WHERE podcast_id NOT IN(SELECT user_id FROM `$video_table` WHERE live_in = 1) AND `status`=2");
  745. if ($res) {
  746. $history = DB_PREFIX . 'game_log_history';
  747. $log_table = DB_PREFIX . 'user_game_log';
  748. $log_history = DB_PREFIX . 'user_game_log_history';
  749. Connect::beginTransaction();
  750. /**
  751. * 游戏记录迁移
  752. * @var [type]
  753. */
  754. $res = Connect::exec("INSERT INTO `$history`(SELECT * FROM `$table` WHERE podcast_id NOT IN(SELECT user_id FROM `$video_table` WHERE live_in = 1) AND `status`=2)");
  755. if ($res === false) {
  756. Connect::rollback();
  757. $return_data['clear_log'] = array('error:' . __LINE__);
  758. }
  759. $res = Connect::exec("DELETE FROM `$table` WHERE podcast_id NOT IN (SELECT user_id FROM `$video_table` WHERE live_in = 1) AND `status`=2");
  760. if ($res === false) {
  761. Connect::rollback();
  762. $return_data['clear_log'] = array('error:' . __LINE__);
  763. }
  764. /**
  765. * 下注记录迁移
  766. * @var [type]
  767. */
  768. $res = Connect::exec("INSERT INTO `$log_history`(SELECT * FROM `$log_table` WHERE `game_log_id` NOT IN(SELECT `id` FROM `$table`))");
  769. if ($res === false) {
  770. Connect::rollback();
  771. $return_data['clear_log'] = array('error:' . __LINE__);
  772. }
  773. $res = Connect::exec("DELETE FROM `$log_table` WHERE `game_log_id` NOT IN (SELECT `id` FROM `$table`)");
  774. if ($res === false) {
  775. Connect::rollback();
  776. $return_data['clear_log'] = array('error:' . __LINE__);
  777. }
  778. Connect::commit();
  779. }
  780. }
  781. public function autoCrontab()
  782. {
  783. $define = defined('GAME_AUTO_START') && GAME_AUTO_START;
  784. if (!$define) {
  785. return 'no_define';
  786. }
  787. $video_model = self::build('video');
  788. $list = $video_model->field('id,group_id,user_id')->select(['live_in' => 1]);
  789. if (!$list) {
  790. return 'no_list';
  791. }
  792. $res = [];
  793. $m_config = load_auto_cache("m_config");
  794. $auto_time = $m_config['auto_time'];
  795. $auto_time = $auto_time > 1 ? $auto_time : 5;
  796. self::checkFile();
  797. foreach ($list as $video) {
  798. $video_id = $video['id'];
  799. if (!self::$video_redis->getOne_db($video_id, 'auto_start')) {
  800. continue;
  801. }
  802. $game_log_id = self::$video_redis->getOne_db($video_id, 'game_log_id');
  803. $game = self::$redis->get($game_log_id, 'game_id,long_time,create_time,video_id,group_id');
  804. if ($game['create_time'] + $game['long_time'] + $auto_time > NOW_TIME) {
  805. continue;
  806. }
  807. if (self::$redis->isVideoLock($video_id)) {
  808. continue;
  809. }
  810. $res[] = self::startGame($game['game_id'], $video_id, $video['group_id'], $video['user_id']);
  811. }
  812. return $res;
  813. }
  814. protected static function checkFile()
  815. {
  816. if (!self::$redis) {
  817. fanwe_require(APP_ROOT_PATH . 'mapi/lib/redis/BaseRedisService.php');
  818. fanwe_require(APP_ROOT_PATH . 'mapi/lib/redis/GamesRedisService.php');
  819. self::$redis = new GamesRedisService();
  820. }
  821. if (!self::$video_redis) {
  822. fanwe_require(APP_ROOT_PATH . 'mapi/lib/redis/BaseRedisService.php');
  823. fanwe_require(APP_ROOT_PATH . 'mapi/lib/redis/VideoRedisService.php');
  824. self::$video_redis = new VideoRedisService();
  825. }
  826. }
  827. public static function startGame($id, $video_id, $group_id, $user_id)
  828. {
  829. self::checkFile();
  830. $game = self::build('games')->selectOne(['id' => $id]);
  831. if (!$game) {
  832. return '游戏参数错误';
  833. }
  834. list(
  835. $last_game,
  836. $last_log_id,
  837. $banker_status,
  838. $banker_id
  839. ) = self::getLastGameByVideoId($video_id);
  840. if ($last_game) {
  841. return '上局游戏未结束';
  842. }
  843. if (self::$redis->isVideoLock($video_id)) {
  844. return '操作频率太高了,请等下再点!';
  845. }
  846. self::$redis->lockVideo($video_id);
  847. if ($banker_status == 1) {
  848. self::stopRedisBanker($video_id, $group_id);
  849. }
  850. $game_log_id = self::build('game_log')->addLog($user_id, $game['long_time'], $id, $banker_id);
  851. if (!$game_log_id) {
  852. self::$redis->unLockVideo($video_id);
  853. return '服务器繁忙';
  854. }
  855. self::$video_redis->update_db($video_id, ['game_log_id' => $game_log_id]);
  856. $data = [
  857. 'podcast_id' => $user_id,
  858. 'long_time' => $game['long_time'],
  859. 'game_id' => $id,
  860. 'create_time' => NOW_TIME,
  861. 'video_id' => $video_id,
  862. 'group_id' => $group_id,
  863. 'option' => $game['option'],
  864. 'bet_option' => $game['bet_option'],
  865. 'status' => 1,
  866. 'banker_id' => $banker_id,
  867. ];
  868. $public_cards = [];
  869. if (in_array($id, [3])) {
  870. fanwe_require(APP_ROOT_PATH . 'mapi/lib/tools/Poker.class.php');
  871. $poker = new Poker();
  872. $public_cards = $poker->pickCards(1);
  873. $data['gp'] = json_encode($public_cards);
  874. foreach ($public_cards as $key => $value) {
  875. $public_cards[$key] = [self::$colors[$value[0]], self::$figures[$value[1]]];
  876. }
  877. }
  878. self::$redis->set($game_log_id, $data); // 插入redis
  879. $option = self::parseOption(json_decode($game['option'], 1));
  880. list($banker_status, $banker_id, $banker_log_id, $banker_name, $banker_img, $coin, $max_bet) = self::getBankerStatus($video_id, $option);
  881. // 新推送
  882. $ext = [
  883. 'type' => 39,
  884. 'desc' => '',
  885. 'room_id' => $video_id,
  886. 'time' => $game['long_time'],
  887. 'game_id' => $id,
  888. 'game_log_id' => $game_log_id,
  889. 'game_status' => 1,
  890. 'game_action' => 1,
  891. 'option' => array_values($option),
  892. 'bet_option' => json_decode($game['bet_option'], 1),
  893. 'game_data' => compact('public_cards'),
  894. 'banker_status' => $banker_status,
  895. 'banker' => compact('banker_status', 'banker_id', 'banker_log_id', 'banker_name', 'banker_img', 'coin', 'max_bet'),
  896. ];
  897. $res = timSystemNotify($group_id, $ext);
  898. $test = 'testtest';
  899. self::pushLog(compact('test', 'res', 'ext', 'group_id'));
  900. self::$redis->unLockVideo($video_id);
  901. return $game_log_id;
  902. }
  903. /**
  904. * 获取游戏状态信息
  905. * @param integer $video_id 直播间id
  906. * @return array [$last_game, $last_log_id, $banker_status, $banker_id]
  907. */
  908. public static function getLastGameByVideoId($video_id)
  909. {
  910. self::checkFile();
  911. $last_game = false;
  912. $video = self::$video_redis->getRow_db($video_id, ['game_log_id', 'banker_status', 'banker_id']);
  913. $last_log_id = intval($video['game_log_id']);
  914. $banker_status = intval($video['banker_status']);
  915. $banker_id = intval($video['banker_id']);
  916. if ($last_log_id) {
  917. $last_game = self::$redis->get($last_log_id, 'create_time,long_time');
  918. $last_game = NOW_TIME < $last_game['create_time'] + $last_game['long_time'] + 1;
  919. }
  920. return [$last_game, $last_log_id, $banker_status, $banker_id];
  921. }
  922. /**
  923. * 获取上庄信息
  924. * @param integer $video_id 直播间id
  925. * @param array $option 下注选项倍数数据
  926. * @return array [$banker_status, $banker_id, $banker_log_id, $banker_name, $banker_img, $coin, $max_bet]
  927. */
  928. public static function getBankerStatus($video_id, $option)
  929. {
  930. self::checkFile();
  931. $video = self::$video_redis->getRow_db(
  932. $video_id, [
  933. 'banker_status',
  934. 'banker_id',
  935. 'banker_log_id',
  936. 'banker_name',
  937. 'banker_img',
  938. 'coin',
  939. ]
  940. );
  941. $banker_status = intval($video['banker_status']);
  942. $banker_id = intval($video['banker_id']);
  943. $banker_log_id = intval($video['banker_log_id']);
  944. $banker_name = $video['banker_name'] ? $video['banker_name'] : '';
  945. $banker_img = $video['banker_img'] ? $video['banker_img'] : '';
  946. $coin = intval($video['coin']);
  947. $max_bet = intval($coin / (max($option) - 1));
  948. return [$banker_status, $banker_id, $banker_log_id, $banker_name, $banker_img, $coin, $max_bet];
  949. }
  950. /**
  951. * 游戏参数转换为字符串(参数类型转换)
  952. * @param array $option 下注选项倍数数据
  953. * @return array 下注选项倍数数据
  954. */
  955. public static function parseOption($option)
  956. {
  957. foreach ($option as $key => $value) {
  958. $option[$key] = $value . '';
  959. }
  960. return $option;
  961. }
  962. /**
  963. * 下庄状态变化,金额返还
  964. * @param integer $video_id 直播间id
  965. * @param string $group_id IM群组id
  966. * @return [type] [description]
  967. */
  968. public static function stopRedisBanker($video_id, $group_id)
  969. {
  970. self::build('banker_log')->returnCoin(['video_id' => $video_id, 'status' => ['in', [1, 3]]], '主播下庄');
  971. $data = [
  972. 'banker_id' => 0,
  973. 'banker_status' => 0,
  974. 'banker_log_id' => 0,
  975. 'banker_name' => '',
  976. 'banker_img' => '',
  977. 'coin' => 0,
  978. ];
  979. self::$video_redis->update_db($video_id, $data);
  980. unset($data['banker_status']);
  981. $ext = [
  982. 'type' => 43,
  983. 'desc' => '',
  984. 'room_id' => $video_id,
  985. 'action' => 4,
  986. 'banker_status' => 0,
  987. 'data' => [
  988. 'banker' => $data,
  989. ],
  990. ];
  991. $res = timSystemNotify($group_id, $ext);
  992. return compact('res', 'ext', 'video_id', 'group_id');
  993. }
  994. protected static function pushLog($data)
  995. {
  996. if (IS_DEBUG) {
  997. fanwe_require(APP_ROOT_PATH . 'mapi/lib/tools/PushLog.class.php');
  998. PushLog::log($data);
  999. }
  1000. }
  1001. }