[ 'gamemode' => ['Champion'], 'type' => 'integer', 'default' => 2, 'description' => 'Point bonus for who made the best lap time' ], self::SETTING_MATCH_S_CHATTIME => [ 'gamemode' => ['Global'], 'type' => 'integer', 'default' => 10, 'description' => 'Time before loading the next map' ], self::SETTING_MATCH_S_CUMULATEPOINTS => [ 'gamemode' => ['Teams'], 'type' => 'boolean', 'default' => false, 'description' => 'Cumulate players points to the team score (false = 1 point to the winner team)' ], self::SETTING_MATCH_S_DISABLEGIVEUP => [ 'gamemode' => ['Champion', 'Laps'], 'type' => 'boolean', 'default' => false, 'description' => 'Disable GiveUp' ], self::SETTING_MATCH_S_EARLYENDMATCHCALLBACK => [ 'gamemode' => ['Champion', 'Knockout'], 'type' => 'boolean', 'default' => true, 'description' => 'Send End Match Callback early (expert user only)' ], self::SETTING_MATCH_S_ELIMINATEDPLAYERSNBRANKS => [ 'gamemode' => ['Knockout'], 'type' => 'string', 'default' => '4', 'description' => 'Rank at which one more player is eliminated per round (use coma to add more values. Ex COTD: 8,16,16)' ], self::SETTING_MATCH_S_ENDROUNDPOSTSCOREUPDATEDURATION => [ 'gamemode' => ['Champion'], 'type' => 'integer', 'default' => 5, 'description' => 'Time after score computed on scoreboard' ], self::SETTING_MATCH_S_ENDROUNDPRESCOREUPDATEDURATION => [ 'gamemode' => ['Champion'], 'type' => 'integer', 'default' => 5, 'description' => 'Time before score computed on scoreboard' ], self::SETTING_MATCH_S_FINISHTIMEOUT => [ 'gamemode' => ['Champion', 'Cup', 'Knockout', 'Laps', 'Teams', 'Rounds'], 'type' => 'integer', 'default' => 10, 'description' => 'Time after the first finished (-1 = based on Author time)' ], self::SETTING_MATCH_S_FORCELAPSNB => [ 'gamemode' => ['Global'], 'type' => 'integer', 'default' => -1, 'description' => 'Force number of laps for laps maps (-1 = author, 0 for unlimited in TA)' ], self::SETTING_MATCH_S_FORCEWINNERSNB => [ 'gamemode' => ['Champion'], 'type' => 'integer', 'default' => 0, 'description' => 'Force the number of players who will win points (0 = for use S_WinnersRatio)' ], self::SETTING_MATCH_S_INFINITELAPS => [ 'gamemode' => ['Global'], 'type' => 'boolean', 'default' => false, 'description' => 'Never end a race in laps (override S_ForceLapsNb)' ], self::SETTING_MATCH_S_MAPSPERMATCH => [ 'gamemode' => ['Teams', 'Rounds'], 'type' => 'integer', 'default' => 3, 'description' => 'Number of maps maximum in the match' ], self::SETTING_MATCH_S_MATCHPOSITION => [ 'gamemode' => ['Knockout'], 'type' => 'integer', 'default' => -1, 'description' => 'Server number to define global player rank (by server of 64, used for COTD, mostly useless)' ], self::SETTING_MATCH_S_MAXPOINTSPERROUND => [ 'gamemode' => ['Teams'], 'type' => 'integer', 'default' => 6, 'description' => 'The maximum number of points attributed to the first player (exclude by S_UseCustomPointsRepartition)' ], self::SETTING_MATCH_S_NBOFWINNERS => [ 'gamemode' => ['Cup'], 'type' => 'integer', 'default' => 1, 'description' => 'Number of winners' ], self::SETTING_MATCH_S_PAUSEBEFOREROUNDNB => [ 'gamemode' => ['Champion'], 'type' => 'integer', 'default' => 0, 'description' => 'Run a pause before the round number (depend of S_PauseDuration) (0 = disabled)' ], self::SETTING_MATCH_S_PAUSEDURATION => [ 'gamemode' => ['Champion'], 'type' => 'integer', 'default' => 360, 'description' => 'Pause time in seconds (depend of S_PauseBeforeRoundNb) (0 = disabled)' ], self::SETTING_MATCH_S_POINTSGAP => [ 'gamemode' => ['Teams'], 'type' => 'integer', 'default' => 0, 'description' => 'Points Gap to win (depend of S_PointsLimit & S_UseTieBreak)' ], self::SETTING_MATCH_S_POINTSLIMIT => [ 'gamemode' => ['Champion', 'Cup', 'Teams', 'Rounds'], 'type' => 'integer', 'default' => 100, 'description' => 'Limit number of points (0 = unlimited for Ch & R)' ], self::SETTING_MATCH_S_POINTSREPARTITION => [ 'gamemode' => ['Champion', 'Cup', 'Knockout', 'Teams', 'Rounds'], 'type' => 'string', 'default' => '10,6,4,3,2,1', 'description' => 'Point repartition from first to last' ], self::SETTING_MATCH_S_RESPAWNBEHAVIOUR => [ 'gamemode' => ['Global'], 'type' => 'integer', 'default' => [0,1,2,3,4,5], 'description' => 'Respawn behavior (0 = GM setting, 1 = normal, 2 = do nothing, 3 = DNF before 1st CP, 4 = always DNF, 5 = never DNF)' ], self::SETTING_MATCH_S_ROUNDSLIMIT => [ 'gamemode' => ['Champion'], 'type' => 'integer', 'default' => 6, 'description' => 'Number of rounds to play before finding a winner of the step' ], self::SETTING_MATCH_S_ROUNDSPERMAP => [ 'gamemode' => ['Cup', 'Knockout', 'Teams', 'Rounds'], 'type' => 'integer', 'default' => 5, 'description' => 'Number of rounds par map (0 = unlimited) (multiple maps doesn\'t work in KO)' ], self::SETTING_MATCH_S_ROUNDSWITHAPHASECHANGE => [ 'gamemode' => ['Champion'], 'type' => 'string', 'default' => '3,5', 'description' => 'Rounds with a Phase change (Openning, Semi-Final, Final)' ], self::SETTING_MATCH_S_ROUNDSWITHOUTELIMINATION => [ 'gamemode' => ['Knockout'], 'type' => 'integer', 'default' => 1, 'description' => 'Rounds without elimination (like a Warmup, but just for the first map)' ], self::SETTING_MATCH_S_TIMELIMIT => [ 'gamemode' => ['Champion', 'Laps', 'TimeAttack'], 'type' => 'integer', 'default' => 600, 'description' => 'Time limit (0 = unlimited)' ], self::SETTING_MATCH_S_TIMEOUTPLAYERSNUMBER => [ 'gamemode' => ['Champion'], 'type' => 'integer', 'default' => 0, 'description' => 'Number of players who must finish before starting S_FinishTimeout (0 = S_ForceWinnersNb)' ], self::SETTING_MATCH_S_USEALTERNATERULES => [ 'gamemode' => ['Teams'], 'type' => 'boolean', 'default' => false, 'description' => 'F: Give 1 point to the all first players of a team | T: MaxPoints - Rank - 1 (exclude by S_UseCustomPointsRepartition)' ], self::SETTING_MATCH_S_USECUSTOMPOINTSREPARTITION => [ 'gamemode' => ['Teams'], 'type' => 'boolean', 'default' => false, 'description' => 'Use S_PointsRepartition (instead of rules defined by S_UseAlternateRules)' ], self::SETTING_MATCH_S_USETIEBREAK => [ 'gamemode' => ['Champion', 'Teams', 'Rounds'], 'type' => 'boolean', 'default' => false, 'description' => 'Use Tie Break (Only available when S_MapsPerMatch > 1)' ], self::SETTING_MATCH_S_WARMUPDURATION => [ 'gamemode' => ['Global'], 'type' => 'integer', 'default' => -1, 'description' => 'Duration of 1 Warm Up in sec (-1 = one round, 0 = based on Author time)' ], self::SETTING_MATCH_S_WARMUPNB => [ 'gamemode' => ['Global'], 'type' => 'integer', 'default' => 1, 'description' => 'Number of Warm Up' ], self::SETTING_MATCH_S_WARMUPTIMEOUT => [ 'gamemode' => ['Global'], 'type' => 'integer', 'default' => -1, 'description' => 'Time after the first finished the WarmUP (-1 = based on Author time, only when S_WarmUpDuration = -1)' ], self::SETTING_MATCH_S_WINNERSRATIO => [ 'gamemode' => ['Champion'], 'type' => 'float', 'default' => 0.5, 'description' => 'Ratio of players who will win points' ] ]; /* * Private properties */ private $matchStarted = false; /** @var ManiaControl $maniaControl */ private $maniaControl = null; private $chatprefix = '$<$fc3$w🏆$m$> '; // Would like to create a setting but MC database doesn't support utf8mb4 private $times = array(); private $nbmaps = 0; private $nbrounds = 0; private $playersreadystate = array(); private $nbplayers = 0; private $nbspectators = 0; private $currentgmbase = ""; private $currentmap = null; // Settings to keep in memory private $settings_nbroundsbymap = 5; private $settings_nbwinner = 2; private $settings_nbmapsbymatch = 0; private $settings_pointlimit = 100; private $nbwinners = 0; private $nbstillalive = 0; private $scriptSettings = array(); private $currentscore = array(); private $currentteamsscore = array(); private $playerpause = array(); private $pausetimer = 0; private $pauseasked = false; private $pauseon = false; private $pauseaskedbyplayer = ""; private $numberpause = 0; private $skipround = false; private $settingsloaded = false; private $postmatch = false; private $mapsshuffled = false; private $currentgmsettings = []; private $matchid = ""; /** * @param ManiaControl $maniaControl * @see \ManiaControl\Plugins\Plugin::prepare() */ public static function prepare(ManiaControl $maniaControl) { } /** * @see \ManiaControl\Plugins\Plugin::getId() */ public static function getId() { return self::PLUGIN_ID; } /** * @see \ManiaControl\Plugins\Plugin::getName() */ public static function getName() { return self::PLUGIN_NAME; } /** * @see \ManiaControl\Plugins\Plugin::getVersion() */ public static function getVersion() { return self::PLUGIN_VERSION; } /** * @see \Man$this->maniaControl = $maniaControl;iaControl\Plugins\Plugin::getAuthor() */ public static function getAuthor() { return self::PLUGIN_AUTHOR; } /** * @see \ManiaControl\Plugins\Plugin::getDescription() */ public static function getDescription() { return 'Plugin offers a match Plugin'; } public function load(ManiaControl $maniaControl) { // Init plugin $this->maniaControl = $maniaControl; $this->initTables(); $this->maniaControl->getModeScriptEventManager()->unblockCallback("Trackmania.Event.WayPoint"); $this->maniaControl->getModeScriptEventManager()->unBlockAllCallbacks(); $this->maniaControl->getModeScriptEventManager()->enableCallbacks(); //Settings $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_AUTHLEVEL, AuthenticationManager::getPermissionLevelNameArray(AuthenticationManager::AUTH_LEVEL_ADMIN), "Admin level needed to use the plugin"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_CUSTOM_GAMEMODE, "", "Load custom gamemode script (some functions can bug, for expert only)"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_GAMEMODE_AFTERMATCH, array("TimeAttack"), "Gamemode to launch after the match"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_GAMEMODE_BASE, array("Champion", "Cup", "Knockout", "Laps", "Teams", "TimeAttack", "Rounds"), "Gamemode to launch for the match"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_LOAD_MAPLIST_FILE, true, "Load Maps + Matchsettings from the file (or use the current maplist on the server)"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_MAPLIST, "match.txt", "Maps + Matchsettings file to load (empty to use server login)"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_MATCHSETTINGS_CONF, false, "Load configuration from matchsettings file instead of Admin Interface (can be usefull with a custom script)"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_PAUSE_DURATION, 120, "Default Pause Duration in seconds"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_PAUSE_MAXNUMBER, 0, "Number of pause a player can ask during a match"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_PAUSE_POSX, 0, "Position of the Pause Countdown (on X axis)"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_PAUSE_POSY, 43, "Position of the Pause Countdown (on Y axis)"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_READY_HEIGHT, 6, "Height of the Ready widget"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_READY_MODE, false, "Activate Ready widget"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_READY_NBPLAYERS, 2, "Minimal number of players to start a match if all are ready"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_READY_POSX, 152.5, "Position of the Ready widget (on X axis)"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_READY_POSY, 40, "Position of the Ready widget (on Y axis)"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_READY_WIDTH, 15, "Width of the Ready widget"); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_SHUFFLEMAPS, true, "Shuffle maps order"); // Gamemodes Settings foreach (self::GAMEMODES_LIST_SETTINGS as $setting => $n) { $this->maniaControl->getSettingManager()->initSetting($this, $setting, $n['default'], $this->getDescriptionPrefix($setting) . $n['description']); } //Register Admin Commands $this->maniaControl->getCommandManager()->registerCommandListener('matchstart', $this, 'onCommandMatchStart', true, 'Start a match'); $this->maniaControl->getCommandManager()->registerCommandListener('matchstop', $this, 'onCommandMatchStop', true, 'Stop a match'); $this->maniaControl->getCommandManager()->registerCommandListener('matchendround', $this, 'onCommandMatchEndRound', true, 'Force end a round during a match'); $this->maniaControl->getCommandManager()->registerCommandListener('matchendwu', $this, 'onCommandMatchEndWU', true, 'Force end a WU during a match'); $this->maniaControl->getCommandManager()->registerCommandListener('matchsetpoints', $this, 'onCommandSetPoints', true, 'Sets points to a player.'); $this->maniaControl->getCommandManager()->registerCommandListener(array('matchpause','pause'), $this, 'onCommandSetPause', true, 'Set pause during a match. [time] in seconds can be added to force another value'); $this->maniaControl->getCommandManager()->registerCommandListener(array('matchendpause','endpause'), $this, 'onCommandUnsetPause', true, 'End the pause during a match.'); //Register Player Commands $this->maniaControl->getCommandManager()->registerCommandListener('pause', $this, 'onCommandSetPausePlayer', false, 'Set pause during a match.'); $this->maniaControl->getCommandManager()->registerCommandListener('ready', $this, 'onCommandSetReadyPlayer', false, 'Change status to Ready.'); //Register Callbacks $this->maniaControl->getCallbackManager()->registerCallbackListener(SettingManager::CB_SETTING_CHANGED, $this, 'updateSettings'); $this->maniaControl->getCallbackManager()->registerCallbackListener(GameModeSettings::CB_GAMEMODESETTINGS_CHANGED, $this, 'updateGMvariables'); $this->maniaControl->getCallbackManager()->registerCallbackListener(PlayerManager::CB_PLAYERCONNECT, $this, 'handlePlayerConnect'); $this->maniaControl->getCallbackManager()->registerCallbackListener(PlayerManager::CB_PLAYERDISCONNECT, $this, 'handlePlayerDisconnect'); $this->maniaControl->getCallbackManager()->registerCallbackListener(PlayerManager::CB_PLAYERINFOCHANGED, $this, 'handlePlayerInfoChanged'); $this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::TM_SCORES, $this, 'handleEndRoundCallback'); $this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::MP_STARTROUNDSTART, $this, 'handleBeginRoundCallback'); $this->maniaControl->getCallbackManager()->registerCallbackListener(CallbackManager::CB_MP_BEGINMATCH, $this, 'handleBeginMatchCallback'); $this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::TM_ONFINISHLINE, $this, 'handleFinishCallback'); $this->maniaControl->getCallbackManager()->registerCallbackListener(CallbackManager::CB_MP_MAPLISTMODIFIED, $this, 'handleMapListModified'); // Register Socket commands $this->maniaControl->getCommunicationManager()->registerCommunicationListener("Match.GetMatchStatus", $this, function () { return new CommunicationAnswer($this->getMatchStatus()); }); $this->maniaControl->getCommunicationManager()->registerCommunicationListener("Match.GetCurrentScore", $this, function () { return new CommunicationAnswer($this->getCurrentScore()); }); $this->maniaControl->getCommunicationManager()->registerCommunicationListener("Match.GetPlayers", $this, function () { return new CommunicationAnswer($this->getPlayers()); }); $this->maniaControl->getCommunicationManager()->registerCommunicationListener("Match.MatchStart", $this, function () { return new CommunicationAnswer($this->MatchStart()); }); $this->maniaControl->getCommunicationManager()->registerCommunicationListener("Match.MatchStop", $this, function () { return new CommunicationAnswer($this->MatchStop()); }); $this->maniaControl->getCommunicationManager()->registerCommunicationListener("Match.GetMatchOptions", $this, function () { return new CommunicationAnswer($this->getGMSettings()); }); // Register Timers $this->maniaControl->getTimerManager()->registerTimerListening($this, 'Periodic5SecondsLoop', 5000); // Register ManiaLink Pages $this->maniaControl->getManialinkManager()->registerManialinkPageAnswerListener(self::ACTION_READY, $this, 'handleReady'); // Init Ready mode $players = $this->maniaControl->getPlayerManager()->getPlayers(); foreach ($players as $player) { $this->handlePlayerConnect($player); } } /** * @see \ManiaControl\Plugins\Plugin::unload() */ public function unload() { $this->closeReadyWidget(); } /** * Initialize needed database tables */ private function initTables() { $mysqli = $this->maniaControl->getDatabase()->getMysqli(); $query = 'CREATE TABLE IF NOT EXISTS `' . self::DB_MATCHESINDEX . '` ( `matchid` VARCHAR(100) NOT NULL, `server` VARCHAR(60) NOT NULL, `gamemodebase` VARCHAR(32) NOT NULL, `started` INT(10) NOT NULL, `ended` INT(10) NOT NULL, PRIMARY KEY (`matchid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error, E_USER_ERROR); } $query = 'CREATE TABLE IF NOT EXISTS `' . self::DB_ROUNDSINDEX . '` ( `matchid` VARCHAR(100) NOT NULL, `timestamp` INT(10) NOT NULL, `nbmaps` INT(4) NOT NULL, `nbrounds` INT(4) NOT NULL, `settings` TEXT NOT NULL, `map` VARCHAR(100) NOT NULL, `nbplayers` INT(4) NOT NULL, `nbspectators` INT(4) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error, E_USER_ERROR); } $query = 'CREATE TABLE IF NOT EXISTS `' . self::DB_ROUNDSDATA . '` ( `matchid` VARCHAR(100) NOT NULL, `timestamp` INT(10) NOT NULL, `rank` INT(4) NOT NULL, `login` VARCHAR(30) NOT NULL, `matchpoints` INT(10) NOT NULL, `roundpoints` INT(10) NOT NULL, `time` INT(10) NOT NULL, `teamid` VARCHAR(30) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error, E_USER_ERROR); } $query = 'CREATE TABLE IF NOT EXISTS `' . self::DB_TEAMSDATA . '` ( `matchid` VARCHAR(100) NOT NULL, `timestamp` INT(10) NOT NULL, `id` VARCHAR(30) NOT NULL, `team` VARCHAR(30) NOT NULL, `points` INT(10) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'; $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error, E_USER_ERROR); } } /** * Generate description prefix (ex: [*] or [Ch,C,KO]) * * @param string $gamesetting */ public function getDescriptionPrefix(string $gamesetting) { if (in_array('Global', self::GAMEMODES_LIST_SETTINGS[$gamesetting]['gamemode'])) { $prefix = '[*] '; } else { $prefix = '['; foreach (self::GAMEMODES_LIST_SETTINGS[$gamesetting]['gamemode'] as $gamemode) { if ($gamemode == "Champion") { $prefix .= 'Ch,'; } elseif ($gamemode == "TimeAttack") { $prefix .= 'TA,'; } elseif ($gamemode == "Knockout") { $prefix .= 'KO,'; } else { $prefix .= substr($gamemode, 0 ,1) . ','; } } $prefix = substr($prefix, 0, -1) . '] '; } return $prefix; } public function getMatchStatus() { return $this->matchStarted; } public function getCountRound() { return $this->nbrounds . "/" . $this->settings_nbroundsbymap; } public function getCountMap() { return $this->nbmaps . "/" . $this->settings_nbmapsbymatch; } public function getCurrentGamemodeSettings() { return $this->currentgmsettings; } public function getCurrentScore() { return $this->currentscore; } public function getCurrentTeamsScore() { return $this->currentteamsscore; } public function getPlayersReadyState() { return $this->playersreadystate; } public function getRoundNumber() { return $this->nbrounds; } public function getMatchPointsLimit() { return $this->settings_pointlimit; } public function getNbWinners() { return $this->settings_nbwinners; } /** * Update Widgets on Setting Changes * * @param Setting $setting */ public function updateSettings(Setting $setting = null) { if ($setting->belongsToClass($this)) { $players = $this->maniaControl->getPlayerManager()->getPlayers(); foreach ($players as $player) { $this->displayReadyWidget($player->login); } if ($this->matchStarted) { if ($setting->setting == self::SETTING_MATCH_GAMEMODE_BASE && $setting->value != $this->currentgmbase) { $setting->value = $this->currentgmbase; $this->maniaControl->getSettingManager()->saveSetting($setting); $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'You can\'t change Gamemode during a Match'); } else { if (!$this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_MATCHSETTINGS_CONF)) { Logger::log("Load Script Settings"); try { $this->maniaControl->getClient()->setModeScriptSettings($this->getGMSettings()); Logger::log("Parameters updated"); $this->maniaControl->getChat()->sendSuccessToAdmins($this->chatprefix . 'Parameters updated'); } catch (InvalidArgumentException $e) { Logger::log("Parameters not updated"); $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'Parameters not updated'); } $this->updateGMvariables(); } else { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'Settings are loaded by Matchsettings file only.'); } } } } } /** * Get Array with all settings of the Gamemode */ public function getGMSettings() { $gamesettings = []; foreach (self::GAMEMODES_LIST_SETTINGS as $gamesetting => $info) { if (in_array('Global', $info['gamemode']) || in_array($this->currentgmbase, $info['gamemode'])) { $value = $this->maniaControl->getSettingManager()->getSettingValue($this, $gamesetting); settype($value, $info['type']); $gamesettings = array_merge($gamesettings , array($gamesetting => $value )); } } return $gamesettings; } /** * Load functionnal variables */ public function updateGMvariables() { Logger::log("Updating internal variables"); $this->currentgmsettings = $this->maniaControl->getClient()->getModeScriptSettings(); if (isset($this->currentgmsettings[self::SETTING_MATCH_S_POINTSLIMIT])) { $this->settings_pointlimit = (int) $this->currentgmsettings[self::SETTING_MATCH_S_POINTSLIMIT]; } if (isset($this->currentgmsettings[self::SETTING_MATCH_S_NBOFWINNERS])) { $this->settings_nbwinners = (int) $this->currentgmsettings[self::SETTING_MATCH_S_NBOFWINNERS]; } if (isset($this->currentgmsettings[self::SETTING_MATCH_S_ROUNDSPERMAP])) { $this->settings_nbroundsbymap = (int) $this->currentgmsettings[self::SETTING_MATCH_S_ROUNDSPERMAP]; } if ($this->currentgmbase == "Champion") { $this->settings_nbmapsbymatch = (int) $this->currentgmsettings[self::SETTING_MATCH_S_ROUNDSLIMIT]; } elseif (isset($this->currentgmsettings[self::SETTING_MATCH_S_MAPSPERMATCH])) { $this->settings_nbmapsbymatch = (int) $this->currentgmsettings[self::SETTING_MATCH_S_MAPSPERMATCH]; } if (isset($this->currentgmsettings[self::SETTING_MATCH_S_POINTSGAP])) { $this->settings_pointsgap = (int) $this->currentgmsettings[self::SETTING_MATCH_S_POINTSGAP]; } if (isset($this->currentgmsettings[self::SETTING_MATCH_S_USETIEBREAK])) { $this->settings_usetiebreak = (int) $this->currentgmsettings[self::SETTING_MATCH_S_USETIEBREAK]; } } /** * Function called to start the match */ public function MatchStart() { $this->matchid = $this->maniaControl->getServer()->login . "-" . time(); $this->currentgmbase = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_GAMEMODE_BASE); $maplist = ""; if (empty($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_CUSTOM_GAMEMODE))) { $scriptName = "Trackmania/TM_" ; $scriptName .= $this->currentgmbase; $scriptName .= "_Online.Script.txt"; $this->maniaControl->getChat()->sendSuccess($this->chatprefix . 'Match start in ' . $this->currentgmbase . ' mode!'); } else { $scriptName = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_CUSTOM_GAMEMODE); $this->maniaControl->getChat()->sendSuccess($this->chatprefix . 'Match start with script ' . $scriptName . ' (based on ' . $this->currentgmbase . ')'); } Logger::log("Match start with script " . $scriptName . '!'); if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_LOAD_MAPLIST_FILE)) { Logger::log("Loading maplist + matchsettings"); if (empty($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_MAPLIST))) { $server = $this->maniaControl->getServer()->login; $maplist = 'MatchSettings' . DIRECTORY_SEPARATOR . $server . ".txt"; } else { $maplist = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_MAPLIST); $maplist = 'MatchSettings' . DIRECTORY_SEPARATOR . $maplist; } Logger::log("Load matchsettings: " . $maplist); $this->maniaControl->getClient()->loadMatchSettings($maplist); Logger::log("Restructure maplist"); $this->maniaControl->getMapManager()->restructureMapList(); } else { if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_MATCHSETTINGS_CONF)) { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'FYI, No Settings will be load, check "' . self::SETTING_MATCH_MATCHSETTINGS_CONF . "\" and \"" . self::SETTING_MATCH_MAPLIST . "\""); } } Logger::log("Load Script"); $this->maniaControl->getClient()->setScriptName($scriptName); $this->matchStarted = true; $this->nbmaps = 0; $this->nbrounds = 0; Logger::log("Get Players"); $players = $this->maniaControl->getPlayerManager()->getPlayers(); Logger::log("Player State"); foreach ($players as $player) { $this->handlePlayerConnect($player); } //Reset Player Pause counter foreach ($players as $player) { if (!$player->isSpectator) { $this->playerpause[$player->login] = 0; } } $this->pauseasked = false; $this->pauseaskedbyplayer = ""; // MYSQL DATA INSERT $mysqli = $this->maniaControl->getDatabase()->getMysqli(); $query = 'INSERT INTO `' . self::DB_MATCHESINDEX . '` (`matchid`, `server`, `gamemodebase`, `started`, `ended`) VALUES ("' . $this->matchid . '","' . $this->maniaControl->getServer()->login . '","' . $this->currentgmbase . '","' . time() . '","0" )'; $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error); return false; } // Trigger Callback $settings = [ 'currentgmbase' => $this->currentgmbase, 'scriptName' => $scriptName, 'maplist' => $maplist, 'mapsshuffled' => $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_SHUFFLEMAPS)]; $this->maniaControl->getCallbackManager()->triggerCallback(self::CB_MATCHMANAGER_STARTMATCH, $this->matchid, $settings); Logger::log("Skip map"); $this->maniaControl->getMapManager()->getMapActions()->skipMap(); } /** * Function called to end the match */ public function MatchEnd() { $scriptName = "Trackmania/TM_" ; $scriptName .= $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_GAMEMODE_AFTERMATCH); $scriptName .= "_Online.Script.txt"; try { $this->maniaControl->getClient()->setScriptName($scriptName); // MYSQL DATA INSERT $settings = json_encode($this->maniaControl->getClient()->getModeScriptSettings()); $mysqli = $this->maniaControl->getDatabase()->getMysqli(); $query = 'UPDATE `' . self::DB_MATCHESINDEX . '` SET `ended` = "' . time() . '" WHERE `matchid` = "' . $this->matchid . '"'; $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error); } // Trigger Callback $this->maniaControl->getCallbackManager()->triggerCallback(self::CB_MATCHMANAGER_ENDMATCH, $this->matchid, $this->currentscore, $this->currentteamsscore); // End notifications $this->maniaControl->getChat()->sendSuccess($this->chatprefix . "Match finished"); Logger::log("Loading script: $scriptName"); Logger::log("Match finished"); $this->matchStarted = false; $this->settingsloaded = false; $this->mapsshuffled = false; $this->postmatch = true; $this->currentscore = []; $this->matchid = ""; // KO Specifics variables $this->nbstillalive = 0; // Teams Specifics variables $this->currentteamsscore = []; $players = $this->maniaControl->getPlayerManager()->getPlayers(); foreach ($players as $player) { $this->handlePlayerConnect($player); } } catch (Exception $e) { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'Can not finish match: ' . $e->getMessage()); } } /** * Function called to stop the match */ public function MatchStop() { Logger::log("Match stop"); $scriptName = "Trackmania/TM_" ; $scriptName .= $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_GAMEMODE_AFTERMATCH); $scriptName .= "_Online.Script.txt"; try { // Trigger Callback $this->maniaControl->getCallbackManager()->triggerCallback(self::CB_MATCHMANAGER_STOPMATCH, $this->matchid, $this->currentscore, $this->currentteamsscore); $this->maniaControl->getChat()->sendError($this->chatprefix . 'Match stopped by an Admin!'); $this->maniaControl->getClient()->setScriptName($scriptName); Logger::log("Loading script: $scriptName"); $this->matchStarted = false; $this->settingsloaded = false; $this->mapsshuffled = false; $this->postmatch = true; $this->matchid = ""; $players = $this->maniaControl->getPlayerManager()->getPlayers(); foreach ($players as $player) { $this->handlePlayerConnect($player); } } catch (Exception $e) { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'Can not stop match: ' . $e->getMessage()); } Logger::log("Restarting map to load Gamemode"); $this->maniaControl->getClient()->restartMap(); } /** * Set pause * * @param boolean $admin * @param integer $time */ private function setNadeoPause($admin = false, $time = null) { Logger::log("Nadeo Pause"); if ($time === null) { $this->pausetimer = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_PAUSE_DURATION); } else { $this->pausetimer = $time; } $this->numberpause++; $numberpause = $this->numberpause; $this->pauseon = true; $this->maniaControl->getModeScriptEventManager()->startPause(); $this->maniaControl->getChat()->sendSuccessToAdmins($this->chatprefix . 'You can interrupt the pause with the command //matchendpause'); if ($this->pausetimer > 0) { $this->maniaControl->getTimerManager()->registerOneTimeListening($this, function () use (&$numberpause) { if ($numberpause == $this->numberpause) { $this->unsetNadeoPause(); } else { Logger::log("Pause not stopped because another is in progress!"); } }, $this->pausetimer * 1000); $this->displayPauseWidget($numberpause); } } /** * Unset pause */ private function unsetNadeoPause() { if ($this->pauseon) { Logger::log("End Pause"); $this->closePauseWidget(); $this->maniaControl->getModeScriptEventManager()->endPause(); } } /** * Display (or not) the Ready Widget * * @param string $login */ public function displayReadyWidget($login) { if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_READY_MODE) && (!$this->matchStarted)) { $posX = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_READY_POSX); $posY = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_READY_POSY); $width = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_READY_WIDTH); $height = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_READY_HEIGHT); $quadStyle = $this->maniaControl->getManialinkManager()->getStyleManager()->getDefaultQuadStyle(); $quadSubstyle = $this->maniaControl->getManialinkManager()->getStyleManager()->getDefaultQuadSubstyle(); $maniaLink = new ManiaLink(self::MLID_MATCH_READY_WIDGET); // mainframe $frame = new Frame(); $maniaLink->addChild($frame); $frame->setSize($width, $height); $frame->setPosition($posX, $posY); // Background Quad $backgroundQuad = new Quad(); $frame->addChild($backgroundQuad); $backgroundQuad->setSize($width, $height); $backgroundQuad->setStyles($quadStyle, $quadSubstyle); $backgroundQuad->setAction(self::ACTION_READY); $label = new Label_Text(); $frame->addChild($label); $label->setPosition(0, 1.5, 0.2); $label->setVerticalAlign($label::TOP); $label->setTextSize(2); if ($this->playersreadystate[$login] == 1) { $label->setTextColor('0f0'); } else { $label->setTextColor('f00'); } $label->setText("Ready?"); // Send manialink $this->maniaControl->getManialinkManager()->sendManialink($maniaLink, $login); } else { $this->playersreadystate[$login] = 0; $this->closeReadyWidget($login); } } /** * Display Pause Widget * * @param integer $numberpause */ public function displayPauseWidget($numberpause) { $posX = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_PAUSE_POSX); $posY = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_PAUSE_POSY); $maniaLink = new ManiaLink(self::MLID_MATCH_PAUSE_WIDGET); // mainframe $frame = new Frame(); $maniaLink->addChild($frame); $frame->setSize(30, 20); $frame->setPosition($posX, $posY); $label = new Label_Text(); $frame->addChild($label); $label->setPosition(0, 2, 0.2); $label->setVerticalAlign($label::TOP); $label->setTextSize(8); $label->setTextFont("GameFontBlack"); $label->setTextPrefix('$s'); if ($this->pausetimer < 10) { $label->setTextColor('f00'); } else { $label->setTextColor('fff'); } $label->setText($this->pausetimer); // Send manialink $this->maniaControl->getManialinkManager()->sendManialink($maniaLink); $this->maniaControl->getTimerManager()->registerOneTimeListening($this, function () use (&$numberpause) { if ($numberpause == $this->numberpause) { if ($this->pausetimer > 0 && $this->pauseon) { $this->pausetimer--; $this->displayPauseWidget($numberpause); } else { $this->closePauseWidget(); } } }, 1000); } /** * Close Pause Widget * * @param string $login */ public function closePauseWidget($login = null) { $this->maniaControl->getManialinkManager()->hideManialink(self::MLID_MATCH_PAUSE_WIDGET, $login); } /** * Close Ready Widget * * @param string $login */ public function closeReadyWidget($login = null) { $this->maniaControl->getManialinkManager()->hideManialink(self::MLID_MATCH_READY_WIDGET, $login); } /** * Run this function every 5 seconds. Used to start a match with Ready button */ public function Periodic5SecondsLoop() { if (!$this->matchStarted) { if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_READY_MODE)) { $nbplayers = $this->maniaControl->getPlayerManager()->getPlayerCount(); if ($nbplayers >= $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_READY_NBPLAYERS)) { $nbready = 0; foreach ($this->playersreadystate as $readystate) { if ($readystate == 1) { $nbready++; } } if ($nbready >= $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_READY_NBPLAYERS)) { $players = $this->maniaControl->getPlayerManager()->getPlayers(); foreach ($players as $player) { $this->playersreadystate[$player->login] = 0; } Logger::log('Start Match via Ready Button'); $this->MatchStart(); } } } } } /** * Handle when a player connect * * @param \ManiaControl\Players\Player $player */ public function handlePlayerConnect(Player $player) { if ($player->isSpectator) { $this->playersreadystate[$player->login] = -1; $this->nbspectators++; } else { $this->playersreadystate[$player->login] = 0; $this->nbplayers++; $this->displayReadyWidget($player->login); } if ($this->pauseon) { $this->displayPauseWidget($player->login); } if ($this->matchStarted) { if (!isset($this->playerpause[$player->login])) { $this->playerpause[$player->login] = 0; } } } /** * Handle when a player disconnects * * @param \ManiaControl\Players\Player $player */ public function handlePlayerDisconnect(Player $player) { $this->playersreadystate[$player->login] = -1; $this->nbplayers--; $this->closeReadyWidget($player->login); $this->closePauseWidget($player->login); } /** * Handle Ready state of the player * * @param array $callback * @param \ManiaControl\Players\Player $player */ public function handleReady(array $callback, Player $player) { Logger::log("handleReady"); if ($this->playersreadystate[$player->login]) { if ($this->playersreadystate[$player->login] == 0) { $this->playersreadystate[$player->login] = 1; $this->nbplayers++; $this->displayReadyWidget($player->login); $this->maniaControl->getChat()->sendInformation($this->chatprefix . 'Player $<$ff0' . $player->nickname . '$> now is $<$z$0f0ready$>'); } elseif ($this->playersreadystate[$player->login] == 1) { $this->playersreadystate[$player->login] = 0; $this->nbplayers--; $this->displayReadyWidget($player->login); $this->maniaControl->getChat()->sendInformation($this->chatprefix . 'Player $<$ff0' . $player->nickname . '$> now is $<$z$f00not ready$>'); } } else { $this->playersreadystate[$player->login] = 1; $this->nbplayers++; $this->displayReadyWidget($player->login); $this->maniaControl->getChat()->sendInformation($this->chatprefix . 'Player $<$ff0' . $player->nickname . '$> now is $<$z$0f0ready$>'); } } /** * Handle callback "MapListModified" */ public function handleMapListModified() { Logger::log("handleMapListModified"); if ($this->matchStarted && !$this->mapsshuffled && $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_SHUFFLEMAPS)) { Logger::log("Shuffle maplist"); $this->maniaControl->getMapManager()->shuffleMapList(); $this->mapsshuffled = true; } } /** * Handle callback "BeginMatch" */ public function handleBeginMatchCallback() { Logger::log("handleBeginMatchCallback"); if ($this->matchStarted === true) { Logger::log("Check settingsloaded: " . $this->settingsloaded); if (!($this->settingsloaded)) { Logger::log("Loading settings"); $this->settingsloaded = true; if (!$this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_MATCHSETTINGS_CONF)) { Logger::log("Load Script Settings"); $this->maniaControl->getClient()->setModeScriptSettings($this->getGMSettings()); } $this->updateGMvariables(); Logger::log("Restarting Map for load settings"); $this->maniaControl->getClient()->restartMap(); } else { $this->nbmaps++; Logger::log('nbmaps: ' . $this->nbmaps); $this->nbrounds = 0; if ($this->nbmaps > 0) { Logger::log("Map: " . $this->nbmaps); $maps = $this->maniaControl->getMapManager()->getMaps(); $i = 1; $this->currentmap = $this->maniaControl->getMapManager()->getCurrentMap(); $message = $this->chatprefix . '$o$iCurrent Map:' . "\n"; $message .= '$o$i' . Formatter::stripCodes($this->currentmap->name); $this->maniaControl->getChat()->sendInformation($message); Logger::log("Current Map: " . Formatter::stripCodes($this->currentmap->name)); $continue = false; $current = false; $message = $this->chatprefix . '$o$iNext Maps:'; //TODO remove Next map if no next map foreach ($maps as $map) { //TODO check no nextmap in cup mode if ($this->currentmap->uid == $map->uid) { $continue = true; $current = true; } if ($continue && $this->nbmaps < $this->settings_nbmapsbymatch) { if ($current) { $current = false; } elseif (($this->nbmaps + $i) <= ($this->settings_nbmapsbymatch)) { if ($i > 0) { Logger::log("Map " . $i . ": " . Formatter::stripCodes($map->name)); $message .= "\n" . '$o$i' . $i . ": " . Formatter::stripCodes($map->name); } $nbmaps = $this->maniaControl->getMapManager()->getMapsCount(); $i++; if ($this->nbmaps == ($nbmaps - ($i - 1) + 1) or $this->settings_nbmapsbymatch == (($i - 1) + $this->nbmaps - 1)) { $continue = false; } } } } $this->maniaControl->getChat()->sendInformation($message); } // Trigger Callback $currentstatus = [ 'nbmaps' => $this->nbmaps, 'settings_nbmapsbymatch' => $this->settings_nbmapsbymatch]; $this->maniaControl->getCallbackManager()->triggerCallback(self::CB_MATCHMANAGER_BEGINMAP,$this->matchid, $currentstatus, $this->currentmap); } } if ($this->postmatch) { $scriptName = $this->maniaControl->getClient()->getScriptName()['CurrentValue']; Logger::log("scriptName: " . $scriptName); if ($scriptName == "Trackmania/TM_TimeAttack_Online.Script.txt") { $this->postmatch = false; Logger::log("Load Script Settings"); $postmatchsettings = [ self::SETTING_MATCH_S_FORCELAPSNB => 0, self::SETTING_MATCH_S_RESPAWNBEHAVIOUR => 0, self::SETTING_MATCH_S_WARMUPNB => 0, self::SETTING_MATCH_S_TIMELIMIT => 600 ]; $this->maniaControl->getClient()->setModeScriptSettings($postmatchsettings); Logger::log("Restarting Map for load settings"); $this->maniaControl->getClient()->restartMap(); } else { // Depending of the load of the server and the match gamemode, the script could be not loaded, this is a workaround to reload thhe script $this->maniaControl->getClient()->restartMap(); } } } /** * Handle callback "BeginRound" */ public function handleBeginRoundCallback() { Logger::log("handleBeginRoundCallback"); $this->times = array(); if ($this->pauseasked) { $this->pauseasked = false; Logger::log("Set Pause"); $this->setNadeoPause(); } if ($this->matchStarted && $this->nbmaps > 0) { if (in_array($this->currentgmbase, ["Cup", "Teams", "Rounds"])) { $this->maniaControl->getModeScriptEventManager()->getPauseStatus()->setCallable(function (StatusCallbackStructure $structure) { if ($structure->getActive()) { $this->maniaControl->getChat()->sendSuccess($this->chatprefix . 'The match is currently on $<$F00pause$>!'); Logger::log("Pause"); } else { if ($this->pauseon) { $this->pauseon = false; } $this->maniaControl->getChat()->sendInformation($this->chatprefix . '$o$iRound: ' . ($this->nbrounds + 1) . ' / ' . $this->settings_nbroundsbymap); Logger::log("Round: " . ($this->nbrounds + 1) . ' / ' . $this->settings_nbroundsbymap); } }); } elseif (in_array($this->currentgmbase, ["Laps", "TimeAttack"])) { if ($this->nbmaps > 0) { $this->maniaControl->getChat()->sendInformation($this->chatprefix . '$s$<$o$iMap: ' . ($this->nbmaps)); Logger::log("Map: " . $this->nbmaps); } } } } /** * Handle Finish Callback * * @param \ManiaControl\Callbacks\Structures\TrackMania\OnWayPointEventStructure $structure */ public function handleFinishCallback(OnWayPointEventStructure $structure) { if ($this->matchStarted) { if ($structure->getRaceTime() <= 0) { Logger::log("handleFinishCallback: Invalid time"); return; } $player = $structure->getPlayer(); if (!$player) { return; } $this->times[] = array($player->login, $structure->getRaceTime()); } } /** * Handle when a player becomes a spectator (or vice versa) * * @param \ManiaControl\Players\Player $player */ public function handlePlayerInfoChanged(Player $player) { //TODO optimize $this->handlePlayerConnect($player); if ($this->playersreadystate[$player->login]) { if ($player->isSpectator) { if ($this->playersreadystate[$player->login] == 1 || $this->playersreadystate[$player->login] == 0) { $this->nbplayers--; } $this->playersreadystate[$player->login] = -1; $this->closeReadyWidget($player->login); } else { if ($this->playersreadystate[$player->login] == -1) { $this->nbplayers++; } $this->playersreadystate[$player->login] = 0; $this->displayReadyWidget($player->login); } } } /** * Handle callback "EndRound" * * @param OnScoresStructure $structure */ public function handleEndRoundCallback(OnScoresStructure $structure) { Logger::log("handleEndRoundCallback-" . $structure->getSection()); if ($this->matchStarted && $this->settingsloaded && !$this->postmatch) { Logger::log("Section: " . $structure->getSection()); if ($structure->getSection() == "EndMatch") { $this->MatchEnd(); } else { $timestamp = time(); if ($structure->getSection() == "PreEndRound" && in_array($this->currentgmbase, ["Cup", "Teams", "Rounds"])) { $realSection = true; } elseif ($structure->getSection() == "EndRound" && in_array($this->currentgmbase, ["Champion", "Knockout", "Laps", "TimeAttack"])) { $realSection = true; } else { $realSection = false; } if ($realSection) { if ($this->nbmaps != 0 and ($this->nbrounds != $this->settings_nbroundsbymap || $this->nbrounds == 0 )) { $database = ""; $this->currentscore = array(); $results = $structure->getPlayerScores(); $scores = array(); // CUP Specific variables $this->nbwinners = 0; // Knockout Specific variables $this->nbstillalive = 0; $pointsrepartition = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_S_POINTSREPARTITION); $pointsrepartition = explode(',', $pointsrepartition); $dbquery = 'INSERT INTO `' . self::DB_ROUNDSDATA . '` (`matchid`,`timestamp`,`rank`,`login`,`matchpoints`,`roundpoints`,`time`,`teamid`) VALUES '; foreach ($results as $result) { $rank = $result->getRank(); $player = $result->getPlayer(); $time = $result->getPrevRaceTime(); if (in_array($this->currentgmbase, ["Champion", "Cup", "Knockout", "Teams", "Rounds"]) && !($result->getMatchPoints() == 0 && ($player->isSpectator || $player->isFakePlayer()))) { $roundpoints = $result->getRoundPoints(); $points = $result->getMatchPoints(); if ($this->currentgmbase == "Champion") { $this->currentscore = array_merge($this->currentscore, array(array($rank, $player->login, $points , $result->getMapPoints(), $time, ""))); } elseif ($this->currentgmbase == "Cup") { $this->currentscore = array_merge($this->currentscore, array(array($rank, $player->login, ($points + $roundpoints), $roundpoints, $time, "-1"))); } elseif ($this->currentgmbase == "Rounds" ) { $this->currentscore = array_merge($this->currentscore, array(array($rank, $player->login, ($points + $roundpoints), $roundpoints, $time, "-1"))); } elseif ($this->currentgmbase == "Teams") { $this->currentscore = array_merge($this->currentscore, array(array($rank, $player->login, ($points + $roundpoints), $roundpoints, $time, $player->teamId))); } elseif ($this->currentgmbase == "Knockout") { $this->currentscore = array_merge($this->currentscore, array(array($rank, $player->login, $points, "-1", $time, "-1"))); } } elseif (in_array($this->currentgmbase, ["Laps", "TimeAttack"]) && !(($time == 0 || $time == -1) && ($player->isSpectator || $player->isFakePlayer()))) { $besttime = $result->getBestRaceTime(); if ($this->currentgmbase == "Laps") { $nbcp = count($result->getBestRaceCheckpoints()); $this->currentscore = array_merge($this->currentscore, array(array($rank, $player->login, $nbcp, "-1", $besttime, "-1"))); } elseif ($this->currentgmbase == "TimeAttack") { $this->currentscore = array_merge($this->currentscore, array(array($rank, $player->login, "-1", "-1", $besttime, "-1"))); } } } Logger::log('Count number of players finish: '. count($this->times)); if (!$this->pauseon && !$this->skipround) { $this->nbrounds++; } if ($this->skipround) { $this->skipround = false; } if ($this->currentgmbase == "Knockout" && $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_S_ROUNDSWITHOUTELIMINATION) <= $this->nbrounds && $this->nbmaps == 1) { Logger::log("Round without elimination"); } // MYSQL DATA INSERT $settings = json_encode($this->maniaControl->getClient()->getModeScriptSettings()); $mysqli = $this->maniaControl->getDatabase()->getMysqli(); $query = 'INSERT INTO `' . self::DB_ROUNDSINDEX . '` (`matchid`,`timestamp`,`nbmaps`,`nbrounds`,`settings`,`map`,`nbplayers`,`nbspectators`) VALUES ("'. $this->matchid . '","' . $timestamp . '","' . $this->nbmaps . '","' . $this->nbrounds . '",' . "'" . $settings . "'" . ',"' . $this->currentmap->uid . '","' . $this->maniaControl->getPlayerManager()->getPlayerCount() . '","' . $this->maniaControl->getPlayerManager()->getSpectatorCount() . '")'; $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error); } // Round data foreach ($this->currentscore as $value) { $dbquery .= '("' . $this->matchid . '","' . $timestamp . '","' . implode('","',$value) . '"),'; } $dbquery = substr($dbquery, 0, -1); $mysqli->query($dbquery); if ($mysqli->error) { trigger_error($mysqli->error); } Logger::log("Rounds finished: " . $this->nbrounds); // Trigger Callback $this->maniaControl->getCallbackManager()->triggerCallback(self::CB_MATCHMANAGER_ENDROUND, $this->matchid, $this->currentscore, []); } } elseif ($structure->getSection() == "EndRound" && $this->currentgmbase == "Teams") { // Teams Specific variables $teamresults = $structure->getTeamScores(); $this->currentteamsscore = array(); $teamdbquery = 'INSERT INTO `' . self::DB_TEAMSDATA . '` (`matchid`,`timestamp`,`id`,`team`,`points`) VALUES '; $this->currentteamsscore = []; $rank = 1; foreach ($teamresults as $teamresult) { $this->currentteamsscore = array_merge($this->currentteamsscore, array(array($rank, $teamresult->getTeamId(), $teamresult->getMatchPoints()))); $teamdbquery .= '("' . $this->matchid . '","' . $timestamp . '","' . $teamresult->getTeamId() . '","' . $teamresult->getName() . '","' . $teamresult->getMatchPoints() . '"),'; $rank++; } $teamdbquery = substr($teamdbquery, 0, -1); $mysqli = $this->maniaControl->getDatabase()->getMysqli(); // Teams data $mysqli->query($teamdbquery); if ($mysqli->error) { trigger_error($mysqli->error); } $this->maniaControl->getCallbackManager()->triggerCallback(self::CB_MATCHMANAGER_ENDROUND, $this->matchid, $this->currentscore, $this->currentteamsscore); } } return true; } } /** * Command /matchstart for admins * * @param array $chatCallback * @param \ManiaControl\Players\Player $player */ public function onCommandMatchStart(array $chatCallback, Player $player) { $authLevel = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_AUTHLEVEL); if (!$this->maniaControl->getAuthenticationManager()->checkRight($player, AuthenticationManager::getAuthLevel($authLevel))) { $this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); return; } $this->MatchStart(); } /** * Command /matchstop for admins * * @param array $chatCallback * @param \ManiaControl\Players\Player $player */ public function onCommandMatchStop(array $chatCallback, Player $player) { $authLevel = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_AUTHLEVEL); if (!$this->maniaControl->getAuthenticationManager()->checkRight($player, AuthenticationManager::getAuthLevel($authLevel))) { $this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); return; } if ($this->pauseon == false) { $this->MatchStop(); } else { $this->maniaControl->getChat()->sendError($this->chatprefix . 'Impossible to stop a match during a pause' ,$player); } } /** * Command //matchendround for admin * * @param array $chatCallback * @param \ManiaControl\Players\Player $player */ public function onCommandMatchEndRound(array $chatCallback, Player $player) { $authLevel = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_AUTHLEVEL); if (!$this->maniaControl->getAuthenticationManager()->checkRight($player, AuthenticationManager::getAuthLevel($authLevel))) { $this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); return; } $this->skipround = true; $this->maniaControl->getModeScriptEventManager()->forceTrackmaniaRoundEnd(); } /** * Command //matchendwu for admin * * @param array $chatCallback * @param \ManiaControl\Players\Player $player */ public function onCommandMatchEndWU(array $chatCallback, Player $player) { $authLevel = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_AUTHLEVEL); if (!$this->maniaControl->getAuthenticationManager()->checkRight($player, AuthenticationManager::getAuthLevel($authLevel))) { $this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); return; } try { $this->maniaControl->getModeScriptEventManager()->triggerModeScriptEvent("Trackmania.WarmUp.ForceStop"); } catch (InvalidArgumentException $e) { } } /** * Command //matchpause or //pause for admin * * @param array $chatCallback * @param \ManiaControl\Players\Player $player */ public function onCommandSetPause(array $chatCallback, Player $player) { Logger::log("Pause asked by admin"); $authLevel = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_AUTHLEVEL); if (!$this->maniaControl->getAuthenticationManager()->checkRight($player, AuthenticationManager::getAuthLevel($authLevel))) { $this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); return; } if (($this->matchStarted) && ($this->currentgmbase != "TimeAttack" || !empty($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_CUSTOM_GAMEMODE)))) { $text = $chatCallback[1][2]; $text = explode(" ", $text); if (isset($text[1]) && $text[1] != "") { if (is_numeric($text[1]) && $text[1] > 0) { $this->maniaControl->getChat()->sendSuccess($this->chatprefix . 'Admin force a break for ' . $text[1] . ' seconds!'); $this->setNadeoPause(true, $text[1]); } elseif (is_numeric($text[1]) && $text[1] == 0) { $this->maniaControl->getChat()->sendSuccess($this->chatprefix . 'Admin force an unlimited break'); $this->setNadeoPause(true, $text[1]); } else { $this->maniaControl->getChat()->sendError($this->chatprefix . 'Pause time sent is invalid', $player); } } else { $this->maniaControl->getChat()->sendSuccess($this->chatprefix . 'Admin force a break for ' . $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_PAUSE_DURATION) . ' seconds!'); $this->setNadeoPause(true); } } else { $this->maniaControl->getChat()->sendError($this->chatprefix . 'Can\'t start Pause, match not started (or TA)', $player); } } /** * Command /matchendpause for admins * * @param array $chatCallback * @param \ManiaControl\Players\Player $player */ public function onCommandUnsetPause(array $chatCallback, Player $player) { $authLevel = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_AUTHLEVEL); if (!$this->maniaControl->getAuthenticationManager()->checkRight($player, AuthenticationManager::getAuthLevel($authLevel))) { $this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); return; } if (($this->matchStarted) && ($this->currentgmbase != "TimeAttack" || !empty($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_CUSTOM_GAMEMODE))) && $this->pauseon) { $this->maniaControl->getChat()->sendSuccess($this->chatprefix . 'Admin stopped the break'); $this->unsetNadeoPause(); } else { $this->maniaControl->getChat()->sendError($this->chatprefix . 'No pause in progress', $player->login); } } /** * Command //matchsetpoints for admin * * @param array $chatCallback * @param \ManiaControl\Players\Player $player */ public function onCommandSetPoints(array $chatCallback, Player $adminplayer) { $authLevel = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_AUTHLEVEL); if (!$this->maniaControl->getAuthenticationManager()->checkRight($adminplayer, AuthenticationManager::getAuthLevel($authLevel))) { $this->maniaControl->getAuthenticationManager()->sendNotAllowed($adminplayer); return; } $text = $chatCallback[1][2]; $text = explode(" ", $text); if (isset($text[1]) && isset($text[2]) && is_numeric($text[2]) && $text[2] >= 0 ) { if (strcasecmp($text[1], "Blue") == 0 || $text[1] == "0") { //TODO: add support of Custom teams $this->maniaControl->getModeScriptEventManager()->setTrackmaniaTeamPoints("0", "", $text[2], $text[2]); $this->maniaControl->getChat()->sendSuccess($this->chatprefix . '$<$00fBlue$> Team now has ' . $text[2] . ' points!'); } elseif (strcasecmp($text[1], "Red") == 0 || $text[1] == "1") { $this->maniaControl->getModeScriptEventManager()->setTrackmaniaTeamPoints("1", "", $text[2] , $text[2]); $this->maniaControl->getChat()->sendSuccess($this->chatprefix . '$<$f00Red$> Team now has ' . $text[2] . ' points!'); } else { $mysqli = $this->maniaControl->getDatabase()->getMysqli(); $query = 'SELECT login FROM `' . PlayerManager::TABLE_PLAYERS . '` WHERE nickname LIKE "' . $text[1] . '"'; $result = $mysqli->query($query); $array = mysqli_fetch_array($result); if (isset($array[0])) { $login = $array[0]; } elseif (strlen($peopletoadd) == 22) { $login = $peopletoadd ; } if ($mysqli->error) { trigger_error($mysqli->error, E_USER_ERROR); } if (isset($login)) { $player = $this->maniaControl->getPlayerManager()->getPlayer($login); if ($player) { $this->maniaControl->getModeScriptEventManager()->setTrackmaniaPlayerPoints($player, "", "", $text[2]); $this->maniaControl->getChat()->sendSuccess($this->chatprefix . 'Player $<$ff0' . $player->nickname . '$> now has ' . $text[2] . ' points!'); } else { $this->maniaControl->getChat()->sendError($this->chatprefix . 'Player ' . $text[1] . " doesn't exist", $adminplayer); } } else { $this->maniaControl->getChat()->sendError($this->chatprefix . 'Player ' . $text[1] . " doesn't exist", $adminplayer); } } } else { $this->maniaControl->getChat()->sendError($this->chatprefix . 'Missing or invalid parameters', $adminplayer); } } /** * Command /ready for players * * @param array $chatCallback * @param \ManiaControl\Players\Player $player */ public function onCommandSetReadyPlayer(array $chatCallback, Player $player) { if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_READY_MODE) && (!$this->matchStarted)) { $this->handleReady($chatCallback, $player); } } /** * Command /pause for players * * @param OnScoresStructure $structure */ public function onCommandSetPausePlayer(array $chatCallback, Player $player) { if (($this->matchStarted) && ($this->currentgmbase != "TimeAttack" || !empty($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_CUSTOM_GAMEMODE))) && (!$player->isSpectator && !$player->isPureSpectator)) { if ($this->playerpause[$player->login] < $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_PAUSE_MAXNUMBER)) { if ($this->pauseasked === false && $this->pauseon === false) { $this->maniaControl->getChat()->sendSuccess($this->chatprefix . 'Player $<$ff0' . $player->nickname . '$> ask for a break of ' . $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_PAUSE_DURATION) . ' seconds! It will start after this round.'); $this->playerpause[$player->login] = $this->playerpause[$player->login] + 1; Logger::log($this->playerpause[$player->login] . " pause for " . $player->login); $this->pauseasked = true; $this->pauseaskedbyplayer = $player->login; } else { $this->maniaControl->getChat()->sendError($this->chatprefix . 'Pause already asked by a player!', $player); } } else { $this->maniaControl->getChat()->sendError($this->chatprefix . 'Pause not available, too many pause asked', $player); } } else { $this->maniaControl->getChat()->sendError($this->chatprefix . 'Pause not available (TA or you are spectator)', $player); } } }