<?php
/**
 * 单人排位赛
 */
namespace Game\Model\Pvp\Mode;

use Framework\Log\LogMark;
use Framework\DB\Handler\PlayerDBHandler;
use Framework\Logic\CommonDataLogic;
use Framework\Logic\PacketCacheLogic;
use Framework\Logic\TemplateHelp;
use Game\Config\GameConfig;
use Game\Constant\ClientErrorCode;
use Game\Constant\ConstTemplate\TemplateCar;
use Game\Constant\ConstTemplate\TemplateConst;
use Game\Constant\ConstTemplate\TemplateIntegral;
use Game\Constant\ConstTemplate\TemplateSeasonRewardCondition;
use Game\Constant\EventTypeDefine;
use Game\Constant\GameConstantDefine;
use Game\Constant\GameErrorCode;
use Game\Constant\ModelTypeDefine;
use Game\Constant\TemplateDefine;
use Game\Data\PaiWei\PaiweiLevelData;
use Game\Data\PvpPacket\PvpMsgData;
use Game\Data\RaceResultData;
use Game\Data\RecordData;
use Game\Data\RoomData;
use Game\Logic\CarLogic;
use Game\Logic\ItemLogic;
use Game\Logic\PaiweiLevelLogic;
use Game\Logic\Pvp\PvpLogic;
use Game\Logic\Pvp\PvpMatchLogic;
use Game\Logic\Pvp\PvpSettlementLogic;
use Game\Method\Player\AddPlayerExp;
use Game\Model\Pvp\PvpBaseModel;
use Game\Model\RoomModel;
use Game\Protobuf\CarShow;
use Game\Protobuf\GCCancelMatch;
use Game\Protobuf\GCRaceResult;
use Game\Protobuf\GCStartMatching;
use Game\Protobuf\GMJoinMatch;
use Game\Protobuf\PacketId;
use Game\Protobuf\PlayerInfo;
use Game\Protobuf\GCPVPMatchingSuccess;
use Game\Protobuf\PlayerShow;
use Game\Protobuf\RewardItem;
use Game\Protobuf\RoomPlayers;
use Game\Protobuf\SingleRankingMatchParam;

class SingleRankingModel
{
    use PlayerDBHandler;
    use PaiweiLevelLogic;
    use TemplateHelp;
    use CarLogic;
    use ItemLogic;
    use PvpLogic;
    use PacketCacheLogic;
    use PvpMatchLogic;
    use PvpSettlementLogic;
    use AddPlayerExp;
    use CommonDataLogic;

    public int $playerId;

    private bool $isWin = false;            //胜负标志
    private int $carPositioning;            //车辆定位
    private ?array $constConfigData;        //配置表
    private array $mvpScoreDict = array();  //mvp分数信息 (playerId=>mvpScore)
    private int $joinId = 0;
    private ?array $paiweiConfigData;       //排位赛积分配置表
    private array $scoreArray = array();    //段位分获得id
    private array $proficiencyArray = array();  //熟练度获取详情

    private array $sendRaceResultList = array();
    private GCRaceResult $sendMessage;
    public GCStartMatching $startMatchingMsg;
    public GCCancelMatch   $cancelMatchMsg;

    public function __construct()
    {
        $this->startMatchingMsg = new GCStartMatching();
        $this->cancelMatchMsg = new GCCancelMatch();
    }
    public function setPlayerId($playerId)
    {
        $this->playerId = $playerId;
    }

