unity3d广东麻将算法

来源:互联网 发布:tw6805a监控软件 编辑:程序博客网 时间:2024/04/26 10:57
欢迎一起学习交流
QQ:51267195
电话:18816791911 微信同号

package com.linyun.xgame.service.impl;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.log4j.Logger;
import com.linyun.base.constant.ErrorCodeConstant;
import com.linyun.base.constant.GameConstant;
import com.linyun.base.constant.LogConstant;
import com.linyun.base.domain.CardDown;
import com.linyun.base.domain.NormalGameRecord;
import com.linyun.base.domain.Player;
import com.linyun.base.domain.SystemConfigPara;
import com.linyun.base.domain.VipGameRecord;
import com.linyun.base.domain.VipRoomRecord;
import com.linyun.base.msg.friend.BeInvitedEnterVipRoomMsg;
import com.linyun.base.msg.friend.InviteFriendEnterVipRoomMsg;
import com.linyun.base.networkbase.NetMsgBase;
import com.linyun.xgame.common.DateService;
import com.linyun.xgame.common.SpringService;
import com.linyun.xgame.common.SystemConfig;
import com.linyun.xgame.common.UUIDGenerator;
import com.linyun.xgame.constant.GameConfigConstant;
import com.linyun.xgame.domain.GameRoom;
import com.linyun.xgame.domain.GameTable;
import com.linyun.xgame.domain.ItemBase;
import com.linyun.xgame.domain.MahjongCheckResult;
import com.linyun.xgame.machine.IMachineService;
import com.linyun.xgame.machine.impl.MachineService;
import com.linyun.xgame.msg.EnterVipRoomMsg;
import com.linyun.xgame.msg.GameStartMsg;
import com.linyun.xgame.msg.PlayerGameOpertaionAckMsg;
import com.linyun.xgame.msg.PlayerGameOverMsgAck;
import com.linyun.xgame.msg.PlayerOperationNotifyMsg;
import com.linyun.xgame.msg.PlayerTableOperationMsg;
import com.linyun.xgame.msg.RequestStartGameMsgAck;
import com.linyun.xgame.msg.SearchVipRoomMsgAck;
import com.linyun.xgame.msg.TalkingInGameMsg;
import com.linyun.xgame.msg.VipRoomCloseMsg;
import com.linyun.xgame.service.ISystemConfigService;
public class GameLogicProcess {
 private static Logger logger = Logger.getLogger(GameLogicProcess.class);
 private List<GameRoom> gameRoomList = new ArrayList<GameRoom>();
 private Map<Integer, GameRoom> gameRoomMap = new HashMap<Integer, GameRoom>();
 private DBServerPlayerService playerService = null;
 private ISystemConfigService cfgService = null;
 // 麻将逻辑处理
 private MahjongProcess mjProc = new MahjongProcess();
 private IMachineService machineService = new MachineService();
 //
 private boolean showCardLog = true;
 //
 public GameLogicProcess(DBServerPlayerService ps) {
  playerService = ps;
  SystemConfig.gameLogic = this;
 }
 //
 public void init() {
 }
 // 房间配置规则在t_global表中,字段PARA_ID 2001到2050,VALUE_INT是底注,PRO_2是最小携带,PRO_3是最大携带
 // PRO_1房间类型
 //
 public void load_room_settings() {
  if (cfgService == null)
   cfgService = (ISystemConfigService) SpringService
     .getBean("sysConfigService");
  //
  for (int i = GameConfigConstant.CONF_ROOM_OF_PRIMARY; i < 2050; i++) {
   SystemConfigPara cfg = cfgService.getPara(i);
   if (cfg == null)
    continue;
   //
   GameRoom gr = new GameRoom();
   gr.price = cfg.getValueInt();// 底注
   gr.cfgId = cfg.getParaID();
   gr.maxGold = cfg.getPro_3();
   gr.minGold = cfg.getPro_2();
   gr.roomType = cfg.getPro_1();
   gr.roomID = i;
   gr.serviceFee = cfg.getPro_4();// 台费
   //
   if (gr.roomType == GameConstant.ROOM_TYPE_VIP) {
    gr.fixedGold = cfg.getPro_5(); // VIP房间固定带入金币数
   }
   //
   gameRoomList.add(gr);
   gameRoomMap.put(i, gr);
  }
 }
 // 重连回来没有色的提示
 // 不能碰自己的清楚色
 public void updateRoom(SystemConfigPara cfg) {
  if (cfg.getParaID() >= GameConfigConstant.CONF_ROOM_OF_PRIMARY
    && cfg.getParaID() < 2050) {
   boolean found = false;
   for (int i = 0; i < gameRoomList.size(); i++) {
    GameRoom gr = gameRoomList.get(i);
    //
    if (gr.cfgId == cfg.getParaID()) {
     //
     found = true;
     //
     gr.price = cfg.getValueInt();// 底注
     gr.maxGold = cfg.getPro_3();
     gr.minGold = cfg.getPro_2();
     gr.roomType = cfg.getPro_1();
     gr.serviceFee = cfg.getPro_4();// 台费
     if (gr.roomType == GameConstant.ROOM_TYPE_VIP) {
      gr.fixedGold = cfg.getPro_5(); // VIP房间固定带入金币数
     }
     //
     if (gr.price == 0)// 0的意思是把这个房间关闭
     {
      gameRoomList.remove(i);
     }
     //
     break;
    }
   }
   //
   //
   if (found == false) {
    GameRoom gr = new GameRoom();
    gr.price = cfg.getValueInt();// 底注
    gr.maxGold = cfg.getPro_3();
    gr.minGold = cfg.getPro_2();
    gr.roomType = cfg.getPro_1();
    gr.serviceFee = cfg.getPro_4();// 台费
    if (gr.roomType == GameConstant.ROOM_TYPE_VIP) {
     gr.fixedGold = cfg.getPro_5(); // VIP房间固定带入金币数
    }
    //
    if (gr.price > 0)// 0的意思是把这个房间关闭
    {
     gameRoomList.add(gr);
    }
   }
  }
 }
 //
 public GameTable popFreeTable() {
  GameTable gt = new GameTable();
  //
  return gt;
 }
 //
 //
 public GameRoom getRoom(int roomID) {
  return gameRoomMap.get(roomID);
 }
 public int getRoomPlayerNum(int roomID) {
  GameRoom gr = gameRoomMap.get(roomID);
  if (gr != null)
   return gr.getPlayerNum();
  return 0;
 }
 //
 public int getRoomPlayerNumByType(int type) {
  return 0;
 }
 public int getPlayerVipTableID(Player pl) {
  int roomID = pl.getRoomID();
  GameRoom gr = getRoom(roomID);
  if (gr == null)
   return 0;
  GameTable gt = gr.getTable(pl.getTableID(), false);
  if (gt == null) {
   return 0;
  }
  if (gt.isVipTable()) {
   return gt.getVipTableID();
  }
  return 0;
 }
 /** 客户端通知服务器,游戏结束,玩家继续游戏* */
 public void game_continue(Player pl) {
  // 返回给玩家,
  RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
  ack.gold = pl.getGold();
  int roomID = pl.getRoomID();
  GameRoom gr = getRoom(roomID);
  if (gr == null)
   return;
  if (GameConstant.ROOM_TYPE_VIP != gr.roomType) {
   // 校验金币
   if (pl.getGold() < gr.minGold) {
    // 返回给玩家,
    RequestStartGameMsgAck Error_ack = new RequestStartGameMsgAck();
    Error_ack.gold = pl.getGold();
    Error_ack.result = ErrorCodeConstant.GOLD_LOW_THAN_MIN_LIMIT;
    // 进入桌子失败
    Error_ack.sessionID = pl.getPlayerLobbySessionID();
    SystemConfig.gameSocketServer.sendMsg(pl.getSession(),
      Error_ack);
    return;
   } else if (pl.getGold() > gr.maxGold) {
    // 返回给玩家,
    RequestStartGameMsgAck Error_ack = new RequestStartGameMsgAck();
    Error_ack.gold = pl.getGold();
    Error_ack.result = ErrorCodeConstant.GOLD_HIGH_THAN_MAX_LIMIT;
    // 进入桌子失败
    Error_ack.sessionID = pl.getPlayerLobbySessionID();
    SystemConfig.gameSocketServer.sendMsg(pl.getSession(),
      Error_ack);
    return;
   }
  }
  //
  GameTable gt = gr.getTable(pl.getTableID(), false);
  if (gt == null) {
   // 重新进新桌吧,老桌子没了
   // System.out.println("继续游戏:"+pl.getPlayerName()+"重新进新桌吧,老桌子没了");
   this.enter_room(pl, roomID);
   return;
  }
  ack.createPlayerID = gt.getCreatorPlayerID();
  // 玩家的状态必须是在等待继续状态
  if (pl.getGameState() != GameConstant.PALYER_GAME_STATE_IN_TABLE_GAME_OVER_WAITING_TO_CONTINUE)
   return;
  // 如果VIP房间的圈数用完了,就不能继续了
  if ((GameConstant.ROOM_TYPE_VIP == gr.roomType)
    && (gt.isVipTableTimeOver())) {
   ack.result = ErrorCodeConstant.VIP_TABLE_IS_GAME_OVER; // VIP桌子已经结束
   ack.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
   return;
  }
  //
  pl.setGameState(GameConstant.PALYER_GAME_STATE_IN_TABLE_READY);
  //
  ack.result = ErrorCodeConstant.CMD_EXE_OK;
  //
  ack.init_players(gt.getPlayers(), gt.isVipTable());
  //
  ack.gold = pl.getGold();
  //
  if (gt.isVipTable()) {
   ack.totalHand = gt.getHandsTotal();
   ack.vipTableID = gt.getVipTableID();
   ack.createPlayerID = gt.getCreatorPlayerID();
   ack.currentHand = gt.getHandNum();
  } else
   ack.vipTableID = 0;
  //
  ack.roomID = roomID;
  // ack.tablePos=pl.getTablePos();
  ack.tablePos = pl.getTablePos() | (gt.getMaxPlayer() << 16);
  //
  ack.newPlayWay = gt.getVip_rule();
  //
  // 进入桌子,返回消息给玩家
  ack.sessionID = pl.getPlayerLobbySessionID();
  SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
  //
  // 给桌子上的其他玩家发个进入新玩家的消息
  PlayerGameOpertaionAckMsg axk = new PlayerGameOpertaionAckMsg();
  axk.opertaionID = GameConstant.GAME_OPERTAION_TABLE_ADD_NEW_PLAYER;
  axk.playerName = pl.getPlayerName();
  axk.targetPlayerName = pl.getHeadImageUrl();
  //
  if (gt.isVipTable())
   axk.gold = pl.getVipTableGold();
  else
   axk.gold = pl.getGold();
  //
  axk.headImg = pl.getHeadImg();
  axk.sex = pl.getSex();
  axk.tablePos = pl.getTablePos();
  axk.playerID = pl.getPlayerID();
  axk.playerIndex = pl.getPlayerIndex();
  axk.canFriend = pl.getCanFriend();
  axk.ip = pl.getClientIP();
  axk.sessionID = pl.getPlayerLobbySessionID();
  axk.opValue = gt.getMaxPlayer();
  this.sendMsgToTableExceptMe(gt, axk, pl.getPlayerID());
  
  try_Closevip(gt,pl);
 }
 
