Permalink
Cannot retrieve contributors at this time
1195 lines (1112 sloc)
46.8 KB
| <?php | |
| class LogParser | |
| { | |
| private $log = array(); //Json log | |
| private $playerRounds = array(); //All player round objects | |
| private $playerLifeforms = array(); //All player lifeform objects | |
| // private $playerWeapons = array(); | |
| private $roundStructures = array(); | |
| private $lifeforms = array(); | |
| private $weapons = array(); | |
| private $structures = array(); | |
| private $upgrades = array(); | |
| private $roundId; //Id of the round | |
| private $serverId; | |
| private $round; | |
| private $pickables = array(); | |
| private $message; | |
| private $startTime = null; | |
| private $logRandomId = 0; | |
| private $logpath; | |
| function parseStarted() | |
| { | |
| //log speed | |
| $gentime = microtime(); | |
| $gentime = explode(' ', $gentime); | |
| $gentime = $gentime[1] + $gentime[0]; | |
| $this->startTime = $gentime; | |
| } | |
| function addTimeStamp($text) | |
| { | |
| //end of your page | |
| $gentime = microtime(); | |
| $gentime = explode(' ', $gentime); | |
| $gentime = $gentime[1] + $gentime[0]; | |
| $pg_end = $gentime; | |
| $totaltime = ($pg_end - $this->startTime); | |
| $showtime = number_format($totaltime, 4, '.', ''); | |
| $tmp = $showtime . " s \t: " . $text . "\n"; | |
| $filename = Yii::app()->params['logDirectory'] . "parselogs/" . "log-" . $this->serverId . "-" . $this->logRandomId; | |
| $fp = fopen($filename, "a"); | |
| fwrite($fp, $tmp); | |
| fclose($fp); | |
| } | |
| protected function loadLog($logPath) | |
| { | |
| $this->log = array(); | |
| Yii::beginProfile('loadLog'); | |
| ini_set('memory_limit', '780M'); | |
| $handle = @fopen($logPath, "r"); | |
| if ($handle) | |
| { | |
| // $start_memory = memory_get_usage(); | |
| $regex = <<<'END' | |
| / | |
| ( | |
| (?: [\x00-\x7F] # single-byte sequences 0xxxxxxx | |
| | [\xC0-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx | |
| | [\xE0-\xEF][\x80-\xBF]{2} # triple-byte sequences 1110xxxx 10xxxxxx * 2 | |
| | [\xF0-\xF7][\x80-\xBF]{3} # quadruple-byte sequence 11110xxx 10xxxxxx * 3 | |
| ){1,100} # ...one or more times | |
| ) | |
| | . # anything else | |
| /x | |
| END; | |
| while (($buffer = fgets($handle)) !== false) | |
| { | |
| $this->log[] = json_decode(preg_replace($regex, '$1', $buffer), true); | |
| } | |
| if (!feof($handle)) | |
| { | |
| echo "Error: unexpected fgets() fail\n"; | |
| } | |
| fclose($handle); | |
| } | |
| Yii::endProfile('loadLog'); | |
| } | |
| public function createRound($logDirectory, $logFile, $serverId) | |
| { | |
| $this->message = new stdClass(); | |
| $this->loadLog($logDirectory . $logFile); | |
| $round = new Round(); | |
| //Round start | |
| Yii::beginProfile('roundStart'); | |
| foreach ($this->log as $logRow) | |
| { | |
| if ($logRow['action'] == 'game_start') | |
| { | |
| $dateInfo = date_parse_from_format('Y-m-d H:i:s', $logRow['time']); | |
| $unixTimestamp = mktime( | |
| $dateInfo['hour'], $dateInfo['minute'], $dateInfo['second'], $dateInfo['month'], $dateInfo['day'], $dateInfo['year'] | |
| ); | |
| $round->start = $unixTimestamp; | |
| break; | |
| } | |
| } | |
| Yii::endProfile('roundStart'); | |
| //Round end | |
| Yii::beginProfile('roundEnd'); | |
| foreach ($this->log as $logRow) | |
| { | |
| if ($logRow['action'] == 'game_ended') | |
| { | |
| $server = Server::model()->findByPk($serverId); | |
| $server->name = $logRow['serverName']; | |
| $server->stats_version = substr($logRow['statsVersion'], 0, 5); | |
| if ($logRow['private'] == true) | |
| $server->private = 1; | |
| else | |
| $server->private = 0; | |
| //serverInfo by players | |
| $tmp = explode(":", $logRow['serverInfo']["IP"]); | |
| if (isset($tmp) && count($tmp) == 2) | |
| { | |
| $server->ip = $tmp[0]; | |
| $server->port = $tmp[1]; | |
| //password available: | |
| //$logRow['serverInfo']["password"] | |
| } | |
| $server->save(); | |
| $round->private = $server->private; | |
| $round->server_id = $serverId; | |
| $round->map_id = Map::getIdByName($logRow['map']); | |
| if (isset($logRow['tags']) && $logRow['tags'] != null) | |
| $round->tags = implode(' | ', $logRow['tags']); | |
| $dateInfo = date_parse_from_format('Y-m-d H:i:s', $logRow['time']); | |
| $unixTimestamp = mktime( | |
| $dateInfo['hour'], $dateInfo['minute'], $dateInfo['second'], $dateInfo['month'], $dateInfo['day'], $dateInfo['year'] | |
| ); | |
| $round->end = $unixTimestamp; | |
| $round->added = strtotime(date('Y-m-d H:i:s')); | |
| $round->winner = $logRow['winner']; | |
| $round->team_1_start = $logRow['start_location1']; | |
| $round->team_2_start = $logRow['start_location2']; | |
| $round->build = $logRow['version']; | |
| if (isset($logRow['gamemode'])) | |
| $round->gamemode = $logRow['gamemode']; | |
| $round->log_file = $logFile; | |
| break; | |
| } | |
| } | |
| Yii::endProfile('roundEnd'); | |
| if ($round->start == 0) | |
| throw new CHttpException(404, "Log is not finished"); | |
| if ($round->save()) | |
| { | |
| //print messages | |
| $id = Yii::app()->db->getLastInsertID(); | |
| $this->message->link = "/round/round/" . $id; | |
| echo json_encode($this->message); | |
| ob_flush(); | |
| return $id; | |
| } | |
| else | |
| throw new Exception("saving of round failed" . print_r($round->getErrors(), true), 401, null); | |
| } | |
| public function parse($logPath, $serverId, $roundId) | |
| { | |
| set_time_limit(5 * 60); | |
| ini_set('memory_limit', '780M'); | |
| $this->logpath = $logPath; | |
| $this->loadLog($logPath); | |
| $this->serverId = $serverId; | |
| $this->logRandomId = rand(1, 999999); | |
| $this->parseStarted(); | |
| $this->addTimeStamp("PARSE_STARTED"); | |
| $this->roundId = $roundId; | |
| $this->round = Round::model()->findByPk($roundId); | |
| $this->round->parse_status = 2; | |
| $this->round->save(); | |
| // $this->roundId = $this->createRound(); | |
| $started = 0; | |
| /* First loop | |
| * The First loop saves everything needed to display the end round scoreboard | |
| */ | |
| Yii::beginProfile('firstLoop'); | |
| $transaction = Yii::app()->db->beginTransaction(); | |
| try | |
| { | |
| foreach ($this->log as $logRow) | |
| { | |
| //Create starting players | |
| if ($logRow['action'] == 'player_list_start' && $started == 0) | |
| { | |
| $this->createPlayerRounds($logRow['list']); | |
| $started = 1; | |
| } | |
| if ($started) | |
| { | |
| //Create death | |
| if ($logRow['action'] == 'death') | |
| { | |
| if ($logRow['attacker_weapon'] == 'natural causes') | |
| $this->createDeath($logRow); | |
| else if (isset($logRow['attacker_steamId'])) | |
| $this->createDeath($logRow); | |
| } | |
| //Join team | |
| if ($logRow['action'] == 'player_join_team') | |
| { | |
| if (is_numeric($logRow['steamId']) && $logRow['steamId'] > 0) | |
| { | |
| $this->joinTeam($logRow); | |
| } | |
| } | |
| //Create disconnects | |
| if ($logRow['action'] == 'disconnect') | |
| { | |
| if (is_numeric($logRow['steamId']) && $logRow['steamId'] > 0) | |
| { | |
| $this->leaveTeam($logRow); | |
| } | |
| } | |
| //Player list | |
| if ($logRow['action'] == 'player_list_end') | |
| { | |
| $this->endRound($logRow); | |
| } | |
| //Save mods | |
| if ($logRow['action'] == 'game_ended') | |
| { | |
| if (isset($logRow['mods'])) | |
| $this->saveMods($logRow['mods']); | |
| } | |
| } | |
| } | |
| $transaction->commit(); | |
| } | |
| catch (Exception $e) | |
| { | |
| echo "error 14123: " . $e; | |
| $transaction->rollback(); | |
| } | |
| Yii::endProfile('firstLoop'); | |
| $playerRounds = PlayerRound::model()->findAllByAttributes(array('round_id' => $this->roundId)); | |
| $this->deleteByPlayerCount(9.5, $playerRounds); | |
| if ($this->round->private) | |
| $this->findTeams($playerRounds); | |
| $this->round->parse_status = 3; | |
| $this->round->save(); | |
| $started = 0; | |
| /* | |
| * Second loop | |
| * The seconds loop saves rest of the data displayed in the end round page | |
| */ | |
| Yii::beginProfile('secondLoop'); | |
| $transaction = Yii::app()->db->beginTransaction(); | |
| try | |
| { | |
| foreach ($this->log as $logRow) | |
| { | |
| if ($logRow['action'] == 'game_start') | |
| $started = 1; | |
| if ($started) | |
| { | |
| //Create lifeform change | |
| if ($logRow['action'] == 'lifeform_change') | |
| { | |
| if (is_numeric($logRow['steamId']) && $logRow['steamId'] > 0) | |
| { | |
| $this->createLifeformChange($logRow); | |
| } | |
| } | |
| //Create upgrade | |
| if ($logRow['action'] == 'upgrade_started') | |
| { | |
| $this->createUpgrade($logRow); | |
| } | |
| //Create upgrade | |
| if ($logRow['action'] == 'upgrade_finished') | |
| { | |
| $this->endUpgrade($logRow); | |
| } | |
| if ($logRow['action'] == 'structure_dropped') | |
| { | |
| $this->dropStructure($logRow); | |
| } | |
| if ($logRow['action'] == 'ghost_destroy') | |
| { | |
| $this->destroyStructure($logRow, 0, 0, 1); | |
| } | |
| //Create structure | |
| if ($logRow['action'] == 'structure_built') | |
| { | |
| $this->buildStructure($logRow); | |
| } | |
| //Kill structure | |
| if ($logRow['action'] == 'structure_killed') | |
| { | |
| $this->destroyStructure($logRow, 1); | |
| } | |
| //Suicide structure | |
| if ($logRow['action'] == 'structure_suicide') | |
| { | |
| $this->destroyStructure($logRow); | |
| } | |
| //Recycle structure | |
| if ($logRow['action'] == 'structure_recycle') | |
| { | |
| $this->destroyStructure($logRow, 0, 1); | |
| } | |
| //Resources gathered | |
| if ($logRow['action'] == 'resources_gathered') | |
| { | |
| $this->resourcesGathered($logRow); | |
| } | |
| if ($logRow['action'] == 'chat_message') | |
| { | |
| $this->chatMessage($logRow); | |
| } | |
| } | |
| } | |
| $transaction->commit(); | |
| } | |
| catch (Exception $e) | |
| { | |
| echo "Error 1235d: $e"; | |
| $transaction->rollback(); | |
| } | |
| Yii::endProfile('secondLoop'); | |
| $this->round->parse_status = 4; | |
| $this->round->save(); | |
| foreach ($this->playerRounds as $playerRound) | |
| { | |
| $this->endLifeForm($playerRound->player->steam_id, round($this->round->end - $this->round->start)); | |
| } | |
| $this->saveELOs(); | |
| $started = 0; | |
| /* | |
| * Third loop | |
| * The third loop saves data not displayed in the end round page | |
| */ | |
| Yii::beginProfile('thirdLoop'); | |
| $transaction = Yii::app()->db->beginTransaction(); | |
| try | |
| { | |
| foreach ($this->log as $logRow) | |
| { | |
| //if (Yii::app()->request->getQuery('debug')) { | |
| // echo json_encode($logRow) . '<br />'; | |
| // ob_flush(); | |
| // } | |
| if ($logRow['action'] == 'game_start') | |
| $started = 1; | |
| if ($started) | |
| { | |
| //Weapon hit | |
| // if ($logRow['action'] == 'hit_player')// || $logRow['action'] == 'structure') | |
| // $this->hit($logRow); | |
| // //Drop Pickable | |
| // if ($logRow['action'] == 'pickable_ability_dropped' || $logRow['action'] == 'pickable_item_dropped') | |
| // $this->dropPickable($logRow); | |
| // //Pick Pickable | |
| // if ($logRow['action'] == 'pickable_ability_picked' || $logRow['action'] == 'pickable_item_picked') | |
| // $this->pickPickable($logRow); | |
| // //Destroy Pickable | |
| // if ($logRow['action'] == 'pickable_ability_destroyed' || $logRow['action'] == 'pickable_item_destroyed') | |
| // $this->destroyPickable($logRow); | |
| //End round | |
| if ($logRow['action'] == 'player_list_end') | |
| { | |
| foreach ($this->roundStructures as $roundStructure) | |
| { | |
| if (isset($roundStructure->attributes)) | |
| { | |
| $roundStructure->destroy = round($logRow['gametime']); | |
| if (isset($roundStructure->attributes)) | |
| $roundStructure->save(); | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| $transaction->commit(); | |
| } | |
| catch (Exception $e) | |
| { | |
| echo "Error 1203: $e"; | |
| $transaction->rollback(); | |
| } | |
| Yii::endProfile('thirdLoop'); | |
| $this->round->parse_status = 0; | |
| $this->round->save(); | |
| rename($logPath, Yii::app()->params['logDirectory'] . 'completed/' . $this->round->log_file); | |
| $this->addTimeStamp("PARSE_FINISHED"); | |
| } | |
| protected function createPlayerRounds($playerList) | |
| { | |
| Yii::beginProfile('createPlayerRounds'); | |
| $this->addTimeStamp("CREATE_PLAYER_ROUNDS"); | |
| foreach ($playerList as $player) | |
| { | |
| // if (!isset($player['steamId'])) | |
| // { | |
| // echo "steamId not set: " . print_r($player,true); | |
| // die(); | |
| // } | |
| if (is_numeric($player['steamId']) && $player['steamId'] > 0 && ($player['teamnumber'] == 1 || $player['teamnumber'] == 2)) | |
| { | |
| Yii::beginProfile('createPlayerRoundIteration'); | |
| $playerId = Player::getIdBySteamId($player['steamId'], $player['ipaddress']); | |
| $playerModel = Player::model()->findByPk($playerId); | |
| $playerModel->ip = $player['ipaddress']; | |
| $playerModel->save(); | |
| $playerRound = new PlayerRound(); | |
| $playerRound->player_id = $playerId; | |
| $playerRound->round_id = $this->roundId; | |
| $playerRound->team = $player['teamnumber']; | |
| $playerRound->score = 0; | |
| if (!isset($player['name'])) | |
| $player['name'] = 'n/a'; | |
| $playerRound->name = $player['name']; | |
| $playerRound->start = 0; | |
| $playerRound->save(); | |
| //Set starting lifeform | |
| $playerRound->id = Yii::app()->db->getLastInsertID(); | |
| $this->playerRounds[$player['steamId']] = $playerRound; | |
| //lifeform fix 2014-11-1 | |
| if (!isset($player['lifeform']) && isset($player['Lifeform'])) | |
| $player['lifeform'] = $player['Lifeform']; | |
| $startingLifeFormData = array( | |
| 'steamId' => $player['steamId'], | |
| 'gametime' => 0, | |
| 'lifeform' => $player['lifeform'], | |
| ); | |
| $this->createLifeformChange($startingLifeFormData); | |
| Yii::endProfile('createPlayerRoundIteration'); | |
| } | |
| } | |
| Yii::endProfile('createPlayerRounds'); | |
| } | |
| protected function createDeath($logRow) | |
| { | |
| $this->addTimeStamp("CREATE_DEATH"); | |
| $death = new Death(); | |
| //Has attacker | |
| if (isset($logRow['attacker_steamId'])) | |
| { | |
| $death->attacker_team = $logRow['attacker_team']; | |
| $death->attacker_armor = intval($logRow['attacker_armor']); | |
| $death->attacker_health = intval(round($logRow['attacker_hp'])); | |
| $death->attacker_x = round($logRow['attackerx'], 3); | |
| $death->attacker_y = round($logRow['attackery'], 3); | |
| $death->attacker_z = round($logRow['attackerz'], 3); | |
| //Attacker is not a bot | |
| if (is_numeric($logRow['attacker_steamId']) && $logRow['attacker_steamId'] > 0) | |
| { | |
| // if (!isset($this->playerRounds[$logRow['attacker_steamId']])) { | |
| // foreach ($this->playerRounds as $player) | |
| // var_dump($player->attributes); | |
| // var_dump($logRow); | |
| // die(); | |
| // } | |
| $attacker = $this->playerRounds[$logRow['attacker_steamId']]; | |
| $death->attacker_id = $attacker->id; | |
| $death->attacker_weapon_id = $this->getWeaponIdByName($logRow['attacker_weapon']); | |
| $death->attacker_lifeform_id = $this->getLifeformIdByName($logRow['attacker_lifeform']); | |
| if (is_numeric($logRow['target_steamId']) && $logRow['target_steamId'] > 0) | |
| { | |
| Yii::beginProfile('calculateKillEloRank'); | |
| $target = $this->playerRounds[$logRow['target_steamId']]; | |
| $eloCalculator = new EloCalculator($attacker->player->kill_elo_rating, $target->player->kill_elo_rating, 1, 0); | |
| $eloResult = $eloCalculator->getNewRatings(); | |
| $attacker->player->kill_elo_rating = round($eloResult['a']); | |
| $target->player->kill_elo_rating = round($eloResult['b']); | |
| Yii::endProfile('calculateKillEloRank'); | |
| } | |
| } | |
| } | |
| if (is_numeric($logRow['target_steamId']) && $logRow['target_steamId'] > 0) | |
| { | |
| $target = $this->playerRounds[$logRow['target_steamId']]; | |
| $death->target_id = $target->id; | |
| $death->target_weapon_id = $this->getWeaponIdByName($logRow['target_weapon']); | |
| $death->target_lifeform_id = $this->getLifeformIdByName($logRow['target_lifeform']); | |
| $death->target_team = $logRow['target_team']; | |
| $death->target_x = round($logRow['targetx'], 3); | |
| $death->target_y = round($logRow['targety'], 3); | |
| $death->target_z = round($logRow['targetz'], 3); | |
| $death->target_lifetime = round($logRow['target_lifetime']); | |
| $death->time = round($logRow['gametime']); | |
| $death->save(); | |
| } | |
| } | |
| protected function createLifeformChange($logRow) | |
| { | |
| $this->addTimeStamp("CREATE_LIFEFORM_CHANGE"); | |
| //End old lifeform | |
| $this->endLifeForm($logRow['steamId'], $logRow['gametime']); | |
| //Save new lifeform | |
| if (isset($this->playerRounds[$logRow['steamId']])) | |
| { | |
| $playerRound = $this->playerRounds[$logRow['steamId']]; | |
| $playerLifeform = new PlayerLifeform(); | |
| $playerLifeform->player_round_id = $playerRound->id; | |
| //Separate Alien and Marine Commanders | |
| if ($logRow['lifeform'] == 'Commander' && $playerRound->team == 1) | |
| $logRow['lifeform'] = 'Marine Commander'; | |
| if ($logRow['lifeform'] == 'Commander' && $playerRound->team == 2) | |
| $logRow['lifeform'] = 'Alien Commander'; | |
| $playerLifeform->lifeform_id = $this->getLifeformIdByName($logRow['lifeform']); | |
| $playerLifeform->start = round($logRow['gametime']); | |
| $this->playerLifeforms[$logRow['steamId']] = $playerLifeform; | |
| } | |
| } | |
| protected function endLifeForm($steamId, $gameTime) | |
| { | |
| // $this->endWeapon($steamId, $gameTime); | |
| if (!empty($this->playerLifeforms[$steamId])) | |
| { | |
| $playerLifeform = $this->playerLifeforms[$steamId]; | |
| $playerLifeform->end = round($gameTime); | |
| // $pr = PlayerRound::model()->findByPk($playerLifeform->player_round_id); | |
| // var_dump($playerLifeform->player_round_id); | |
| // if(!$pr) | |
| // die(); | |
| $playerLifeform->save(); | |
| } | |
| } | |
| protected function joinTeam($logRow) | |
| { | |
| $this->addTimeStamp("JOIN_TEAM"); | |
| //End old player round | |
| $this->leaveTeam($logRow); | |
| //Join marines or aliens | |
| if ($logRow['team'] == 1 || $logRow['team'] == 2) | |
| { | |
| //Create new player round | |
| $playerId = Player::getIdBySteamId($logRow['steamId']); | |
| $playerRound = new PlayerRound(); | |
| $playerRound->player_id = $playerId; | |
| $playerRound->round_id = $this->roundId; | |
| $playerRound->team = $logRow['team']; | |
| $playerRound->score = 0; | |
| $playerRound->name = $logRow['name']; | |
| // $playerRound->name = ' asa'; | |
| $playerRound->start = round($logRow['gametime']); | |
| $playerRound->save(); | |
| $playerRound->id = Yii::app()->db->getLastInsertID(); | |
| $this->playerRounds[$logRow['steamId']] = $playerRound; | |
| } | |
| } | |
| protected function leaveTeam($logRow) | |
| { | |
| $this->addTimeStamp("LEAVE_TEAM"); | |
| $this->endLifeForm($logRow['steamId'], $logRow['gametime']); | |
| //End old player round | |
| if (!empty($this->playerRounds[$logRow['steamId']])) | |
| { | |
| $playerRound = $this->playerRounds[$logRow['steamId']]; | |
| $playerRound->end = round($logRow['gametime']); | |
| if (isset($logRow['score'])) | |
| $playerRound->score = $logRow['score']; | |
| $playerRound->save(); | |
| // $this->playerRounds[$logRow['steamId']] = null; | |
| } | |
| } | |
| protected function endRound($logRow) | |
| { | |
| $this->addTimeStamp("END_ROUND"); | |
| $playerList = $logRow['list']; | |
| foreach ($playerList as $player) | |
| { | |
| if (is_numeric($player['steamId']) && $player['steamId'] > 0) | |
| { | |
| if (isset($this->playerRounds[$player['steamId']])) | |
| { | |
| $playerRound = $this->playerRounds[$player['steamId']]; | |
| if ($playerRound->team == 1 || $playerRound->team == 2) | |
| { | |
| $playerRound->score = $player['score']; | |
| if (isset($player['assists'])) | |
| $playerRound->assists = $player['assists']; | |
| else | |
| { | |
| error_log('$player["assists"] were not defined ' . $this->logpath); | |
| $playerRound->assists = 0; | |
| } | |
| $playerRound->finished = 1; | |
| $playerRound->end = round($logRow['gametime']); | |
| if (isset($playerRound->attributes)) | |
| $playerRound->save(); | |
| if (isset($playerRound->player_id)) | |
| { | |
| $playerRound->player->ip = $player['ipaddress']; | |
| //rating> | |
| $ratingChange = 0; | |
| //win+lose | |
| if ($this->round->winner == $playerRound->team) | |
| $ratingChange += 30; | |
| else | |
| $ratingChange -= 15; | |
| //kills + deaths + assits, kills/deaths done with another way | |
| $ratingChange += $player['kills'] * 2; | |
| $ratingChange -= $player['deaths']; | |
| $ratingChange += $playerRound->assists; | |
| //commander bonus (TODO) | |
| //Score bonus (TODO) | |
| //modifiers (TODO) | |
| //apply rating | |
| $playerRound->player->rating += $ratingChange; | |
| //rating< | |
| $playerRound->player->save(); | |
| } | |
| } | |
| foreach ($player['weapons'] as $weapon) | |
| { | |
| $playerWeapon = new PlayerWeapon(); | |
| $playerWeapon->player_round_id = $playerRound->id; | |
| $playerWeapon->weapon_id = $this->getWeaponIdByName($weapon['name']); | |
| $playerWeapon->time = round($weapon['time']); | |
| $playerWeapon->miss = round($weapon['miss']); | |
| $playerWeapon->player_hit = round($weapon['player_hit']); | |
| $playerWeapon->player_damage = round($weapon['player_damage']); | |
| $playerWeapon->structure_hit = round($weapon['structure_hit']); | |
| $playerWeapon->structure_damage = round($weapon['structure_damage']); | |
| $playerWeapon->save(); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| protected function createUpgrade($logRow) | |
| { | |
| if (isset($logRow['commander_steamid']) && $logRow['commander_steamid'] != 0) | |
| { | |
| $roundUpgrade = new RoundUpgrade(); | |
| $roundUpgrade->round_id = $this->roundId; | |
| if (isset($logRow['name'])) | |
| $name = $logRow['name']; | |
| else | |
| $name = $logRow['upgrade_name']; | |
| $roundUpgrade->upgrade_id = $this->getUpgradeIdByName($name); | |
| $roundUpgrade->team = $logRow['team']; | |
| $roundUpgrade->cost = $logRow['cost']; | |
| $commander = $this->playerRounds[$logRow['commander_steamid']]; | |
| $roundUpgrade->commander_id = $commander->id; | |
| $this->upgrades[$logRow['structure_id'] . '-' . $logRow['upgrade_name']] = $roundUpgrade; | |
| } | |
| } | |
| protected function endUpgrade($logRow) | |
| { | |
| if ($logRow['upgrade_name'] !== 'AdvancedWeaponry') //does not have upgrade started, finishes same time with advancedarmory | |
| { | |
| if (!isset($this->upgrades[$logRow['structure_id'] . '-' . $logRow['upgrade_name']])) | |
| { | |
| //die("Undefined index on upgades: {$logRow['upgrade_name']} ({$logRow['structure_id']}) <br />" . print_r($logRow, true)); | |
| // | |
| //! WARNING! does not show notice if upgrade fails to save.. | |
| } | |
| else | |
| { | |
| $roundUpgrade = $this->upgrades[$logRow['structure_id'] . '-' . $logRow['upgrade_name']]; | |
| $roundUpgrade->time = round($logRow['gametime']); | |
| $roundUpgrade->save(); | |
| } | |
| } | |
| } | |
| protected function dropStructure($logRow) | |
| { | |
| if ($logRow['structure_name'] == 'PowerPoint') | |
| return; | |
| $roundStructure = new RoundStructure(); | |
| $roundStructure->round_id = $this->roundId; | |
| $roundStructure->structure_id = $this->getStructureIdByName($logRow['structure_name']); | |
| $roundStructure->team = $logRow['team']; | |
| $roundStructure->drop = round($logRow['gametime']); | |
| $roundStructure->cost = $logRow['structure_cost']; | |
| $roundStructure->x = $logRow['structure_x']; | |
| $roundStructure->y = $logRow['structure_y']; | |
| $roundStructure->z = $logRow['structure_z']; | |
| if ($logRow['steamId'] > 0) | |
| { | |
| $commander = $this->playerRounds[$logRow['steamId']]; | |
| $roundStructure->commander_id = $commander->id; | |
| } | |
| if (round($logRow['gametime']) == 0) | |
| $roundStructure->build = 0; | |
| $this->roundStructures[$logRow['id']] = $roundStructure; | |
| } | |
| protected function buildStructure($logRow) | |
| { | |
| if (!in_array($logRow['id'], array_keys($this->roundStructures))) | |
| return; | |
| if ($logRow['structure_name'] == 'Egg') | |
| return; | |
| $roundStructure = $this->roundStructures[$logRow['id']]; | |
| if (isset($roundStructure->attributes)) | |
| { | |
| if ($logRow['structure_name'] == 'Hydra') | |
| if ($roundStructure == null) | |
| { | |
| $this->dropStructure($logRow); | |
| $roundStructure = $this->roundStructures[$logRow['id']]; | |
| } | |
| $roundStructure->build = round($logRow['gametime']); | |
| if ($logRow['steamId'] > 0) | |
| { | |
| $builder = $this->playerRounds[$logRow['steamId']]; | |
| $roundStructure->builder_id = $builder->id; | |
| } | |
| $this->roundStructures[$logRow['id']] = $roundStructure; | |
| } | |
| } | |
| protected function destroyStructure($logRow, $killed = 0, $recycled = 0, $ghost = 0) | |
| { | |
| if (!in_array($logRow['id'], array_keys($this->roundStructures))) | |
| return; | |
| if ($this->roundStructures[$logRow['id']] == null) | |
| return; | |
| if ($logRow['structure_name'] == 'MAC' || $logRow['structure_name'] == 'ARC' || $logRow['structure_name'] == 'Drifter') | |
| return; | |
| if ($logRow['structure_name'] == 'Egg') | |
| return; | |
| $roundStructure = $this->roundStructures[$logRow['id']]; | |
| if ($killed && $logRow['killer_steamId'] > 0) | |
| { | |
| $attacker = $this->playerRounds[$logRow['killer_steamId']]; | |
| $roundStructure->attacker_id = $attacker->id; | |
| $roundStructure->attacker_lifeform_id = $this->getLifeformIdByName($logRow['killer_lifeform']); | |
| $roundStructure->attacker_weapon_id = $this->getWeaponIdByName($logRow['killerweapon']); | |
| } | |
| if ($recycled) | |
| { | |
| $roundStructure->recycle_res_back = round($logRow['givenback']); | |
| } | |
| if ($ghost) | |
| { | |
| $roundStructure->recycle_res_back = $roundStructure->cost; | |
| } | |
| $roundStructure->destroy = round($logRow['gametime']); | |
| if (isset($roundStructure->attributes)) | |
| $roundStructure->save(); | |
| $this->roundStructures[$logRow['id']] = null; | |
| } | |
| protected function hit($logRow) | |
| { | |
| $hit = new Hit(); | |
| //Has attacker | |
| if (isset($logRow['attacker_steamId'])) | |
| { | |
| $hit->attacker_team = $logRow['attacker_team']; | |
| $hit->attacker_armor = $logRow['attacker_armor']; | |
| $hit->attacker_health = round($logRow['attacker_hp']); | |
| $hit->attacker_x = round($logRow['attackerx'], 3); | |
| $hit->attacker_y = round($logRow['attackery'], 3); | |
| $hit->attacker_z = round($logRow['attackerz'], 3); | |
| //Attacker is not a bot | |
| if (is_numeric($logRow['attacker_steamId']) && $logRow['attacker_steamId'] > 0) | |
| { | |
| $attacker = $this->playerRounds[$logRow['attacker_steamId']]; | |
| $hit->attacker_id = $attacker->id; | |
| $hit->attacker_weapon_id = $this->getWeaponIdByName($logRow['attacker_weapon']); | |
| $hit->attacker_lifeform_id = $this->getLifeformIdByName($logRow['attacker_lifeform']); | |
| } | |
| } | |
| if ($logRow['action'] == 'hit_player') | |
| if (isset($logRow['target_steamId'])) | |
| { | |
| if (is_numeric($logRow['target_steamId']) && $logRow['target_steamId'] > 0) | |
| { | |
| $target = $this->playerRounds[$logRow['target_steamId']]; | |
| $hit->target_id = $target->id; | |
| } | |
| } | |
| $hit->target_weapon_id = $this->getWeaponIdByName($logRow['target_weapon']); | |
| $hit->target_lifeform_id = $this->getLifeformIdByName($logRow['target_lifeform']); | |
| $hit->target_team = $logRow['target_team']; | |
| if ($logRow['action'] == 'hit_player') | |
| { | |
| $hit->target_x = round($logRow['targetx'], 3); | |
| $hit->target_y = round($logRow['targety'], 3); | |
| $hit->target_z = round($logRow['targetz'], 3); | |
| } | |
| if ($logRow['action'] == 'hit_structure') | |
| { | |
| $roundStructure = $this->roundStructures[$logRow['id']]; | |
| $hit->target_structure_id = $roundStructure->id; | |
| $hit->target_x = round($logRow['structure_x'], 3); | |
| $hit->target_y = round($logRow['structure_y'], 3); | |
| $hit->target_z = round($logRow['structure_z'], 3); | |
| } | |
| $hit->damage_type = $logRow['damageType']; | |
| $hit->damage = round($logRow['damage'], 2); | |
| $hit->time = round($logRow['gametime']); | |
| if (!$hit->save()) | |
| error_log('save for hit_player failed:' . print_r($hit->getErrors(), true) . ' for row: ' . print_r($logRow, true)); | |
| } | |
| protected function dropPickable($logRow) | |
| { | |
| if ($logRow['name'] == 'nanoshield') | |
| return; | |
| $pickable = new Pickable(); | |
| $pickable->drop = round($logRow['gametime']); | |
| $pickable->cost = $logRow['cost']; | |
| $pickable->name = $logRow['name']; | |
| $pickable->team = $logRow['team']; | |
| $pickable->x = round($logRow['x'], 4); | |
| $pickable->y = round($logRow['y'], 4); | |
| $pickable->z = round($logRow['z'], 4); | |
| if ($logRow['commander_steamid'] > 0) | |
| { | |
| $commander = $this->playerRounds[$logRow['commander_steamid']]; | |
| $pickable->commander_id = $commander->id; | |
| } | |
| if (isset($logRow['instanthit'])) | |
| if ($logRow['instanthit']) | |
| $pickable->instant_hit = 1; | |
| else | |
| $pickable->instant_hit = 0; | |
| $this->pickables[$logRow['id']] = $pickable; | |
| } | |
| protected function pickPickable($logRow) | |
| { | |
| if ($logRow['name'] == 'nanoshield') | |
| return; | |
| $pickable = $this->pickables[$logRow['id']]; | |
| $pickable->pick = round($logRow['gametime']); | |
| $pickable->save(); | |
| } | |
| protected function destroyPickable($logRow) | |
| { | |
| if ($logRow['name'] == 'nanoshield') | |
| return; | |
| $pickable = $this->pickables[$logRow['id']]; | |
| $pickable->destroy = round($logRow['gametime']); | |
| $pickable->save(); | |
| } | |
| protected function resourcesGathered($logRow) | |
| { | |
| $resources = new Resources(); | |
| $resources->time = round($logRow['gametime']); | |
| $resources->team = $logRow['team']; | |
| $resources->gathered = $logRow['amount']; | |
| $resources->round_id = $this->roundId; | |
| $resources->save(); | |
| } | |
| protected function chatMessage($logRow) | |
| { | |
| if (isset($this->playerRounds[$logRow['steamid']])) | |
| { | |
| $playerRound = $this->playerRounds[$logRow['steamid']]; | |
| $chatMessage = new ChatMessage(); | |
| $chatMessage->message = $logRow['message']; | |
| $chatMessage->team_number = $logRow['team']; | |
| $chatMessage->player_round_id = $playerRound->id; | |
| if ($logRow['toteam'] == false) | |
| $chatMessage->to_team = 0; | |
| else | |
| $chatMessage->to_team = 1; | |
| $chatMessage->player_name = $logRow['name']; | |
| $chatMessage->gametime = round($logRow['gametime']); | |
| $chatMessage->save(); | |
| } | |
| } | |
| /* Cache functions */ | |
| protected function getWeaponIdByName($name) | |
| { | |
| if (!isset($this->weapons[$name])) | |
| { | |
| $weaponId = Weapon::getIdByName($name); | |
| $this->weapons[$name] = $weaponId; | |
| } | |
| return $this->weapons[$name]; | |
| } | |
| protected function getLifeformIdByName($name) | |
| { | |
| if (!isset($this->lifeforms[$name])) | |
| { | |
| $lifeformId = Lifeform::getIdByName($name); | |
| $this->lifeforms[$name] = $lifeformId; | |
| } | |
| return $this->lifeforms[$name]; | |
| } | |
| protected function getUpgradeIdByName($name) | |
| { | |
| if (!isset($this->upgrades[$name])) | |
| { | |
| $upgradeId = Upgrade::getIdByName($name); | |
| $this->upgrades[$name] = $upgradeId; | |
| } | |
| return $this->upgrades[$name]; | |
| } | |
| protected function getStructureIdByName($name) | |
| { | |
| if (!isset($this->structures[$name])) | |
| { | |
| $structureId = Structure::getIdByName($name); | |
| $this->structures[$name] = $structureId; | |
| } | |
| return $this->structures[$name]; | |
| } | |
| protected function deleteByPlayerCount($minPlayerCount, $playerRounds) | |
| { | |
| if (!YII_DEBUG) | |
| { | |
| $timePlayed = 0; | |
| // var_dump($this->round->attributes); | |
| foreach ($playerRounds as $playerRound) | |
| { | |
| // var_dump($playerRound->attributes); | |
| $timePlayed += $playerRound->end - $playerRound->start; | |
| } | |
| if ($timePlayed <= $minPlayerCount * ($this->round->end - $this->round->start)) | |
| { | |
| $this->round->delete(); | |
| $this->message->error = 'NOT_ENOUGH_PLAYERS'; | |
| echo json_encode($this->message); | |
| ob_flush(); | |
| $this->message->error = null; | |
| $this->addTimeStamp("NOT_ENOUGH_PLAYERS"); | |
| rename($this->logPath, Yii::app()->params['logDirectory'] . 'other/' . $this->round->log_file); | |
| $this->addTimeStamp("PARSE_FINISHED"); | |
| die(); | |
| } | |
| } | |
| } | |
| protected function findTeams($playerRounds) | |
| { | |
| $this->addTimeStamp("FIND_TEAMS"); | |
| $team1 = 0; | |
| $team2 = 0; | |
| foreach ($playerRounds as $playerRound) | |
| { | |
| $playerTeams = PlayerTeam::model()->findAllByAttributes(array('player_id' => $playerRound->player_id)); | |
| $playerTeamList = array(); | |
| foreach ($playerTeams as $playerTeam) | |
| $playerTeamList[] = $playerTeam->team_id; | |
| if ($playerRound->team == 1) | |
| if (is_array($team1)) | |
| $team1 = array_intersect($team1, $playerTeamList); | |
| else | |
| $team1 = $playerTeamList; | |
| if ($playerRound->team == 2) | |
| if (is_array($team2)) | |
| $team2 = array_intersect($team2, $playerTeamList); | |
| else | |
| $team2 = $playerTeamList; | |
| } | |
| if (isset($team1[0])) | |
| $this->round->team_1 = $team1[0]; | |
| if (isset($team2[0])) | |
| $this->round->team_2 = $team2[0]; | |
| $this->round->save(); | |
| } | |
| protected function calculateELOs($playerRounds) | |
| { | |
| Yii::beginProfile('calculateElos'); | |
| //Calculate team and commander ELO Ratings | |
| $team1EloRating = array(); | |
| $marineEloRating = array(); | |
| $team2EloRating = array(); | |
| $alienEloRating = array(); | |
| foreach ($playerRounds as $playerRound) | |
| { | |
| if ($playerRound->isCommander()) | |
| { | |
| if ($playerRound->team == 1) | |
| { | |
| $team1CommanderEloRating = $playerRound->player->commander_elo_rating; | |
| $marineCommanderEloRating = $playerRound->player->marine_commander_elo; | |
| } | |
| if ($playerRound->team == 2) | |
| { | |
| $team2CommanderEloRating = $playerRound->player->commander_elo_rating; | |
| $alienCommanderEloRating = $playerRound->player->alien_commander_elo; | |
| } | |
| } | |
| if ($playerRound->end - $playerRound->start > ($this->round->end - $this->round->start) * 0.5) | |
| { | |
| if ($playerRound->team == 1) | |
| { | |
| $team1EloRating[] = $playerRound->player->win_elo_rating; | |
| $marineEloRating[] = $playerRound->player->marine_win_elo; | |
| } | |
| if ($playerRound->team == 2) | |
| { | |
| $team2EloRating[] = $playerRound->player->win_elo_rating; | |
| $alienEloRating[] = $playerRound->player->alien_win_elo; | |
| } | |
| } | |
| } | |
| //avoid division by zero | |
| if (count($team1EloRating) !== 0 && count($team2EloRating) !== 0 && count($marineEloRating) !== 0 && count($alienEloRating) !== 0) | |
| { | |
| $team1EloRating = array_sum($team1EloRating) / count($team1EloRating); | |
| $team2EloRating = array_sum($team2EloRating) / count($team2EloRating); | |
| $marineEloRating = array_sum($marineEloRating) / count($marineEloRating); | |
| $alienEloRating = array_sum($alienEloRating) / count($alienEloRating); | |
| } | |
| else | |
| { | |
| $team1EloRating = 1500; | |
| $team2EloRating = 1500; | |
| $marineEloRating = 1500; | |
| $alienEloRating = 1500; | |
| } | |
| if (isset($team1CommanderEloRating) && isset($team2CommanderEloRating)) | |
| { | |
| $team1CommanderEloRating = ($team1CommanderEloRating + $team1EloRating) / 2; | |
| $team2CommanderEloRating = ($team2CommanderEloRating + $team2EloRating) / 2; | |
| $marineCommanderEloRating = ($marineCommanderEloRating + $marineEloRating) / 2; | |
| $alienCommanderEloRating = ($alienCommanderEloRating + $alienEloRating) / 2; | |
| if ($this->round->winner == 1) | |
| { | |
| $eloCalculator = new EloCalculator($team1CommanderEloRating, $team2CommanderEloRating, 1, 0); | |
| $commanderElos = $eloCalculator->getNewRatings(); | |
| $eloCalculator = new EloCalculator($marineCommanderEloRating, $alienCommanderEloRating, 1, 0); | |
| $marineAlienCommanderElos = $eloCalculator->getNewRatings(); | |
| } | |
| if ($this->round->winner == 2) | |
| { | |
| $eloCalculator = new EloCalculator($team1CommanderEloRating, $team2CommanderEloRating, 0, 1); | |
| $commanderElos = $eloCalculator->getNewRatings(); | |
| $eloCalculator = new EloCalculator($marineCommanderEloRating, $alienCommanderEloRating, 0, 1); | |
| $marineAlienCommanderElos = $eloCalculator->getNewRatings(); | |
| } | |
| } | |
| if ($this->round->winner == 1) | |
| { | |
| $eloCalculator = new EloCalculator($team1EloRating, $team2EloRating, 1, 0); | |
| $teamElos = $eloCalculator->getNewRatings(); | |
| $eloCalculator = new EloCalculator($marineEloRating, $alienEloRating, 1, 0); | |
| $marineAlienElos = $eloCalculator->getNewRatings(); | |
| } | |
| else if ($this->round->winner == 2) | |
| { | |
| $eloCalculator = new EloCalculator($team1EloRating, $team2EloRating, 0, 1); | |
| $teamElos = $eloCalculator->getNewRatings(); | |
| $eloCalculator = new EloCalculator($marineEloRating, $alienEloRating, 0, 1); | |
| $marineAlienElos = $eloCalculator->getNewRatings(); | |
| } | |
| $result = array( | |
| 'team1EloChange' => round($teamElos['a'] - $team1EloRating), | |
| 'team2EloChange' => round($teamElos['b'] - $team2EloRating), | |
| 'marineEloChange' => round($marineAlienElos['a'] - $marineEloRating), | |
| 'alienEloChange' => round($marineAlienElos['b'] - $alienEloRating), | |
| ); | |
| if (isset($commanderElos)) | |
| { | |
| $result['team1CommanderEloChange'] = round($commanderElos['a'] - $team1CommanderEloRating); | |
| $result['team2CommanderEloChange'] = round($commanderElos['b'] - $team2CommanderEloRating); | |
| $result['marineCommanderEloChange'] = round($marineAlienCommanderElos['a'] - $marineCommanderEloRating); | |
| $result['alienCommanderEloChange'] = round($marineAlienCommanderElos['b'] - $alienCommanderEloRating); | |
| } | |
| Yii::endProfile('calculateElos'); | |
| return $result; | |
| } | |
| protected function saveELOs() | |
| { | |
| $ELOs = $this->calculateELOs($this->playerRounds); | |
| foreach ($this->playerRounds as $playerRound) | |
| { | |
| if ($playerRound->team == 1 || $playerRound->team == 2) | |
| { | |
| //Save win ELO rankings | |
| if ($playerRound->end - $playerRound->start > ($this->round->end - $this->round->start) * 0.5) | |
| { | |
| if ($playerRound->team == 1) | |
| { | |
| $playerRound->player->win_elo_rating += $ELOs['team1EloChange']; | |
| $playerRound->player->marine_win_elo += $ELOs['marineEloChange']; | |
| } | |
| if ($playerRound->team == 2) | |
| { | |
| $playerRound->player->win_elo_rating += $ELOs['team2EloChange']; | |
| $playerRound->player->alien_win_elo += $ELOs['alienEloChange']; | |
| } | |
| } | |
| //Save commander ELO rankings | |
| if ($playerRound->isCommander()) | |
| { | |
| $playerRound->commander = 1; | |
| if (isset($ELOs['marineCommanderEloChange']) && isset($ELOs['alienCommanderEloChange'])) | |
| { | |
| if ($playerRound->team == 1) | |
| { | |
| $playerRound->player->commander_elo_rating += $ELOs['team1CommanderEloChange']; | |
| $playerRound->player->marine_commander_elo += $ELOs['marineCommanderEloChange']; | |
| } | |
| if ($playerRound->team == 2) | |
| { | |
| $playerRound->player->commander_elo_rating += $ELOs['team2CommanderEloChange']; | |
| $playerRound->player->alien_commander_elo += $ELOs['alienCommanderEloChange']; | |
| } | |
| } | |
| $playerRound->save(); | |
| } | |
| $playerRound->player->save(); | |
| } | |
| } | |
| } | |
| protected function saveMods($mods) | |
| { | |
| if (!is_array($mods)) | |
| $mods = explode(',', $mods); | |
| if (!is_array($mods)) | |
| return; | |
| foreach ($mods as $modName) | |
| { | |
| $modName = trim($modName); | |
| if (strlen($modName) > 0 && strpos($modName, 'NS2Stats') === false) | |
| { | |
| $modId = Mod::getIdByName($modName); | |
| $modRound = new ModRound(); | |
| $modRound->round_id = $this->roundId; | |
| $modRound->mod_id = $modId; | |
| $modRound->save(); | |
| } | |
| } | |
| } | |
| } |