    // 加入匹配
    public function sendJoinMatchPacket(int $joinID, RoomData $room, bool $isRand): bool {
        $playerID = $this->playerId;
        $serverID = GameConfig::getInstance()->SERVER_ID();
        $playerInfo = [];
        //生成匹配数据
        foreach($room->playerInfo as $id => $data) {
            $player = new RoomPlayers();
            $player->setPlayerID($id);
            $player->setPlayerShow($this->makePlayerShowString($id, $data));
            $player->setCarShow($this->makeCarShowString($id, $data, $room->mapID));
            $playerInfo[] = $player;
        }

        // 通过相应的protobuf 组装发送匹配数据
        $match = new GMJoinMatch();
        $match->setPlayerID($playerID);
        $match->setServerID($serverID);
        $match->setJoinID($joinID);
        $match->setMapID($room->mapID);
        $match->setMatchType($room->modeType);
        $match->setPlayer($playerInfo);
        //排位赛匹配参数
        $match->setMatchParam($this->getRankingMatchParam($room->playerInfo, $match));
        LogMark::getInstance()->markInfo("[PVPFlowLog][SingleRankingModel] matching param:".$match->serializeToJsonString());
        //发送匹配消息
        if($this->sendJoinMatchingPacket($match)) {
            //发送成功
            LogMark::getInstance()->markInfo(
                "[PVPFlowLog][2][SingleRankingModel]joinMatching success",
                (array)$room + ['joinID' => $joinID]
            );
            $this->joinRoomMsg(ClientErrorCode::CLIENT_SUCCESS);
            $this->addJoinRoomMsg($room->playerInfo);
            $room->setPlayType(RoomModel::ROOM_GAME_MATCH_OR_PLAY);
            if($isRand) {
                //随机地图房间 地图继续显示随机
                $room->mapID = PvpBaseModel::RandMapNum;
            }
            if(!$room->saveDB()) {
                LogMark::getInstance()->markError(
                    GameErrorCode::DATA_UPDATE_ERROR,
                    "[PVPFlowLog][SingleRankingModel] joinMatching change room play type fail",
                    (array)$room
                );
                return false;
            }
        } else {
            //发送失败
            LogMark::getInstance()->markError(
                GameErrorCode::DATA_UPDATE_ERROR,
                "[PVPFlowLog][SingleRankingModel]joinMatching fail",
                (array)$room
            );
            $this->joinRoomMsg(ClientErrorCode::PVP_JOIN_MATCH_ERROR);
            $this->joinRoomMsgSend();
            return false;
        }
        return true;
    }

    /**
     * 排位赛匹配特殊参数
     * @param array $roomPlayer
     * @param GMJoinMatch $match
     * @return string 平均排位分,需要匹配的真实敌人数量
     */
    private function getRankingMatchParam(array $roomPlayer, GMJoinMatch $match): string
    {
        //匹配保护机制--直接匹AI
        //1.当玩家段位为青铜4（最低段位）时，匹配ai对手。
        //2.当玩家段位为青铜3-黄金1时，玩家三连败时，下一场匹配ai对手。
        //3.当玩家段位为铂金-钻石时，玩家5连败后，下一场匹配ai对手。
        //个人赛：除了我都是ai  团队赛：友方真人，对手ai
        $ownerLv = 1;   //房主段位
        $joinTime = 0;
        $allAI = false;
        $rankingScore = array();    //排位分
        $constConfig = $this->getTable(TemplateDefine::TYPE_CONST);
        foreach($roomPlayer as $pid => $data) {
            $rankingScore[] = $this->getRankingScore($pid);
            $paiWeiData = $this->getTargetPaiWeiLevel($pid);
            //查找房主
            if ($joinTime == 0) {
                $joinTime = $data[RoomData::JOIN_TIME];
                $ownerLv = $paiWeiData->levelId;
            }
            if ($joinTime < $data[RoomData::JOIN_TIME]) {
                $joinTime = $data[RoomData::JOIN_TIME];
                $ownerLv = $paiWeiData->levelId;
            }
            if ($paiWeiData->levelId == $constConfig[TemplateConst::Const_Ranking_AI_Min_Level][TemplateConst::ConstNum]) {
                $allAI = true;
            } elseif ($paiWeiData->levelId >= $constConfig[TemplateConst::Const_Ranking_AI_1_Min_Level][TemplateConst::ConstNum] &&
                $paiWeiData->levelId <= $constConfig[TemplateConst::Const_Ranking_AI_1_Max_Level][TemplateConst::ConstNum] &&
                $paiWeiData->record <= $constConfig[TemplateConst::Const_Ranking_AI_1_Lose_Num][TemplateConst::ConstNum]) {
                $allAI = true;
            } elseif ($paiWeiData->levelId >= $constConfig[TemplateConst::Const_Ranking_AI_2_Min_Level][TemplateConst::ConstNum] &&
                $paiWeiData->levelId <= $constConfig[TemplateConst::Const_Ranking_AI_2_Max_Level][TemplateConst::ConstNum] &&
                $paiWeiData->record <= $constConfig[TemplateConst::Const_Ranking_AI_2_Lose_Num][TemplateConst::ConstNum]) {
                $allAI = true;
            }
        }
        //需要的真实敌人数量
        $realPlayerNum = 6 - count($roomPlayer);
        if ($allAI) {
            $realPlayerNum = 0;
        }
        //根据房主段位,查询匹配配置
        [$maxTime, $lvRange, $matchTimeProto] = $this->getRankingConfig($ownerLv);
        $matchParam = new SingleRankingMatchParam();
        $matchParam->setLevel($ownerLv);
        $matchParam->setLevelRange($lvRange);
        $matchParam->setScore($this->getAvgRankingScore($rankingScore));
        $matchParam->setMatchTimeScore($matchTimeProto);
        $match->setMaxTime($maxTime);
        $match->setNeedPlayerNum(0);
        $match->setNeedTargetNum($realPlayerNum);
        LogMark::getInstance()->markInfo(
            '[SingleRankingModel] getRankingMatchParam:'.$matchParam->serializeToJsonString(),
        );
        return base64_encode($matchParam->serializeToString());
    }