 private void try_Closevip(GameTable gt,Player pl){
  if(gt.isVipTable()){
   if(gt.getClearCloseVipRoomMapSize() > 0 && gt.getClearCloseVipRoomMapSize() < gt.getMaxPlayer()){
    for(Player gp: gt.getPlayers()){
     if(!gt.containVipRoomCloseRequester(gp.getPlayerID())){
      PlayerGameOpertaionAckMsg msgx = new PlayerGameOpertaionAckMsg();
      msgx.playerName = pl.getPlayerName();
      msgx.opertaionID = GameConstant.MAHJONG_OPERTAION_WAITING_OR_CLOSE_VIP;
      msgx.playerIndex = pl.getPlayerIndex();
    
      msgx.sessionID = pl.getPlayerLobbySessionID();
      SystemConfig.gameSocketServer.sendMsg(gp.getSession(), msgx);
     }
    }
   }
  }
 }
 //
 private void player_recover(GameTable gt, Player pl) {
  // 如果没有手牌,游戏还没开始,不能发GameStartMsg消息,否则游戏界面没有手牌
  if (0 == pl.getCardNumInHand()) {
   return;
  }
  // 把牌发给玩家
  GameStartMsg msg = new GameStartMsg();
  msg.myTablePos = pl.getTablePos();
  msg.myCards = pl.getCardsInHand();
  msg.newPlayWay = gt.getVip_rule();
  //
  Player pl0 = gt.getPlayerAtIndex(0);
  if (pl0 != null) {
   msg.player0Cards = pl0.getCardsBefore();
   msg.player0CardsDown = pl0.getCardsDown();
   msg.player0WinLoseEqual = pl0.getTotalBattles();
   msg.player0Win = pl0.getDiamond();
   msg.player0Buhua = pl0.getHuaValue();
   msg.baibannum0 = pl0.getBaibanhua();
  }
  Player pl1 = gt.getPlayerAtIndex(1);
  if (pl1 != null) {
   msg.player1Cards = pl1.getCardsBefore();
   msg.player1CardsDown = pl1.getCardsDown();
   msg.player1WinLoseEqual = pl1.getTotalBattles();
   msg.player1Win = pl1.getDiamond();
   msg.player1Buhua = pl1.getHuaValue();
   msg.baibannum1 = pl1.getBaibanhua();
  }
  //
  msg.dealerPos = gt.getDealerPos();
  msg.quanNum = gt.getHandNum();// gt.getQuanNum();
  // 是否听牌
  List<Player> players = gt.getPlayers();
  for (int i = 0; i < players.size(); i++) {
   Player pxx = gt.getPlayerAtIndex(i);
   if (pxx == null)
    continue;
   // 胡牌标志
   if (pxx.isHuuuuued()) {
    int huCd = pxx.getHuCard() & 0xff;
    msg.tingPlayers |= (huCd << (i * 8));
   }
   //
   // 是否离线
   if ((pxx.getOnTable() == false) || (pxx.isOnline() == false)) {
    msg.OffLinePlayers |= (1 << (i * 8));
   }
   // 设置金币
   if (pxx != null) {
    int ipt = pxx.getTablePos();
    if (gt.isVipTable()) {
     if (ipt == 0)
      msg.player0Gold = pxx.getVipTableGold();
     else if (ipt == 1)
      msg.player1Gold = pxx.getVipTableGold();
     else if (ipt == 2)
      msg.player2Gold = pxx.getVipTableGold();
     else if (ipt == 3)
      msg.player3Gold = pxx.getVipTableGold();
    } else {
     if (ipt == 0)
      msg.player0Gold = pxx.getGold();
     else if (ipt == 1)
      msg.player1Gold = pxx.getGold();
     else if (ipt == 2)
      msg.player2Gold = pxx.getGold();
     else if (ipt == 3)
      msg.player3Gold = pxx.getGold();
    }
   }
  }
  //
  Player pl2 = gt.getPlayerAtIndex(2);
  if (pl2 != null) {
   msg.player2Cards = pl2.getCardsBefore();
   msg.player2CardsDown = pl2.getCardsDown();
   msg.player2WinLoseEqual = pl2.getTotalBattles();
   msg.player2Win = pl2.getDiamond();
   msg.player2Buhua = pl2.getHuaValue();
   msg.baibannum2 = pl2.getBaibanhua();
  }
  Player pl3 = gt.getPlayerAtIndex(3);
  if (pl3 != null) {
   msg.player3Cards = pl3.getCardsBefore();
   msg.player3CardsDown = pl3.getCardsDown();
   msg.player3WinLoseEqual = pl3.getTotalBattles();
   msg.player3Win = pl3.getDiamond();
   msg.player3Buhua = pl3.getHuaValue();
   msg.baibannum3 = pl3.getBaibanhua();
  }
  //
  msg.chuCardPlayerIndex = gt.getCardOpPlayerIndex();
  msg.chuCard = gt.getCurrentCard() & 0xff;
  msg.serviceGold = gt.getHandsTotal();
  msg.baoCard = gt.getBaoCard();
  msg.baoCard |= (gt.getBaoCard2() << 8);
  //
  msg.sessionID = pl.getPlayerLobbySessionID();
  SystemConfig.gameSocketServer.sendMsg(pl.getSession(), msg);
 }
 //
 public void inviteFriend(InviteFriendEnterVipRoomMsg msg, Player pl) {
  Player friend = playerService.getPlayerByPlayerID(msg.playerID);
  if (friend == null)
   return;
  //
  GameRoom gr = getRoom(msg.roomID);
  if (gr == null)
   return;
  //
  GameTable gt = gr.getVipTableByVipTableID(msg.vipTableID);
  if (gt == null)
   return;
  //
  // 只有房主可以邀请
  if (gt.getCreatorPlayerID().equals(pl.getPlayerID())) {
   //
   BeInvitedEnterVipRoomMsg msx = new BeInvitedEnterVipRoomMsg();
   msx.tableID = gt.getTableID();
   msx.playerID = pl.getPlayerID();
   msx.roomID = msg.roomID;
   msx.vipTableID = msg.vipTableID;
   msx.password = gt.getVipPswMd5();
   //
   msx.sessionID = friend.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(friend.getSession(), msx);
  }
 }
 //
 public void enterVipRoom(EnterVipRoomMsg msg, Player pl) {
  GameRoom rm = null;
  GameTable gt = null;
  //
  if (msg.tableID.equals("enter_room")) {
   int vip_table_id = msg.roomID;
   msg.roomID = 2002;
   //
   rm = gameRoomMap.get(2002);
   gt = rm.getVipTableByVipTableID(vip_table_id);
  } else {
   rm = gameRoomMap.get(msg.roomID);
   if (rm == null) {
    logger.error("enterVipRoom,rm==null, playerIndex="
      + pl.getPlayerIndex());
    return;
   }
   //
   gt = rm.getTable(msg.tableID, false);
  }
  //
  if (gt == null) {
   RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
   ack.gold = pl.getGold();
   //
   ack.result = ErrorCodeConstant.VIP_TABLE_NOT_FOUND;
   // 进入桌子,返回消息给玩家
   ack.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
   logger.error("enterVipRoom,gt==null, playerIndex="
     + pl.getPlayerIndex());
   return;
  }
  if (gt.isVipTable()) {
   if (!gt.isPayVipKa()) {
    int diamond_need = playerService.getTableDiamondCost(gt
      .getBaseHandsTotal());
    if (false == playerService.preuse_fanka(pl, diamond_need))
     return;
   }
  }
  // 现在不校验密码
  // 密码错误
  // if(gt.getVipPswMd5().equals(msg.psw)==false)
  // {
  // RequestStartGameMsgAck ack=new RequestStartGameMsgAck();
  // ack.gold=pl.getGold();
  // //
  // ack.result=ErrorCodeConstant.WRONG_PASSWORD;
  // //进入桌子,返回消息给玩家
  // ack.sessionID=pl.getPlayerLobbySessionID();
  // SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
  // return;
  // }
  //
  gt.setDizhu(rm.price);
  //
  int old_tablePos = gt.findPlayerIndex(pl);
  boolean old_table = false;
  if (old_tablePos >= 0)// 已经存在,离开又进来
  {
   old_table = true;
   //
   pl.setTableID(gt.getTableID());
   pl.setVipTableID(gt.getTableID());
  } else {
   if (gt.isFull()) {
    RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
    ack.gold = pl.getGold();
    //
    ack.result = ErrorCodeConstant.VIP_TABLE_IS_FULL;
    // 进入桌子,返回消息给玩家
    ack.sessionID = pl.getPlayerLobbySessionID();
    SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
    return;
   }
   // 新玩家进来,设置VIP房间金币
   // if(pl.getVipTableGold() <= 0)
   // {
   // GameRoom gr=getRoom(gt.getRoomID());
   // if( (gr!=null) && (gr.roomType == GameConstant.ROOM_TYPE_VIP))
   // {
   // pl.setVipTableGold(gr.fixedGold);
   // }
   // }
   gt.enterTable(pl);
  }
  // 如等待玩家中,满了就开始,如果中间断线再进入,就不要这个状态切换
  if (gt.isFull()
    && gt.getState() == GameConstant.GAME_TABLE_STATE_WAITING_PLAYER) {
   gt.setState(GameConstant.GAME_TABLE_STATE_READY_GO);
  }
  //
  pl.setRoomID(msg.roomID);
  pl.setTableID(gt.getTableID());
  pl.setVipTableID(gt.getTableID());
  //
  boolean re_enter = false;
  if (old_table && gt.isFull())
   re_enter = true;
  enter_table_done(pl, gt, re_enter);
 }
 //
 // vip开房间,在服务器理解为创建一个vip桌子
 public void create_vip_table(Player pl, String psw, int quanNum,
   int roomID, int vip_rule) {
  GameRoom rm = gameRoomMap.get(roomID);
  if (rm == null)
   return;
  String vip_tb_id = pl.getVipTableID();
  if (vip_tb_id != null && vip_tb_id.length() > 1
    && rm.getPlayingTablesMap().containsKey(vip_tb_id)) {
   logger.error("player index:" + pl.getPlayerIndex() + ",md5:" + psw
     + ",ordin vip_rule:" + vip_rule + ",vip tableid:"
     + pl.getVipTableID());
   return;
  }
  // vip默认具有的打法,毋须客户端配置
  int default_rule = rm.get_default_vip_table_rule(SystemConfig.mjType);
  //
  vip_rule |= default_rule;
  
  
  int personNum = 4;
  if ((vip_rule & GameConstant.GAME_PLAY_2_PERSON) != 0) {
   personNum = 2;
  } else if ((vip_rule & GameConstant.GAME_PLAY_3_PERSON) != 0) {
   personNum = 2;
  }
  //
  GameTable gt = rm.createVipTable(psw, pl, personNum);
  if (gt == null)
   return;
  //
  gt.setBaseHandsTotal(quanNum);
  logger.info("tableid=" + gt.getTableID() + ",hands=" + quanNum);
  gt.setVip_rule(vip_rule);
  //
  if (gt.has_vip_rule(GameConstant.GAME_PLAY_2_PERSON))
   gt.setMaxPlayer(2);
  else if (gt.has_vip_rule(GameConstant.GAME_PLAY_3_PERSON))
   gt.setMaxPlayer(2);
  else
   gt.setMaxPlayer(4);

  //
  Date ct = DateService.getCurrentUtilDate();
  gt.setVipCreateTime(ct.getTime());
  // 总圈数
  gt.setHandsTotal(quanNum);
  //
  // 设置为未支付房卡
  gt.setPayVipKa(false);
  // 设置VIP房间带入金额
  pl.setVipTableGold(0);
  pl.setOnTable(true);
  //
  // 返回给玩家,
  RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
  ack.gold = pl.getGold();
  ack.totalHand = gt.getHandsTotal();
  ack.currentHand = gt.getHandNum();
  //
  ack.newPlayWay = gt.getVip_rule();
  //
  ack.result = ErrorCodeConstant.CMD_EXE_OK;
  //
  ack.init_players(gt.getPlayers(), gt.isVipTable());
  //
  ack.roomID = roomID;
  // ack.tablePos=pl.getTablePos();
  ack.tablePos = pl.getTablePos() | (gt.getMaxPlayer() << 16);
  //
  ack.vipTableID = gt.getVipTableID();
  ack.creatorName = gt.getCreatorPlayerName();
  ack.createPlayerID = gt.getCreatorPlayerID();
  // 进入桌子,发消息给玩家
  ack.sessionID = pl.getPlayerLobbySessionID();
  SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
  //
  // System.out.println("vip table id="+gt.getVipTableID());
  // 测试允许机器人进入vip
  // machineService.newset_machinetime(pl,gt);
  /*
   * //在游戏开始的时候4个人一起创建,因为房间有可能没开始游戏就解散了 //创建一条vip房间记录 VipRoomRecord
   * vrr=new VipRoomRecord();
   * vrr.setStartTime(DateService.getCurrentUtilDate());
   * vrr.setRoomID(gt.getTableID()); vrr.setRoomIndex(gt.getVipTableID());
   * vrr.setPlayer1ID(pl.getPlayerID()); //
   * vrr.setHostName(pl.getPlayerName()); //
   * vrr.setRecordID(UUIDGenerator.generatorUUID()); //
   * playerService.createVipRoomRecord(vrr); // pl.setVrr(vrr);
   */
 }
 // 看看是否有老桌需要他进去,牌局未结束,不能离开
 private boolean enter_old_table(Player pl) {
  int roomID = pl.getRoomID();
  GameRoom rm = gameRoomMap.get(roomID);
  if (rm == null)
   return false;
  GameTable gt = rm.getTable(pl.getTableID(), pl.isPlayingSingleTable());
  if (gt != null
    && /* (gt.getState()==GameConstant.GAME_TABLE_STATE_PAUSED) && */(gt
      .findPlayerIndex(pl) >= 0)) {
   if ((gt.getState() == GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE || gt
     .getState() != GameConstant.GAME_TABLE_STATE_WAITING_PLAYER)) {
    if (!validatePlayerGold(rm, pl))
     return false;
   }
   enter_table_done(pl, gt, true);
   return true;
  }
  return false;
 }
 //
 public void enter_room(Player pl, int roomID) {
  // 重置异常标志
  pl.setNeedCopyGameState(false);
  // 当前正在vip房间中,不能进其他房间,自动进vip房
  if (pl.getVipTableID().length() > 0) {
   GameRoom rm = gameRoomMap.get(pl.getRoomID());
   if (rm == null)
    return;
   GameTable gt = rm.getTable(pl.getTableID(), false);
   if (gt != null) {
    EnterVipRoomMsg mxg = new EnterVipRoomMsg();
    mxg.tableID = gt.getTableID();
    mxg.psw = gt.getVipPswMd5();
    mxg.roomID = pl.getRoomID();
    enterVipRoom(mxg, pl);
    return;
   }
  }
  GameRoom rm = gameRoomMap.get(roomID);
  // 看看是否进老桌子
  if (enter_old_table(pl)) {
   return;
  } else {
   // 看看是否还在桌子上
   List<GameTable> oldTables = this.getPlayingTables(pl
     .getPlayerIndex());
   if (oldTables != null && oldTables.size() >= 1) {
    // 还在老桌子中
    GameTable oldTable = oldTables.get(0);
    if (oldTable != null) {
     // logger.error("玩家:" + pl.getPlayerIndex() +
     // ",断线重连,遍历房间才找到老桌子,roomID=" + oldTable.getRoomID());
     pl.setRoomID(oldTable.getRoomID());
     pl.setTableID(oldTable.getTableID());
     pl.setNeedCopyGameState(true); // 玩家数据异常需要恢复游戏数据
     if (oldTable.isVipTable()) {
      pl.setVipTableID(oldTable.getTableID());
      // VIP房间处理
      EnterVipRoomMsg mxg = new EnterVipRoomMsg();
      mxg.tableID = oldTable.getTableID();
      mxg.psw = oldTable.getVipPswMd5();
      mxg.roomID = pl.getRoomID();
      enterVipRoom(mxg, pl);
      return;
     }
    }
   }
   // 校验金币是否足够
   if (!validatePlayerGold(rm, pl))
    return;
  }
  // 判断今日输赢是否已达到上限
  if (cfgService == null)
   cfgService = (ISystemConfigService) SpringService
     .getBean("sysConfigService");
  if (Math.abs(pl.getTodayRecordByRoomType(rm.roomType)) >= cfgService
    .getRoomMaxWinLose(rm.roomType)) {
   // 已达到场次输赢上限
   RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
   ack.gold = cfgService.getRoomMaxWinLose(rm.roomType);
   ack.result = ErrorCodeConstant.TODAY_GAME_RECORD_OUT_LIMIT_IN_ROOM;
   // 进入桌子失败
   ack.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
   return;
  } else if (Math.abs(pl.getTodayRecordCount()) >= cfgService
    .getMaxWinLoseEveryDay()) {
   // 达到个人输赢上限
   RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
   ack.gold = cfgService.getMaxWinLoseEveryDay();
   ack.result = ErrorCodeConstant.TODAY_GAME_RECORD_OUT_LIMIT_IN_GAME;
   // 进入桌子失败
   ack.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
   return;
  }
  //
  GameTable gt = rm.enterRoom(pl, SystemConfig.mjType);
  enter_table_done(pl, gt, false);
  //
  machineService.newset_machinetime(pl, gt);
 }
 public boolean validatePlayerGold(GameRoom rm, Player pl) {
  if (rm == null)
   return false;
  if (cfgService == null)
   cfgService = (ISystemConfigService) SpringService
     .getBean("sysConfigService");
  //
  // 进新桌,需要校验金币
  int minGold = rm.minGold;
  // 如果是进入VIP房间,只要校验完金币就可以了
  if (rm.roomType == GameConstant.ROOM_TYPE_VIP) {
   // 返回给玩家,
   RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
   ack.gold = pl.getGold();
   ack.roomID = rm.roomID;
   ack.result = ErrorCodeConstant.CAN_ENTER_VIP_ROOM;
   //
   // 可以进入VIP房间
   ack.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
   return false;
  }
  if (pl.getGold() < minGold) {
   // 返回给玩家,
   RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
   ack.gold = pl.getGold();
   ack.result = ErrorCodeConstant.GOLD_LOW_THAN_MIN_LIMIT;
   // 进入桌子失败
   ack.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
   return false;
  } else if (pl.getGold() > rm.maxGold) {
   // 返回给玩家,
   RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
   ack.gold = pl.getGold();
   ack.result = ErrorCodeConstant.GOLD_HIGH_THAN_MAX_LIMIT;
   // 进入桌子失败
   ack.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
   return false;
  }
  return true;
 }
 //
 private void re_notify_current_operation_player(GameTable gt) {
  // 1先看看有没有吃碰杠提示的玩家
  MahjongCheckResult result = gt.getWaitingPlayerOperate();
  if (result != null) {
   Player plx = gt.getPlayerAtIndex(result.playerTableIndex);
   if (plx != null) {
    //
    PlayerOperationNotifyMsg msg = new PlayerOperationNotifyMsg();
    // 提示玩家出牌
    msg.operation = result.opertaion;
    msg.player_table_pos = result.playerTableIndex;
    msg.chi_card_value = result.chi_card_value;
    if (((msg.operation & GameConstant.MAHJONG_OPERTAION_CHU) == GameConstant.MAHJONG_OPERTAION_CHU)
      && (plx.getCardGrab() != 0)) {
     msg.chi_card_value = plx.getCardGrab(); // 新摸到的牌
    }
    msg.peng_card_value = result.peng_card_value;
    msg.target_card = result.targetCard;
    msg.tingList = result.tingList;
    msg.gangList = result.gangList;
    msg.chi_flag = result.chi_flag;
    msg.cardLeftNum = gt.getCardLeftNum();
    //
    msg.sessionID = plx.getPlayerLobbySessionID();
    // SystemConfig.gameSocketServer.sendMsg(plx.getSession(), msg);
    this.sengMsgToPlayer(gt, plx, msg);
    //
    // 发给其他玩家,让他们知道当前轮到谁操作
    PlayerOperationNotifyMsg msg2 = new PlayerOperationNotifyMsg();
    msg2.operation = GameConstant.MAHJONG_OPERTAION_TIP;
    msg2.cardLeftNum = gt.getCardLeftNum();
    msg2.player_table_pos = plx.getTablePos();
    this.sendMsgToTable(gt, msg2);
   }
  } else {
   // 没有吃碰听,那就当前玩家出牌
   player_chu_notify(gt, true, true);
  }
 }
 //
 // 离开重新进入
 private void player_re_enter(Player pl, GameTable gt) {
  // 恢复状态
  if (gt.getBackup_state() == GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE) {
   pl.setGameState(GameConstant.PALYER_GAME_STATE_IN_TABLE_READY);
   // 给桌子上的其他玩家发个进入新玩家的消息
   PlayerGameOpertaionAckMsg axk = new PlayerGameOpertaionAckMsg();
   axk.opertaionID = GameConstant.GAME_OPERTAION_TABLE_ADD_NEW_PLAYER;
   axk.playerName = pl.getPlayerName();
   axk.targetPlayerName = pl.getHeadImageUrl();
   if (gt.isVipTable()) {
    axk.gold = pl.getVipTableGold();
   } else {
    axk.gold = pl.getGold();
   }
   axk.headImg = pl.getHeadImg();
   axk.sex = pl.getSex();
   axk.tablePos = pl.getTablePos();
   axk.playerID = pl.getPlayerID();
   axk.playerIndex = pl.getPlayerIndex();
   axk.canFriend = pl.getCanFriend();
   axk.ip = pl.getClientIP();
   axk.sessionID = pl.getPlayerLobbySessionID();
   axk.opValue = gt.getMaxPlayer();
   this.sendMsgToTableExceptMe(gt, axk, pl.getPlayerID());
  } else {
   pl.setGameState(GameConstant.PALYER_GAME_STATE_IN_TABLE_PLAYING);
   // 给桌子上的其他玩家发个玩家上线的消息
   PlayerOperationNotifyMsg axk = new PlayerOperationNotifyMsg();
   axk.operation = GameConstant.MAHJONG_OPERTAION_ONLINE;
   axk.player_table_pos = pl.getTablePos();
   axk.sessionID = pl.getPlayerLobbySessionID();
   this.sendMsgToTableExceptMe(gt, axk, pl.getPlayerID());
  }
  // 取消托管
  pl.setAutoOperation(0);
  // 发送断线重连消息
  player_recover(gt, pl);
  // 看看桌子上玩家是否都已经到齐
  gt.pauseContinue();
  // 打印所有玩家的状态
  // logger.info("玩家:" + pl.getPlayerIndex() + "断线重回,房间ID:" +
  // gt.getRoomID() + ",桌子状态:" + gt.getState() + ",前一个状态:" +
  // gt.getBackup_state());
  // for(Player onePl:gt.getPlayers())
  // {
  // logger.info("玩家ID:" + onePl.getPlayerIndex() + " 状态:" +
  // onePl.getGameState());
  // }
  if (gt.getState() == GameConstant.GAME_TABLE_STATE_PLAYING) {
   // 断线回来,如果当前桌子子状态为0,说明没有等待状态,直接提示当前玩家行动
   if (gt.getPlaySubstate() == 0)//
   {
    // 通知玩家行动
    re_notify_current_operation_player(gt);
   } else {
    // 否则就把等待时间设置为当前,系统等待一定时间后,提示玩家进行应该进行的动作,比如有玩家吃碰等
    Date dt = DateService.getCurrentUtilDate();
    gt.setWaitingStartTime(dt.getTime());
   }
  }
  //
  // System.out.println("back:"+pl.getPlayerName()+",player
  // num="+gt.getPlayers().size());
  
  try_Closevip(gt,pl);
 }
 //
 private void enter_table_done(Player pl, GameTable gt, boolean re_enter) {
  // 玩家坐在桌子上
  pl.setOnTable(true);
  pl.setAutoOperation(0);
  RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
  ack.totalHand = gt.getHandsTotal();
  ack.currentHand = gt.getHandNum();
  if (gt.getState() == GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE) {
   pl.setGameState(GameConstant.PALYER_GAME_STATE_IN_TABLE_READY);
   // gt.set_not_ready_player_ready();
  } else if (gt.getState() == GameConstant.GAME_TABLE_STATE_PAUSED) {
   if (gt.getBackup_state() == GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE) {
    pl.setGameState(GameConstant.PALYER_GAME_STATE_IN_TABLE_READY);
   } else {
    pl
      .setGameState(GameConstant.PALYER_GAME_STATE_IN_TABLE_PLAYING);
   }
  }
  //
  ack.result = ErrorCodeConstant.CMD_EXE_OK;
  //
  ack.init_players(gt.getPlayers(), gt.isVipTable());
  //
  ack.gold = pl.getGold();
  //
  ack.roomID = pl.getRoomID();
  // ack.tablePos=pl.getTablePos();
  ack.tablePos = pl.getTablePos() | (gt.getMaxPlayer() << 16);
  ack.newPlayWay = gt.getVip_rule();
  GameRoom gr = getRoom(gt.getRoomID());
  if ((gr != null) && (gr.roomType == GameConstant.ROOM_TYPE_VIP)) {
   ack.vipTableID = gt.getVipTableID();
  }
  ack.creatorName = gt.getCreatorPlayerName();
  ack.createPlayerID = gt.getCreatorPlayerID();
  //
  // Date ct=DateService.getCurrentUtilDate();
  // 进入桌子,返回消息给玩家
  ack.sessionID = pl.getPlayerLobbySessionID();
  SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
  //
  if (re_enter
    && (gt.getState() != GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE/*
                         * ||
                         * gt.isVipTable()
                         */))// 断线返回,VIP房间在结算的时候断线回来要走下面的分支
  {
   player_re_enter(pl, gt);
  } else {
   // 设置VIP房间带入金额
   // if( (gr!=null) && (gr.roomType == GameConstant.ROOM_TYPE_VIP) &&
   // (pl.getVipTableGold() <= 0))
   // {
   // pl.setVipTableGold(gr.fixedGold);
   // }
   // 给桌子上的其他玩家发个进入新玩家的消息
   PlayerGameOpertaionAckMsg axk = new PlayerGameOpertaionAckMsg();
   axk.opertaionID = GameConstant.GAME_OPERTAION_TABLE_ADD_NEW_PLAYER;
   axk.playerName = pl.getPlayerName();
   axk.targetPlayerName = pl.getHeadImageUrl();
   if (gt.isVipTable()) {
    axk.gold = pl.getVipTableGold();
   } else {
    axk.gold = pl.getGold();
   }
   axk.headImg = pl.getHeadImg();
   axk.sex = pl.getSex();
   axk.tablePos = pl.getTablePos();
   axk.playerID = pl.getPlayerID();
   axk.playerIndex = pl.getPlayerIndex();
   axk.canFriend = pl.getCanFriend();
   axk.ip = pl.getClientIP();
   axk.sessionID = pl.getPlayerLobbySessionID();
   axk.opValue = gt.getMaxPlayer();
   this.sendMsgToTableExceptMe(gt, axk, pl.getPlayerID());
   //
   // System.out.println("enter:"+pl.getPlayerName()+",player
   // num="+gt.getPlayers().size());
  }
 }
 // 游戏循环
 public void run_one_loop() {
  if (cfgService == null)
   cfgService = (ISystemConfigService) SpringService
     .getBean("sysConfigService");
  // System.out.println("房间数量:"+gameRooms.size());
  for (Integer rid : gameRoomMap.keySet()) {
   GameRoom gr = gameRoomMap.get(rid);
   game_room_tick(gr);
  }
 }
 //
 public void use_item(Player pl, ItemBase ib) {
 }
 //
 //
 public void player_left_table(Player pl) {
  if (pl == null)
   return;
  GameRoom gr = this.getRoom(pl.getRoomID());
  if (gr == null)
   return;
  //
  GameTable gt = gr.getTable(pl.getTableID(), pl.isPlayingSingleTable());
  if (gt == null) {
   return;
  }
  // 玩家不在桌子上
  pl.setOnTable(false);
  //
  if (gt.couldLeft(pl)) {
   //
   boolean found = gt.removePlayer(pl.getPlayerID());
   if (pl.isRobot()) {
    machineService.death_machine(pl.getPlayerIndex());
   }
   // if(gt.isAllRobot()){
   // gt.remove_robots_table();
   // death_machine(gt);
   // }
   //
   if (found) {
    gr.setPlayerNum(gr.getPlayerNum() - 1);
    gt.addFreePos(pl.getTablePos());
   }
   // 如果vip离开桌子,全部清理
   if (gt.isVipTable()
     && pl.getPlayerID().equals(gt.getCreatorPlayerID())) {
    PlayerGameOpertaionAckMsg axk = new PlayerGameOpertaionAckMsg();
    axk.opertaionID = GameConstant.GAME_OPERTAION_ROOM_DISMISS;
    axk.sessionID = pl.getPlayerLobbySessionID();
    this.sendMsgToTableExceptMe(gt, axk, pl.getPlayerID());
    //
    gt.clear_all();
   }
   //
   if (gt.getPlayerNum() > 0) {
    // 如果还有玩家,通知他们有玩家离开
    if (found) {
     PlayerGameOpertaionAckMsg axk = new PlayerGameOpertaionAckMsg();
     axk.opertaionID = GameConstant.GAME_OPERTAION_PLAYER_LEFT_TABLE;
     axk.playerName = pl.getPlayerName();
     axk.gold = pl.getGold();
     axk.headImg = pl.getHeadImg();
     axk.sex = pl.getSex();
     axk.playerID = pl.getPlayerID();
     axk.playerIndex = pl.getPlayerIndex();
     axk.canFriend = pl.getCanFriend();
     axk.tablePos = pl.getTablePos();
     axk.ip = pl.getClientIP();
     axk.sessionID = pl.getPlayerLobbySessionID();
     this.sendMsgToTableExceptMe(gt, axk, pl.getPlayerID());
    }
    if (!gt.isVipTable() && gt.isAllRobot()) {
     machineService.reset_machinetime_current(gt);
     machineService.newset_machinetime(pl, gt);
    }
   }
   //
   if (gt.shouldRecycleTable()) {
    // death_machine(gt);
    // 空桌回收
    gt.setState(GameConstant.TABLE_STATE_INVALID);
   }
   pl.clear_game_state();
  } else {
   // 玩家正在游戏,保持数据,等待一定时间,等他回来
   if (gt.isVipTable()) {
    // 游戏暂停
    // if( (gt.getState()!=GameConstant.GAME_TABLE_STATE_PAUSED) &&
    // (gt.getState() !=
    // GameConstant.GAME_TABLE_STATE_WAITING_PLAYER) )
    // {
    // 保存当前状态
    // gt.setBackup_state(gt.getState());
    // gt.setState(GameConstant.GAME_TABLE_STATE_PAUSED);
    // Date ct=DateService.getCurrentUtilDate();
    // gt.setPausedTime(ct.getTime());
    // }
   } else {
    // 普通房间设置成托管
    pl.setAutoOperation(1);
   }
   // 玩家状态,暂停
   pl.setGameState(GameConstant.PALYER_GAME_STATE_IN_TABLE_PAUSED);
   //
   // 玩家离开
   PlayerOperationNotifyMsg msg = new PlayerOperationNotifyMsg();
   msg.operation = GameConstant.MAHJONG_OPERTAION_OFFLINE;
   msg.player_table_pos = pl.getTablePos();
   msg.sessionID = pl.getPlayerLobbySessionID();
   this.sendMsgToTableExceptMe(gt, msg, pl.getPlayerID());
  }
  // debug,如果玩家都离开了,把桌子回收;
  if (gt.isAllPlayerLeft()) {
   if (gt.isVipTable()) {
    // 不马上结束,保留一段时间
    // vip_table_end(gr, gt);
   } else {
    gt.clear_all();
    gt.setState(GameConstant.TABLE_STATE_INVALID);
   }
  }
 }
 //
 private void game_room_tick(GameRoom gr) {
  List<GameTable> removed = new ArrayList<GameTable>();
  Map<String, GameTable> tables = gr.getPlayingTablesMap();
  for (String tID : tables.keySet()) {
   GameTable t = tables.get(tID);
   //
   //
   game_table_tick(t);
   SystemConfig.gameLogic.getMachineService().thread_deal_msg();
   // 如果桌子状态非法,回收掉
   if (t.getState() == GameConstant.TABLE_STATE_INVALID) {
    removed.add(t);
   }
  }
  //
  for (int i = 0; i < removed.size(); i++) {
   GameTable t = removed.get(i);
   death_machine(t);
   //
   tables.remove(t.getTableID());
   //
   gr.beforeRecycle(t);
   //
   t.feeTable();
  }
 }
 private void playing_table_tick(GameTable gt, long ctt) {
  int substate = gt.getPlaySubstate();
  Player currentPl = null;
  //
  int ext_wait_time = 0;
  MahjongCheckResult waiting = gt.getWaitingPlayerOperate();
  if (waiting != null)// 如果有等待操作,就让对方操作
   currentPl = gt.getPlayerAtIndex(waiting.playerTableIndex);
  else
   // 如果没有等待玩家,就是当前按位置的玩家
   currentPl = gt.getCurrentOperationPlayer();
  //
  //
  //
  if (currentPl == null) {
   gt.addTickError();
   // 错误大于300次自动清除桌子
   if (gt.getTickError() > 3000) {
    // 清除桌子
    // 先测试金币够不够
    for (int i = 0; i < gt.getPlayers().size(); i++) {
     Player pl = gt.getPlayers().get(i);
     // player_left_table(pl);
     logger
       .error("current operation player not found contail player:"
         + pl.getPlayerIndex());
    }
    logger.error("current operation player not found, tableID="
      + gt.getTableID() + ",State=" + gt.getState()
      + ",BackUpState=" + gt.getBackup_state()
      + ",GameStartTime=" + gt.getGameStartTime()
      + ",CurrentOperateIndex="
      + gt.getCurrentOpertaionPlayerIndex());
    gt.clearGameState();
    gt.setState(GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE);
    gt.set_all_player_state(GameConstant.PALYER_GAME_STATE_IN_TABLE_GAME_OVER_WAITING_TO_CONTINUE);
    gt.setHandEndTime(System.currentTimeMillis());
    // 设为非法状态,系统会自动清理
    gt.setState(GameConstant.TABLE_STATE_INVALID);
    gt.reSetTickError();
   }
   return;
  }
  if (substate == GameConstant.GAME_TABLE_SUB_STATE_PLAYING_CHI_PENG_ANIMATION) {
   if (ctt - gt.getWaitingStartTime() > 1000 + ext_wait_time)// 动画播完
   {
    gt.setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_IDLE);
    // 吃完,碰完不能立刻胡
    boolean could_hu = false;
    // 通知玩家出牌
    player_chu_notify(gt, could_hu, false);
   }
  } else if (substate == GameConstant.GAME_TABLE_SUB_STATE_PLAYING_GANG_ANIMATION) {
   if (ctt - gt.getWaitingStartTime() > 1000 + ext_wait_time)// 动画播完
   {
    gt.setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_IDLE);
    // 通知玩家出牌
    player_chu_gangkaihua(gt, true, true);
   }
  } else if (substate == GameConstant.GAME_TABLE_SUB_STATE_PLAYING_QISHOU_GANG_ANIMATION) {
   if (ctt - gt.getWaitingStartTime() > 1000 + ext_wait_time)// 动画播完
   {
    gt.setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_IDLE);
    // 通知玩家出牌
    player_qishou_ganghua_deal(gt, true, true, true);
   }
  } else if (substate == GameConstant.GAME_TABLE_SUB_STATE_PLAYING_CHU_ANIMATION) {
   if (ctt - gt.getWaitingStartTime() > 500 + ext_wait_time)// 动画播完
   {
    // 下一个玩家操作
    gt.setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_IDLE);
    // 找找下个玩家
    next_player_operation_notify(gt);
   }
  } else if (substate == GameConstant.GAME_TABLE_SUB_STATE_PLAYING_BUHUA_ANIMATION1) {
   if (ctt - gt.getWaitingStartTime() > 800 + ext_wait_time)// 动画播完
   {
    currentPl.setCardGrab((byte) 0);
    PlayerTableOperationMsg msg = new PlayerTableOperationMsg();
    msg.operation = GameConstant.MAHJONG_OPERTAION_BU_HUA;
    msg.player_table_pos = currentPl.getTablePos();
    msg.buHuas1 = currentPl.getHuaValue();
    msg.unused_0 = currentPl.getBaibanhua();
    msg.cardLeftNum = gt.getCardLeftNum();
    msg.handCards = currentPl.getCardsInHand();
    Date dt = DateService.getCurrentUtilDate();
    gt.setWaitingStartTime(dt.getTime());
    gt
      .setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_PLAYING_BUHUA_ANIMATION2);
    this.sendMsgToTable(gt, msg);
   }
  } else if (substate == GameConstant.GAME_TABLE_SUB_STATE_PLAYING_BUHUA_ANIMATION2) {
   if (ctt - gt.getWaitingStartTime() > 1500 + ext_wait_time)// 动画播完
   {
    // 下一个玩家操作
    gt.setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_IDLE);
    // 补花完成摸牌
    player_mo(gt);
   }
  } else if (substate == GameConstant.GAME_TABLE_SUB_STATE_PLAYING_BUHUA_ANIMATION3) {
   if (ctt - gt.getWaitingStartTime() > 800 + ext_wait_time)// 动画播完
   {
    currentPl.setCardGrab((byte) 0);
    PlayerTableOperationMsg msg = new PlayerTableOperationMsg();
    msg.operation = GameConstant.MAHJONG_OPERTAION_BU_HUA;
    msg.player_table_pos = currentPl.getTablePos();
    msg.unused_0 = currentPl.getBaibanhua();
    msg.buHuas1 = currentPl.getHuaValue();
    msg.cardLeftNum = gt.getCardLeftNum();
    msg.handCards = currentPl.getCardsInHand();
    Date dt = DateService.getCurrentUtilDate();
    gt.setWaitingStartTime(dt.getTime());
    gt
      .setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_PLAYING_BUHUA_ANIMATION4);
    this.sendMsgToTable(gt, msg);
   }
  } else if (substate == GameConstant.GAME_TABLE_SUB_STATE_PLAYING_BUHUA_ANIMATION4) {
   if (ctt - gt.getWaitingStartTime() > 1500 + ext_wait_time)// 动画播完
   {
    // 下一个玩家操作
    gt.setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_IDLE);
    // 找找下个玩家
    Player plx = gt.getCurFengPlayer();
    if (plx == null)
     return;
    byte b = gt.popCard(); // 要不要摸屁股的最后一张牌
    gt.setLastMoCardPlayerTablePos(plx.getTablePos());
    plx.setCardGrab(b);// 先摸一张,等动画播完
    plx.setMoCardNum(plx.getMoCardNum() + 1);
    player_qishou_ganghua_deal(gt, true, true, false);
   }
  } else if (substate == GameConstant.GAME_TABLE_SUB_STATE_IDLE) {
   // 普通房间,如果玩家时托管状态,则直接帮他操作,否则等他超时
   if(gt.isVipTable() == false){
    if (((1 == currentPl.getAutoOperation()) || (ctt
      - currentPl.getOpStartTime() > (cfgService.getPara(
      GameConfigConstant.CONF_OPERATION_OVER_TIME)
      .getValueInt() * 1000 + 2000))))// 玩家超时
    {
     overtime_proc(currentPl, gt);
    }
   }
   else{
    if(gt.getClearCloseVipRoomMapSize() > 0){
     if((ctt-gt.getRequestVipCloseTime()) > 300*1000){
      logger.error("玩家太久没回应解散房间请求,自动解散房间:"+gt.getVipTableID());
      
      GameRoom gr = this.getRoom(gt.getRoomID());
      if (gr == null)
       return;
      // 结束VIP房间
      vip_table_end(gr, gt);
     }
    }
   }
   
   
   
   
  }
 }
 private void last_card_notify(GameTable gt) {
  /*
   * Player plx=gt.getCurrentOperationPlayer(); if(plx==null) return;
   *  // PlayerOperationNotifyMsg msg=new PlayerOperationNotifyMsg();
   *
   * MahjongCheckResult wait=new MahjongCheckResult();
   * wait.playerTableIndex=plx.getTablePos(); wait.opertaion=0;
   *
   * byte b1 = gt.getLast1Card(); byte b2 = gt.getLast2Card();
   *
   * //提示玩家抓尾巴 msg.operation =GameConstant.MAHJONG_OPERTAION_POP_LAST;
   * msg.player_table_pos=plx.getTablePos();
   * msg.cardLeftNum=gt.getCardLeftNum(); msg.target_card = ((b2 << 8)|
   * b1); //msg.target_card = plx.getCardGrab(); msg.chi_flag =
   * plx.getCardGrab(); //
   *
   *  // wait.opertaion=msg.operation; gt.setWaitingPlayerOperate(wait); //
   * long ctt=DateService.getCurrentUtilDate().getTime();
   * plx.setOpStartTime(ctt);
   *  // //发给其他玩家,让他们知道当前轮到谁操作 PlayerOperationNotifyMsg msg2=new
   * PlayerOperationNotifyMsg();
   * msg2.operation=GameConstant.MAHJONG_OPERTAION_TIP;
   * msg2.cardLeftNum=gt.getCardLeftNum();
   * msg2.player_table_pos=plx.getTablePos();
   * this.sendMsgToTable(gt,msg2); //
   *
   *
   * //发消息给玩家,提示他出牌 msg.sessionID=plx.getPlayerLobbySessionID();
   * SystemConfig.gameSocketServer.sendMsg(plx.getSession(), msg);
   *
   */
 }
 // 检测是否玩家输光,第一局玩家扣金币
 private boolean vip_table_check(GameTable gt) {
  List<Player> plist = gt.getPlayers();
  // vip房间第一把牌,把数据清理下,
  if (gt.isVipTable() && gt.getHandNum() == 0) {
   GameRoom gr = getRoom(gt.getRoomID());
   if (gr == null) {
    gt.setState(GameConstant.TABLE_STATE_INVALID);
    return false;
   }
   //
   for (int i = 0; i < plist.size(); i++) {
    Player pl = plist.get(i);
    pl.clearVipTableInfo();
    // 金币带到桌子上
    pl.setVipTableGold(0);
    // 输赢数据清零
    pl.setWinLoseTotal(0);
    pl.setWinLoseGoldNum(0);
   }
  }
  return true;
 }
 // 每局扣服务费
 private void service_fee(GameTable gt) {
  GameRoom gr = this.getRoom(gt.getRoomID());
  //
  if (gr == null || gr.serviceFee <= 0)
   return;
  //
  List<Player> plist = gt.getPlayers();
  for (int i = 0; i < plist.size(); i++) {
   Player pl = plist.get(i);
   if (pl.getGold() > gr.serviceFee) {
    String remark = "服务费=" + gr.serviceFee;
    this.playerService.sub_player_gold(pl, gr.serviceFee,
      LogConstant.OPERATION_TYPE_SUB_GOLD_GAME_SERVICE_FEE,
      remark);
   }
  }
 }
 //
 // 发牌
 public void sendCards(GameTable gt, int service_gold, int operationTime,
   int isDealerAgain) {
  // 当前轮到庄家打牌
  gt.sendCards();
  int dealerPos = gt.getDealerPos();
  //
  List<Player> players = gt.getPlayers();
  List<Byte> cards = gt.getCards();
  // 先清理
  for (int i = 0; i < players.size(); i++) {
   Player pl = players.get(i);
   pl.clear_cards();
  }
  byte bao1 = 0;
  byte bao2 = 0;
  if(gt.has_vip_rule(GameConstant.GAME_PLAY_RULE_HONGZHONGGUIPAI)){
   bao1 =0x35;
  }
  else if(gt.has_vip_rule(GameConstant.GAME_PLAY_RULE_SUIJIGIUPAI)){
   bao1 = gt.getLast1Card();
  }
  
  gt.setBaoCard(bao1);
  gt.setBaoCard2(bao2);
  gt.setCurFengPos((byte) 0x31);
  //
  for (int i = 0; i < players.size(); i++) {
   Player pl = players.get(i);
   pl.setZifeng(dealerPos, gt.getMaxPlayer());
   //
   List<Byte> cl = pl.getCardsInHand();
   cl.clear();
   //
   List<Byte> src = new ArrayList<Byte>();
   /*
    if(pl.getPlayerIndex() == 102) {
        src.add((byte)0x01);
     src.add((byte)0x01);
     src.add((byte)0x01);
     src.add((byte)0x01);
    
     src.add((byte)0x02);
     src.add((byte)0x02);
     src.add((byte)0x02);
    
     src.add((byte)0x03);
     src.add((byte)0x04);
     src.add((byte)0x05);
     src.add((byte)0x06);
    
     src.add((byte)0x07);
     src.add((byte)0x08);
       }
      else*/
    {
    for (int j = 0; j < 13; j++) {
     Byte b = cards.remove(0);
     src.add(b);
    }
   }
   //
   // 庄家开始多抓一张
   if (i == dealerPos) {
    Byte b = cards.remove(0);
    // b=0x35;//
    src.add(b);
    //
    pl.setMoCardNum(1);// 庄家默认已经摸了一张
    gt.setLastMoCardPlayerTablePos(pl.getTablePos());
   }
   // 排个序
   gt.sort_cards(src, cl);
   src.clear();
   // 把牌发给玩家
   GameStartMsg msg = new GameStartMsg();
   msg.newPlayWay = gt.getVip_rule();
   msg.myCards = cl;
   msg.myTablePos = pl.getTablePos();
   msg.quanNum = gt.getHandNum();// gt.getQuanNum();
   msg.dealerPos = dealerPos;
   // //下面这2句没用的吧
   Player pl0 = players.get(0);
   msg.player0CardsDown = pl0.getCardsDown();
   if (players.size() > 1) {
    Player pl1 = players.get(1);
    msg.player1CardsDown = pl1.getCardsDown();
   }
   if (players.size() > 2) {
    Player pl2 = players.get(2);
    msg.player2CardsDown = pl2.getCardsDown();
   }
   if (players.size() > 3) {
    Player pl3 = players.get(3);
    msg.player3CardsDown = pl3.getCardsDown();
   }
   //
   msg.baoCard = bao1 | (bao2 << 8);
   msg.setup_gold(players, gt.isVipTable());
   msg.serviceGold = gt.getHandsTotal();
   msg.playerOperationTime = operationTime;
   msg.isDealerAgain = isDealerAgain;
   msg.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), msg);
  }
  //
 }
 // 去桌子上的所有玩家发消息
 public void sendMsgToTable(GameTable gt, NetMsgBase msg) {
  if (msg == null)
   return;
  //
  List<Player> players = gt.getPlayers();
  for (int i = 0; i < players.size(); i++) {
   Player pl = players.get(i);
   msg.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), msg);
  }
 }
 // 去桌子上的所有玩家发消息,除了我
 public void sendMsgToTableExceptMe(GameTable gt, NetMsgBase msg,
   String myPlayerID) {
  if (msg == null || myPlayerID == null)
   return;
  //
  List<Player> players = gt.getPlayers();
  for (int i = 0; i < players.size(); i++) {
   Player pl = players.get(i);
   if (pl.getPlayerID().equals(myPlayerID)) {
    // System.out.print("send desk player name
    // :"+pl.getPlayerName()+"\n");
    continue;
   }
   // System.out.print("rececise desk player name
   // :"+pl.getPlayerName()+"\n");
   msg.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), msg);
  }
 }
 //
 private void game_start(GameTable gt) {
  // vip桌子校验
  if (gt.isVipTable()) {
   if (vip_table_check(gt) == false)
    return;
  }
  if (gt.isVipTable()) {
   if (!gt.isPayVipKa()) {
    if (!playerService.use_fangka(gt)) {
     logger.info("房卡不足,关闭房间,vip:" + gt.getVipTableID());
     cleanTable(gt);
     return;
    }
    gt.setPayVipKa(true);
   }
  }
  Player sanXiangPaoPl;
  //
  int hu_player_num = 0;// 有几个人胡了,有可能一炮3响
  List<Player> plist = gt.getPlayers();
  for (int i = 0; i < plist.size(); i++) {
   Player pl = plist.get(i);
   pl.setAutoOperation(0);
   if (null != pl) {
    pl.setOnTable(true);
   }
   //
   if (pl.isHuuuuued()) {
    hu_player_num++;
    if (hu_player_num == 3) {
     sanXiangPaoPl = pl.getHuPaoPL();
    }
   }
  }
  //
  Date ct = DateService.getCurrentUtilDate();
  long ctt = ct.getTime();
  // 把玩家按座位排序
  gt.re_position();
  // 先洗牌
  gt.washCards();
  //
  // 收台费
  service_fee(gt);
  // 判断是否连庄
  int isDealerAgain = 0;
  //
  // 继续当庄
  if(gt.getCurrentHuPlayerIndex() == -1){
   gt.moveDealer();
  }
  if ((gt.getCurrentHuPlayerIndex() != -1)
    && (gt.getDealerPos() == gt.getCurrentHuPlayerIndex())) {
   isDealerAgain = 1;
   gt.setLianZhuangNum(gt.getLianZhuangNum() + 1);
  }
  else if(gt.getCurrentHuPlayerIndex() != -1){
   gt.setDealerPos(gt.getCurrentHuPlayerIndex());
  }
  else{
   gt.moveDealer();
  }
  //
  // vip桌子,第一把开房人当庄
  if (gt.isVipTable() && gt.getHandNum() <= 1) {
   gt.setDealerPos(gt.getPlayerTablePos());
  }
  //
  //
  //
  // System.out.println("游戏正式开始");
  // 游戏开始
  gt.setState(GameConstant.GAME_TABLE_WAITING_CLIENT_SHOW_INIT_CARDS);
  gt.setHandStartTime(ctt);
  gt.setHandEndTime(0);
  // 玩家全体进入游戏状态
  gt.set_all_player_state(GameConstant.PALYER_GAME_STATE_IN_TABLE_PLAYING);
  //
  // 台费
  // int service_gold = 0;
  // GameRoom gr=this.getRoom(gt.getRoomID());
  // service_gold = gr.serviceFee;
  // 玩家操作时间
  int operationTime = cfgService.getPara(
    GameConfigConstant.CONF_OPERATION_OVER_TIME).getValueInt();
  if (operationTime < 5) {
   operationTime = 5;
  }
  // 发牌
  this.sendCards(gt, 0, operationTime, isDealerAgain);
  //
  gt.setCurrentHuPlayerIndex(-1);
  vip_table_log_create(gt);
 }
 //
 private void vip_table_log_create(GameTable gt) {
  Date ct = DateService.getCurrentUtilDate();
  List<Player> plist = gt.getPlayers();
  // 打第一把,创建下非房主的房间记录,开一次房,4个人,4条记录
  if (gt.isVipTable() && gt.getHandNum() == 1) {
   // playerService.use_fangka(gt.get, itemBaseID);
   gt.setGameStartTime(ct);
   //
   for (int i = 0; i < plist.size(); i++) {
    Player pl = plist.get(i);
    // 创建一条vip房间记录
    VipRoomRecord vrr = new VipRoomRecord();
    vrr.setStartTime(ct);
    vrr.setRoomID(gt.getTableID());
    vrr.setRoomIndex(gt.getVipTableID());
    vrr.setPlayer1ID(pl.getPlayerID());
    vrr.setHostName(gt.getCreatorPlayerIndex() + "-"
      + gt.getCreator().getPlayerNameNoEmoji());
    //
    int num = 0;
    for (int j = 0; j < plist.size(); j++) {
     Player plj = plist.get(j);
     if (plj.getPlayerID().equals(pl.getPlayerID()) == false) {
      if (num == 0) {
       vrr.setPlayer2Name(plj.getPlayerIndex() + "-"
         + plj.getPlayerNameNoEmoji());
       vrr.setScore2(plj.getWinLoseTotal());
      } else if (num == 1) {
       vrr.setPlayer3Name(plj.getPlayerIndex() + "-"
         + plj.getPlayerNameNoEmoji());
       vrr.setScore3(plj.getWinLoseTotal());
      } else if (num == 2) {
       vrr.setPlayer4Name(plj.getPlayerIndex() + "-"
         + plj.getPlayerNameNoEmoji());
       vrr.setScore4(plj.getWinLoseTotal());
      }
      //
      num++;
     }
    }
    //
    vrr.setRecordID(UUIDGenerator.generatorUUID());
    //
    playerService.createVipRoomRecord(vrr);
    //
    pl.setVrr(vrr);
   }
  } else {
   for (int i = 0; i < plist.size(); i++) {
    Player plj = plist.get(i);
    playerService.roomnotify(plj);
   }
  }
 }
 //
 private void search_vip_room(PlayerTableOperationMsg msg, Player pl) {
  int roomID = msg.card_value;// room id存在card_value中
  GameRoom gr = this.getRoom(roomID);
  if (gr == null)
   return;
  //
  GameTable gt = null;
  //
  if (msg.opValue == 0) {
   gt = gr.getTable(pl.getVipTableID(), false);
   if (gt == null)
    return;// 默认查找自己开的房间,如果没有,不返回数据
  } else {
   gt = gr.getVipTableByVipTableID(msg.opValue);
  }
  //
  SearchVipRoomMsgAck axk = new SearchVipRoomMsgAck();
  //
  if (gt != null) {
   // 房主回来
   if (gt.getCreatorPlayerID().equals(pl.getPlayerID())) {
    EnterVipRoomMsg msgx = new EnterVipRoomMsg();
    msgx.tableID = gt.getTableID();
    msgx.psw = gt.getVipPswMd5();
    msgx.roomID = roomID;
    enterVipRoom(msgx, pl);
    return;
   } else {
    // 判断是否其他玩家离开又回来
    int old_idx = gt.findPlayerIndex(pl);
    if (old_idx >= 0)// 已经存在,离开又进来
    {
     // 直接让他进入房间
     EnterVipRoomMsg msgx = new EnterVipRoomMsg();
     msgx.tableID = gt.getTableID();
     msgx.psw = gt.getVipPswMd5();
     msgx.roomID = roomID;
     enterVipRoom(msgx, pl);
     return;
    }
   }
   axk.vipTableID = gt.getVipTableID();
   axk.psw = gt.getVipPswMd5();
   axk.numPlayer = gt.getPlayerNum();
   axk.tableID = gt.getTableID();
   axk.dizhu = gr.price;
   axk.createName = gt.getCreatorPlayerName();
   axk.minGold = gr.fixedGold;
   axk.newPlayWay = gt.getVip_rule();
  }
  axk.sessionID = pl.getPlayerLobbySessionID();
  SystemConfig.gameSocketServer.sendMsg(pl.getSession(), axk);
 }
 // vip续卡
 private void extend_vip_table(PlayerTableOperationMsg msg, Player pl) {
  GameRoom gr = this.getRoom(pl.getRoomID());
  if (gr == null)
   return;
  GameTable gt = gr.getTable(pl.getTableID(), pl.isPlayingSingleTable());
  if (gt == null) {
   return;
  }
  //
  int diamond_need = playerService.getTableDiamondCost(gt
    .getBaseHandsTotal());
  // t_global pro_4设置每局需要多少房卡
  // 续卡
  if (msg.opValue == 0) {
   SystemConfigPara config = cfgService
     .getPara(GameConfigConstant.CONF_IS_VIP_FREE);
   if (pl.getDiamond() >= diamond_need || config.getValueInt() == 1) {
    if (playerService.preuse_fanka(pl, diamond_need)) {
     gt.setHandsTotal(gt.getHandsTotal()
       + gt.getBaseHandsTotal());
     gt.setPayVipKa(false);
     // 续卡成功
     PlayerOperationNotifyMsg msxg = new PlayerOperationNotifyMsg();
     msxg.operation = GameConstant.MAHJONG_OPERTAION_EXTEND_CARD_SUCCESSFULLY;
     // SystemConfig.gameSocketServer.sendMsg(pl.getSession(),
     // msxg);
     msxg.sessionID = pl.getPlayerLobbySessionID();
     this.sendMsgToTable(gt, msxg);
     logger.info("玩家ID:" + pl.getPlayerIndex() + "续房成功");
     return;
    }
   }
   // 提醒房卡不足
   PlayerOperationNotifyMsg msxg = new PlayerOperationNotifyMsg();
   msxg.operation = GameConstant.MAHJONG_OPERTAION_EXTEND_CARD_FAILED;
   msxg.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), msxg);
   logger.info("玩家ID:" + pl.getPlayerIndex() + "续卡,但房卡不足");
  } else {
   logger.info("玩家ID:" + pl.getPlayerIndex() + "不续房");
  }
  // 如果VIP圈数到了,就结束房间
  if (gt.isVipTableTimeOver()) {
   logger.info("VIP圈数到了,不续卡或房卡不足,VIP房间结束 gt.getState() = "
     + gt.getState() + ",gt.getBackup_state()"
     + gt.getBackup_state());
   if (gt.getState() == GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE
     || (gt.getState() == GameConstant.GAME_TABLE_STATE_PAUSED && gt
       .getBackup_state() == GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE)) {
    logger.info("玩家ID:" + pl.getPlayerIndex() + "不续卡或房卡不足,VIP房间:"
      + gt.getVipTableID() + "结束");
    // 不续卡,或者房卡不足,直接结束房间
    vip_table_end(gr, gt);
   }
  }
 }
 private void cleanTable(GameTable gt) {
  if (gt != null) {
   logger.error("房间ID:" + gt.getRoomID() + " 桌子ID:" + gt.getTableID()
     + "," + gt.getVipTableID() + " 桌子状态State:" + gt.getState()
     + " 当前人数:" + gt.getPlayerNum());
   logger.error("本局开始时间:" + new Date(gt.getHandStartTime())
     + " 当前操作人currentOpertaionPlayerIndex:"
     + gt.getCurrentOpertaionPlayerIndex());
   for (Player ply : gt.getPlayers()) {
    if (null != ply) {
     String cards = "";
     for (Byte card : ply.getCardsInHand()) {
      cards += card;
      cards += "-";
     }
     // logger.error("玩家"+ ply.getPlayerIndex() + " 座位号:" +
     // ply.getTablePos() + " 手牌:" +
     // cards+",吃碰:"+ply.getDescCardsDown()+"
     // 宝:"+gt.getBaoCard()+" 摸牌:"+ply.getCardGrab());
     // logger.error(" 玩家打下的牌:"+ply.getCardsBefore());
     // 清理要把所有vip设置回0
     ply.setVipTableGold(0);
    }
   }
   gt.clearGameState();
   gt
     .setState(GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE);
   gt
     .set_all_player_state(GameConstant.PALYER_GAME_STATE_IN_TABLE_GAME_OVER_WAITING_TO_CONTINUE);
   gt.setHandEndTime(System.currentTimeMillis());
   // 设为非法状态,系统会自动清理
   gt.setState(GameConstant.TABLE_STATE_INVALID);
  } else {
   logger.info("找不到桌子,不需要结束");
  }
 }
 //
 private void close_vip_table(PlayerTableOperationMsg msg, Player pl) {
  GameRoom gr = this.getRoom(pl.getRoomID());
  if (gr == null)
   return;
  GameTable gt = gr.getTable(pl.getTableID(), pl.isPlayingSingleTable());
  if (gt == null) {
   return;
  }
  //
  if (msg.opValue == 1)// 1是请求解散,2是同意解散
  {
   logger.error("玩家" + pl.getPlayerIndex() + ",请求解散VIP房间:"+ gt.getVipTableID());
    
    //桌子进入等待解散状态
    //...........................
    
    // 有一个请求,前面的请求就清理掉
   gt.clearCloseVipRoomMap();
    //
   PlayerGameOpertaionAckMsg msgx = new PlayerGameOpertaionAckMsg();
   msgx.playerName = pl.getPlayerName();
   msgx.opertaionID = GameConstant.MAHJONG_OPERTAION_WAITING_OR_CLOSE_VIP;
   msgx.playerIndex = pl.getPlayerIndex();
 
   this.sendMsgToTableExceptMe(gt, msgx, pl.getPlayerID());
    // 有2个人同意结束,则结束房间
   gt.addVipRoomCloseRequester(pl.getPlayerID(),1);
   gt.setRequestVipCloseTime(System.currentTimeMillis());
  } else if (msg.opValue == 2) {
   logger.error("玩家" + pl.getPlayerIndex() + ",同意解散VIP房间:"+ gt.getVipTableID());
   gt.addVipRoomCloseRequester(pl.getPlayerID(),1);
  }
  else if (msg.opValue == 3) {
   gt.addVipRoomCloseRequester(pl.getPlayerID(),0);
  }
  
  //
  //
  
  // 现在1人提成,2人同意,马上解散
  int num = 3;
  if (gt.getMaxPlayer() < 4)
   num = 2;
  if (gt.getCloseVipRoomRequesterNum() >= num) {
   logger.error("同意人数达到" + num + "人,解散VIP房间:" + gt.getVipTableID());
   // 结束VIP房间
   vip_table_end(gr, gt);
   gt.clearCloseVipRoomMap();
  }
  else if(gt.getClearCloseVipRoomMapSize() == gt.getMaxPlayer()){
   gt.clearCloseVipRoomMap();
  }
 }
 /** 房主申请解散VIP房间 */
 public void applyCloseVipTable(Player pl) {
  GameRoom gr = this.getRoom(pl.getRoomID());
  if (gr == null) {
   logger.error("房主:" + pl.getPlayerIndex() + ",申请解散VIP房间 gr==null");
   return;
  }
  GameTable gt = gr.getTable(pl.getTableID(), pl.isPlayingSingleTable());
  if (gt == null) {
   logger.error("房主" + pl.getPlayerIndex() + ",申请解散VIP房间 gt==null");
   return;
  }
  if (gt.getHandNum() > 1) {
   logger.error("房主" + pl.getPlayerIndex() + ",申请解散VIP房间,游戏局数大于1");
   return;
  }
  if (gt.getCreatorPlayerID().equals(pl.getPlayerID()) && gt.getHandNum() == 0) {
   // 结束VIP房间
   vip_table_end(gr, gt);
   logger.error("房主" + pl.getPlayerIndex() + ",申请解散VIP房间:"+ gt.getVipTableID() + ",成功!");
  } else {
   // 离开房间
   player_left_vip_room(pl, gt, gr);
  }
 }
 //
 private void player_left_vip_room(Player pl, GameTable gt, GameRoom gr) {
  //
  int vipgold = pl.getVipTableGold();
  if (vipgold > 0 && vipgold < gr.fixedGold)// 他的vip金币异常,不让退出
  {
   logger.error("玩家" + pl.getPlayerIndex() + ",离开VIP房间:"
     + gt.getVipTableID() + ",操作失败,vip金币=" + vipgold);
   return;
  }
  //
  int state = gt.getState();
  // 如果是vip房,一旦开始游戏,就不能离开
  if (gt.isVipTable()
    && state != GameConstant.GAME_TABLE_STATE_WAITING_PLAYER) {
   logger.error("玩家" + pl.getPlayerIndex() + ",离开VIP房间:"
     + gt.getVipTableID() + ",操作失败,桌子状态不是在等待中");
   return;
  }
  //
  if (state == GameConstant.GAME_TABLE_STATE_PLAYING
    || state == GameConstant.GAME_TABLE_STATE_SHOW_GAME_OVER_SCREEN
    || state == GameConstant.GAME_TABLE_STATE_PAUSED
    || state == GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE) {
   logger.error("玩家" + pl.getPlayerIndex() + ",离开VIP房间:"
     + gt.getVipTableID() + ",操作失败,桌子状态=" + state);
   return;
  }
  //
  // 玩家不在桌子上
  pl.setOnTable(false);
  //
  boolean found = gt.removePlayer(pl.getPlayerID());
  if (found) {
   if (found) {
    gr.setPlayerNum(gr.getPlayerNum() - 1);
    gt.addFreePos(pl.getTablePos());
   }
   //
   if (gt.getPlayerNum() > 0) {
    // 如果还有玩家,通知他们有玩家离开
    PlayerGameOpertaionAckMsg axk = new PlayerGameOpertaionAckMsg();
    axk.opertaionID = GameConstant.GAME_OPERTAION_PLAYER_LEFT_TABLE;
    axk.playerName = pl.getPlayerName();
    axk.gold = pl.getGold();
    axk.headImg = pl.getHeadImg();
    axk.sex = pl.getSex();
    axk.playerID = pl.getPlayerID();
    axk.playerIndex = pl.getPlayerIndex();
    axk.canFriend = pl.getCanFriend();
    axk.tablePos = pl.getTablePos();
    axk.ip = pl.getClientIP();
    axk.sessionID = pl.getPlayerLobbySessionID();
    this.sendMsgToTableExceptMe(gt, axk, pl.getPlayerID());
   }
   //
   pl.clear_game_state();
   pl.setVipTableID("");
   pl.setVipTableGold(0);
   logger.info("玩家" + pl.getPlayerIndex() + ",离开VIP房间:"
     + gt.getVipTableID() + ",操作成功");
  } else {
   logger.info("玩家" + pl.getPlayerIndex() + ",离开VIP房间:"
     + gt.getVipTableID() + ",桌子上未找到这个玩家");
  }
 }
 //
 public void playerOperation(PlayerTableOperationMsg msg, Player pl) {
  if (msg == null || pl == null)
   return;
  // 玩家主动续卡
  if (msg.operation == GameConstant.MAHJONG_OPERTAION_EXTEND_CARD_REMIND) {
   extend_vip_table(msg, pl);
   return;
  }
  // 有玩家同意关闭房间
  if (msg.operation == GameConstant.MAHJONG_OPERTAION_WAITING_OR_CLOSE_VIP) {
   close_vip_table(msg, pl);
   return;
  }
  // 查找vip房间
  if (msg.operation == GameConstant.MAHJONG_OPERTAION_SEARCH_VIP_ROOM) {
   search_vip_room(msg, pl);
   return;
  }
  //
  GameRoom gr = this.getRoom(pl.getRoomID());
  if (gr == null)
   return;
  if (msg.operation == GameConstant.MAHJONG_OPERTAION_GAME_OVER_CHANGE_TABLE) {
   // 桌子可能已经撤掉了
   // 游戏结束,换桌
   // 记录roomid
   int roomID = pl.getRoomID();
   // 先离开
   player_left_table(pl);
   // 再加入
   enter_room(pl, roomID);
   return;
  }
  // 游戏结束,继续,开始
  else if (msg.operation == GameConstant.MAHJONG_OPERTAION_GAME_OVER_CONTINUE) {
   game_continue(pl);
   return;
  }
  //
  GameTable gt = gr.getTable(pl.getTableID(), pl.isPlayingSingleTable());
  if (gt == null) {
   return;
  }
  // 剩余多少张牌
  msg.cardLeftNum = gt.getCardLeftNum();
  // //玩家出牌
  if ((msg.operation & GameConstant.MAHJONG_OPERTAION_CHU) == GameConstant.MAHJONG_OPERTAION_CHU) {
   if (pl.getOverTimeState() == GameConstant.PALYER_GAME_OVERTIME_STATE_IN_TABLE_WAITING_TO_OVERTIMECHU) {
    return;
   }
   player_op_chu(gr, gt, msg, pl);
  } else if ((msg.operation & GameConstant.MAHJONG_OPERTAION_OVERTIME_AUTO_CHU) == GameConstant.MAHJONG_OPERTAION_OVERTIME_AUTO_CHU) {
   if (pl.getOverTimeState() == GameConstant.PALYER_GAME_OVERTIME_STATE_IN_TABLE_NOWAITING_TO_OVERTIMECHU)
    return;
   //
   msg.operation = GameConstant.MAHJONG_OPERTAION_CHU;
   player_op_chu(gr, gt, msg, pl);
  }
  // //玩家吃牌
  else if ((msg.operation & GameConstant.MAHJONG_OPERTAION_CHI) == GameConstant.MAHJONG_OPERTAION_CHI) {
   // 清理掉刚才的杠
   gt.setGangPl(null);
   player_op_chi(gr, gt, msg, pl);
  }
  // //玩家碰牌
  else if ((msg.operation & GameConstant.MAHJONG_OPERTAION_PENG) == GameConstant.MAHJONG_OPERTAION_PENG) {
   player_op_peng(gr, gt, msg, pl);
  }
  // //玩家杠牌,补管啥杠,客户端都发的这个明杠参数,服务器自己会判断是什么杠,客户端用这个MAHJONG_OPERTAION_MING_GANG
  else if ((msg.operation & GameConstant.MAHJONG_OPERTAION_MING_GANG) == GameConstant.MAHJONG_OPERTAION_MING_GANG) {
   player_op_gang(gr, gt, msg, pl);
  }
  // //玩家去消吃碰牌
  else if ((msg.operation & GameConstant.MAHJONG_OPERTAION_CANCEL) == GameConstant.MAHJONG_OPERTAION_CANCEL) {
   player_cancel_chi_peng_gang_hu(gr, gt, msg, pl);
  } else if ((msg.operation & GameConstant.MAHJONG_OPERTAION_HU) == GameConstant.MAHJONG_OPERTAION_HU) {
   player_op_hu(gt, msg, pl);
  } else {
   logger.error("##nooperations##" + msg.operation);
  }
 }
 //
 private void player_op_get_gang_card(GameRoom gr, GameTable gt,
   PlayerTableOperationMsg msg, Player pl) {
  MahjongCheckResult waiting = gt.getWaitingPlayerOperate();
  if (waiting == null) {
   logger.error("no such operation, PlayerIndex="
     + pl.getPlayerIndex());
   return;// 当前没有在等待某个玩家操作;
  }
  if (waiting.playerTableIndex != pl.getTablePos()) {
   logger
     .error("player_op_get_gang_card,table position invalid,player_index="
       + pl.getPlayerIndex());
   return;// 当前不是在等这个玩家操作
  }
  // 吃,或者吃听
  /*
   * if((waiting.opertaion&GameConstant.MAHJONG_OPERTAION_POP_LAST)!=GameConstant.MAHJONG_OPERTAION_POP_LAST) {
   * logger.error("operation invalid"); return;//当前不能吃; }
   */
  int gsc = msg.card_value;
  byte b1 = 0;
  if (gsc == 1) {
   b1 = gt.getLast1Card();
   gt.popLastCard(1);
   gt.setBaoCard(gt.getLast1Card());
   gt.setBaoCard2(gt.getLast2Card());
  } else if (gsc == 2) {
   b1 = gt.getLast2Card();
   gt.popLastCard(2);
   gt.setBaoCard(gt.getLast1Card());
   gt.setBaoCard2(gt.getLast2Card());
  }
  if (b1 == 0)
   return;
  // 设置吃的一组牌,客户端好表现
  msg.opValue = b1;
  // msg.player_table_pos = pl.getTablePos();
  msg.card_value = ((gt.getBaoCard2() << 8) | gt.getBaoCard());
  this.sendMsgToTable(gt, msg);
  //
  gt.setCurrentCard((byte) 0);
  gt.setCardOpPlayerIndex(-1);
  pl.setCardGrab(b1);
  MahjongCheckResult hu_xx = null;
  //
  hu_xx = mjProc.check_hu(b1, pl, gt, true); //
  if (hu_xx != null)// 胡了
  {
   // 判断是否五梅花
   // 杠上开花
   PlayerOperationNotifyMsg msg1 = new PlayerOperationNotifyMsg();
   msg1.operation = GameConstant.MAHJONG_OPERTAION_HU;
   msg1.target_card = b1;
   msg1.unused_0 = GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA;
   waiting.playerTableIndex = pl.getTablePos();
   waiting.targetCard = b1;
   waiting.opertaion = GameConstant.MAHJONG_OPERTAION_HU;
   waiting.fanResult |= GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA;
   gt.setWaitingPlayerOperate(waiting);
   msg1.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), msg1);
   return;
  } else {
   player_chu_notify(gt, false, true);
  }
  // gt.setWaitingPlayerOperate(null);
  // 等待客户端播动画
  // Date dt=DateService.getCurrentUtilDate();
  // gt.setWaitingStartTime(dt.getTime());
  // gt.setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_PLAYING_GANG_CART_LAST_ANIMATION);
 }
 //
 private void player_op_chi(GameRoom gr, GameTable gt,
   PlayerTableOperationMsg msg, Player pl) {
  // 玩家吃牌
  int v1 = msg.card_value & 0xff;
  int v2 = (msg.card_value >> 8) & 0xff;
  //
  MahjongCheckResult waiting = gt.getWaitingPlayerOperate();
  if (waiting == null) {
   logger.error("no such operation, PlayerIndex="
     + pl.getPlayerIndex());
   return;// 当前没有在等待某个玩家操作;
  }
  if (waiting.playerTableIndex != pl.getTablePos()) {
   logger.error("player_op_chi,table position invalid,player_index="
     + pl.getPlayerIndex());
   return;// 当前不是在等这个玩家操作
  }
  // 吃,或者吃听
  if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_CHI) != GameConstant.MAHJONG_OPERTAION_CHI) {
   logger.error("operation invalid");
   return;// 当前不能吃;
  }
  if (waiting.chi_check(v1, v2) == false) {
   logger.error("chi parameter invalid, PlayerIndex="
     + pl.getPlayerIndex() + ",v1=" + v1 + ",v2=" + v2
     + ",isAuto=" + pl.getAutoOperation());
   return;// 吃的牌不对;
  }
  print_player_log(pl, GameConstant.MAHJONG_OPERTAION_CHI, msg.card_value);
  // 有可能玩家吃听,这时候要把当前操作的索引改成此玩家
  gt.setCurrentOpertaionPlayerIndex(pl.getTablePos());
  //
  pl.removeCardInHand(v1);
  pl.removeCardInHand(v2);
  //
  // 通知客户端把被碰的牌拿走
  if (gt.getChuPlayer() != null) {
   PlayerOperationNotifyMsg removeChuMsg = new PlayerOperationNotifyMsg();
   removeChuMsg.operation = GameConstant.MAHJONG_OPERTAION_REMOE_CHU_CARD;
   removeChuMsg.player_table_pos = gt.getChuPlayer().getTablePos();
   removeChuMsg.target_card = waiting.targetCard & 0xff;
   removeChuMsg.cardLeftNum = gt.getCardLeftNum();
   this.sendMsgToTable(gt, removeChuMsg);
  }
  // 
  CardDown down = pl.addCardDown(waiting.targetCard, v1, v2,
    GameConstant.MAHJONG_OPERTAION_CHI);
  down.chuPlayer = gt.getChuPlayer();
  if (down.chuPlayer == null)// 必须得有出牌的人
  {
   logger.error("chu player==null,chi pl idx=" + pl.getPlayerIndex()
     + ",chi card v1=" + v1 + " v2=" + v2);
  }
  // 吃了就不限制其他人碰和胡了
  gt.clearOpLimits(pl);
  gt.setgenzhang(false);
  gt.setCanGenzhang(false);
  //
  // 设置吃的一组牌,客户端好表现
  msg.opValue = down.cardValue;
  this.sendMsgToTable(gt, msg);
  //
  // 服务器清除等待玩家操作的数据
  gt.setWaitingPlayerOperate(null);
  // 等待客户端播动画
  Date dt = DateService.getCurrentUtilDate();
  gt.setWaitingStartTime(dt.getTime());
  gt
    .setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_PLAYING_CHI_PENG_ANIMATION);
  //
  gt.setCurrentCard((byte) 0);
  gt.setCardOpPlayerIndex(-1);
 }
 //
 private MahjongCheckResult auto__hu_other_plaeyr(GameTable gt, byte card,
   Player opPlayer, int chuCardPlayerTableIndex) {
  List<Player> plist = gt.getPlayers();
  int pl_index = opPlayer.getTablePos() + 1;
  if (pl_index >= plist.size())
   pl_index = 0;
  //
  Player chuPl = gt.getPlayerAtIndex(chuCardPlayerTableIndex);
  //
  for (int i = 0; i < plist.size() - 1; i++) {
   Player pl = plist.get(pl_index);
   if (pl.getTablePos() == chuCardPlayerTableIndex)
    break;
   if (pl.isHuuuuued() == false) {
    // 先检测卡胡
    MahjongCheckResult hu = mjProc.check_hu(card, pl, gt, false);
    //
    if (hu != null) {
     this.player_hu(gt, pl, chuPl, hu.fanResult, hu.targetCard,
       hu.keZiNum, hu.same2Shunzi, hu);
    }
   }
   pl_index++;
   if (pl_index >= plist.size())
    pl_index = 0;
  }
  //
  return null;
 }
 //
 private void player_op_hu(GameTable gt, PlayerTableOperationMsg msg,
   Player pl) {
  // System.out.println("index:"+pl.getPlayerIndex());
  //
  MahjongCheckResult waiting = gt.getWaitingPlayerOperate();
  if (waiting == null) {
   logger.error("no such operation, PlayerIndex="
     + pl.getPlayerIndex());
   return;// 当前没有在等待某个玩家操作;
  }
  if (waiting.playerTableIndex != pl.getTablePos()) {
   logger.error("player_op_chi,table position invalid,player_index="
     + pl.getPlayerIndex());
   return;// 当前不是在等这个玩家操作
  }
  //
  if (((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_HU) != GameConstant.MAHJONG_OPERTAION_HU)) {
   logger.error("hu operation invalid");
   return;// 当前不能吃;
  }
  MahjongCheckResult hu_xx = mjProc.check_hu(waiting.targetCard, pl, gt,
    (waiting.chuPlayer == null));
  if (hu_xx == null) {
   logger.error("hu operation failed,card=" + waiting.targetCard);
   return;
  }
  if ((waiting.fanResult & GameConstant.MAHJONG_HU_CODE_QIANG_GANG_HU) == GameConstant.MAHJONG_HU_CODE_QIANG_GANG_HU) {
   hu_xx.fanResult |= GameConstant.MAHJONG_HU_CODE_QIANG_GANG_HU;
  }
  if ((waiting.fanResult & GameConstant.MAHJONG_HU_CODE_DI_HU) == GameConstant.MAHJONG_HU_CODE_DI_HU) {
   hu_xx.fanResult |= GameConstant.MAHJONG_HU_CODE_DI_HU;
  }
  if ((waiting.fanResult & GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA) == GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA) {
   hu_xx.fanResult |= GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA;
  }
  // 玩家胡了
  this.player_hu(gt, pl, waiting.chuPlayer, hu_xx.fanResult,
    hu_xx.targetCard, hu_xx.keZiNum, hu_xx.same2Shunzi, hu_xx);
  // 剩下几家就自动胡了
  // if(waiting.chuPlayer!=null )//看看是否有一炮多响
  // {
  // auto__hu_other_plaeyr(gt,hu_xx.targetCard,
  // pl,waiting.chuPlayer.getTablePos());
  // }
  gt.setWaitingPlayerOperate(null);
  //
  game_over_hu(gt, false);
 }
 //
 //
 private void player_hu(GameTable gt, Player pl, Player dianPaoPl,
   int fanResult, byte huCard, int keZiNum, int shuangPuZi,
   MahjongCheckResult hu) {
  // 打印手牌
  print_player_log(pl, GameConstant.MAHJONG_OPERTAION_HU, huCard);
  //
  // 玩家已经胡牌
  pl.playerHu(huCard, dianPaoPl, 0);
  // 统计
  if (gt.isVipTable() && dianPaoPl != null) {
   dianPaoPl.setDianpaoCount(dianPaoPl.getDianpaoCount() + 1);// 点炮+1
  }
  // 只记录第一个胡的人
  //if (gt.getCurrentHuPlayerIndex() == -1) {
  gt.setCurrentHuPlayerIndex(pl.getTablePos());
  //}
  //
  //
  // logger.info("player "+pl.getPlayerIndex()+" hu card="+huCard);
  // player_hu(gt, pl, waiting.targetCard, waiting.chuPlayer,
  // waiting.fanResult);
  // 结算番型和金币,并开马
  win_lose_gold_calculate_hu(gt, pl, huCard, dianPaoPl, fanResult, hu);
  pl.setHuuuuued(true);
  // 通知所有玩家,有人胡了
  PlayerOperationNotifyMsg huMsg = new PlayerOperationNotifyMsg();
  huMsg.operation = GameConstant.MAHJONG_OPERTAION_PLAYER_HU_CONFIRMED;
  huMsg.player_table_pos = pl.getTablePos();
  huMsg.target_card = huCard;
  huMsg.chi_card_value = pl.getFanType();
  huMsg.cardLeftNum = gt.getCardLeftNum();
  //
  this.sendMsgToTable(gt, huMsg);
  //
 }
 //
 private void wait_player_chu(GameTable gt, MahjongCheckResult waiting,
   Player pl) {
  PlayerOperationNotifyMsg notify_msg = new PlayerOperationNotifyMsg();
  notify_msg.operation = GameConstant.MAHJONG_OPERTAION_CHU;
  notify_msg.player_table_pos = waiting.playerTableIndex;
  notify_msg.sessionID = pl.getPlayerLobbySessionID();
  notify_msg.cardLeftNum = gt.getCardLeftNum();
  // SystemConfig.gameSocketServer.sendMsg(pl.getSession(), notify_msg);
  this.sengMsgToPlayer(gt, pl, notify_msg);
  // 等待玩家出牌
  MahjongCheckResult chu = new MahjongCheckResult();
  chu.playerTableIndex = waiting.playerTableIndex;
  chu.opertaion = GameConstant.MAHJONG_OPERTAION_CHU;
  gt.setWaitingPlayerOperate(chu);
 }
 //
 //
 private void player_cancel_chi_peng_gang_hu(GameRoom gr, GameTable gt,
   PlayerTableOperationMsg msg, Player pl) {
  // 玩家取消
  MahjongCheckResult waiting = gt.getWaitingPlayerOperate();
  if (waiting == null) {
   logger.error("peng,no such operation, player_index="
     + pl.getPlayerIndex());
   return;// 当前没有在等待某个玩家操作;
  }
  //
  if (waiting.playerTableIndex != pl.getTablePos()) {
   logger
     .error("player_cancel_chi_peng_gang,table position invalid, player_index="
       + pl.getPlayerIndex());
   return;// 当前不是在等这个玩家操作
  }
  if (waiting.hua_flag == GameConstant.GAME_TABLE_STATE_CHECK_LIANG_HUA) {
   if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_GANG) == GameConstant.MAHJONG_OPERTAION_GANG) {
    gt.incCurFengPos();
    gt.setState(GameConstant.GAME_TABLE_STATE_CHECK_LIANG_HUA);
   } else if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_HU) == GameConstant.MAHJONG_OPERTAION_HU) {
    gt.setTianTingTime(System.currentTimeMillis());
    gt.incCurFengPos();
    gt.setState(GameConstant.GAME_TABLE_STATE_CHECK_LIANG_HUA);
   } else {
    gt.setTianTingTime(System.currentTimeMillis());
    gt.setState(GameConstant.GAME_TABLE_STATE_CHECK_LIANG_HUA);
   }
   return;
  }
  // 自己摸起来暗杠,或者补杠,玩家取消
  if (((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_GANG) == GameConstant.MAHJONG_OPERTAION_GANG)
    && gt.getLastMoCardPlayerTablePos() == pl.getTablePos()) {
   wait_player_chu(gt, waiting, pl);
   return;
  }
  // 如果是最后一张牌,玩家点过,直接结束
  if (gt.isEnd())// 流局了
  {
   gt.setCurrentHuPlayerIndex(-1);
   game_over_hu(gt, true);
   return;
  }
  //
  // 打印手牌
  print_player_log(pl, GameConstant.MAHJONG_OPERTAION_CANCEL,
    waiting.opertaion);
  // 找到出牌的那个玩家,是他引起其他玩家可以吃碰之类
  int chu_Card_pl_idx = gt.getCardOpPlayerIndex();
  Player pl_chu = gt.getPlayerAtIndex(chu_Card_pl_idx);
  // 再找到按顺序,出牌的下家,应该是当前操作的玩家,如果没有吃碰
  Player plx = gt.getCurrentOperationPlayer();
  if (plx == null)
   return;
  // 不胡,这里先处理自己摸的牌不想胡,其他人打的在后面处理
  if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_HU) == GameConstant.MAHJONG_OPERTAION_HU) {
   // 我自己摸起来的牌,我自己不胡
   if ((pl_chu == null || pl_chu.getPlayerID()
     .equals(pl.getPlayerID()))
     && plx.getPlayerID().equals(pl.getPlayerID())) {
    wait_player_chu(gt, waiting, pl);
    return;//
   }
  }
  //
  if (pl_chu == null)
   return;
  // 玩家不碰杠(被提示玩家只有碰杠的操作),那就看看当前玩家是否可以吃,不能吃就摸牌
  if (((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_PENG) == GameConstant.MAHJONG_OPERTAION_PENG)
    || ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_MING_GANG) == GameConstant.MAHJONG_OPERTAION_MING_GANG)
    || ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_GANG) == GameConstant.MAHJONG_OPERTAION_GANG))
  {
   if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_PENG) == GameConstant.MAHJONG_OPERTAION_PENG)
    pl.addLimitPeng(waiting.targetCard);
   // 如果不是下家碰牌,那可能下家可以吃牌,看看他吃不吃
   if (plx.getTablePos() != pl.getTablePos()) {
    MahjongCheckResult result = mjProc.check_chi(gt,
      waiting.targetCard, plx);
    if (result != null) {
     // 说明其他玩家有碰不碰,当前玩家可以吃,提示他吃不吃
     // 设置当前桌子的当地玩家操作,等玩家操作的时候,再核查一下
     gt.setWaitingPlayerOperate(result);
     // 设置操作开始时间
     long ctt = DateService.getCurrentUtilDate().getTime();
     Player result_pl = gt
       .getPlayerAtIndex(result.playerTableIndex);
     result_pl.setOpStartTime(ctt);
     //
     PlayerOperationNotifyMsg notify_msg = new PlayerOperationNotifyMsg();
     notify_msg.operation = GameConstant.MAHJONG_OPERTAION_CHI;
     notify_msg.chi_card_value = result.chi_card_value;
     notify_msg.peng_card_value = result.peng_card_value;
     notify_msg.player_table_pos = result.playerTableIndex;
     notify_msg.target_card = result.targetCard;
     //
     //
     notify_msg.sessionID = plx.getPlayerLobbySessionID();
     SystemConfig.gameSocketServer.sendMsg(plx.getSession(),
       notify_msg);
     // 机器人操作提示
     if (plx.isRobot()) {
      machineService.post_msg(gt, plx, notify_msg);
     }
    } else {
     // 4如果当前玩家不能吃,摸牌
     player_mo(gt);
    }
   } else {
    // 4如果当前玩家不能吃,摸牌
    player_mo(gt);
   }
   return;//
  } else if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_HU) == GameConstant.MAHJONG_OPERTAION_HU) {
   // 如果某一回合中,有人点炮,该玩家在第一次没有胡,其他玩家在该回合中再次点炮时,
   // 即使加番或杠上开花该玩家也不能胡(自摸除外);
   // 当该玩家有动牌(即碰、杠、摸牌)后,该回合过手胡解除限制;
   pl.setCancelHu(true);
   pl.addLimitHu(waiting.targetCard);
   //
   // 别人打的牌,我不胡,看看其他人有人胡不
   MahjongCheckResult hu = table_loop_check(gt, waiting.targetCard,
     pl, GameConstant.MAHJONG_OPERTAION_HU, chu_Card_pl_idx);
   if (hu != null) {
    Player hu_pl = gt.getPlayerAtIndex(hu.playerTableIndex);
    //
    PlayerOperationNotifyMsg huMsg = new PlayerOperationNotifyMsg();
    huMsg.operation = GameConstant.MAHJONG_OPERTAION_HU;
    huMsg.player_table_pos = hu_pl.getTablePos();
    huMsg.target_card = waiting.targetCard & 0xff;
    huMsg.cardLeftNum = gt.getCardLeftNum();
    //
    hu.chuPlayer = pl_chu;
    gt.setWaitingPlayerOperate(hu);
    //
    huMsg.sessionID = hu_pl.getPlayerLobbySessionID();
    // SystemConfig.gameSocketServer.sendMsg(hu_pl.getSession(),
    // huMsg);
    this.sengMsgToPlayer(gt, hu_pl, huMsg);
    //
    // 设置操作开始时间
    long ctt = DateService.getCurrentUtilDate().getTime();
    hu_pl.setOpStartTime(ctt);
   } else {
    // 去掉可能的被抢杠前的记录
    gt.setGangOpBackup(null);
    gt.setGangMsgBackup(null);
    // 别人点炮,你不胡,检测是否吃碰杠
    check_next_player_op(gt, waiting.targetCard, pl_chu,
      GameConstant.MAHJONG_OPERTAION_MING_GANG
        | GameConstant.MAHJONG_OPERTAION_PENG
        | GameConstant.MAHJONG_OPERTAION_CHI);
   }
   return;//
  }
  // 玩家不吃(有可能同时有吃碰提示),那就摸牌
  else if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_CHI) == GameConstant.MAHJONG_OPERTAION_CHI) {
   // 4如果什么操作都没有,下个玩家进行摸牌动作
   player_mo(gt);
   return;//
  }
 }
 //
 public byte getAutoChuCard(GameTable gt, Player pl) {
  byte card = 0;
  if (pl.getCardGrab() != 0) {
   card = pl.getCardGrab();
    return card;
  }
  List<Byte> lt = pl.getCardsInHand();
  for (byte cc : lt) {
    return cc;
  }
  //
  return pl.getCard(0);
 }
 // 超时处理,打第一张牌
 private void overtime_proc(Player pl, GameTable gt) {
  // if(pl.isRobot())
  // return;
  if (gt.getState() == GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE
    || gt.getState() == GameConstant.GAME_TABLE_STATE_WAITING_PLAYER) {
   pl.setAutoOperation(0);
   gt.setWaitingPlayerOperate(null);
   return;
  }
  //
  PlayerTableOperationMsg msg = new PlayerTableOperationMsg();
  //
  MahjongCheckResult wt = gt.getWaitingPlayerOperate();
  // 自动吃碰听
  if (wt != null) {
   // 所有操作全部按过处理
   // 所有操作全部按过处理
   if (((wt.opertaion & GameConstant.MAHJONG_OPERTAION_CHI) == GameConstant.MAHJONG_OPERTAION_CHI)
     || ((wt.opertaion & GameConstant.MAHJONG_OPERTAION_PENG) == GameConstant.MAHJONG_OPERTAION_PENG)
     || ((wt.opertaion & GameConstant.MAHJONG_OPERTAION_GANG) == GameConstant.MAHJONG_OPERTAION_GANG)
     || ((wt.opertaion & GameConstant.MAHJONG_OPERTAION_HU) == GameConstant.MAHJONG_OPERTAION_HU)) {
    msg.player_table_pos = wt.playerTableIndex;
    msg.operation = GameConstant.MAHJONG_OPERTAION_CANCEL;
    // 通知客户端隐藏吃、碰、听提示框
    PlayerOperationNotifyMsg CancelMsg = new PlayerOperationNotifyMsg();
    CancelMsg.operation = GameConstant.MAHJONG_OPERTAION_CANCEL;
    CancelMsg.player_table_pos = pl.getTablePos();
    CancelMsg.cardLeftNum = gt.getCardLeftNum();
    CancelMsg.sessionID = pl.getPlayerLobbySessionID();
    SystemConfig.gameSocketServer.sendMsg(pl.getSession(),
      CancelMsg);
   } else {
    if ((wt.opertaion & GameConstant.MAHJONG_OPERTAION_CHU) != GameConstant.MAHJONG_OPERTAION_CHU) {
     logger.info("tuoguan_wt:" + wt.opertaion);
    }
   }
  }
  // else{
  // player_mo(gt);
  // return;
  // }
  //
  if (msg.operation == 0) {
   // 自动出牌
   msg.operation = GameConstant.MAHJONG_OPERTAION_OVERTIME_AUTO_CHU;
   msg.player_table_pos = pl.getTablePos();
   //
   if (msg.card_value == 0) {
    msg.card_value = getAutoChuCard(gt, pl);
   }
   // 自己是自动出牌
   PlayerOperationNotifyMsg autoMsg = new PlayerOperationNotifyMsg();
   autoMsg.operation = GameConstant.MAHJONG_OPERTAION_OVERTIME_AUTO_CHU;
   autoMsg.player_table_pos = pl.getTablePos();
   autoMsg.target_card = msg.card_value;
   autoMsg.cardLeftNum = gt.getCardLeftNum();
   autoMsg.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), autoMsg);
  }
  // 设置成托管状态
  pl.setAutoOperation(1);
  playerOperation(msg, pl);
  // pl.setGameState(GameConstant.PALYER_GAME_STATE_IN_TABLE_PLAYING);
  //
 }
 //
 private void print_player_log(Player pl, int op, int opCard) {
  if (showCardLog) {
   String pop = "==null==";
   if (op == GameConstant.MAHJONG_OPERTAION_PENG)
    pop = "==PENG==";
   else if (op == GameConstant.MAHJONG_OPERTAION_HU)
    pop = "==HU==";
   else if (op == GameConstant.MAHJONG_OPERTAION_MING_GANG)
    pop = "==GANG==";
   else if (op == GameConstant.MAHJONG_OPERTAION_CANCEL)
    pop = "==CANCEL==";
   else if (op == GameConstant.MAHJONG_OPERTAION_CHU)
    pop = "==CHU==";
   else if (op == GameConstant.MAHJONG_OPERTAION_CHI)
    pop = "==CHI==";
   String xx = pop + " opCard=" + Integer.toHexString(opCard) + ","
     + pl.getPlayerDebugDesc() + ",tableID=" + pl.getTableID();
   logger.info(xx);
  }
 }
 //
 private void player_op_chu(GameRoom gr, GameTable gt,
   PlayerTableOperationMsg msg, Player pl) {
  MahjongCheckResult waiting = gt.getWaitingPlayerOperate();
  if (waiting == null) {
   logger.error("no such chu operation, PlayerIndex="
     + pl.getPlayerIndex());
   return;// 当前没有在等待某个玩家操作;
  }
  if (waiting.playerTableIndex != pl.getTablePos()) {
   logger.error("player_op_chu,table position invalid,player_index="
     + pl.getPlayerIndex());
   return;// 当前不是在等这个玩家操作
  }
  // 出
  if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_CHU) != GameConstant.MAHJONG_OPERTAION_CHU) {
   logger.error("operation invalid");
   return;// 当前不能吃;
  }
  //
  // 玩家出牌
  byte card_value = (byte) (msg.card_value & 0xff);
  Player prechuPl = gt.getChuPlayer();
  byte prechucard = 0;
  if (prechuPl != null) {
   prechucard = gt.getCurrentCard();
  }
  // 记录出牌的人
  gt.setChuPlayer(pl);
  print_player_log(pl, GameConstant.MAHJONG_OPERTAION_CHU, card_value);
  // 出牌次数加1
  pl.setChuPaiNum(pl.getChuPaiNum() + 1);
  int pl_pos = msg.player_table_pos;
  // 看看之前刚摸的牌有没有,摸的牌,先放cardgrab变量里面,等他出牌的时候再放进去,这样断线重连的时候,他摸的还是原来那张
  byte moCard = pl.getCardGrab();
  if (moCard != 0) {
   pl.addCardInHand(moCard);
   pl.setCardGrab((byte) 0);
  }
  //
  byte card_v = pl.findCardInHand(card_value);
  //
  if (card_v == card_value && pl_pos == pl.getTablePos()) {
   /*
    * if(pl.getPlayerIndex()!=20821) { card_v = 0x33; card_value =
    * 0x33; msg.card_value = 0x33; }
    */
   // 出财神不能吃碰杠别人,也不能自摸,只能补杠,暗杠
   if (gt.getBaoCard() > 0x40) {
    if (card_v > 0x40) {
     pl.setChucaishen(true);
    }
   } else {
    if (card_v == gt.getBaoCard()) {
     pl.setChucaishen(true);
    }
   }
   // 1把牌从玩家手里拿走
   pl.removeCardInHand(card_value);
   gt.add_Down_cards(card_value);
   //
   // 2把牌放在桌子中间,如果没有吃碰胡之类,牌就放在这个玩家面前
   gt.setCurrentCard(card_v);
   gt.setCardOpPlayerIndex(pl.getTablePos());
   if (prechuPl != null) {
    gt.setgenzhang(false);
    int distant = pl.getTablePos() - prechuPl.getTablePos();
    if ((distant == 1 || distant == -3) && gt.canGenzhang()) {
     if (card_v == prechucard) {
      gt.setgenzhang(true);
     }
    }
   }
   gt.setCanGenzhang(true);
   //
   this.sendMsgToTableExceptMe(gt, msg, pl.getPlayerID());
   // 有问题,不能用
   // 给出牌玩家也发一条出牌信息,包含手牌、出牌、吃碰牌信息,用于服务端、客户端数据同步
   msg.handCards = pl.getCardsInHand();
   msg.beforeCards = pl.getCardsBefore();
   msg.downCards = pl.getCardsDown();
   msg.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), msg);
   // 服务器清除等待玩家操作的数据
   gt.setWaitingPlayerOperate(null);
   // 等待客户端播动画
   Date dt = DateService.getCurrentUtilDate();
   gt.setWaitingStartTime(dt.getTime());
   gt
     .setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_PLAYING_CHU_ANIMATION);
   //
   // 提示胡牌
   // update_player_hu_card_list(gt,pl);
  } else {
   logger.error("出牌错误。");
  }
  //
 }
 //
 private void add_card_unique(List<Byte> cds, int cd) {
  byte bb = (byte) (cd & 0xff);
  int v = cd & 0xf;
  if (v <= 0 || v > 9)
   return;
  //
  for (int i = 0; i < cds.size(); i++) {
   byte b = cds.get(i);
   if (b == cd)
    return;
   //
   if (cd <= b) {
    cds.add(i, bb);
    return;
   }
  }
  // 插在末尾
  cds.add(bb);
 }
 //
 private void update_player_hu_card_list(GameTable gt, Player pl) {
  if (pl.isRobot())
   return;
  //
  List<Byte> huList = new ArrayList<Byte>();
  //
  List<Byte> cds = new ArrayList<Byte>();
  List<Byte> cds_inhand = pl.getCardsInHand();
  for (int i = 0; i < cds_inhand.size(); i++) {
   int b = cds_inhand.get(i);
   add_card_unique(cds, b);
   add_card_unique(cds, b - 1);
   add_card_unique(cds, b + 1);
  }
  //
  for (int i = 0; i < cds.size(); i++) {
   byte b = cds.get(i);
   MahjongCheckResult hu = mjProc.check_hu(b, pl, gt, true);
   if (hu != null)
    huList.add(b);
  }
  //
  cds.clear();
  //
  // 提醒玩家可以胡的牌
  PlayerOperationNotifyMsg huMsg = new PlayerOperationNotifyMsg();
  huMsg.operation = GameConstant.MAHJONG_OPERTAION_HU_CARD_LIST_UPDATE;
  huMsg.player_table_pos = pl.getTablePos();
  huMsg.tingList = huList;// 有没有都返回给客户端,没有,客户端就清空原先假设已经有的
  huMsg.cardLeftNum = gt.getCardLeftNum();
  huMsg.sessionID = pl.getPlayerLobbySessionID();
  SystemConfig.gameSocketServer.sendMsg(pl.getSession(), huMsg);
 }
 // 玩家进行杠,看看有抢的没
 private void player_op_gang(GameRoom gr, GameTable gt,
   PlayerTableOperationMsg msg, Player pl) {
  byte v1 = (byte) (msg.card_value & 0xff);
  //
  //
  // 玩家出牌
  MahjongCheckResult waiting = gt.getWaitingPlayerOperate();
  if (waiting == null) {
   logger.error("gang,no such operation, player_index="
     + pl.getPlayerIndex());
   return;// 当前没有在等待某个玩家操作;
  }
  if (waiting.playerTableIndex != pl.getTablePos()) {
   logger.error("gang,table position invalid, player_index="
     + pl.getPlayerIndex());
   return;// 当前不是在等这个玩家操作
  }
  //
  if (waiting.find_gang(pl, msg.card_value) == false) {
   logger.error("gang,parameter invalid, player_index="
     + pl.getPlayerIndex());
   return;// gang的牌不对;
  }
  //
  // 哪种形式的杠
  int gang_type = 0;
  int newcard = 0;
  if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_MING_GANG) == GameConstant.MAHJONG_OPERTAION_MING_GANG) {
   gang_type = GameConstant.MAHJONG_OPERTAION_MING_GANG;
  } else {
   if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_AN_GANG) == GameConstant.MAHJONG_OPERTAION_AN_GANG) {
    gang_type = GameConstant.MAHJONG_OPERTAION_AN_GANG;
   } else if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_BU_GANG) == GameConstant.MAHJONG_OPERTAION_BU_GANG) {
    gang_type = GameConstant.MAHJONG_OPERTAION_BU_GANG;
   }
   // 补杠的时候是刚摸牌,把摸的放进来
   byte cd = pl.getCardGrab();
   if (cd != 0) {
    newcard = cd;
    pl.addCardInHand(cd);
    pl.setCardGrab((byte) 0);
   }
  }
  //
  if (gang_type == 0) {
   logger.error("GANG,operation invalid, player_index="
     + pl.getPlayerIndex());
   return;// 当前不能gang;
  }
  v1 = waiting.targetCard;
  gt.clearCancelHu();
  // 打印手牌
  print_player_log(pl, GameConstant.MAHJONG_OPERTAION_MING_GANG, v1);
  pl.setCancelHu(false);
  pl.setCouldNotChuCards(0);
  // 2把牌放在桌子中间,如果没有吃碰胡之类,牌就放在这个玩家面前
  gt.setCurrentCard(v1);
  gt.setCardOpPlayerIndex(pl.getTablePos());
  //
  PlayerTableOperationMsg mxg = new PlayerTableOperationMsg();
  mxg.operation = GameConstant.MAHJONG_OPERTAION_MING_GANG;// 通知其他客户端,有人杠,都用这个明杠消息
  mxg.card_value = v1;
  mxg.unused_0 = gang_type;
  mxg.unused_1 = newcard;
  mxg.player_table_pos = pl.getTablePos();
  // mxg.useXiaoNum = waiting.useXiaojiNum;
  mxg.opValue = GameConstant.MAHJONG_OPERTAION_GANG_NOTIFY;//
  this.sendMsgToTable(gt, mxg);
  //
  if (gang_type == GameConstant.MAHJONG_OPERTAION_BU_GANG)// 补杠可以抢胡
  {
   // 按优先级,先胡
   MahjongCheckResult hu_result = table_loop_check(gt, v1, pl,
     GameConstant.MAHJONG_OPERTAION_HU, pl.getTablePos());
   if (hu_result != null) {
    // logger.info("##BUGANGQIANG##vipid="+gt.getVipTableID()+",playerid:"+pl.getPlayerID()+",opercard="+v1);
    // 抢杠前先备份数据,万一人家不抢,可以恢复再杠
    waiting.gangOpPl = pl;
    gt.setGangOpBackup(waiting);
    gt.setGangMsgBackup(msg);
    // 可能倍抢,先移走,等下如果对方不抢杠胡再放回来
    pl.removeCardInHand(v1);
    //
    // 提示可以抢胡
    Player hu_pl = gt.getPlayerAtIndex(hu_result.playerTableIndex);
    //
    PlayerOperationNotifyMsg huMsg = new PlayerOperationNotifyMsg();
    huMsg.operation = GameConstant.MAHJONG_OPERTAION_HU;
    huMsg.player_table_pos = hu_pl.getTablePos();
    huMsg.target_card = v1 & 0xff;
    huMsg.cardLeftNum = gt.getCardLeftNum();
    //
    hu_result.chuPlayer = pl;// 记录被抢杠的人
    hu_result.fanResult |= GameConstant.MAHJONG_HU_CODE_QIANG_GANG_HU;// 抢杠胡
    gt.setWaitingPlayerOperate(hu_result);
    //
    huMsg.sessionID = hu_pl.getPlayerLobbySessionID();
    // SystemConfig.gameSocketServer.sendMsg(hu_pl.getSession(),
    // huMsg);
    this.sengMsgToPlayer(gt, hu_pl, huMsg);
    //
    long ctt = DateService.getCurrentUtilDate().getTime();
    hu_pl.setOpStartTime(ctt);
   } else {
    real_player_op_gang(gt, msg, pl);
   }
  } else {
   // 暗杠不能抢
   // 明杠,手里有3个,别人打一个,会先判断吃听,再杠,所以,也不需要判断抢杠,
   // 明杠不用抢胡,胡之前已经先判断过了
   real_player_op_gang(gt, msg, pl);
  }
 }
 //
 //
 private void put_not_hu_player(GameTable gt, CardDown down, Player gangPl) {
  down.beGangPlayerList.clear();
  //
  List<Player> plist = gt.getPlayers();
  for (int i = 0; i < plist.size(); i++) {
   Player pl = plist.get(i);
   //if (pl.isHuuuuued())
    //continue;
   if (pl.getPlayerID().equals(gangPl.getPlayerID()))
    continue;
   down.beGangPlayerList.add(pl);
  }
 }
 // 玩家进行杠,检查完,没有要抢的,
 private void real_player_op_gang(GameTable gt, PlayerTableOperationMsg msg,
   Player pl) {
  int v1 = msg.card_value & 0xff;
  // 玩家出牌
  MahjongCheckResult waiting = gt.getWaitingPlayerOperate();
  if (waiting == null) {
   logger.error("gang,no such operation, player_index="
     + pl.getPlayerIndex());
   return;// 当前没有在等待某个玩家操作;
  }
  //
  if (waiting.playerTableIndex != pl.getTablePos()) {
   logger.error("gang,table position invalid, player_index="+ pl.getPlayerIndex());
   return;// 当前不是在等这个玩家操作
  }
  // 哪种形式的杠
  int gang_type = 0;
  if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_MING_GANG) == GameConstant.MAHJONG_OPERTAION_MING_GANG) {
   gang_type = GameConstant.MAHJONG_OPERTAION_MING_GANG;
  } else {
   if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_AN_GANG) == GameConstant.MAHJONG_OPERTAION_AN_GANG) {
    gang_type = GameConstant.MAHJONG_OPERTAION_AN_GANG;
   } else if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_BU_GANG) == GameConstant.MAHJONG_OPERTAION_BU_GANG) {
    gang_type = GameConstant.MAHJONG_OPERTAION_BU_GANG;
   }
  }
  //
  if (gang_type == 0) {
   logger.error("GANG,operation invalid, player_index="
     + pl.getPlayerIndex());
   return;// 当前不能gang;
  }
  if (waiting.find_gang(pl, msg.card_value) == false) {
   logger.error("gang,parameter invalid, player_index="
     + pl.getPlayerIndex());
   return;// gang的牌不对;
  }
  // v1 = waiting.targetCard;
  //
  // 真正杠了
  gt.setGangPl(pl);
  //
  if (gang_type == GameConstant.MAHJONG_OPERTAION_MING_GANG
    && gt.getChuPlayer() != null) {
   // 通知客户端把被碰的牌拿走
   PlayerOperationNotifyMsg removeChuMsg = new PlayerOperationNotifyMsg();
   removeChuMsg.operation = GameConstant.MAHJONG_OPERTAION_REMOE_CHU_CARD;
   removeChuMsg.player_table_pos = gt.getChuPlayer().getTablePos();
   removeChuMsg.target_card = msg.card_value;
   removeChuMsg.cardLeftNum = gt.getCardLeftNum();
   this.sendMsgToTable(gt, removeChuMsg);
  }
  // 这时候要把当前操作的索引改成此玩家,这样他出牌的时候,当前操作玩家的索引才是正确的
  gt.setCurrentOpertaionPlayerIndex(pl.getTablePos());
  //
  pl.setLastGangChuPlayer(null);
  //
  int card_down = 0;
  //
  if (gang_type == GameConstant.MAHJONG_OPERTAION_MING_GANG) {
   for (int j = 0; j < 4; j++) {
    pl.removeCardInHand(v1);
    // gt.add_Down_cards((byte)v1);
   }
   // CardDown
   // dd=pl.addCardDown(v1,v1,v1,GameConstant.MAHJONG_OPERTAION_MING_GANG);
   CardDown dd = pl.addGangCardDown(msg.card_value,
     GameConstant.MAHJONG_OPERTAION_MING_GANG);
   dd.chuPlayer = waiting.chuPlayer;// 记录放杠的人,他掏钱
   card_down = dd.cardValue;
   //
   if (dd.chuPlayer != null) {
    logger.info("ming gang ,chu pl="
      + dd.chuPlayer.getPlayerIndex());
    dd.setChuOffset(dd.chuPlayer.getTablePos(), pl.getTablePos());
    //
    msg.chuOffset = dd.chuOffset;
    //
    pl.setLastGangChuPlayer(waiting.chuPlayer);
   } else {
    logger.error("ming gang ,gang pl==null" + pl.getPlayerIndex());
   }
  } else if (gang_type == GameConstant.MAHJONG_OPERTAION_AN_GANG) {
   // 把摸的牌先放进来
   byte moCard = pl.getCardGrab();
   if (moCard != 0) {
    pl.addCardInHand(moCard);
    pl.setCardGrab((byte) 0);
   }
   // 暗杠的时候,如果有小鸡的话,要把小鸡移走并替换一张牌
   for (int i = 0; i < 4; i++) {
    pl.removeCardInHand(v1);
    gt.add_Down_cards((byte) v1);
   }
   // CardDown
   // dd=pl.addCardDown(v1,v1,v1,GameConstant.MAHJONG_OPERTAION_AN_GANG);
   CardDown dd = pl.addGangCardDown(msg.card_value,
     GameConstant.MAHJONG_OPERTAION_AN_GANG);
   card_down = dd.cardValue;
   //
   put_not_hu_player(gt, dd, pl);
   //
  } else if (gang_type == GameConstant.MAHJONG_OPERTAION_BU_GANG) {
   pl.removeCardInHand(v1);
   gt.add_Down_cards((byte) v1);
   //
   // CardDown dd=pl.bu_gang((byte)v1);
   CardDown dd = pl.bu_gang(msg.card_value);
   card_down = dd.cardValue;
   msg.chuOffset = dd.chuOffset;
   //
   put_not_hu_player(gt, dd, pl);
  }
  // 杠了就不限制其他人碰和胡了
  gt.clearOpLimits(pl);
  gt.setgenzhang(false);
  gt.setCanGenzhang(false);
  // 发给其他玩家,让他们知道当前轮到谁操作
  PlayerOperationNotifyMsg msg2 = new PlayerOperationNotifyMsg();
  msg2.operation = GameConstant.MAHJONG_OPERTAION_TIP;
  msg2.cardLeftNum = gt.getCardLeftNum();
  msg2.player_table_pos = pl.getTablePos();
  // msg2.buHuas1=msg.useXiaoNum;
  this.sendMsgToTable(gt, msg2);
  // 
  // 杠的话,玩家手里有的这个牌都给他放倒
  // card_down=v1|(v1<<8)|(v1<<16)|(v1<<24);
  card_down = msg.card_value;
  // 设置碰的一组牌,客户端好表现
  msg.opValue = card_down;
  msg.card_value = card_down;
  msg.operation = gang_type;
  this.sendMsgToTable(gt, msg);
  // 服务器清除等待玩家操作的数据
  gt.setWaitingPlayerOperate(null);
  // 碰完了轮到他操作,进行打牌
  gt.setCurrentOpertaionPlayerIndex(pl.getTablePos());
  // 等待客户端播动画
  Date dt = DateService.getCurrentUtilDate();
  gt.setWaitingStartTime(dt.getTime());
  if (waiting.hua_flag > 0) {
   gt.setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_PLAYING_QISHOU_GANG_ANIMATION);
  } else {
   gt.setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_PLAYING_GANG_ANIMATION);
  }
  //
  gt.setCurrentCard((byte) 0);
  gt.setCardOpPlayerIndex(-1);
  // 杠玩告诉玩家选牌
  // 杠完摸一张
  if (pl.getCardNumInHand() % 3 == 1 || waiting.hua_flag > 0) {
   // 给玩家摸一张
   byte b = gt.popCard(); // 要不要摸屁股的最后一张牌
   gt.setLastMoCardPlayerTablePos(pl.getTablePos());
   
   
   if(cfgService.containTest(pl)){
    if(gt.getCardLeftNum()>1){
     MahjongCheckResult res  = mjProc.check_hu(b, pl, gt, true);
     
     if(res != null && !radzhong(gt,pl,res)){
      gt.swapcard(b);
      b = gt.popCard();
     }
    }
   }
   // byte test =pl.getTestCard();
   //   
   // if(test > 0)
   // b = test;
   pl.setCardGrab(b);// 先摸一张,等动画播完
   pl.setMoCardNum(pl.getMoCardNum() + 1);
  }
 }
 
 private boolean radzhong(GameTable gt,Player pl,MahjongCheckResult res){
  if(!gt.isVipTable())
   return true;
  
  Random rad = new Random();
  int ir = rad.nextInt(100);
  
  if ((res.fanResult & GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA) == GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA) {
   return ir<10;
  }
  
  int tai = test_win_lose_gold_calculate_hu(gt,pl,res);
  
  if(tai>5 && tai<20){
   return ir<40;
  }
  else if(tai>=20 && tai<=30){
   return ir>80;
  }
  else if(tai>30){
   return ir>90;
  }
  
  if(pl.getWinLoseTotal()>= 100 && pl.getWinLoseTotal()<= 200){
   return ir>60;
  }
  
  if(pl.getWinLoseTotal()> 200){
   return ir>80;
  }
  
  
  
  return true;
 }
 //
 private void player_op_peng(GameRoom gr, GameTable gt,
   PlayerTableOperationMsg msg, Player pl) {
  int v1 = msg.card_value & 0xff;
  // 玩家出牌
  MahjongCheckResult waiting = gt.getWaitingPlayerOperate();
  if (waiting == null) {
   logger.error("peng,no such operation, player_index="
     + pl.getPlayerIndex());
   return;// 当前没有在等待某个玩家操作;
  }
  if (waiting.playerTableIndex != pl.getTablePos()) {
   logger.error("peng,table position invalid, player_index="
     + pl.getPlayerIndex());
   return;// 当前不是在等这个玩家操作
  }
  if ((waiting.opertaion & GameConstant.MAHJONG_OPERTAION_PENG) != GameConstant.MAHJONG_OPERTAION_PENG) {
   logger.error("peng,operation invalid, player_index="
     + pl.getPlayerIndex());
   return;// 当前不能碰;
  }
  if (waiting.peng_card_value != msg.card_value) {
   logger.error("peng,parameter invalid, player_index="
     + pl.getPlayerIndex());
   return;// 碰的牌不对;
  }
  if (v1 == 0) {
   v1 = waiting.peng_card_value & 0xff;
  }
  // 打印手牌
  print_player_log(pl, GameConstant.MAHJONG_OPERTAION_PENG, v1);
  //
  pl.setLastGangChuPlayer(null);
  pl.setCancelHu(false);
  pl.setCouldNotChuCards(0);
  // 去掉可能的被抢杠前的记录
  gt.setGangOpBackup(null);
  gt.setGangMsgBackup(null);
  // 通知客户端把被碰的牌拿走
  if (gt.getChuPlayer() != null) {
   PlayerOperationNotifyMsg removeChuMsg = new PlayerOperationNotifyMsg();
   removeChuMsg.operation = GameConstant.MAHJONG_OPERTAION_REMOE_CHU_CARD;
   removeChuMsg.player_table_pos = gt.getChuPlayer().getTablePos();
   removeChuMsg.target_card = v1;
   removeChuMsg.cardLeftNum = gt.getCardLeftNum();
   this.sendMsgToTable(gt, removeChuMsg);
  }
  //
  // 清理杠记录
  gt.setGangPl(null);
  // 这时候要把当前操作的索引改成此玩家,这样他出牌的时候,当前操作玩家的索引才是正确的
  gt.setCurrentOpertaionPlayerIndex(pl.getTablePos());
  //
  pl.removeCardInHand(v1);
  pl.removeCardInHand(v1);
  gt.add_Down_cards((byte) v1);
  gt.add_Down_cards((byte) v1);
  //
  // 发给其他玩家,让他们知道当前轮到谁操作
  PlayerOperationNotifyMsg msg2 = new PlayerOperationNotifyMsg();
  msg2.operation = GameConstant.MAHJONG_OPERTAION_TIP;
  msg2.cardLeftNum = gt.getCardLeftNum();
  msg2.player_table_pos = pl.getTablePos();
  this.sendMsgToTable(gt, msg2);
  
  CardDown down = pl.addCardDown(v1, v1, v1,GameConstant.MAHJONG_OPERTAION_PENG);
  int card_down = down.cardValue;
  down.chuPlayer = gt.getChuPlayer();
  if (down.chuPlayer != null) {
   down.setChuOffset(down.chuPlayer.getTablePos(), pl.getTablePos());
   //
   msg.chuOffset = down.chuOffset;
  } else {
   logger.error("peng ,chu pl==null" + pl.getPlayerIndex());
  }
  //
  gt.clearCancelHu();
  // 碰了就不限制其他人碰和胡
  gt.clearOpLimits(pl);
  gt.setgenzhang(false);
  gt.setCanGenzhang(false);
  // 设置碰的一组牌,客户端好表现
  msg.opValue = card_down;
  msg.card_value = v1 | (v1 << 8);
  this.sendMsgToTable(gt, msg);
  // 服务器清除等待玩家操作的数据
  gt.setWaitingPlayerOperate(null);
  // 碰完了轮到他操作,进行打牌
  gt.setCurrentOpertaionPlayerIndex(pl.getTablePos());
  // 等待客户端播动画
  Date dt = DateService.getCurrentUtilDate();
  gt.setWaitingStartTime(dt.getTime());
  gt
    .setPlaySubstate(GameConstant.GAME_TABLE_SUB_STATE_PLAYING_CHI_PENG_ANIMATION);
  gt.setCurrentCard((byte) 0);
  gt.setCardOpPlayerIndex(-1);
 }
 // 有玩家打了一张牌,现在看看下一个玩家怎么行动,可能是胡,吃,碰
 private void next_player_operation_notify(GameTable gt) {
  byte card = gt.getCurrentCard();
  Player chuPlayer = gt.getPlayerAtIndex(gt.getCardOpPlayerIndex());
  //
  // 顺序,轮到下一个玩家行动
  gt.move_to_next_player();
  //
  Player plx = gt.getCurrentOperationPlayer();
  if (plx == null)
   return;
  //
  
   // 可以吃,碰,杠, 点炮
  check_next_player_op(gt, card, chuPlayer,
       GameConstant.MAHJONG_OPERTAION_PENG
       | GameConstant.MAHJONG_OPERTAION_MING_GANG);
 }
 //
 private void sengMsgToPlayer(GameTable gt, Player pl,
   PlayerOperationNotifyMsg msg) {
  // 其他从操作发给自己
  msg.sessionID = pl.getPlayerLobbySessionID();
  SystemConfig.gameSocketServer.sendMsg(pl.getSession(), msg);
  if (pl.isRobot()) {
   machineService.post_msg(gt, pl, msg);
  }
 }
 //
 // 按顺序查询下玩家能否进行某个操作
 // chuCardPlayerTableIndex为出牌玩家的位置,一个人出牌,引发多人吃,每次检测到了出牌那个位置,肯定要停止了,不能无限循环
 private MahjongCheckResult table_loop_check(GameTable gt, byte card,
   Player opPlayer, int checkOp, int chuCardPlayerTableIndex) {
  MahjongCheckResult code = null;
  List<Player> plist = gt.getPlayers();
  int pl_index = opPlayer.getTablePos() + 1;
  if (pl_index >= plist.size())
   pl_index = 0;

  for (int i = 0; i < plist.size() - 1; i++) {
   Player pl = plist.get(pl_index);
   if (pl.getTablePos() == chuCardPlayerTableIndex)
    break;
   if (pl.isChucaishen()) {
    pl_index++;
    if (pl_index >= plist.size())
     pl_index = 0;
    continue;
   }
   //
   // System.out.println("index:"+pl.getPlayerIndex());
   // 已经听牌,看看能胡不
   if (checkOp == GameConstant.MAHJONG_OPERTAION_HU) {
    // 先检测卡胡
    code = mjProc.check_hu(card, pl, gt, false);
    if (code != null) {
     // System.out.println("index:"+pl.getPlayerIndex());
     if (pl.getMoCardNum() == 0) {
      if (gt.hasDichu()) {
       code.fanResult |= GameConstant.MAHJONG_HU_CODE_DI_HU;
      }
     }
    }
   }
   // 杠
   if (checkOp == GameConstant.MAHJONG_OPERTAION_MING_GANG) {
    code = mjProc.check_gang(gt, card, pl, false);
   }
   // 碰
   if (checkOp == GameConstant.MAHJONG_OPERTAION_PENG)
    code = mjProc.check_peng(gt, card, pl);
   //
   // 可以操作
   if (code != null) {
    // 所有操作只有一个玩家有可能进行
    break;
   }
   //
   pl_index++;
   if (pl_index >= plist.size())
    pl_index = 0;
  }
  //
  return code;
 }
 private void check_next_player_op(GameTable gt, byte card, Player opPlayer,
   int checkOps) {
  if (opPlayer == null)
   return;
  //
  MahjongCheckResult result = null;
  PlayerOperationNotifyMsg msg = new PlayerOperationNotifyMsg();
  do {
   // 看看有没有玩家杠
   if ((checkOps & GameConstant.MAHJONG_OPERTAION_MING_GANG) == GameConstant.MAHJONG_OPERTAION_MING_GANG) {
    result = table_loop_check(gt, card, opPlayer,
      GameConstant.MAHJONG_OPERTAION_MING_GANG, opPlayer
        .getTablePos());
    if (result != null) {
     //
     msg.peng_card_value = result.peng_card_value;
     // 杠的同时,也可以碰
     // result.opertaion |=GameConstant.MAHJONG_OPERTAION_PENG;
     // 记录那个出的牌,这样杠算钱也好算
     result.chuPlayer = opPlayer;
     //
     msg.operation |= result.opertaion;
     msg.gangList = result.gangList;
     // 杠的同时,肯定可以碰,也提示了
     // msg.operation |=
     // GameConstant.MAHJONG_OPERTAION_MING_GANG;
     MahjongCheckResult pengresult = table_loop_check(gt, card,
       opPlayer, GameConstant.MAHJONG_OPERTAION_PENG,
       opPlayer.getTablePos());
     if (pengresult != null) {
      msg.peng_card_value = pengresult.peng_card_value;
      result.peng_card_value = msg.peng_card_value;
      //
      msg.operation |= GameConstant.MAHJONG_OPERTAION_PENG;
      //
      // 如果没有吃碰杠,检查下家是否可以吃
      Player plx = gt.getCurrentOperationPlayer();
      if (plx != null
        && plx.getTablePos() == pengresult.playerTableIndex) {
       MahjongCheckResult chi_result = mjProc.check_chi(
         gt, card, plx);
       if (chi_result != null) {
        msg.operation |= GameConstant.MAHJONG_OPERTAION_CHI;
        result.opertaion |= GameConstant.MAHJONG_OPERTAION_CHI;
        msg.chi_card_value = chi_result.chi_card_value;
        result.chi_card_value = chi_result.chi_card_value;// 后面读取的是result的值
        break;
       }
      }
      break;
     }
     break;
    }
   }
   // 2看看有没有玩家可以碰
   if ((checkOps & GameConstant.MAHJONG_OPERTAION_PENG) == GameConstant.MAHJONG_OPERTAION_PENG) {
    result = table_loop_check(gt, card, opPlayer,
      GameConstant.MAHJONG_OPERTAION_PENG, opPlayer
        .getTablePos());
    if (result != null) {
     msg.peng_card_value = result.peng_card_value;
     //
     msg.operation |= GameConstant.MAHJONG_OPERTAION_PENG;
     //
     // 如果没有吃碰杠,检查下家是否可以吃
     Player plx = gt.getCurrentOperationPlayer();
     if (plx != null
       && plx.getTablePos() == result.playerTableIndex) {
      MahjongCheckResult chi_result = mjProc.check_chi(gt,
        card, plx);
      if (chi_result != null) {
       msg.operation |= GameConstant.MAHJONG_OPERTAION_CHI;
       result.opertaion |= GameConstant.MAHJONG_OPERTAION_CHI;
       msg.chi_card_value = chi_result.chi_card_value;
       result.chi_card_value = chi_result.chi_card_value;// 后面读取的是result的值
       break;
      }
     }
     break;
    }
   }
   if ((checkOps & GameConstant.MAHJONG_OPERTAION_CHI) == GameConstant.MAHJONG_OPERTAION_CHI) {
    // 如果没有吃碰杠,检查下家是否可以吃
    Player plx = gt.getCurrentOperationPlayer();
    result = mjProc.check_chi(gt, card, plx);
    if (result != null) {
     msg.operation = GameConstant.MAHJONG_OPERTAION_CHI;
     break;
    }
    //
   }
   //
  } while (false);
  //
  if (result != null) {
   // 设置当前桌子的当地玩家操作,等玩家操作的时候,再核查一下
   result.opertaion = msg.operation;// 以msg的操作为准;
   //
   gt.setWaitingPlayerOperate(result);
   //
   msg.chi_card_value = result.chi_card_value;
   msg.peng_card_value = result.peng_card_value;
   msg.player_table_pos = result.playerTableIndex;
   msg.target_card = result.targetCard;
   msg.cardLeftNum = opPlayer.getTablePos(); // 吃、碰、听谁的,借用这个字段
   //
   //
   Player pl = gt.getPlayerAtIndex(msg.player_table_pos);
   // 设置操作开始时间
   long ctt = DateService.getCurrentUtilDate().getTime();
   pl.setOpStartTime(ctt);
   // 其他从操作发给自己
   msg.sessionID = pl.getPlayerLobbySessionID();
   // SystemConfig.gameSocketServer.sendMsg(pl.getSession(), msg);
   this.sengMsgToPlayer(gt, pl, msg);
  } else {
   // 4如果什么操作都没有,下个玩家进行摸牌动作
   player_mo(gt);
  }
 }
 //
 // 出牌结束,没有吃碰胡
 private void chu_end(GameTable gt) {
  byte card = gt.getCurrentCard();
  if (card == 0)
   return;// 没有出的牌
  int idx = gt.getCardOpPlayerIndex();
  Player pl = gt.getPlayerAtIndex(idx);
  pl.addCardBefore(card);
  //
  // 现在客户端自动放在桌子一张牌,不需要这个了,//如果被碰走,服务器会通知客户端拿走那张被碰的牌
  // 添加一张出的牌,在某个玩家的面前,没有被吃碰胡
  PlayerOperationNotifyMsg chuMsg = new PlayerOperationNotifyMsg();
  chuMsg.operation = GameConstant.MAHJONG_OPERTAION_ADD_CHU_CARD;
  chuMsg.player_table_pos = pl.getTablePos();
  chuMsg.target_card = card & 0xff;
  chuMsg.cardLeftNum = gt.getCardLeftNum();
  chuMsg.sessionID = pl.getPlayerLobbySessionID();
  this.sendMsgToTable(gt, chuMsg);
  //
  gt.setCurrentCard((byte) 0);
  gt.setCardOpPlayerIndex(-1);
  //
 }
 // 当前玩家摸牌
 public void player_mo(GameTable gt) {
  Player plx = gt.getCurrentOperationPlayer();
  if (plx == null)
   return;
  // 发给其他玩家,让他们知道当前轮到谁操作
  PlayerOperationNotifyMsg msg2 = new PlayerOperationNotifyMsg();
  msg2.operation = GameConstant.MAHJONG_OPERTAION_TIP;
  msg2.cardLeftNum = gt.getCardLeftNum();
  msg2.player_table_pos = plx.getTablePos();
  this.sendMsgToTable(gt, msg2);
  plx.setLastGangChuPlayer(null);
  // 有人摸牌了,前面的杠不需要记录了
  gt.setGangPl(null);
  //
  plx.setCancelHu(false);
  plx.setCouldNotChuCards(0);
  // 去掉可能的被抢杠前的记录
  gt.setGangOpBackup(null);
  gt.setGangMsgBackup(null);
  // 在玩家摸牌之前,把上家的打出来的牌,放到玩家面前(因为没有吃碰胡)
  chu_end(gt);
  // 服务器清除等待玩家操作的数据
  gt.setWaitingPlayerOperate(null);
  //
  if (gt.isInFinalStage()) {
   game_only_zimo(gt);
  } else {
   // 手里11张,5对加1张
   if (plx.getCardNumInHand() % 3 == 1) {
    // 给玩家摸一张
    byte b = gt.popCard();

    if(cfgService.containTest(plx)){
     if(gt.getCardLeftNum()>1){
      MahjongCheckResult res  = mjProc.check_hu(b, plx, gt, true);
      
      if(res!=null && !radzhong(gt,plx,res)){
        gt.swapcard(b);
        b = gt.popCard();
      }
     }
    }
    
    /*
    if(plx.getPlayerIndex()==118) {
      b = 0x08;
    }
    */
    plx.setCardGrab(b);
    // 记录摸牌人的座位
    gt.setLastMoCardPlayerTablePos(plx.getTablePos());
    //
    plx.setMoCardNum(plx.getMoCardNum() + 1);
    // 摸牌时候把自己的碰限制和胡限制去掉
    plx.clearLimitHu();
    plx.clearLimitPeng();
    //
    //
    player_chu_notify(gt, true, true);
   }
  }
 }
 //
 /** 最后分张阶段判断玩家是否能自摸* */
 private boolean game_only_zimo(GameTable gt) {
  for (int i = 0; i < gt.getMaxPlayer(); i++) {
   Player plx = gt.getCurrentOperationPlayer();
   if (plx == null) {
    continue;
   }
   // 给玩家摸一张
   
   if(gt.getCards().size() == 0)
    continue;
   
   byte b = gt.popCard();
   
   
   
   plx.setCardGrab(b);
   byte newCard = plx.getCardGrab();
   // //3看看自摸胡没
   MahjongCheckResult hu_xx = null;
   hu_xx = mjProc.check_hu(newCard, plx, gt, true);
   if (hu_xx != null) {
    hu_xx.addFanResult(GameConstant.MAHJONG_HU_HAIDILAOYUE);
    player_hu(gt, plx, null, hu_xx.fanResult, hu_xx.targetCard,
      hu_xx.keZiNum, hu_xx.same2Shunzi, hu_xx);
    game_over_hu(gt, false);
    return true;
   }
   //
   PlayerOperationNotifyMsg msg = new PlayerOperationNotifyMsg();
   // 提示玩家出牌
   msg.operation = GameConstant.MAHJONG_OPERTAION_ONLY_ZIMO_TIME;
   msg.player_table_pos = plx.getTablePos();
   msg.chi_card_value = newCard;
   msg.cardLeftNum = gt.getCardLeftNum();
   // 发消息给玩家,提示他出牌
   // 其他人也发了,更新剩余牌数量
   this.sendMsgToTable(gt, msg);
   // 顺序,轮到下一个玩家行动
   gt.move_to_next_player();
  }
  // 如果分张阶段,没有人胡,那么流局了
  long ctt = DateService.getCurrentUtilDate().getTime();
  gt.setState(GameConstant.GAME_TABLE_STATE_SHOW_GAME_OVER_SCREEN);
  gt.setHandEndTime(ctt);
  // 设置胡牌玩家为-1
  gt.setCurrentHuPlayerIndex(-1);
  return false;
 }
 //
 private void gang_score_calculate(GameTable gt) {
  List<Player> plist = gt.getPlayers();
  for (int i = 0; i < plist.size(); i++) {
   Player pl = plist.get(i);
   pl.setGangMoneyNum(0);
  }
  //
  int dizhu = gt.getDizhu();
  //
  for (int i = 0; i < plist.size(); i++) {
   Player pl = plist.get(i);
   int score = 0;
   //
   score = pl.getGangScore(dizhu, gt.getBaoCard(), gt
     .getSecondBaoCard())
     * dizhu;
   //
   if (score > 0) {
    int sc = score / 3;// 其他人一人扣1/3
    for (int j = 0; j < plist.size(); j++) {
     Player plx = plist.get(j);
     if (plx.getPlayerID().equals(pl.getPlayerID()))
      continue;
     //
     // 其他玩家扣分
     plx.setGangMoneyNum(plx.getGangMoneyNum() - sc);
    }
    // 自己加分
    pl.setGangMoneyNum(pl.getGangMoneyNum() + score);
   }
  }
  for (int j = 0; j < plist.size(); j++) {
   Player plx = plist.get(j);
   if (plx.getGangMoneyNum() > 0) {
    plx.setHuDesc(plx.getHuDesc() + " 杠分+" + plx.getGangMoneyNum());
   } else if (plx.getGangMoneyNum() < 0) {
    plx.setHuDesc(plx.getHuDesc() + " 杠分" + plx.getGangMoneyNum());
   }
  }
 }
 // 只胡一张
 public boolean is_real_si_jia(GameTable gt, Player pl, byte card,
   boolean zimo) {
  List<Byte> cards = new ArrayList<Byte>();
  List<Byte> cds = pl.getCardsInHand();
  for (int i = 0; i < cds.size(); i++) {
   byte c = cds.get(i);
   byte c_1 = (byte) (c - 1);
   byte c_2 = (byte) (c + 1);
   boolean found1 = false;
   boolean found_1 = false;
   boolean found_2 = false;
   //
   int v1 = c_1 & 0xf;
   int v2 = c_2 & 0xf;
   if (v1 <= 1)
    found_1 = true;// 不要插入
   if (v2 >= 9)
    found_2 = true;// 不要插入
   //
   for (int k = 0; k < cards.size(); k++) {
    byte d = cards.get(k);
    if (c == d) {
     found1 = true;
    }
    if (c_1 == d) {
     found_1 = true;
    }
    if (c_2 == d) {
     found_2 = true;
    }
   }
   //
   if (found1 == false)
    cards.add(c);
   if (found_1 == false)
    cards.add(c_1);
   if (found_2 == false)
    cards.add(c_2);
  }
  //
  int hu_num = 0;
  //
  for (int k = 0; k < cards.size(); k++) {
   byte d = cards.get(k);
   MahjongCheckResult hu = mjProc.check_hu(d, pl, gt, zimo);
   if (hu != null)
    hu_num++;
   if (hu_num > 1)
    return false;
  }
  return true;
 }
 private String get_player_pos_desc(GameTable gt, Player pl) {
  String pos = "";
  int offset = gt.getDealerPos() - pl.getTablePos();
  //
  if (offset == -1 || offset == 3)// 下家
  {
   pos = "下家";
  } else if (offset == -2 || offset == 2)// 对家
  {
   pos = "对家";
  } else if (offset == -3 || offset == 1)// 上家
  {
   pos = "上家";
  }
  return pos;
 }
 // 是否中码
 private boolean is_hit(GameTable gt, Player pl, byte ma) {
  long v = ma & 0xf;
  
  if(ma > 0x34){
   v = v % 4;
  }
  int offset = gt.getDealerPos() - pl.getTablePos();
  //
  if (offset == -1 || offset == 3)// 下家
  {
   if (v == 2 || v == 6)
    return true;
  } else if (offset == -2 || offset == 2)// 对家
  {
   if (v == 3 || v == 7)
    return true;
  } else if (offset == -3 || offset == 1)// 上家
  {
   if (v == 4 || v == 8)
    return true;
  } else if (offset == 0)// 庄家
  {
   if (v == 1 || v == 5 || v == 9)
    return true;
  } else {
   logger.info("is_hit error ,dealer pos=" + gt.getDealerPos()
     + ",pl pos=" + pl.getTablePos());
  }
  return false;
 }
 
 private int getshuziMa(GameTable gt, Player pl){
  int maNum = 1;
  
  //
  
  //
  int hit_num = 0;
  //
  int zhongMaIndex = 0;
  //
  for (int i = 0; i < maNum; i++) {
   byte ma = gt.popCard();
   if (ma == 0)
    break;
   logger.info("horse" + i + "=" + Long.toHexString(ma));
   int num = ma & 0x0f;
   
   if(ma > 0x34){
    num = num % 4;
   }
   
   hit_num = num;
   zhongMaIndex |= (1 << i);
   gt.addMa(ma);
  }
  //
  pl.setZhongMaIndex(zhongMaIndex);
  //
  return hit_num;
 }
 //
 // 返回中马数量
 private int getHorseHitNum(GameTable gt, Player pl) {
  //
  int maNum = 12;
  if (gt.has_vip_rule(GameConstant.GAME_PLAY_RULE_MA_2))
   maNum = 2;
  else if (gt.has_vip_rule(GameConstant.GAME_PLAY_RULE_MA_4))
   maNum = 4;
  else if (gt.has_vip_rule(GameConstant.GAME_PLAY_RULE_MA_8))
   maNum = 8;
  else if (gt.has_vip_rule(GameConstant.GAME_PLAY_RULE_MA_12))
   maNum = 12;
  else
   return 0;
  //
  //
  int hit_num = 0;
  //
  int zhongMaIndex = 0;
  //
  for (int i = 0; i < maNum; i++) {
   byte ma = gt.popCard();
   logger.info("horse" + i + "=" + Long.toHexString(ma));
   
   if (ma == 0)
    break;
   
   if (is_hit(gt, pl, ma)) {
    hit_num++;
    zhongMaIndex |= (1 << i);
   }
   //
   gt.addMa(ma);
  }
  //
  pl.setZhongMaIndex(zhongMaIndex);
  //
  return hit_num;
 }
 // 吃三笔:一家碰或吃或碰杠同一玩家三次,则为吃三笔;
 private boolean has_3_relations(Player p1, Player p2) {
  if (p1 == null || p2 == null)
   return false;
  //
  if (p1.getRelationNum(p2) >= 3)
   return true;
  if (p2.getRelationNum(p1) >= 3)
   return true;
  //
  return false;
 }
 //
 //
 private boolean isOther3PlayerHasNoJing(GameTable gt, Player pl) {
  int bao2 = gt.getSecondBaoCard();
  List<Player> plist = gt.getPlayers();
  for (int i = 0; i < plist.size(); i++) {
   Player px = plist.get(i);
   //
   if (px.getPlayerID().equals(pl.getPlayerID()))
    continue;
   //
   int num = px.getCardXNumAll(gt.getBaoCard());
   if (num > 0)
    return false;
   num = px.getCardXNumAll(bao2);
   if (num > 0)
    return false;
  }
  return true;
 }
 private int test_win_lose_gold_calculate_hu(GameTable gt,Player pl,MahjongCheckResult huresult) {
  int fanResult = huresult.fanResult;
  int tai = 0;
  
  if ((fanResult & GameConstant.MAHJONG_HU_CODE_QIANG_GANG_HU) == GameConstant.MAHJONG_HU_CODE_QIANG_GANG_HU) {
   tai += 2;
   
   
  }
  
  boolean canshisanyao = gt.has_vip_rule(GameConstant.shisanyao);
  if (canshisanyao && ((fanResult & GameConstant.MAHJONG_HU_CODE_SHISANYAO) == GameConstant.MAHJONG_HU_CODE_SHISANYAO)) {
   tai += 13;
  }
  
  boolean canqingyise = gt.has_vip_rule(GameConstant.qingyise);
  if (canqingyise && ((fanResult & GameConstant.MAHJONG_HU_CODE_QINGYISE) == GameConstant.MAHJONG_HU_CODE_QINGYISE)) {
   tai += 3;
  }
  
  if ((fanResult & GameConstant.MAHJONG_HU_CODE_PENG_PENG_HU) == GameConstant.MAHJONG_HU_CODE_PENG_PENG_HU) {
   tai += 2;
  }
  
  boolean canhaohuaqixiaodui = gt.has_vip_rule(GameConstant.longqidui);
  if (canhaohuaqixiaodui && ((fanResult & GameConstant.MAHJONG_HU_CODE_LONG_QIDUI) == GameConstant.MAHJONG_HU_CODE_LONG_QIDUI)) {
   tai += 4;
  }
  else if ((fanResult & GameConstant.MAHJONG_HU_CODE_QIXIAODUI) == GameConstant.MAHJONG_HU_CODE_QIXIAODUI) {
   tai += 2;
  }
  
  boolean canquanqiiuren = gt.has_vip_rule(GameConstant.quanqiuren);
  if (canquanqiiuren && ((fanResult & GameConstant.MAHJONG_HU_CODE_QUANQIUREN) == GameConstant.MAHJONG_HU_CODE_QUANQIUREN)) {
   tai += 4;
  }
  
  
  
  if ((fanResult & GameConstant.MAHJONG_HU_HAIDILAOYUE) == GameConstant.MAHJONG_HU_HAIDILAOYUE) {
   tai += 2;
  }
  
  if ((fanResult & GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA) == GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA) {
   tai += 2;
  }
 
  
  tai = pl.getGangNum()*3;
  
  
  int zhongmacount = 0;
  boolean isshuzima = false;
  if(gt.has_vip_rule(GameConstant.GAME_PLAY_RULE_MA_SHUZI)){
   zhongmacount = getshuziMa(gt,pl);
   isshuzima = true;
  }
  else{
   zhongmacount = getHorseHitNum(gt,pl);
  }
  
  int suportmanum = gt.getRuleMaNum();
  
  if(suportmanum > 0){
   int zhongmatai = tai * zhongmacount;
   if(zhongmacount > 0){
    tai +=zhongmatai;
   }
  }
  
  gt.cleMa();
  pl.setZhongMaIndex(0);
  return tai;
 }
 
 
 //
 // 计算金币输赢
 private void win_lose_gold_calculate_hu(GameTable gt, Player pl,
   byte moCard, Player pao_pl, int fanResult,
   MahjongCheckResult huresult) {
  // int pmhuNum = huresult.huNum;
  // 不能自己点自己
  if (pao_pl != null && pao_pl.getPlayerID().equals(pl.getPlayerID())) {
   logger.error("win_lose_gold_calculate_hu, error");
   return;
  }
  //
  Player gangPl = gt.getGangPl();
  // 1.基本胡:胡牌1分;自摸三家各出2分;
  int tai = 0;
  String desc = "";
  boolean iszimo = false;
  boolean isbaosanjia = false;
  if (pao_pl == null) {
   iszimo = true;
   tai += 2;
   desc += "自摸+2 ";
  } else {
   tai += 2;
   desc += "胡牌+2 ";
  }
  
  
  if ((fanResult & GameConstant.MAHJONG_HU_CODE_QIANG_GANG_HU) == GameConstant.MAHJONG_HU_CODE_QIANG_GANG_HU) {
   tai += 2;
   desc += "抢杠胡+2 ";
   
   if(gt.has_vip_rule(GameConstant.gangbaobaosanjia)){
    isbaosanjia = true;
   }
   
  }
  
  boolean canshisanyao = gt.has_vip_rule(GameConstant.shisanyao);
  if (canshisanyao && ((fanResult & GameConstant.MAHJONG_HU_CODE_SHISANYAO) == GameConstant.MAHJONG_HU_CODE_SHISANYAO)) {
   tai += 13;
   desc += "十三幺+13 ";
  }
  
  boolean canqingyise = gt.has_vip_rule(GameConstant.qingyise);
  if (canqingyise && ((fanResult & GameConstant.MAHJONG_HU_CODE_QINGYISE) == GameConstant.MAHJONG_HU_CODE_QINGYISE)) {
   tai += 3;
   desc += "清一色+3 ";
  }
  
  if ((fanResult & GameConstant.MAHJONG_HU_CODE_PENG_PENG_HU) == GameConstant.MAHJONG_HU_CODE_PENG_PENG_HU) {
   tai += 2;
   desc += "碰碰胡+2 ";
  }
  
  boolean canhaohuaqixiaodui = gt.has_vip_rule(GameConstant.longqidui);
  if (canhaohuaqixiaodui && ((fanResult & GameConstant.MAHJONG_HU_CODE_LONG_QIDUI) == GameConstant.MAHJONG_HU_CODE_LONG_QIDUI)) {
   tai += 4;
   desc += "豪华七大对+4 ";
  }
  else if ((fanResult & GameConstant.MAHJONG_HU_CODE_QIXIAODUI) == GameConstant.MAHJONG_HU_CODE_QIXIAODUI) {
   tai += 2;
   desc += "七大对+2 ";
  }
  
  boolean canquanqiiuren = gt.has_vip_rule(GameConstant.quanqiuren);
  if (canquanqiiuren && ((fanResult & GameConstant.MAHJONG_HU_CODE_QUANQIUREN) == GameConstant.MAHJONG_HU_CODE_QUANQIUREN)) {
   tai += 4;
   desc += "全求人+4 ";
  }
  
  
  
  if ((fanResult & GameConstant.MAHJONG_HU_HAIDILAOYUE) == GameConstant.MAHJONG_HU_HAIDILAOYUE) {
   tai += 2;
   desc += "海底捞月+2 ";
  }
  
  if ((fanResult & GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA) == GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA) {
   tai += 2;
   desc += "杠爆+2 ";
  }
 
  
  
  
  
  // 计算大牌
  mjProc.calGang(gt);
  
  for(Player gpl:gt.getPlayers()){
   if (gpl.getPlayerID().equals(pl.getPlayerID())) {
    if(gpl.getWinOtherLoseGoldNum() > 0){
     desc +="杠+" +gpl.getWinOtherLoseGoldNum()+ " ";
    }
    else if(gpl.getWinOtherLoseGoldNum() < 0){
     desc +="杠-" +(gpl.getWinOtherLoseGoldNum()*-1)+ " ";
    }
   }
   else{
    if(gpl.getWinOtherLoseGoldNum() > 0){
     gpl.addHuDesc("杠+" +gpl.getWinOtherLoseGoldNum()+ " ");
    }
    else if(gpl.getWinOtherLoseGoldNum() < 0){
     gpl.addHuDesc("杠-" +(gpl.getWinOtherLoseGoldNum()*-1)+ " ");
    }
   }
   
   
  }
  
  boolean isfengding = gt.has_vip_rule(GameConstant.GAME_PLAY_RULE_FENGDING_8);
  
  if(isfengding && tai > 16){
   tai = 16;
  }
  
  //计算马
  int zhongmacount = 0;
  boolean isshuzima = false;
  if(gt.has_vip_rule(GameConstant.GAME_PLAY_RULE_MA_SHUZI)){
   zhongmacount = getshuziMa(gt,pl);
   isshuzima = true;
  }
  else{
   zhongmacount = getHorseHitNum(gt,pl);
  }
  
  int suportmanum = gt.getRuleMaNum();
  
  if(suportmanum > 0){
   int zhongmatai = tai * zhongmacount;
   if(zhongmacount > 0){
    tai +=zhongmatai;
   }
   
   if(isshuzima){
    desc += "数字马+" + zhongmatai + " ";
   }
   else{
    desc += "中马+" + zhongmatai + " ";
   }
   
   
  }
  
  // 庄家位置
  int dealer_pos = gt.getDealerPos();
  int dizhu = gt.getDizhu();
  //
  List<Player> plist = gt.getPlayers();
  //
  if (pao_pl == null) {
   pl.setFanType(pl.getFanType() | GameConstant.MAHJONG_HU_CODE_WIN
     | GameConstant.MAHJONG_HU_CODE_ZI_MO);
  } else {
   pl.setFanType(pl.getFanType() | GameConstant.MAHJONG_HU_CODE_WIN
     | GameConstant.MAHJONG_HU_CODE_DIAN_PAO);
  }
  //
  int win_total = 0;
  // 计算下输家
  pl.setHuDesc(desc);
  
  
  for (int i = 0; i < plist.size(); i++) {
   Player px = plist.get(i);
   // 赢家不计算
   if (px.getPlayerID().equals(pl.getPlayerID())) {
    continue;
   }
   //
   px.setFanType(GameConstant.MAHJONG_HU_CODE_LOSE);
   int temtai = tai;
   
   if(isbaosanjia && pao_pl!=null ){
    pao_pl.addWinLoseGoldNum(-temtai);
   }
   else{
    px.setWinLoseGoldNum(-temtai);
   }
   
   px.calWinLoseGoldNum();
   win_total += temtai;
  }
  // 赢
  pl.setWinLoseGoldNum(win_total);
  pl.calWinLoseGoldNum();
  
  
  for (int i = 0; i < plist.size(); i++){
   Player px = plist.get(i);
   
   int fan = px.getWinLoseGoldNum() ;
   
   px.setWinLoseGoldNum(fan * dizhu);
  }
 }
 //
 //
 private void win_lose_money_submit(GameTable gt) {
  // 杠算分
  //
  List<Player> plist = gt.getPlayers();
  //
  int dizhu = gt.getDizhu();
  //
  // 最后输赢处理
  for (int i = 0; i < plist.size(); i++) {
   Player px = plist.get(i);
   px.setFanNum(px.getWinLoseGoldNum() / gt.getDizhu());
   if (px.getWinLoseGoldNum() == 0)
    continue;
   //
   String remark = "输金币=" + px.getWinLoseGoldNum() + "描述="
     + px.getFanDesc();
   //
   if (gt.isVipTable())// 扣桌子上的钱
   {
    px.setVipTableGold(px.getVipTableGold()
      + px.getWinLoseGoldNum());
    remark += ",桌上金币=" + px.getVipTableGold();
    if (px.getWinLoseGoldNum() < 0)
     playerService.createPlayerLog(px.getPlayerID(), px
       .getPlayerIndex(), px.getPlayerName(),
       px.getGold(), LogConstant.OPERATION_TYPE_SUB_GOLD,
       LogConstant.OPERATION_TYPE_SUB_GOLD_GAME_LOSE, px
         .getVipTableGold(), remark,
       LogConstant.MONEY_TYPE_GOLD);
    else
     playerService.createPlayerLog(px.getPlayerID(), px
       .getPlayerIndex(), px.getPlayerName(),
       px.getGold(), LogConstant.OPERATION_TYPE_ADD_GOLD,
       LogConstant.OPERATION_TYPE_ADD_GOLD_GAME_WIN, px
         .getVipTableGold(), remark,
       LogConstant.MONEY_TYPE_GOLD);
   } else {
    if (px.getWinLoseGoldNum() > 0)
     playerService.add_player_gold(px, px.getWinLoseGoldNum(),
       LogConstant.OPERATION_TYPE_ADD_GOLD_GAME_WIN,
       remark);
    else
     playerService.sub_player_gold(px, px.getWinLoseGoldNum()
       * (-1),
       LogConstant.OPERATION_TYPE_SUB_GOLD_GAME_LOSE,
       remark);
   }
  }
 }
 private void game_over_update_vip(GameTable gt) {
  List<Player> plist = gt.getPlayers();
  // 坐庄次数
  for (int i = 0; i < plist.size(); i++) {
   Player px = plist.get(i);
   if (px.getTablePos() == gt.getDealerPos()) {
    px.setZhuangCount(px.getZhuangCount() + 1);
   }
   //
   if (px.isHuuuuued()) {
    px.setWinCount(px.getWinCount() + 1);
   }
   //
   px.setGangCount(px.getGangCount() + px.getGangNum());
   px.setAnGangNum(px.getAnGangNum() + px.getAnGangCounter());
   px.setMingGangNum(px.getMingGangNum() + px.getGongGangNum());
  }
 }
 // pao_pl是放炮的玩家,如果没有就是null,isKaHu是否是卡胡,isHuBao是不是胡的那种刚好是宝牌,自摸
 private void game_over_hu(GameTable gt, boolean isLiuJu) {
  // 不是流局
  if (isLiuJu == false) {
   gt.setLiuJuNoPlayerHu(false);
   //
   game_over_update_vip(gt);
  } else {
   gt.setLiuJuNoPlayerHu(true);
  }
  // 流局不流局,杠必须算分
  // 合并计算提交数据库
  win_lose_money_submit(gt);
  //
  gt.setState(GameConstant.GAME_TABLE_STATE_SHOW_GAME_OVER_SCREEN);
  //
  long ctt = DateService.getCurrentUtilDate().getTime();
  gt.setHandEndTime(ctt);
 }
 private void player_qishou_ganghua_deal(GameTable gt, boolean couldHu,
   boolean couldGang, boolean iskaihua) {
  Player plx = gt.getCurFengPlayer();
  if (plx == null)
   return;
  if (plx.getTablePos() != gt.getDealerPos()) {
   couldHu = false;
  }
  //
  byte newCard = plx.getCardGrab();
  PlayerOperationNotifyMsg msg = new PlayerOperationNotifyMsg();
  MahjongCheckResult wait = new MahjongCheckResult();
  wait.playerTableIndex = plx.getTablePos();
  wait.opertaion = 0;
  wait.targetCard = newCard;
  wait.hua_flag = GameConstant.MAHJONG_OPERTAION_LIANG_HUA;
  boolean player_could_hu = false;
  {
   //
   MahjongCheckResult hu_xx = null;
   if (couldHu && hu_xx == null)// 例如玩家碰完不能直接胡,必须出一张;例如玩家手里剩4张2对,别人出牌他不胡,碰,碰完也不能胡,必须打出一张
   {
    hu_xx = mjProc.check_hu(newCard, plx, gt, true);
    //
    if (hu_xx != null)// 胡了
    {
     // if(plx.getMoCardNum()==1){
     // hu_xx.fanResult |=GameConstant.MAHJONG_HU_CODE_DI_HU;
     // }
     if (iskaihua) {
      hu_xx.fanResult |= GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA;
     }
     wait.fanResult = hu_xx.fanResult;
     player_could_hu = true;
    }
   }
   // 提示玩家出牌
   msg.player_table_pos = plx.getTablePos();
   msg.chi_card_value = newCard;
   msg.cardLeftNum = gt.getCardLeftNum();
   msg.chi_flag = 0;
   //
   // 自己摸,看看各种杠
   MahjongCheckResult gang_result = null;
   if (couldGang) {
    gang_result = mjProc.check_gang(gt, newCard, plx, true);
   }
   //
   if (gang_result != null) {
    // 提示玩家听牌,也可以出牌
    msg.gangList = gang_result.gangList;
    msg.peng_card_value = gang_result.peng_card_value;
    msg.operation |= gang_result.opertaion;
    //
    wait.peng_card_value = gang_result.peng_card_value;
    wait.gangList = gang_result.gangList;
   }
   //
   if (player_could_hu) {
    msg.operation |= GameConstant.MAHJONG_OPERTAION_HU;
   }
  }
  if (newCard != 0) {
   plx.addCardInHand(newCard);
   plx.setCardGrab((byte) 0);
  }
  //
  wait.opertaion = msg.operation;
  // msg.operation |= GameConstant.MAHJONG_OPERTAION_CHU;
  gt.setWaitingPlayerOperate(wait);
  gt.setCurrentOpertaionPlayerIndex(plx.getTablePos());
  //
  long ctt = DateService.getCurrentUtilDate().getTime();
  plx.setOpStartTime(ctt);
  //
  // 发给其他玩家,让他们知道当前轮到谁操作
  PlayerOperationNotifyMsg msg2 = new PlayerOperationNotifyMsg();
  msg2.operation = GameConstant.MAHJONG_OPERTAION_TIP;
  msg2.cardLeftNum = gt.getCardLeftNum();
  msg2.player_table_pos = plx.getTablePos();
  this.sendMsgToTable(gt, msg2);
  //
  List<Byte> newInhand = new ArrayList<Byte>();
  newInhand.add(newCard);
  GameStartMsg smsg = new GameStartMsg();
  smsg.newPlayWay = gt.getVip_rule();
  smsg.myCards = newInhand;
  smsg.myTablePos = plx.getTablePos();
  smsg.quanNum = gt.getHandNum();// gt.getQuanNum();
  smsg.dealerPos = gt.getDealerPos();
  //
  smsg.baoCard = gt.getBaoCard() | (0 << 8);
  smsg.setup_gold(gt.getPlayers(), gt.isVipTable());
  smsg.serviceGold = gt.getHandsTotal();
  smsg.isDealerAgain = 0;
  smsg.sessionID = plx.getPlayerLobbySessionID();
  SystemConfig.gameSocketServer.sendMsg(plx.getSession(), smsg);
  if (wait.gangList.size() == 0) {
   gt.incCurFengPos();
   if (!player_could_hu) {
    gt.setWaitingPlayerOperate(null);
   }
  }
  gt.setState(GameConstant.GAME_TABLE_STATE_CHECK_LIANG_HUA);
  // 发消息给玩家,提示他出牌
  msg.sessionID = plx.getPlayerLobbySessionID();
  SystemConfig.gameSocketServer.sendMsg(plx.getSession(), msg);
  //
  if (plx.isRobot()) {
   machineService.post_msg(gt, plx, msg);
  }
 }
 private void player_chu_gangkaihua(GameTable gt, boolean couldHu,
   boolean couldGang) {
  Player plx = gt.getCurrentOperationPlayer();
  if (plx == null)
   return;
  //
  byte newCard = plx.getCardGrab();
  PlayerOperationNotifyMsg msg = new PlayerOperationNotifyMsg();
  MahjongCheckResult wait = new MahjongCheckResult();
  wait.playerTableIndex = plx.getTablePos();
  wait.opertaion = 0;
  wait.targetCard = newCard;
  {
   //
   MahjongCheckResult hu_xx = null;
   //
   boolean player_could_hu = false;
   if (couldHu && hu_xx == null)// 例如玩家碰完不能直接胡,必须出一张;例如玩家手里剩4张2对,别人出牌他不胡,碰,碰完也不能胡,必须打出一张
   {
    hu_xx = mjProc.check_hu(newCard, plx, gt, true);
    //
    if (hu_xx != null)// 胡了
    {
     // if(plx.getMoCardNum()==1){
     // hu_xx.fanResult |=GameConstant.MAHJONG_HU_CODE_DI_HU;
     //      
     // }
     hu_xx.fanResult |= GameConstant.MAHJONG_HU_GANG_SHANG_KAI_HUA;
     wait.fanResult = hu_xx.fanResult;
     player_could_hu = true;
    }
   }
   // 提示玩家出牌
   msg.operation |= GameConstant.MAHJONG_OPERTAION_CHU;
   msg.player_table_pos = plx.getTablePos();
   msg.chi_card_value = newCard;
   msg.cardLeftNum = gt.getCardLeftNum();
   msg.chi_flag = 0;// plx.getCouldNotChuCards();
   //
   // 自己摸,看看各种杠
   MahjongCheckResult gang_result = null;
   if (couldGang) {
    gang_result = mjProc.check_gang(gt, newCard, plx, true);
   }
   //
   if (gang_result != null) {
    // 提示玩家听牌,也可以出牌
    msg.gangList = gang_result.gangList;
    msg.peng_card_value = gang_result.peng_card_value;
    msg.operation |= gang_result.opertaion;
    //
    wait.peng_card_value = gang_result.peng_card_value;
    wait.gangList = gang_result.gangList;
    // logger.info("waittiong gang size:"+wait.gangList.size());
   }
   //
   if (player_could_hu) {
    msg.operation |= GameConstant.MAHJONG_OPERTAION_HU;
   }
  }
  //
  //
  wait.opertaion = msg.operation;
  gt.setWaitingPlayerOperate(wait);
  gt.setCurrentOpertaionPlayerIndex(plx.getTablePos());
  //
  long ctt = DateService.getCurrentUtilDate().getTime();
  plx.setOpStartTime(ctt);
  //
  // 发给其他玩家,让他们知道当前轮到谁操作
  PlayerOperationNotifyMsg msg2 = new PlayerOperationNotifyMsg();
  msg2.operation = GameConstant.MAHJONG_OPERTAION_TIP;
  msg2.cardLeftNum = gt.getCardLeftNum();
  msg2.player_table_pos = plx.getTablePos();
  // msg2.use_xiaoji=msg.use_xiaoji;
  this.sendMsgToTable(gt, msg2);
  //
  // 发消息给玩家,提示他出牌
  msg.sessionID = plx.getPlayerLobbySessionID();
  SystemConfig.gameSocketServer.sendMsg(plx.getSession(), msg);
  //
  if (plx.isRobot()) {
   machineService.post_msg(gt, plx, msg);
  }
 }
 //
 private void player_chu_notify(GameTable gt, boolean couldHu,
   boolean couldGang) {
  Player plx = gt.getCurrentOperationPlayer();
  if (plx == null)
   return;
  //
  byte newCard = plx.getCardGrab();
  PlayerOperationNotifyMsg msg = new PlayerOperationNotifyMsg();
  MahjongCheckResult wait = new MahjongCheckResult();
  wait.playerTableIndex = plx.getTablePos();
  wait.opertaion = 0;
  wait.targetCard = newCard;
  //
  MahjongCheckResult hu_xx = null;
  //
  boolean player_could_hu = false;
  if (couldHu && hu_xx == null)// 例如玩家碰完不能直接胡,必须出一张;例如玩家手里剩4张2对,别人出牌他不胡,碰,碰完也不能胡,必须打出一张
  {
   hu_xx = mjProc.check_hu(newCard, plx, gt, true);
   //
   if (hu_xx != null)// 胡了
   {
    if (plx.getMoCardNum() == 1
      && plx.getTablePos() == gt.getDealerPos()) {
     hu_xx.fanResult |= GameConstant.MAHJONG_HU_CODE_DI_HU;
     wait.fanResult = hu_xx.fanResult;
    }
    player_could_hu = true;
   }
  }
  // 提示玩家出牌
  msg.operation |= GameConstant.MAHJONG_OPERTAION_CHU;
  msg.player_table_pos = plx.getTablePos();
  msg.chi_card_value = newCard;
  msg.cardLeftNum = gt.getCardLeftNum();
  msg.chi_flag = 0;// plx.getCouldNotChuCards();
  //
  // 自己摸,看看各种杠
  MahjongCheckResult gang_result = null;
  if (couldGang) {
   gang_result = mjProc.check_gang(gt, newCard, plx, true);
  }
  //
  if (gang_result != null) {
   // 提示玩家听牌,也可以出牌
   msg.gangList = gang_result.gangList;
   msg.peng_card_value = gang_result.peng_card_value;
   msg.operation |= gang_result.opertaion;
   //
   wait.peng_card_value = gang_result.peng_card_value;
   wait.gangList = gang_result.gangList;
   // logger.info("waittiong gang size:"+wait.gangList.size());
  }
  //
  if (player_could_hu) {
   msg.operation |= GameConstant.MAHJONG_OPERTAION_HU;
  }
  //
  //
  wait.opertaion = msg.operation;
  gt.setWaitingPlayerOperate(wait);
  gt.setCurrentOpertaionPlayerIndex(plx.getTablePos());
  //
  long ctt = DateService.getCurrentUtilDate().getTime();
  plx.setOpStartTime(ctt);
  //
  // 发给其他玩家,让他们知道当前轮到谁操作
  PlayerOperationNotifyMsg msg2 = new PlayerOperationNotifyMsg();
  msg2.operation = GameConstant.MAHJONG_OPERTAION_TIP;
  msg2.cardLeftNum = gt.getCardLeftNum();
  msg2.player_table_pos = plx.getTablePos();
  // msg2.use_xiaoji=msg.use_xiaoji;
  this.sendMsgToTable(gt, msg2);
  //
  //
  if (plx.isRobot()) {
   machineService.post_msg(gt, plx, msg);
  }
  // 发消息给玩家,提示他出牌
  msg.sessionID = plx.getPlayerLobbySessionID();
  SystemConfig.gameSocketServer.sendMsg(plx.getSession(), msg);
 }
 private void death_machine(GameTable gt) {
  // System.out.print(".size:"+gt.getPlayers().size());
  for (Player pl : gt.getPlayers()) {
   if (pl.isRobot())
    machineService.death_machine(pl.getPlayerIndex());
  }
 }
 private int check_first_gang(GameTable gt) {
  MahjongCheckResult code = null;
  List<Player> plist = gt.getPlayers();
  byte currentplhua = gt.getCurFengPos();
  for (int i = 0; i < plist.size(); i++) {
   Player pl = plist.get(i);
   if (pl.getzifeng() != currentplhua) {
    continue;
   }
   code = mjProc.check_gang(gt, (byte) 0, pl, true);
   if (code != null) {
    code.hua_flag = GameConstant.GAME_TABLE_STATE_CHECK_LIANG_HUA;
    PlayerOperationNotifyMsg msg = new PlayerOperationNotifyMsg();
    //
    msg.operation |= code.opertaion;
    msg.gangList = code.gangList;
    // 设置当前桌子的当地玩家操作,等玩家操作的时候,再核查一下
    code.opertaion = msg.operation;// 以msg的操作为准;
    //
    gt.setWaitingPlayerOperate(code);
    //
    msg.chi_card_value = code.chi_card_value;
    msg.peng_card_value = code.peng_card_value;
    msg.player_table_pos = code.playerTableIndex;
    msg.target_card = code.targetCard;
    msg.cardLeftNum = pl.getTablePos();// 吃、碰、听谁的,借用这个字段
    // 设置操作开始时间
    long ctt = DateService.getCurrentUtilDate().getTime();
    pl.setOpStartTime(ctt);
    // 其他从操作发给自己
    msg.sessionID = pl.getPlayerLobbySessionID();
    this.sengMsgToPlayer(gt, pl, msg);
    gt.setState(GameConstant.GAME_TABLE_STATE_PLAYING);
    return 1;
   } else {
    gt.incCurFengPos();
    currentplhua = gt.getCurFengPos();
    if (currentplhua > 0x44) {
     return 0;
    }
   }
  }
  for (int i = 0; i < plist.size(); i++) {
   Player pl = plist.get(i);
   if (pl.getzifeng() != currentplhua) {
    continue;
   }
   code = mjProc.check_gang(gt, (byte) 0, pl, true);
   if (code != null) {
    code.hua_flag = GameConstant.GAME_TABLE_STATE_CHECK_LIANG_HUA;
    PlayerOperationNotifyMsg msg = new PlayerOperationNotifyMsg();
    //
    msg.operation |= code.opertaion;
    msg.gangList = code.gangList;
    // 设置当前桌子的当地玩家操作,等玩家操作的时候,再核查一下
    code.opertaion = msg.operation;// 以msg的操作为准;
    //
    gt.setWaitingPlayerOperate(code);
    //
    msg.chi_card_value = code.chi_card_value;
    msg.peng_card_value = code.peng_card_value;
    msg.player_table_pos = code.playerTableIndex;
    msg.target_card = code.targetCard;
    msg.cardLeftNum = pl.getTablePos();// 吃、碰、听谁的,借用这个字段
    // 设置操作开始时间
    long ctt = DateService.getCurrentUtilDate().getTime();
    pl.setOpStartTime(ctt);
    // 其他从操作发给自己
    msg.sessionID = pl.getPlayerLobbySessionID();
    this.sengMsgToPlayer(gt, pl, msg);
    gt.setState(GameConstant.GAME_TABLE_STATE_PLAYING);
    return 1;
   } else {
    currentplhua = gt.getCurFengPos();
    if (currentplhua > 0x44) {
     gt.resetToDearPos();
     return 0;
    }
   }
  }
  return 0;
 }
 //
 private void game_table_tick(GameTable gt) {
  Date ct = DateService.getCurrentUtilDate();
  long ctt = ct.getTime();
  int state = gt.getState();
  long vip_w_t = cfgService.getPara(
    GameConfigConstant.CONF_VIP_GAME_OVER_ENTER_NEXT_TURN)
    .getValueInt() * 1000;
  long vip_wait_time = cfgService.getPara(
    GameConfigConstant.CONF_VIP_GAME_OVER_WAITING_START_GAME_TIME)
    .getValueInt() * 1000;
  if (gt.isVipTable() && gt.isVipTableTimeOver()) {
   vip_wait_time = 6000;// 如果是vip最后一把,不要等太长时间
   vip_w_t = 10000;
  }
  // gt.printfPosition();
  // 机器人桌,或者空桌回收
  if (gt.shouldRecycleTable()) {
   gt.setState(GameConstant.TABLE_STATE_INVALID);
   return;
  }
  if (state == GameConstant.GAME_TABLE_STATE_WAITING_PLAYER) {
   // 桌子等待超过2秒
   if (gt.getNewWailtOtherPlayerTime() != 0
     && ctt - gt.getNewWailtOtherPlayerTime() > 2000) {
    ivite_machines(gt);
   }
   //
   long delta = ctt - gt.getVipCreateTime();
   if (gt.isVipTable()
     && delta > cfgService.getPara(
       GameConfigConstant.CONF_VIP_ROOM_CREATE_WAIT_START)
       .getValueInt() * 1000)// vip房间如果超过一定时间没有开始游戏,房间结束
   {
    // 通知玩家离开房间
    PlayerOperationNotifyMsg msg = new PlayerOperationNotifyMsg();
    msg.operation = GameConstant.MAHJONG_OPERTAION_NO_START_CLOSE_VIP;
    this.sendMsgToTable(gt, msg);
    gt.clear_all();
    gt.setState(GameConstant.TABLE_STATE_INVALID);
   }
  } else if (state == GameConstant.GAME_TABLE_STATE_READY_GO) {
   long delta = ctt - gt.getReadyTime();
   if (delta > 2000) {
    game_start(gt);
    machineService.reset_machinetime(gt);
   }
  } else if (state == GameConstant.GAME_TABLE_WAITING_CLIENT_SHOW_INIT_CARDS) {
   long delta = ctt - gt.getReadyTime();
   if (delta > 5000) {
    gt.setState(GameConstant.GAME_TABLE_STATE_CHECK_LIANG_HUA);
   }
  }
  else if (state == GameConstant.GAME_TABLE_STATE_CHECK_LIANG_HUA) {
   // 等待玩家点天听2秒操作时间
   long delta = ctt - gt.getTianTingTime();
   //
   if (delta > 1000)// 1秒
   {
    // 发给其他玩家,隐藏操作菜单
    PlayerOperationNotifyMsg msg2 = new PlayerOperationNotifyMsg();
    msg2.operation = GameConstant.MAHJONG_OPERTAION_TIP;
    msg2.cardLeftNum = gt.getCardLeftNum();
    msg2.chi_flag = GameConstant.MAHJONG_OPERTAION_TIP;
    this.sendMsgToTable(gt, msg2);
    //
    gt.setState(GameConstant.GAME_TABLE_STATE_PLAYING);
    // 提示庄家出牌
    player_chu_notify(gt, true, true);
   }
  } else if (state == GameConstant.GAME_TABLE_STATE_PLAYING) {
   playing_table_tick(gt, ctt);
  } else if (state == GameConstant.GAME_TABLE_STATE_SHOW_GAME_OVER_SCREEN) {
   long delta = ctt - gt.getHandEndTime();
   // 游戏结束后2秒,给客户端播放排名
   int maNum = 500 * gt.getMaiMaNum();
   if (delta > 5000 + maNum) {
    game_over(gt);
   }
  } else if (state == GameConstant.GAME_TABLE_STATE_PAUSED) {
   long delta = ctt - gt.getPausedTime();
   // 游戏结束后120秒,给客户选择继续等待2分钟
   // *VIP场有玩家中途离场,玩家选择等待时间
   if (delta >= cfgService.getPara(
     GameConfigConstant.CONF_VIP_PAUSED_CHOOSE_WAIT_TIME)
     .getValueInt() * 1000) {
    if (gt.isSendClientWaitingBreakPlayerNotify() == false) {
     //
     gt.setSendClientWaitingBreakPlayerNotify(true);
     gt.clearCloseVipRoomMap(); // 先清空同意结束房间人数
     // 发送消息给客户端,是否继续等待
     PlayerOperationNotifyMsg msg = new PlayerOperationNotifyMsg();
     msg.operation = GameConstant.MAHJONG_OPERTAION_WAITING_OR_CLOSE_VIP;
     msg.chi_flag = 1;
     this.sendMsgToTable(gt, msg);
    }
   }
   // Vip场有玩家中途离场,房间存活时间
   if (delta > cfgService.getPara(
     GameConfigConstant.CONF_VIP_PAUSED_EXIST_TIME)
     .getValueInt() * 1000)// 超时,关闭房间
   {
    GameRoom gr = this.getRoom(gt.getRoomID());
    logger.info("有玩家中途离场房间存活超时,VIP房间:" + gt.getVipTableID() + "结束");
    vip_table_end(gr, gt);
    gt.clear_all();
    gt.setState(GameConstant.TABLE_STATE_INVALID);
   }
   // VIP圈数用完,等待续卡时间
   if (delta >= cfgService
     .getPara(
       GameConfigConstant.CONF_VIP_GAME_OVER_WAITING_START_GAME_TIME)
     .getValueInt() * 1000) {
    if (gt.isVipTable()
      && gt.isVipTableTimeOver()
      && gt.getBackup_state() == GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE) {
     logger.info("VIP圈数用完,等待续卡时间超过,VIP房间" + gt.getVipTableID()
       + "结束");
     // 不续卡,或者房卡不足,直接结束房间
     GameRoom gr = this.getRoom(gt.getRoomID());
     vip_table_end(gr, gt);
    }
   }
   // 看看桌子上玩家是否都已经到齐
   if (gt.pauseContinue()) {
    if (gt.getState() == GameConstant.GAME_TABLE_STATE_PLAYING) {
     // 断线回来,如果当前桌子子状态为0,说明没有等待状态,直接提示当前玩家行动
     if (gt.getPlaySubstate() == 0)//
     {
      // 通知玩家行动
      re_notify_current_operation_player(gt);
     } else {
      // 否则就把等待时间设置为当前,系统等待一定时间后,提示玩家进行应该进行的动作,比如有玩家吃碰等
      Date dt = DateService.getCurrentUtilDate();
      gt.setWaitingStartTime(dt.getTime());
     }
    }
   }
  } else if (state == GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE) {
   if (gt.getPlayerNum() < gt.getMaxPlayer()
     && gt.getNewWailtOtherPlayerTime() != 0
     && ctt - gt.getNewWailtOtherPlayerTime() > 2000) {
    ivite_machines(gt);
   }
   //
   long delta = ctt - gt.getHandEndTime();
   // 人满随时开始,如果大家都点击了继续
   if (gt.getReadyPlayerNum() == gt.getMaxPlayer()) {
    if (gt.isVipTable() && gt.isVipTableTimeOver()) {
     // vip圈数用光,继续等待,超时就结束
     // vip圈数结束,继续等待时间
     if (delta >= vip_wait_time) {
      GameRoom gr = getRoom(gt.getRoomID());
      logger.info("vip圈数用光超时结束,VIP房间:" + gt.getVipTableID()
        + "结束");
      vip_table_end(gr, gt);
     }
     return;
    } else {
     // 把游戏数据先清理掉,保留玩家
     gt.clearGameState();
     // 人满开始下一局
     gt.setReadyTime(ctt);
     gt.setState(GameConstant.GAME_TABLE_STATE_READY_GO);
    }
   } else if (delta >= vip_w_t && gt.isVipTable())// vip牌局结束15秒,自动进下一把
   {
    // System.out.println("VIP房间结算等待时间超过" + delta + "自动开始下一局");
    if (gt.isVipTableTimeOver()) {
     GameRoom gr = getRoom(gt.getRoomID());
     logger.info("vip圈数用光,VIP房间:" + gt.getVipTableID() + "结束");
     vip_table_end(gr, gt);
    } else {
     if (vip_table_check_next_hand(gt)) {
      vip_next_hand(gt, ctt);
     }
    }
   }
   // 游戏结束后60秒,等60秒继续
   else if (delta >= 30 * 1000) {
    if (!gt.isVipTable()) {
     // System.out.println("房间结算等待时间超过" + delta + "房间结束");
     // 把未准备好的玩家删掉
     // gt.set_not_ready_player_ready();
     gt.remove_not_ready_player();
     if (gt.getPlayerNum() == gt.getMaxPlayer()) {
      next_hand(gt, ctt);
     } else if (gt.getReadyPlayerNum() > 0) {
      // 把游戏数据先清理掉,保留玩家
      gt.clearGameState();
      // 超过满开始下一局
      gt
        .setState(GameConstant.GAME_TABLE_STATE_WAITING_PLAYER);
      // 重新邀请机器人
      machineService.reset_machinetime_current(gt);
     } else {
      // 如果没有人玩,状态非法,后面的逻辑收掉这个桌子
      gt.clear_all();
     }
    }
   }
  }
 }
 private void vip_next_hand(GameTable gt, long ctt) {
  next_hand(gt, ctt);
 }
 public void next_hand(GameTable gt, long ctt) {
  List<Player> plist = gt.getPlayers();
  //
  for (int i = 0; i < plist.size(); i++) {
   Player pl = plist.get(i);
   if (pl.getGameState() == GameConstant.PALYER_GAME_STATE_IN_TABLE_READY)
    continue;
   //
   pl.setGameState(GameConstant.PALYER_GAME_STATE_IN_TABLE_READY);
   //
   RequestStartGameMsgAck ack = new RequestStartGameMsgAck();
   ack.result = ErrorCodeConstant.CMD_EXE_OK;
   ack.totalHand = gt.getHandsTotal();
   ack.currentHand = gt.getHandNum();
   //
   if (gt.isVipTable()) {
    ack.init_players(gt.getPlayers(), true);
    ack.gold = pl.getVipTableGold();
   } else {
    ack.init_players_time_hand(gt.getPlayers());
    ack.gold = pl.getGold();
   }
   //
   ack.roomID = gt.getRoomID();
   // ack.tablePos=pl.getTablePos();
   ack.tablePos = pl.getTablePos() | (gt.getMaxPlayer() << 16);
   ack.vipTableID = gt.getVipTableID();
   ack.creatorName = gt.getCreatorPlayerName();
   ack.createPlayerID = gt.getCreatorPlayerID();
   ack.newPlayWay = gt.getVip_rule();
   //
   // 进入桌子,返回消息给玩家
   ack.sessionID = pl.getPlayerLobbySessionID();
   SystemConfig.gameSocketServer.sendMsg(pl.getSession(), ack);
   // 给桌子上的其他玩家发个进入新玩家的消息
   PlayerGameOpertaionAckMsg axk = new PlayerGameOpertaionAckMsg();
   axk.opertaionID = GameConstant.GAME_OPERTAION_TABLE_ADD_NEW_PLAYER;
   axk.playerName = pl.getPlayerName();
   axk.targetPlayerName = pl.getHeadImageUrl();
   axk.gold = pl.getVipTableGold();
   axk.headImg = pl.getHeadImg();
   axk.sex = pl.getSex();
   axk.tablePos = pl.getTablePos();
   axk.playerID = pl.getPlayerID();
   axk.playerIndex = pl.getPlayerIndex();
   axk.canFriend = pl.getCanFriend();
   axk.ip = pl.getClientIP();
   axk.sessionID = pl.getPlayerLobbySessionID();
   axk.opValue = gt.getMaxPlayer();
   this.sendMsgToTableExceptMe(gt, axk, pl.getPlayerID());
  }
  // 把游戏数据先清理掉,保留玩家
  gt.clearGameState();
  // 人满开始下一局
  gt.setReadyTime(ctt);
  gt.set_all_player_state(GameConstant.PALYER_GAME_STATE_IN_TABLE_READY);
  gt.setState(GameConstant.GAME_TABLE_STATE_READY_GO);
 }
 //
 // vip锅结束
 private void vip_table_end(GameRoom gr, GameTable gt) {
  logger.info("VIP锅结束了");
  List<Player> plist = gt.getPlayers();
  // //记录胜负平日志
  for (int i = 0; i < plist.size(); i++) {
   Player px = plist.get(i);
   int total_gold = px.getVipTableGold();
   if (total_gold > 0)
    px.setWons(px.getWons() + 1);
   else if (total_gold < 0)
    px.setLoses(px.getLoses() + 1);
   else
    px.setEscape(px.getEscape() + 1);
   //
   this.playerService.updatePlayerRecord(px);
  }
  //
  VipRoomCloseMsg closeMsg = new VipRoomCloseMsg();
  closeMsg.unused_0 = gt.getVipTableID();// 房号返回
  //
  closeMsg.init_players(gt.getPlayers(), gt, gr.fixedGold);
  //
  this.sendMsgToTable(gt, closeMsg);
  //
  for (int i = 0; i < plist.size(); i++) {
   Player pl = plist.get(i);
   // 清理掉玩家的桌子vip金币
   pl.setVipTableGold(0);
   // 输赢金币清零
   pl.setWinLoseTotal(0);
   // 清除VIP桌子统计信息
   pl.clearVipTableInfo();
   pl.setVipTableID("");
  }
  gt.clear_all();
  gt.setState(GameConstant.TABLE_STATE_INVALID);
 }
 //
 // 检测是否玩家输光,第一局玩家扣金币
 private boolean vip_table_check_next_hand(GameTable gt) {
  if (gt.isVipTable() == false)
   return false;
  if (gt.getHandNum() == 0)
   return true;
  GameRoom gr = getRoom(gt.getRoomID());
  if (gr == null) {
   gt.setState(GameConstant.TABLE_STATE_INVALID);
   return false;
  }
  // 先测试金币够不够
  // for(int i=0;i<plist.size();i++)
  // {
  // Player pl=plist.get(i);
  // if(pl.getVipTableGold()<gr.minGold)//vip 桌子当玩家金币小于minGold就解散
  // {
  // gt.setState(GameConstant.TABLE_STATE_INVALID);
  //    
  // logger.info("玩家金币不足,VIP房间:" + gt.getVipTableID() +"结束");
  //    
  // vip_table_end(gr,gt);
  // return false;
  // }
  // }
  //
  if (gt.isVipTableTimeOver())
   return false;
  return true;
 }
 //
 private void game_over_log(GameTable gt) {
  // 写日志
  List<Player> plist = gt.getPlayers();
  if (gt.isVipTable()) {
   //
   for (int i = 0; i < plist.size(); i++) {
    Player pl = plist.get(i);
    //
    VipRoomRecord vrr = pl.getVrr();
    if (vrr != null) {
     int num = 0;
     for (int j = 0; j < plist.size(); j++) {
      Player plj = plist.get(j);
      if (plj.getPlayerID().equals(pl.getPlayerID()) == false) {
       if (num == 0) {
        vrr.setPlayer2Name(plj.getPlayerIndex() + "-"
          + plj.getPlayerNameNoEmoji());
        vrr.setScore2(plj.getWinLoseTotal());
       } else if (num == 1) {
        vrr.setPlayer3Name(plj.getPlayerIndex() + "-"
          + plj.getPlayerNameNoEmoji());
        vrr.setScore3(plj.getWinLoseTotal());
       } else if (num == 2) {
        vrr.setPlayer4Name(plj.getPlayerIndex() + "-"
          + plj.getPlayerNameNoEmoji());
        vrr.setScore4(plj.getWinLoseTotal());
       }
       //
       num++;
      } else {
       vrr.setScore1(pl.getWinLoseTotal());
      }
     }
     // 更新结束时间
     vrr.setEndTime(new Date());
     playerService.updateVipRoomRecord(vrr);
     // 积分计算
     SystemConfigPara config = this.cfgService
       .getPara(GameConfigConstant.CONF_SCORE_BEI);
     int incscore = 0;
     if (config != null) {
      if (gt.getCreator().getPlayerID() == pl.getPlayerID()) {
       incscore = config.getPro_3();
      } else {
       incscore = config.getPro_4();
      }
     }
     if (incscore > 0) {
      this.playerService.add_player_scrore(pl, incscore);
     }
    }
    //
    VipGameRecord vgr = new VipGameRecord();
    vgr.setPlayerID(pl.getPlayerID());
    vgr.setPlayerName(pl.getPlayerIndex() + "-"
      + pl.getPlayerNameNoEmoji());
    vgr.setRoomID(gt.getTableID());
    //
    vgr.setGameID(gt.getVipTableID());
    //
    vgr.setGameScore(pl.getWinLoseGoldNum() + pl.getGangMoneyNum());
    vgr.setGameType1(pl.getFanType());
    vgr.setRecordDate(DateService.getCurrentUtilDate());
    vgr.setHandIndex(gt.getHandNum());
    vgr.setGameMultiple(pl.getFanNum());
    //
    this.playerService.createVipGameRecord(vgr);
   }
  } else {
   Player px0 = null;
   Player px1 = null;
   Player px2 = null;
   Player px3 = null;
   if (plist.size() > 0)
    px0 = plist.get(0);
   if (plist.size() > 1)
    px1 = plist.get(1);
   if (plist.size() > 2)
    px2 = plist.get(2);
   if (plist.size() > 3)
    px3 = plist.get(3);
   NormalGameRecord ngr = new NormalGameRecord();
   ngr.setRoomID(gt.getTableID());
   ngr.setRoomType(gt.getRoomID());
   //
   if (px0 != null) {
    ngr.setPlayer1Index(px0.getPlayerIndex());
    ngr.setGameType1(px0.getFanType());
    ngr.setScore1(px0.getWinLoseGoldNum() + px0.getGangMoneyNum());
    ngr.setGameMultiple1(px0.getFanNum());
   }
   //
   if (px1 != null) {
    ngr.setPlayer2Index(px1.getPlayerIndex());
    ngr.setGameType2(px1.getFanType());
    ngr.setScore2(px1.getWinLoseGoldNum() + px1.getGangMoneyNum());
    ngr.setGameMultiple2(px1.getFanNum());
   }
   //
   if (px2 != null) {
    ngr.setPlayer3Index(px2.getPlayerIndex());
    ngr.setGameType3(px2.getFanType());
    ngr.setScore3(px2.getWinLoseGoldNum() + px2.getGangMoneyNum());
    ngr.setGameMultiple3(px2.getFanNum());
   }
   //
   if (px3 != null) {
    ngr.setPlayer4Index(px3.getPlayerIndex());
    ngr.setGameType4(px3.getFanType());
    ngr.setScore4(px3.getWinLoseGoldNum() + px3.getGangMoneyNum());
    ngr.setGameMultiple4(px3.getFanNum());
   }
   ngr.setHostIndex(px0.getPlayerIndex());
   Date tt = new Date(gt.getHandStartTime());
   ngr.setStartTime(tt);
   ngr.setEndTime(DateService.getCurrentUtilDate());
   //
   this.playerService.createNormalGameRecord(ngr);
  }
 }
 private void game_over(GameTable gt) {
  // 发送游戏结束界面
  PlayerGameOverMsgAck gov = new PlayerGameOverMsgAck();
  gov.roomID = gt.getRoomID();
  gov.huCard = gt.getHu_card() & 0xff;
  gov.dealerPos = gt.getDealerPos();
  gov.huPos = gt.getCurrentHuPlayerIndex();
  gov.baoCard = gt.getBaoCard();
  Player hupl = gt.getPlayerAtIndex(gt.getCurrentHuPlayerIndex());
  gov.mas = gt.getMas();
  int b2 = gt.getBaoCard2();
  // int b3=gt.getBaoCard2();
  // int b4=gt.getSecondBaoCard2();
  gov.baoCard |= (b2 << 8);
  // gov.baoCard|=(b3<<16);
  // gov.baoCard|=(b4<<24);
  //
  gov.init_players(gt.getPlayers(), gt);
  //
  if (gt.isVipTable()) {
   gov.isVipTable = 1;
   gov.readyTime = cfgService.getPara(
     GameConfigConstant.CONF_VIP_GAME_OVER_ENTER_NEXT_TURN)
     .getValueInt();
  } else {
   gov.isVipTable = 0;
   gov.readyTime = 30;
  }
  this.sendMsgToTable(gt, gov);
  //
  // vip输赢累加
  List<Player> plist = gt.getPlayers();
  if (gt.isVipTable()) {
   for (int i = 0; i < plist.size(); i++) {
    Player pl = plist.get(i);
    // 带正负号
    pl.setWinLoseTotal(pl.getWinLoseTotal()
      + pl.getWinLoseGoldNum());
   }
  }
  // 日志处理
  game_over_log(gt);
  /** *********现在不需要续卡********* */
  // VIP最后一把,圈数用光
  // if(gt.isVipTableTimeOver())
  // {
  // extend_card_remind(gt);
  // //给其他玩家发个消息,等待房主续卡
  // PlayerOperationNotifyMsg mxg=new PlayerOperationNotifyMsg();
  // mxg.operation=GameConstant.MAHJONG_OPERTAION_EXTEND_CARD_REMIND;
  // mxg.target_card=1;//不是房主才处理这个消息
  //   
  // Player pl=gt.getCreator();
  // if(pl!=null)
  // {
  // this.sendMsgToTableExceptMe(gt,mxg, pl.getPlayerID());
  // }
  // }
  gt.clearGameState();
  gt.set_all_player_state(GameConstant.PALYER_GAME_STATE_IN_TABLE_GAME_OVER_WAITING_TO_CONTINUE);
  // 然后,游戏进入等待玩家继续界面
  gt.setState(GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE);
  GameRoom gr = gameRoomMap.get(gt.getRoomID());
  // 机器人处理
  if (!gt.isVipTable()) {
   for (int i = 0; i < plist.size(); i++) {
    Player pl = plist.get(i);
    if (!pl.getOnTable()) {
     player_left_table(pl);
    } else if (pl.getGold() < gr.minGold) {
     player_left_table(pl);
    } else if (pl.isRobot()) {
     pl.dcRobotgamenum();
     if (pl.getRobotgamenum() <= 0) {
      player_left_table(pl);
     }
    }
   }
  }
  gt.setAllRobotReady();
  gt.setHandEndTime(System.currentTimeMillis());
  machineService.reset_machinetime_current(gt);
 }
 private void ivite_machines(GameTable gt) {
  // vip房间不要机器人
  if (gt.isVipTable())
   return;
  if (gt.getPlayerNum() == 0)
   return;
  if (gt.getMaxPlayer() == gt.getPlayerNum())
   return;
  //
  GameRoom gr = gameRoomMap.get(gt.getRoomID());
  if (gr != null) {
   // if(gr.roomType!=GameConstant.ROOM_TYPE_COMMON_1)
   // return;//只在初级场才有机器人
  }
  long ct = DateService.getCurrentUtilDate().getTime();
  for (Player play : gt.getPlayers()) {
   // 如果有整个桌子等待玩家超过2秒并且有玩家等待超过5秒,立即邀请机器人
   if (play.getInRoomWaitOtherTime() == 0)
    continue;
   if (play.isRobot())
    continue;
   if (ct - play.getInRoomWaitOtherTime() > cfgService
     .get_robotWaitLimitTime() * 1000) {
    gr = gameRoomMap.get(gt.getRoomID());
    machineService.create_machine(gr, gt);
    machineService.reset_machinetime(gt);
    break;
   }
  }
 }
 //
 public ISystemConfigService getCfgService() {
  return cfgService;
 }
 public void setCfgService(ISystemConfigService cfgService) {
  this.cfgService = cfgService;
 }
 public MahjongProcess getDaqingMahjong() {
  return mjProc;
 }
 public List<GameRoom> getGameRoomList() {
  return gameRoomList;
 }
 public void setGameRoomList(List<GameRoom> gameRoomList) {
  this.gameRoomList = gameRoomList;
 }
 public IMachineService getMachineService() {
  return machineService;
 }
 public DBServerPlayerService getPlayerService() {
  return playerService;
 }
 /** 强制结束游戏,用于从后台结束非法桌子 */
 public void game_over_force(Player pl) {
  logger.info("强制清理玩家信息,结束非法桌子");
  int roomID = pl.getRoomID();
  GameRoom rm = gameRoomMap.get(roomID);
  if (rm == null) {
   logger.info("找不到房间,不需要结束");
   return;
  }
  GameTable gt = rm.getTable(pl.getTableID(), pl.isPlayingSingleTable());
  if (gt != null) {
   logger.error("房间ID:" + roomID + " 桌子ID:" + pl.getTableID()
     + " 桌子状态State:" + gt.getState() + " 当前人数:"
     + gt.getPlayerNum());
   logger.error("本局开始时间:" + new Date(gt.getHandStartTime())
     + " 当前操作人currentOpertaionPlayerIndex:"
     + gt.getCurrentOpertaionPlayerIndex());
   for (Player ply : gt.getPlayers()) {
    if (null != ply) {
     String cards = "";
     for (Byte card : ply.getCardsInHand()) {
      cards += card;
      cards += "-";
     }
     logger.error("玩家" + ply.getPlayerIndex() + " 座位号:"
       + ply.getTablePos() + " 手牌:" + cards);
    }
   }
   gt.clearGameState();
   gt
     .setState(GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE);
   gt
     .set_all_player_state(GameConstant.PALYER_GAME_STATE_IN_TABLE_GAME_OVER_WAITING_TO_CONTINUE);
   gt.setHandEndTime(System.currentTimeMillis());
   // 设为非法状态,系统会自动清理
   gt.setState(GameConstant.TABLE_STATE_INVALID);
  } else {
   logger.info("找不到桌子,不需要结束");
  }
 }
 public GameTable getVipTableByVipTableID(int vipTableID) {
  if (vipTableID == 0)
   return null;
  for (Integer rid : gameRoomMap.keySet()) {
   GameRoom gr = gameRoomMap.get(rid);
   GameTable gt = gr.getVipTableByVipTableID(vipTableID);
   if (gt != null) {
    return gt;
   }
  }
  return null;
 }
 public void force_clear_table_by_admin(int vipTableID) {
  if (vipTableID == 0)
   return;
  for (Integer rid : gameRoomMap.keySet()) {
   GameRoom gr = gameRoomMap.get(rid);
   GameTable gt = gr.getVipTableByVipTableID(vipTableID);
   if (gt != null) {
    clear_game_table_by_admin(gt);
    return;
   }
  }
 }
 /** 强制结束游戏,用于从后台结束非法桌子 */
 public void game_over_force_one_table(String table_id) {
  logger.info("==强制清理单个桌子==");
  GameTable gt = null;
  for (Integer rid : gameRoomMap.keySet()) {
   GameRoom gr = gameRoomMap.get(rid);
   Map<String, GameTable> playingTables = gr.getPlayingTablesMap();
   gt = playingTables.get(table_id);
   if (gt != null)
    break;
  }
  if (gt != null) {
   clear_game_table_by_admin(gt);
  } else {
   logger.info("找不到桌子,不需要结束");
  }
 }
 private void clear_game_table_by_admin(GameTable gt) {
  logger.error("vip房间ID:" + gt.getVipTableID() + " 桌子ID:"
    + gt.getTableID() + " State:" + gt.getState()
    + " Backup_state:" + gt.getBackup_state() + " 当前人数:"
    + gt.getPlayerNum());
  logger.error("本局开始时间:" + new Date(gt.getHandStartTime())
    + " 当前操作人currentOpertaionPlayerIndex:"
    + gt.getCurrentOpertaionPlayerIndex());
  for (Player ply : gt.getPlayers()) {
   if (null != ply) {
    String cards = "";
    for (Byte card : ply.getCardsInHand()) {
     cards += card;
     cards += "-";
    }
    logger.error("玩家" + ply.getPlayerIndex() + "座位号:"
      + ply.getTablePos() + ",玩家状态:" + ply.getGameState()
      + ",手牌:" + cards);
   }
  }
  gt.clearGameState();
  gt.setState(GameConstant.GAME_TABLE_STATE_WAITING_PALYER_TO_CONTINUE);
  gt
    .set_all_player_state(GameConstant.PALYER_GAME_STATE_IN_TABLE_GAME_OVER_WAITING_TO_CONTINUE);
  gt.setHandEndTime(System.currentTimeMillis());
  // 设为非法状态,系统会自动清理
  gt.setState(GameConstant.TABLE_STATE_INVALID);
 }
 /** 游戏中玩家发送快捷聊天语句 */
 public void playerTalkingInGame(Player pl, TalkingInGameMsg msg) {
  if (pl == null)
   return;
  GameRoom gr = this.getRoom(pl.getRoomID());
  if (gr == null)
   return;
  GameTable gt = gr.getTable(pl.getTableID(), pl.isPlayingSingleTable());
  if (gt == null)
   return;
  msg.playerSex = pl.getSex();
  msg.playerPos = pl.getTablePos();
  if (msg.msgType == 3)
   // this.sendMsgToTable(gt,msg);
   this.sendMsgToTableExceptMe(gt, msg, pl.getPlayerID());
  else
   // 转发给桌子上其他人
   this.sendMsgToTable(gt, msg);
 }
 /** 获取正在进行游戏的桌子 */
 public List<GameTable> getPlayingTables(int index) {
  List<GameTable> tables = new ArrayList<GameTable>();
  for (Integer rid : gameRoomMap.keySet()) {
   GameRoom gr = gameRoomMap.get(rid);
   Map<String, GameTable> playingTables = gr.getPlayingTablesMap();
   for (String tid : playingTables.keySet()) {
    if (index > 0) {
     if (playingTables.get(tid).isHavePlayer(index)) {
      tables.add(playingTables.get(tid));
     }
    } else {
     tables.add(playingTables.get(tid));
    }
   }
  }
  return tables;
 }
}