diff --git a/DatabaseConverter.php b/DatabaseConverter.php index 09350277..6baac453 100644 --- a/DatabaseConverter.php +++ b/DatabaseConverter.php @@ -7,29 +7,33 @@ //Settings Begin //Connection Settings -$host = "localhost"; -$port = 3306; +$host = "localhost"; +$port = 3306; //Settings of Target Database $targetUser = "maniacontrol"; -$targetDb = "convert_test"; +$targetDb = "convert_test"; $targetPass = ""; //Settings of Source Database -$sourceUser = "maniacontrol"; -$sourceDb = "smesc12"; -$sourcePass = ""; +$sourceUser = "maniacontrol"; +$sourceDb = "smesc12"; +$sourcePass = ""; //Convert Hits to Kills (means each Hit gets Converted to one Kill -$convertHitsToKills = true; +$convertHitsToKills = true; +$convertHitsToLaserHits = true; +$convertShotsToLaserShots = true; //Settings END $converter = new DatabaseConverter($host, $port, $targetUser, $targetPass, $targetDb); $converter->connectToSourceDB($host, $port, $sourceUser, $sourcePass, $sourceDb); -$converter->convertHitsToKills = $convertHitsToKills; -$test1 = $converter->convertPlayersAndStatistics(); -$test2 = $converter->convertMapsAndKarma(); +$converter->convertHitsToKills = $convertHitsToKills; +$converter->convertHitsToLaserHits = $convertHitsToLaserHits; +$converter->convertShotsToLaserShots = $convertShotsToLaserShots; +$test1 = $converter->convertPlayersAndStatistics(); +$test2 = $converter->convertMapsAndKarma(); unset($converter); var_dump($test1 && $test2); @@ -51,6 +55,8 @@ class DatabaseConverter { * Public properties */ public $convertHitsToKills = true; + public $convertHitsToLaserHits = true; + public $convertShotsToLaserShots = true; /** * Private Properties @@ -153,6 +159,7 @@ class DatabaseConverter { /** * Converts the Map Karma + * * @param $serverIndex * @return bool */ @@ -236,9 +243,8 @@ class DatabaseConverter { $statement->close(); - //SELECT PlayerIndex, COUNT(*) FROM `mc_karma` GROUP BY PlayerIndex - $votedMapsQuery = "SELECT PlayerIndex, COUNT(*) as cnt FROM `".self::MC_TABLE_KARMA. "` GROUP BY PlayerIndex;"; + $votedMapsQuery = "SELECT PlayerIndex, COUNT(*) as cnt FROM `" . self::MC_TABLE_KARMA . "` GROUP BY PlayerIndex;"; $result = $this->mysqli->query($votedMapsQuery); @@ -263,7 +269,7 @@ class DatabaseConverter { continue; } - $statId = 15; + $statId = 17; $statement->bind_param('iiii', $row->PlayerIndex, $statId, $row->cnt, $serverIndex); $statement->execute(); if ($statement->error) { @@ -280,6 +286,7 @@ class DatabaseConverter { /** * Converts the Players and Statistics Table + * * @param $serverIndex * @return bool */ @@ -331,6 +338,11 @@ class DatabaseConverter { //Loop through all the players while($row = $result->fetch_object()) { + //Ignore Bots + if (strpos($row->Login, "*fakeplayer") !== false) { + continue; + } + $statement->bind_param('iss', $row->Id, $row->Login, $row->NickName); $statement->execute(); if ($statement->error) { @@ -379,11 +391,17 @@ class DatabaseConverter { $statStatement->bind_param('iiii', $row->Id, $statId, $row->Hits, $serverIndex); $statStatement->execute(); - if($this->convertHitsToKills){ + if ($this->convertHitsToKills) { $statId = 12; $statStatement->bind_param('iiii', $row->Id, $statId, $row->Hits, $serverIndex); $statStatement->execute(); } + + if ($this->convertHitsToLaserHits) { + $statId = 14; + $statStatement->bind_param('iiii', $row->Id, $statId, $row->Hits, $serverIndex); + $statStatement->execute(); + } } if ($row->GotHits > 0) { @@ -408,13 +426,25 @@ class DatabaseConverter { $statId = 13; $statStatement->bind_param('iiii', $row->Id, $statId, $row->Shots, $serverIndex); $statStatement->execute(); + + if ($this->convertShotsToLaserShots) { + $statId = 15; + $statStatement->bind_param('iiii', $row->Id, $statId, $row->Shots, $serverIndex); + $statStatement->execute(); + } } if ($row->attackerWon > 0) { - $statId = 14; + $statId = 16; $statStatement->bind_param('iiii', $row->Id, $statId, $row->attackerWon, $serverIndex); $statStatement->execute(); } + + if ($row->AllPoints > 0) { + $statId = 18; + $statStatement->bind_param('iiii', $row->Id, $statId, $row->AllPoints, $serverIndex); + $statStatement->execute(); + } } $statement->close(); @@ -425,6 +455,7 @@ class DatabaseConverter { /** * Konvert the Players Extra (Donations) + * * @param $serverIndex * @return bool */ @@ -613,7 +644,7 @@ class DatabaseConverter { (2, 'Servertime', 1, ''), (3, 'Donated Planets', 0, ''), (4, 'Survivals', 0, ''), - (5, 'Wins', 0, ''), + (5, 'Map Wins', 0, ''), (6, 'Near Misses', 0, ''), (7, 'Captures', 0, ''), (8, 'Hits', 0, ''), @@ -622,8 +653,11 @@ class DatabaseConverter { (11, 'Respawns', 0, ''), (12, 'Kills', 0, ''), (13, 'Shots', 0, ''), - (14, 'Won Attacks', 0, ''), - (15, 'Voted Maps', 0, '');"; + (14, 'Laser Hits', 0, ''), + (15, 'Laser Shots', 0, ''), + (16, 'Won Attacks', 0, ''), + (17, 'Voted Maps', 0, ''), + (18, 'Points', 0, '');"; $statement = $mysqli->prepare($query); if ($mysqli->error) { diff --git a/application/core/Server/RankingManager.php b/application/core/Server/RankingManager.php new file mode 100644 index 00000000..0ef21851 --- /dev/null +++ b/application/core/Server/RankingManager.php @@ -0,0 +1,108 @@ +rankings; + } + + /** + * Construct player manager + * + * @param \ManiaControl\ManiaControl $maniaControl + */ + public function __construct(ManiaControl $maniaControl) { //TODO statistic wins + $this->maniaControl = $maniaControl; + + //Register Callbacks + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_MP_MODESCRIPTCALLBACK, $this, 'handleCallbacks'); + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_MP_MODESCRIPTCALLBACKARRAY, $this, 'handleCallbacks'); + $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_MC_ONINIT, $this, 'onInit'); + //TODO won message at end of the map (disable as setting) + } + + /** + * Initialize the Rankings + */ + public function onInit() { + $this->maniaControl->client->triggerModeScriptEvent('LibXmlRpc_GetRankings', ''); + } + + + /** + * Handle stats on callbacks + * + * @param array $callback + */ + public function handleCallbacks(array $callback) { + $callbackName = $callback[1][0]; + + //TODO not tested in TrackMania + switch($callbackName) { + case 'LibXmlRpc_Rankings': + case 'updateRankings': + $this->updateRankings($callback[1][1][0]); + break; + case 'endRound': + case 'beginRound': + case 'endMap': + case 'endMap1': + $this->updateRankings($callback[1]); + break; + } + } + + /** + * Update Game Rankings + * + * @param $data + */ + private function updateRankings($data) { + $scores = explode(';', $data); + foreach($scores as $player) { + if (strpos($player, ':') !== false) { + $tmp = explode(':', $player); + $this->rankings[$tmp[0]] = $tmp[1]; + } + } + array_multisort($this->rankings, SORT_DESC, SORT_NUMERIC); + + //TODO if Local Records activated-> sort asc + } + + /** + * Get the Current Leading Players (as Login Array) + * + * @return array|null + */ + public function getLeaders() { + $leaders = array(); + $prev = -1; + foreach($this->rankings as $player => $score) { + if ($prev != -1 && $prev < $score) { + return $leaders; + } + array_push($leaders, $leader); + $prev = $score; + } + return null; + } +} \ No newline at end of file diff --git a/application/core/Server/Server.php b/application/core/Server/Server.php index af46aaef..20b372c6 100644 --- a/application/core/Server/Server.php +++ b/application/core/Server/Server.php @@ -33,7 +33,7 @@ class Server implements CallbackListener { public $dataDirectory = ''; public $serverCommands = null; public $usageReporter = null; - + public $rankingManager = null; /** * Private Properties @@ -52,6 +52,7 @@ class Server implements CallbackListener { $this->serverCommands = new ServerCommands($maniaControl); $this->usageReporter = new UsageReporter($maniaControl); + $this->rankingManager = new RankingManager($maniaControl); // Register for callbacks $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_MC_ONINIT, $this, 'onInit'); diff --git a/application/core/Statistics/SimpleStatsList.php b/application/core/Statistics/SimpleStatsList.php index 779d3708..2e3be268 100644 --- a/application/core/Statistics/SimpleStatsList.php +++ b/application/core/Statistics/SimpleStatsList.php @@ -74,9 +74,9 @@ class SimpleStatsList implements ManialinkPageAnswerListener, CallbackListener, $this->registerStat(StatisticCollector::STAT_ON_DEATH, 50, "D"); $this->registerStat(StatisticCollector::STAT_ON_CAPTURE, 60, "C"); - $this->registerStat(StatisticManager::SPECIAL_STAT_KD_RATIO, 70, "K/D", 10, StatisticManager::STAT_TYPE_FLOAT); - $this->registerStat(StatisticManager::SPECIAL_STAT_LASER_ACC, 80, "Lacc", 13, StatisticManager::STAT_TYPE_FLOAT); - $this->registerStat(StatisticManager::SPECIAL_STAT_HITS_PH, 85, "H/h", 13, StatisticManager::STAT_TYPE_FLOAT); + $this->registerStat(StatisticManager::SPECIAL_STAT_KD_RATIO, 70, "K/D", 12, StatisticManager::STAT_TYPE_FLOAT); + $this->registerStat(StatisticManager::SPECIAL_STAT_LASER_ACC, 80, "Lacc", 15, StatisticManager::STAT_TYPE_FLOAT); + $this->registerStat(StatisticManager::SPECIAL_STAT_HITS_PH, 85, "H/h", 15, StatisticManager::STAT_TYPE_FLOAT); } /** @@ -90,7 +90,7 @@ class SimpleStatsList implements ManialinkPageAnswerListener, CallbackListener, } - public function registerStat($statName, $order, $headShortCut, $width = 8, $format = StatisticManager::STAT_TYPE_INT) { + public function registerStat($statName, $order, $headShortCut, $width = 10, $format = StatisticManager::STAT_TYPE_INT) { $this->statArray[$order] = array(); $this->statArray[$order]["Name"] = $statName; $this->statArray[$order]["HeadShortCut"] = '$o' . $headShortCut; diff --git a/application/core/Statistics/StatisticCollector.php b/application/core/Statistics/StatisticCollector.php index 6580ec2d..eb00b745 100644 --- a/application/core/Statistics/StatisticCollector.php +++ b/application/core/Statistics/StatisticCollector.php @@ -23,6 +23,7 @@ class StatisticCollector implements CallbackListener { * Statistics */ const STAT_PLAYTIME = 'Play Time'; + const STAT_MAP_WINS = 'Map Wins'; const STAT_ON_SHOOT = 'Shots'; const STAT_ON_NEARMISS = 'Near Misses'; const STAT_ON_CAPTURE = 'Captures'; @@ -53,6 +54,7 @@ class StatisticCollector implements CallbackListener { private $maniaControl = null; private $onShootArray = array(); + /** * Construct player manager * @@ -81,6 +83,7 @@ class StatisticCollector implements CallbackListener { public function onInit(array $callback) { //Define Stats MetaData $this->maniaControl->statisticManager->defineStatMetaData(self::STAT_PLAYTIME, StatisticManager::STAT_TYPE_TIME); + $this->maniaControl->statisticManager->defineStatMetaData(self::STAT_MAP_WINS); $this->maniaControl->statisticManager->defineStatMetaData(self::STAT_ON_SHOOT); $this->maniaControl->statisticManager->defineStatMetaData(self::STAT_ON_NEARMISS); $this->maniaControl->statisticManager->defineStatMetaData(self::STAT_ON_CAPTURE); @@ -99,6 +102,25 @@ class StatisticCollector implements CallbackListener { $this->maniaControl->statisticManager->defineStatMetaData(self::STAT_ARROW_SHOT); } + /** + * Handle EndMap + * + * @param array $callback + */ + public function onEndMap(array $callback) { + //Check for Minimum PlayerCount + if (count($this->maniaControl->playerManager->getPlayers()) < $this->maniaControl->settingManager->getSetting($this, self::SETTING_COLLECT_STATS_MINPLAYERS)) { + return; + } + + $leaders = $this->maniaControl->server->rankingManager->getLeaders(); + + foreach($leaders as $leaderLogin) { + $leader = $this->maniaControl->playerManager->getPlayer($leaderLogin); + $this->maniaControl->statisticManager->incrementStat(self::STAT_MAP_WINS, $leader); + } + } + /** * Handle Player Shoots * @@ -142,7 +164,6 @@ class StatisticCollector implements CallbackListener { } } - /** * Gets the Weapon stat * @@ -179,7 +200,6 @@ class StatisticCollector implements CallbackListener { } } - /** * Insert OnShoot Statistic when a player leaves * @@ -213,7 +233,7 @@ class StatisticCollector implements CallbackListener { return; } - //Check for Minplayer + //Check for Minimum PlayerCount if (count($this->maniaControl->playerManager->getPlayers()) < $this->maniaControl->settingManager->getSetting($this, self::SETTING_COLLECT_STATS_MINPLAYERS)) { return; } diff --git a/application/core/Statistics/StatisticManager.php b/application/core/Statistics/StatisticManager.php index 95ede3ad..e52a9716 100644 --- a/application/core/Statistics/StatisticManager.php +++ b/application/core/Statistics/StatisticManager.php @@ -65,6 +65,52 @@ class StatisticManager { * @return int */ public function getStatisticData($statName, $playerId, $serverIndex = -1) { + //Handle Special Stats + switch($statName) { + case self::SPECIAL_STAT_KD_RATIO: + $kills = $this->getStatisticData(StatisticCollector::STAT_ON_KILL, $playerId, $serverIndex); + $deaths = $this->getStatisticData(StatisticCollector::STAT_ON_DEATH, $playerId, $serverIndex); + if ($deaths == 0) { + return -1; + } + return intval($kills) / intval($deaths); + case self::SPECIAL_STAT_HITS_PH: + $hits = $this->getStatisticData(StatisticCollector::STAT_ON_HIT, $playerId, $serverIndex); + $time = $this->getStatisticData(StatisticCollector::STAT_PLAYTIME, $playerId, $serverIndex); + if ($time == 0) { + return -1; + } + return intval($hits) / (intval($time) / 3600); + case self::SPECIAL_STAT_ARROW_ACC: + $hits = $this->getStatisticData(StatisticCollector::STAT_ARROW_HIT, $playerId, $serverIndex); + $shots = $this->getStatisticData(StatisticCollector::STAT_ARROW_SHOT, $playerId, $serverIndex); + if ($shots == 0) { + return -1; + } + return intval($hits) / intval($shots); + case self::SPECIAL_STAT_LASER_ACC: + $hits = $this->getStatisticData(StatisticCollector::STAT_LASER_HIT, $playerId, $serverIndex); + $shots = $this->getStatisticData(StatisticCollector::STAT_LASER_SHOT, $playerId, $serverIndex); + if ($shots == 0) { + return -1; + } + return intval($hits) / intval($shots); + case self::SPECIAL_STAT_NUCLEUS_ACC: + $hits = $this->getStatisticData(StatisticCollector::STAT_NUCLEUS_HIT, $playerId, $serverIndex); + $shots = $this->getStatisticData(StatisticCollector::STAT_NUCLEUS_SHOT, $playerId, $serverIndex); + if ($shots == 0) { + return -1; + } + return intval($hits) / intval($shots); + case self::SPECIAL_STAT_ROCKET_ACC: + $hits = $this->getStatisticData(StatisticCollector::STAT_ROCKET_HIT, $playerId, $serverIndex); + $shots = $this->getStatisticData(StatisticCollector::STAT_ROCKET_SHOT, $playerId, $serverIndex); + if ($shots == 0) { + return -1; + } + return intval($hits) / intval($shots); + } + $mysqli = $this->maniaControl->database->mysqli; $statId = $this->getStatId($statName); @@ -81,7 +127,7 @@ class StatisticManager { $result = $mysqli->query($query); if (!$result) { trigger_error($mysqli->error); - return null; + return -1; } $row = $result->fetch_object(); @@ -108,7 +154,7 @@ class StatisticManager { $statId = $this->getStatId($statName); if ($minValue == -1) { - $query = "SELECT playerId, serverIndex, value FROM `" . self::TABLE_STATISTICS . "` WHERE statId = " . $statId . " ORDER BY value DESC LIMIT 100;"; + $query = "SELECT playerId, serverIndex, value FROM `" . self::TABLE_STATISTICS . "` WHERE statId = " . $statId . " ORDER BY value DESC;"; } else { $query = "SELECT playerId, serverIndex, value FROM `" . self::TABLE_STATISTICS . "` WHERE statId = " . $statId . " AND value >= " . $minValue . " ORDER BY value DESC;"; } diff --git a/application/plugins/ServerRanking.php b/application/plugins/ServerRanking.php index c368d8c7..80c56209 100644 --- a/application/plugins/ServerRanking.php +++ b/application/plugins/ServerRanking.php @@ -66,9 +66,10 @@ class ServerRankingPlugin implements Plugin, CallbackListener, CommandListener { $titleId = $this->maniaControl->server->titleId; $titlePrefix = strtolower(substr($titleId, 0, 2)); + if ($titlePrefix == 'tm') { //TODO also add obstacle here as default $maniaControl->settingManager->initSetting($this, self::SETTING_MIN_RANKING_TYPE, self::RANKING_TYPE_RECORDS); - } else if ($this->maniaControl->client->getScriptName() == "InstaDM.Script.txt") { + } else if ($this->maniaControl->client->getScriptName()["CurrentValue"] == "InstaDM.Script.txt") { $maniaControl->settingManager->initSetting($this, self::SETTING_MIN_RANKING_TYPE, self::RANKING_TYPE_RATIOS); } else { $maniaControl->settingManager->initSetting($this, self::SETTING_MIN_RANKING_TYPE, self::RANKING_TYPE_HITS); @@ -88,6 +89,8 @@ class ServerRankingPlugin implements Plugin, CallbackListener, CommandListener { //Register CommandListener $this->maniaControl->commandManager->registerCommandListener('rank', $this, 'command_showRank', false); $this->maniaControl->commandManager->registerCommandListener('nextrank', $this, 'command_nextRank', false); + + $this->resetRanks(); //TODO only update records count } /** @@ -184,11 +187,13 @@ class ServerRankingPlugin implements Plugin, CallbackListener, CommandListener { if (!isset($killDeathRatios[$player]) || !isset($accuracies[$player])) { continue; } - $ranks[$player] = $killDeathRatios[$player] * $accuracies[$player]; + $ranks[$player] = $killDeathRatios[$player] * $accuracies[$player] * 1000; + } arsort($ranks); + break; case self::RANKING_TYPE_HITS: $minHits = $this->maniaControl->settingManager->getSetting($this, self::SETTING_MIN_HITS_HITS_RANKING); @@ -273,8 +278,7 @@ class ServerRankingPlugin implements Plugin, CallbackListener, CommandListener { * @param array $callback */ public function handlePlayerConnect(array $callback) { - $login = $callback[1][0]; - $player = $this->maniaControl->playerManager->getPlayer($login); + $player = $callback[1]; if (!$player) { return; } @@ -314,7 +318,9 @@ class ServerRankingPlugin implements Plugin, CallbackListener, CommandListener { if ($rankObj != null) { switch($type) { case self::RANKING_TYPE_RATIOS: - $message = '$0f3Your Server rank is $<$ff3' . $rankObj->rank . '$> / $<$fff' . $this->recordCount . '$> Ratio: $fff' . round($rankObj->avg, 2); + $kd = $this->maniaControl->statisticManager->getStatisticData(StatisticManager::SPECIAL_STAT_KD_RATIO, $player->index); + $acc = $this->maniaControl->statisticManager->getStatisticData(StatisticManager::SPECIAL_STAT_LASER_ACC, $player->index); + $message = '$0f3Your Server rank is $<$ff3' . $rankObj->rank . '$> / $<$fff' . $this->recordCount . '$> (K/D: $<$fff' . round($kd, 2) . '$> Acc: $<$fff' . round($acc * 100) . '%$>)'; break; case self::RANKING_TYPE_HITS: $message = '$0f3Your Server rank is $<$ff3' . $rankObj->rank . '$> / $<$fff' . $this->recordCount . '$> Hits: $fff' . $rankObj->avg;