    // 匹配返回结果处理
    public function pvpMatchingRecv(array $msgData): bool
    {
        $playerList = $msgData[PvpMsgData::PLAYER_LIST];
        $MatchRecvMsg = new GCPVPMatchingSuccess();
        $MatchRecvMsg->setIp($msgData[PvpMsgData::IP]);
        $MatchRecvMsg->setPort($msgData[PvpMsgData::PORT]);
        $MatchRecvMsg->setSceneId($msgData[PvpMsgData::MAP_ID]);
        $MatchRecvMsg->setMatchType(GameConstantDefine::MATCH_MODE_SINGLE_PAI_WEI);
        $players = array();
        $joinID = 0;
        foreach ($playerList as $playerData) {
            if($this->playerId == $playerData[PvpMsgData::PLAYER_ID]) {
                $joinID = (int)$playerData[PvpMsgData::JOIN_ID];
            }
            /**
             * @var PlayerShow $playerShow
             */
            $playerShow = $playerData[PvpMsgData::PLAYER_SHOW];
            /**
             * @var CarShow $carShow
             */
            $carShow = $playerData[PvpMsgData::CAR_SHOW];
            $player = new PlayerInfo();
            $player->setPlayerId($playerData[PvpMsgData::PLAYER_ID])
                ->setNickName($playerShow->getNickName())
                ->setHead($playerShow->getHead())
                ->setCarTplId($carShow->getCarTplID())
                ->setGroupID($playerData[PvpMsgData::GROUP_ID])
                ->setExteriorRefit($carShow->getExteriorRefit())
                ->setGender($playerShow->getGender())
                ->setCloth($playerShow->getCloth())
                ->setSkinColor($playerShow->getSkinColor())
                ->setProficiencyLv($carShow->getProficiencyLv())
                ->setProficiency($carShow->getProficiency())
                ->setPosition($playerData[PvpMsgData::POSITION])
                ->setContinuityWin($playerShow->getContinuityWin())
                ->setCarLv($carShow->getCarLv())
                ->setLevel($playerShow->getLevel())
                ->setDan($playerShow->getDan());
            $players[] = $player;
        }
        $MatchRecvMsg->setJoinId($joinID);
        $MatchRecvMsg->setPInfo($players);
        $MatchRecvMsg->setAInfo($msgData[PvpMsgData::AI_INFO]);
        if ($this->addPacket(PacketId::GC_PVPMatchingSuccess, $MatchRecvMsg, $this->playerId)) {
            LogMark::getInstance()->markInfo(
                '[PVPFlowLog][11][SingleRankingModel] match send msg:',
                array("packet" => $MatchRecvMsg->serializeToJsonString())
            );
            $changeData = array(
                RecordData::MATCHING_DATA => $MatchRecvMsg->serializeToJsonString()
            );
            $this->updateRecordData($this->playerId, $joinID, $changeData);
            return true;
        }
        LogMark::getInstance()->markInfo(
            '[PVPFlowLog][SingleRankingModel] match send msg fail:',
            array("packet" => $MatchRecvMsg->serializeToJsonString())
        );
        return false;
    }

    /**
     * PVP结算--单人排位赛
     * @param array $playerList [playerId=>raceResultsData]
     * @param array $breakingRecordInfo [playerId=>RecordBreakingInfo]
     * @return bool
     */
    public function matchSettlement(array $playerList, array $breakingRecordInfo): bool
    {
        LogMark::getInstance()->markDebug(
            "[PVPFlowLog][SingleRankingModel] start pvp single ranking matchSettlement",
            $playerList
        );
        //配置
        $this->constConfigData = $this->getTable(TemplateDefine::TYPE_CONST);
        if (is_null($this->constConfigData)) {
            LogMark::getInstance()->markWarn(
                GameErrorCode::TEMPLATE_ID_NOT_FOUND,
                "[PVPFlowLog][SingleRankingModel] TYPE_CONST tpl table not found",
                array(
                    "TemplateTable" => TemplateDefine::TYPE_CONST
                )
            );
            return false;
        }
        $myRaceResult = null;
        $pIdRank = [];      //playerId=>rank
        $allPlayerParameter = array();  //结算参数
        $no1PlayerId = null;
        foreach ($playerList as $pid => $raceResult) {
            /**
             * @var RaceResultData $raceResult
             */
            //玩家自己结算消息处理
            if ($pid == $this->playerId) {
                $myRaceResult = $raceResult;
                $this->joinId = $raceResult->_joinId;
            }
            if ($raceResult->_rank == 1) {
                $no1PlayerId = $raceResult->_playerId;
            }
            $pIdRank[$raceResult->_playerId] = $raceResult->_rank;
            //添加战斗通用返回消息
            $this->addRaceResultMessage($raceResult);
            $allPlayerParameter[] = $raceResult->parameter;
        }
        //玩家比赛结算
        $record = $this->matchSettlementPlayer($myRaceResult, $pIdRank);

        //每个玩家结算参数
        $this->sendMessage->setParameter($allPlayerParameter);
        //破记录信息
        $this->sendMessage->setMyBreakingInfo($breakingRecordInfo[$this->playerId]);
        //单人模式为第一名数据
        $this->sendMessage->setMvpBreakingInfo($breakingRecordInfo[$no1PlayerId]);
        //发送消息
        $this->sendMessage($this->playerId);
        //记录打点日志
        $this->addCompletaMatchLog($record, $myRaceResult, $playerList);
        return true;
    }

    //玩家比赛结算
    public function matchSettlementPlayer(RaceResultData $raceResult, array $pIdRank): RecordData
    {
        //积分配置表
        $this->paiweiConfigData = $this->getTable(TemplateDefine::TYPE_INTEGRAL);
        if (is_null($this->paiweiConfigData)) {
            LogMark::getInstance()->markWarn(
                GameErrorCode::TEMPLATE_ID_NOT_FOUND,
                "[PVPFlowLog][SingleRankingModel] pvp ranking ConfigData tpl table not found",
                array(
                    "TemplateTable" => TemplateDefine::TYPE_INTEGRAL
                )
            );
        }
        //检查赛季状态,关闭状态不给积分和奖励
        $seasonStatus = $this->getCommonValueByModel(ModelTypeDefine::SEASON_STATUS);
        $seasonIsOpen = false;
        if (!is_null($seasonStatus) && $seasonStatus == GameConstantDefine::SEASON_STATUS_OPEN) {
            $seasonIsOpen = true;
        }
        //检查是否获胜
        if ($raceResult->_rank <= 3) {
            $this->isWin = true;
        }
        //车辆信息 获取玩家当前默认的车
        $carConfigData = $this->getTitle(TemplateDefine::TYPE_CAR, $raceResult->_carId);
        $this->carPositioning = $carConfigData[TemplateCar::Positioning];

        $reward = array();
        $rewardMessage = array();
        $score = $guardScore = $carProficiency = $exp = $carScore = 0;
        $record = $this->getRecordData();
        if ($seasonIsOpen) {
            //获取排位赛积分
            [$score, $guardScore] = $this->getPaiweiScore($raceResult);
            //更新积分
            $this->updateRankingData($score, $guardScore, $this->isWin);
            //获取道具奖励
            $this->getReward($reward, $raceResult->_carId);
            // 比赛模式获取道具
            $this->getModeReward($reward, $raceResult->_modeType);
            $this->setLogAddItemSource(GameConstantDefine::ITEM_ADD_SOURCE_PVP_SETTLEMENT);
            $this->gainItemArr($reward);
            foreach ($reward as $itemId => $num) {
                //道具奖励消息
                $ri = new RewardItem();
                $ri->setId($itemId);
                $ri->setNum($num);
                $rewardMessage[] = $ri;
            }
            //车辆熟练度
            $carProficiency = $this->getCarProficiency($raceResult, $raceResult->_rank <= 3);
            $this->addCarProficiency($raceResult->_carId, $carProficiency, $raceResult->_modeType);

            // 经验
            $exp = $this->getAccountLvExp($raceResult->_rank <= 3, $raceResult->_modeType);
            $this->addPlayerExp($exp, $raceResult->_modeType);

            //计算车辆评分
            $carScore = $this->getCarScore($raceResult, $carProficiency);
        }

        //添加玩家结算奖励消息
        $this->sendMessage = new GCRaceResult();
        $this->sendMessage->setCarProficiencyArray($this->proficiencyArray);
        $this->sendMessage->setAddCarProficiency($carProficiency);
        $this->sendMessage->setAddExp($exp);
        $this->sendMessage->setAddScore($score);
        $this->sendMessage->setAddGuardScore($guardScore);
        $this->sendMessage->setCarScore($carScore);
        $this->sendMessage->setScoreArray($this->scoreArray);
        $this->sendMessage->setItem($rewardMessage);

        //当前段位信息
        $paiweiLevel = $this->getPaiweiLevel();
        $this->sendMessage->setScore($paiweiLevel->score);
        $this->sendMessage->setMaxLevelId($paiweiLevel->maxLevelId);
        $this->sendMessage->setGuardScore($paiweiLevel->guardScore);
        $this->sendMessage->setSeasonId($paiweiLevel->seasonId);
        $this->sendMessage->setMatchId($record->matchUID);

        if ($seasonIsOpen) {
            //触发任务
            $param = array(
                GameConstantDefine::EVENT_KEY_NUM => $score,
                GameConstantDefine::EVENT_KEY_PAI_WEI_LEVEL => $paiweiLevel->levelId
            );
            $this->triggerEvent(EventTypeDefine::EVENT_TYPE_TASK_PAI_WEI_SCORE, $param, false);

            //比赛统计数据
            $this->tidyStatisticsData($raceResult);
            //更新排行榜
            $this->changeRankMap($raceResult->_costTime, $record->mapID);
            $this->updateRankData($raceResult);
            //触发任务
            $this->triggerFinishPVPEvent($raceResult, $record, $this->isWin, $this->playerId);
            // 自己获得mvp 获得赛季积分
            if($raceResult->_mvpIcon) {
                $this->updateSeasonScore(TemplateSeasonRewardCondition::RANK_MVP);
            }
            // 增加赛季积分
            $this->updateSeasonScore(TemplateSeasonRewardCondition::PLAY_RANK);
        }
        //更新房间状态
        $this->changePlayerAndRoomState($record->roomID);
        //更新比赛记录
        $this->updateRecord($raceResult, $this->playerId);
        //更新好友比赛记录
        $this->updateLastGame($pIdRank, $this->playerId, $record->mapID, $record->matchingData);
        //清空比赛状态
        $this->clearJoinId();
        return $record;
    }

    //获取排位赛积分
    private function getPaiweiScore(RaceResultData $raceResult): array
    {
        $score = 0;
        $guardScore = 0;
        $paiweiLevel = $this->getPaiweiLevel();
        //计算通用分
        //冲线==完成比赛
        if ($raceResult->_costTime > 0) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::CHONG_XIAN, $paiweiLevel);
            $guardScore += $this->getPaiweiConfigValue(TemplateIntegral::G_CHONG_XIAN, $paiweiLevel);
        }
        //金牌表现==获得徽章
        if ($raceResult->_raceIcon || $raceResult->_jamIcon || $raceResult->_helpIcon) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::JIN_PAI_BIAO_XIAN, $paiweiLevel);
            $guardScore += $this->getPaiweiConfigValue(TemplateIntegral::G_JIN_PAI, $paiweiLevel);
        }
        //一路领先==领跑占比>=70%
        if ($raceResult->parameter->getLeadRatio() >= 0.7) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::YI_LU_LING_XIAN, $paiweiLevel);
            $guardScore += $this->getPaiweiConfigValue(TemplateIntegral::G_YI_LU_LING_XIAN, $paiweiLevel);
        }
        //比赛失败 加新手保护分
        if ($raceResult->_rank > 3) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::NEW_PLAYER_GUARD1, $paiweiLevel);
            $score += $this->getPaiweiConfigValue(TemplateIntegral::NEW_PLAYER_GUARD2, $paiweiLevel);
        }
        //每日首胜
        if ($this->isWin) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::DAILY_WIN, $paiweiLevel);
        }
        //连胜
        if ($this->isWin && $paiweiLevel->record > 0) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::CONTINUOUS_WIN, $paiweiLevel);
            $guardScore += $this->getPaiweiConfigValue(TemplateIntegral::G_LIAN_SHENG, $paiweiLevel);
        }
        //连败
        if (!$this->isWin && $paiweiLevel->record < 0) {
            $score += $this->getPaiweiConfigValue(TemplateIntegral::CONTINUOUS_FAIL_GUARD, $paiweiLevel);
        }
        //个人积分
        $this->getPaiweiScoreSingle($raceResult, $score, $guardScore, $paiweiLevel);
        return array($score, $guardScore);
    }

    //排位赛积分--个人
    //玩家处于前三名时判定为胜
    //玩家处于后三名时判定为负
    private function getPaiweiScoreSingle(RaceResultData $raceResult, int &$score, int &$guardScore, PaiweiLevelData $paiweiLevel)
    {
        //检查是否获胜
        if ($raceResult->_rank <= 3) {
            //前三保护分
            $guardScore += $this->getPaiweiConfigValue(TemplateIntegral::G_SINGLE_RANK[$raceResult->_rank- 1], $paiweiLevel);
        }
        //个人排名积分
        $id = TemplateIntegral::SINGLE_RANK[$raceResult->_rank - 1];
        $score += $this->getPaiweiConfigValue($id, $paiweiLevel);
    }

    //根据Id获得排位赛积分表对应积分
    private function getPaiweiConfigValue(int $id, PaiweiLevelData $levelData): int
    {
        if (!isset($this->paiweiConfigData[$id])) {
            LogMark::getInstance()->markWarn(
                GameErrorCode::TEMPLATE_ID_NOT_FOUND,
                "[PVPFlowLog][SingleRankingModel] tpl table not found",
                array(
                    "TemplateTable" => TemplateDefine::TYPE_INTEGRAL,
                    "id" => $id
                )
            );
            return 0;
        }
        //检查生效段位范围和场次
        if ($this->paiweiConfigData[$id][TemplateIntegral::MatchNum] == 0) {
            //0不生效
            return 0;
        }
        if ($levelData->levelId >= $this->paiweiConfigData[$id][TemplateIntegral::LvMin] &&
            $levelData->levelId <= $this->paiweiConfigData[$id][TemplateIntegral::LvMax]) {
            if ($this->paiweiConfigData[$id][TemplateIntegral::MatchNum] == -1) {
                //不限次数
                if ($this->paiweiConfigData[$id][TemplateIntegral::BpType] == 1) {
                    $this->scoreArray[] = $id;
                }
                return $this->paiweiConfigData[$id][TemplateIntegral::BpNum];
            }
            if ($levelData->dailyMatchNum <= $this->paiweiConfigData[$id][TemplateIntegral::MatchNum]) {
                if ($this->paiweiConfigData[$id][TemplateIntegral::BpType] == 1) {
                    $this->scoreArray[] = $id;
                }
                return $this->paiweiConfigData[$id][TemplateIntegral::BpNum];
            }
        }
        return 0;
    }


    //匹配消息
    public function joinRoomMsg(int $code) {
        $this->startMatchingMsg->setCode($code);
    }

    public function joinRoomMsgSend() {
        $this->addPacket(PacketId::GC_StartMatching, $this->startMatchingMsg, $this->playerId);
    }

    public function addJoinRoomMsg(array $players) {
        foreach($players as $id => $p) {
            $this->addPacket(PacketId::GC_StartMatching, $this->startMatchingMsg, $id);
        }
    }
}