[ 'gamemode' => ['Global'], 'type' => 'integer', 'default' => 10, 'description' => 'Time before loading the next map' ], self::SETTING_MATCH_S_CRASHDETECTIONTHRESHOLD => [ 'gamemode' => ['TMWC2023'], 'type' => 'integer', 'default' => 2000, 'description' => 'Time delta in ms with the first player that will be considered as a crash' ], 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' => ['Laps'], 'type' => 'boolean', 'default' => false, 'description' => 'Disable GiveUp' ], self::SETTING_MATCH_S_DISABLEGOTOMAP => [ 'gamemode' => ['Global'], 'type' => 'boolean', 'default' => false, 'description' => 'Disable the "Go To Map" in the Pause Menu' ], self::SETTING_MATCH_S_EARLYENDMATCHCALLBACK => [ 'gamemode' => ['Knockout', 'TMWC2023', 'TMWTTeams'], '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_ENABLEDOSSARDCOLOR => [ 'gamemode' => ['TMWC2023', 'TMWTTeams'], 'type' => 'boolean', 'default' => true, 'description' => 'Apply color team on the dossard' ], self::SETTING_MATCH_S_FINISHTIMEOUT => [ 'gamemode' => ['Cup', 'Knockout', 'Laps', 'Teams', 'TMWC2023', 'TMWTTeams', '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_FORCEROADSPECTATORSNB => [ 'gamemode' => ['TMWC2023', 'TMWTTeams'], 'type' => 'integer', 'default' => -1, 'description' => 'Force the number of spectators displayed on the border of the road' ], 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_LOADINGSCREENIMAGEURL => [ 'gamemode' => ['Global'], 'type' => 'string', 'default' => "", 'description' => 'Image URL of the Loading Screen during the map change' ], self::SETTING_MATCH_S_MAPPOINTSLIMIT => [ 'gamemode' => ['TMWC2023', 'TMWTTeams'], 'type' => 'integer', 'default' => 10, 'description' => 'Track points limit' ], self::SETTING_MATCH_S_MAPSPERMATCH => [ 'gamemode' => ['Teams', 'Rounds'], 'type' => 'integer', 'default' => 3, 'description' => 'Number of maps maximum in the match' ], self::SETTING_MATCH_S_MATCHINFO => [ 'gamemode' => ['TMWC2023', 'TMWTTeams'], 'type' => 'string', 'default' => "", 'description' => 'Match info displayed in the UI' ], self::SETTING_MATCH_S_MATCHPOINTSLIMIT => [ 'gamemode' => ['TMWC2023', 'TMWTTeams'], 'type' => 'integer', 'default' => 4, 'description' => 'Match points limit' ], 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_POINTSGAP => [ 'gamemode' => ['Teams'], 'type' => 'integer', 'default' => 0, 'description' => 'Points Gap to win (depend of S_PointsLimit & S_UseTieBreak)' ], self::SETTING_MATCH_S_POINTSLIMIT => [ 'gamemode' => ['Cup', 'Teams', 'Rounds'], 'type' => 'integer', 'default' => 100, 'description' => 'Limit number of points (0 = unlimited for Ch & R)' ], self::SETTING_MATCH_S_POINTSREPARTITION => [ 'gamemode' => ['Cup', 'Knockout', 'Teams', 'TMWC2023', 'TMWTTeams', '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_ROUNDSPERMAP => [ 'gamemode' => ['Cup', 'Knockout', 'Teams', 'Rounds'], 'type' => 'integer', 'default' => 5, 'description' => 'Number of rounds par map (0 = unlimited)' ], 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_SPONSORSURL => [ 'gamemode' => ['TMWC2023', 'TMWTTeams'], 'type' => 'string', 'default' => "", 'description' => 'URLs separated by a space' ], self::SETTING_MATCH_S_TEAMSURL => [ 'gamemode' => ['TMWC2023', 'TMWTTeams'], 'type' => 'string', 'default' => "", 'description' => 'URL where to get the teams info' ], self::SETTING_MATCH_S_TIMELIMIT => [ 'gamemode' => ['Laps', 'TimeAttack', 'RoyalTimeAttack'], 'type' => 'integer', 'default' => 600, 'description' => 'Time limit (0 = unlimited)' ], 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' => ['Teams', 'Rounds'], 'type' => 'boolean', 'default' => false, 'description' => 'Use Tie Break (Only available when S_MapsPerMatch > 1)' ], self::SETTING_MATCH_S_WARMUPDURATION => [ 'gamemode' => ['Cup', 'Knockout', 'Laps', 'Teams', 'TimeAttack', 'TMWC2023', 'TMWTTeams', 'Rounds'], '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' => ['Cup', 'Knockout', 'Laps', 'Teams', 'TimeAttack', 'TMWC2023', 'TMWTTeams', 'Rounds'], 'type' => 'integer', 'default' => 1, 'description' => 'Number of Warm Up' ], self::SETTING_MATCH_S_WARMUPTIMEOUT => [ 'gamemode' => ['Cup', 'Knockout', 'Laps', 'Teams', 'TimeAttack', 'TMWC2023', 'TMWTTeams', 'Rounds'], 'type' => 'integer', 'default' => -1, 'description' => 'Time after the first finished the WarmUP (-1 = based on Author time, only when S_WarmUpDuration = -1)' ] ]; const SETTINGS_MODE_LIST = [ self::SETTING_MODE_MAPS => [ 'mode' => ['All from the plugin'], 'type' => 'string', 'default' => 'Campaigns/Training/Training - 01.Map.Gbx,Campaigns/Training/Training - 02.Map.Gbx', 'description' => 'Map files separated by comma' ], self::SETTING_MODE_SHUFFLE => [ 'mode' => ['All from the plugin'], 'type' => 'boolean', 'default' => false, 'description' => 'Shuffle maps order' ], self::SETTING_MODE_HIDENEXTMAPS => [ 'mode' => ['All from the plugin'], 'type' => 'boolean', 'default' => false, 'description' => 'Hide maps to players' ], self::SETTING_MODE_MAPLIST_FILE => [ 'mode' => ['Maps from file & Settings from plugin', 'All from file'], 'type' => 'string', 'default' => 'match.txt', 'description' => 'Maps + Matchsettings file to load (empty to use server login)' ], self::SETTING_MATCH_CUSTOM_GAMEMODE => [ 'mode' => ['All from the plugin', 'Maps from file & Settings from plugin'], 'type' => 'string', 'default' => '', 'description' => 'Load custom gamemode script (some functions can bug, for expert only)' ], ]; /* * 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 $nbmaps = 0; private $nbrounds = 0; private $currentgmbase = ""; private $currentcustomgm = ""; private $currentsettingmode = ""; private $currentmap = null; private $matchrecover = false; private $pointstorecover = array(); // Settings to keep in memory private $settings_nbroundsbymap = 5; private $settings_nbwinners = 2; private $settings_nbmapsbymatch = 0; private $settings_pointlimit = 100; private $settings_disablegotomap= false; private $currentscore = array(); /** @var OnScoresStructure|null $preendroundscore */ private $preendroundscore = null; private $currentteamsscore = array(); private $pausetimer = 0; private $pauseon = false; private $skipround = false; private $settingsloaded = false; private $postmatch = false; private $mapsshuffled = false; private $mapshidden = false; private $hidenextmaps = false; private $maps = array(); private $currentgmsettings = array(); 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(); //Settings // Last argument is the priority to sort settings, works only with the TrackManiaControl fork (https://git.virtit.fr/beu/TrackManiaControl) if (defined("\ManiaControl\ManiaControl::ISTRACKMANIACONTROL") && $this->maniaControl->getSettingManager()->getSettingValue($this->maniaControl->getSettingManager(), SettingManager::SETTING_ALLOW_UNLINK_SERVER)) { $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_DONT_DELETE_SETTINGS, false, "to prevent to remove a setting of an another server", 5); } $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_AUTHLEVEL, AuthenticationManager::getPermissionLevelNameArray(AuthenticationManager::AUTH_LEVEL_ADMIN), "Admin level needed to use the plugin", 10); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_PAUSE_DURATION, 120, "Default Pause Duration in seconds", 15); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_PAUSE_POSX, 0, "Position of the Pause Countdown (on X axis)", 15); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_PAUSE_POSY, 43, "Position of the Pause Countdown (on Y axis)", 15); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_SETTINGS_MODE, array('All from the plugin', 'Maps from file & Settings from plugin', 'All from file'), "Loading mode for maps and match settings, depending on your needs", 20); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_POST_MATCH_MAPLIST, "", "Load Mapfile after the match (empty to just load TA on the same maps) (can be unstable)", 20); $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MATCH_GAMEMODE_BASE, array("Cup", "Knockout", "Laps", "Teams", "TimeAttack", "TMWC2023", "TMWTTeams", "Rounds", "RoyalTimeAttack"), "Gamemode to launch for the match", 25); // Init dynamics settings $this->updateSettings(); //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('matchrecover', $this, 'onCommandMatchRecover', true, 'Recover 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 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(Callbacks::TM_SCORES, $this, 'handleTrackmaniaScore'); $this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::MP_STARTROUNDSTART, $this, 'handleBeginRoundCallback'); $this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::TM_WARMUPSTARTROUND, $this, 'handleStartWarmUpCallback'); $this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::MP_STARTMATCHSTART, $this, 'handleStartMatchStartCallback'); $this->maniaControl->getCallbackManager()->registerCallbackListener(CallbackManager::CB_MP_BEGINMAP, $this, 'handleBeginMapCallback'); $this->maniaControl->getCallbackManager()->registerCallbackListener(CallbackManager::CB_MP_BEGINMATCH, $this, 'handleBeginMatchCallback'); // 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.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($this->currentgmbase,$this->currentcustomgm)); }); } /** * @see \ManiaControl\Plugins\Plugin::unload() */ public function unload() { $this->closePauseWidget(); } /** * 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(36) NOT NULL, `matchpoints` INT(10) NOT NULL, `mappoints` INT(10) NOT NULL, `roundpoints` INT(10) NOT NULL, `bestracetime` INT(10) NOT NULL, `bestracecheckpoints` VARCHAR(1000) NOT NULL, `bestlaptime` INT(10) NOT NULL, `bestlapcheckpoints` VARCHAR(1000) NOT NULL, `prevracetime` INT(10) NOT NULL, `prevracecheckpoints` VARCHAR(1000) NOT NULL, `teamid` INT(3) 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, `rank` INT(3) NOT NULL, `id` INT(3) NOT NULL, `team` VARCHAR(30) NOT NULL, `matchpoints` INT(10) NOT NULL, `mappoints` INT(10) NOT NULL, `roundpoints` 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); } // Update table data $mysqliconfig = $this->maniaControl->getDatabase()->getConfig(); $query = 'SELECT NULL FROM INFORMATION_SCHEMA.COLUMNS WHERE `table_schema` = "' . $mysqliconfig->name . '" AND `table_name` = "' . self::DB_ROUNDSDATA . '" AND `column_name` = "mappoints";'; if ($mysqli->query($query)->num_rows === 0) { $query = 'ALTER TABLE `' . self::DB_ROUNDSDATA . '` ADD COLUMN `mappoints` INT(10) NOT NULL AFTER `matchpoints`, CHANGE `time` `bestracetime` INT(10) NOT NULL, ADD COLUMN `bestracecheckpoints` VARCHAR(1000) NOT NULL AFTER `bestracetime`, ADD COLUMN `bestlaptime` INT(10) NOT NULL AFTER `bestracecheckpoints`, ADD COLUMN `bestlapcheckpoints` VARCHAR(1000) NOT NULL AFTER `bestlaptime`, ADD COLUMN `prevracetime` INT(10) NOT NULL AFTER `bestlapcheckpoints`, ADD COLUMN `prevracecheckpoints` VARCHAR(1000) NOT NULL AFTER `prevracetime`, MODIFY `teamid` INT(3) NOT NULL;'; $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error, E_USER_ERROR); } $query = 'ALTER TABLE `' . self::DB_TEAMSDATA . '` ADD COLUMN `rank` INT(3) NOT NULL, MODIFY `id` INT(3) NOT NULL, CHANGE `points` `matchpoints` INT(10) NOT NULL, ADD COLUMN `mappoints` INT(10) NOT NULL AFTER `matchpoints`, ADD COLUMN `roundpoints` INT(10) NOT NULL AFTER `mappoints`;'; $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error, E_USER_ERROR); } } $query = 'SELECT NULL FROM INFORMATION_SCHEMA.COLUMNS WHERE `table_schema` = "' . $mysqliconfig->name . '" AND `table_name` = "' . self::DB_ROUNDSDATA . '" AND `column_name` = "login" AND `CHARACTER_MAXIMUM_LENGTH` = 36;'; if ($mysqli->query($query)->num_rows === 0) { $query = 'ALTER TABLE `' . self::DB_ROUNDSDATA . '` MODIFY `login` VARCHAR(36) NOT NULL;'; $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error, E_USER_ERROR); } } } public function getMatchStatus() { return $this->matchStarted; } public function getMatchIsRunning() { return ($this->matchStarted && $this->settingsloaded && !$this->postmatch); } public function getCurrentGamemodeBase() { return $this->currentgmbase; } 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 getRoundNumber() { return $this->nbrounds; } public function getMapNumber() { return $this->nbmaps; } public function getMatchPointsLimit() { return $this->settings_pointlimit; } public function getNbWinners() { return $this->settings_nbwinners; } public function getPauseStatus() { return $this->pauseon; } /** * Update Widgets on Setting Changes * * @param Setting $setting */ public function updateSettings(Setting $setting = null) { if (isset($setting) && $setting->belongsToClass($this) && $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 ($setting->setting == self::SETTING_MATCH_CUSTOM_GAMEMODE && $setting->value != $this->currentcustomgm) { $setting->value = $this->currentcustomgm; $this->maniaControl->getSettingManager()->saveSetting($setting); $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'You can\'t change the Custom Gamemode during a Match'); } else if ($setting->setting == self::SETTING_MATCH_SETTINGS_MODE && $setting->value != $this->currentsettingmode) { $setting->value = $this->currentsettingmode; $this->maniaControl->getSettingManager()->saveSetting($setting); $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'You can\'t change the Setting Mode during a Match'); } else if ($setting->setting == self::SETTING_MODE_HIDENEXTMAPS && $setting->value != $this->hidenextmaps) { $setting->value = $this->hidenextmaps; $this->maniaControl->getSettingManager()->saveSetting($setting); $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'It\'s not possible to choose to hide or display the maps during a match'); } else { if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_SETTINGS_MODE) != 'All from file') { Logger::log("Load Script Settings"); try { $this->loadGMSettings($this->getGMSettings($this->currentgmbase,$this->currentcustomgm)); 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.'); } } } else if (isset($setting) && $setting->belongsToClass($this)) { if ($setting->setting == self::SETTING_MATCH_CUSTOM_GAMEMODE && $setting->value != "") { $scriptfile = $this->maniaControl->getServer()->getDirectory()->getUserDataFolder() . DIRECTORY_SEPARATOR . "Scripts" . DIRECTORY_SEPARATOR . "Modes" . DIRECTORY_SEPARATOR . $setting->value; if (!file_exists($scriptfile)) { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'Unable to find the gamemode file: "' . $setting->value . '"'); } } else if ($setting->setting == self::SETTING_MODE_MAPLIST_FILE && $setting->value != "") { $scriptfile = $this->maniaControl->getServer()->getDirectory()->getMapsFolder() ."MatchSettings" . DIRECTORY_SEPARATOR . $setting->value; if (!file_exists($scriptfile)) { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'Unable to find the Maplist file: "' . $setting->value . '"'); } } else if ($setting->setting == self::SETTING_MATCH_POST_MATCH_MAPLIST && $setting->value != "") { $scriptfile = $this->maniaControl->getServer()->getDirectory()->getMapsFolder() ."MatchSettings" . DIRECTORY_SEPARATOR . $setting->value; if (!file_exists($scriptfile)) { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'Unable to find the Post match Maplist file: "' . $setting->value . '"'); } } else if ($setting->setting == self::SETTING_MODE_MAPS && $setting->value != "") { $maps = explode(',', $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MODE_MAPS)); foreach ($maps as $map) { try { $this->maniaControl->getClient()->getMapInfo($map); } catch (\Exception $e) { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'Unable to find the map: "' . $map . '"'); } } } } if (defined("\ManiaControl\ManiaControl::ISTRACKMANIACONTROL") && $this->maniaControl->getSettingManager()->getSettingValue($this->maniaControl->getSettingManager(), SettingManager::SETTING_ALLOW_UNLINK_SERVER)) { $deletesettings = !$this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_DONT_DELETE_SETTINGS); } else { $deletesettings = true; } $allsettings = $this->maniaControl->getSettingManager()->getSettingsByClass($this); $settingsmode = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_SETTINGS_MODE); $modesettings = $this->getModeSettings($settingsmode); foreach ($allsettings as $key => $value) { $name = $value->setting; if (array_key_exists($name,self::SETTINGS_MODE_LIST)) { if (!isset($modesettings[$name])) { if ($deletesettings) $this->maniaControl->getSettingManager()->deleteSetting($this, $name); } } } foreach ($modesettings as $key => $value) { $this->maniaControl->getSettingManager()->initSetting($this, $key, self::SETTINGS_MODE_LIST[$key]['default'], self::SETTINGS_MODE_LIST[$key]['description'], 50); } if ($settingsmode == 'Maps from file & Settings from plugin' || $settingsmode == 'All from the plugin') { $gmsettings = $this->getGMSettings($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_GAMEMODE_BASE), $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_CUSTOM_GAMEMODE)); foreach ($allsettings as $key => $value) { $name = $value->setting; if (substr($name,0, 2) == "S_" && !isset($gmsettings[$name])) { if ($deletesettings) $this->maniaControl->getSettingManager()->deleteSetting($this, $name); } } foreach ($gmsettings as $key => $value) { $this->maniaControl->getSettingManager()->initSetting($this, $key, $value['default'], $value['description'], 100); } } else { foreach ($allsettings as $key => $value) { $name = $value->setting; if (substr($name,0, 2) == "S_") { if ($deletesettings) $this->maniaControl->getSettingManager()->deleteSetting($this, $name); } } } } /** * Reset match variables * * @param Setting $setting */ public function resetMatchVariables() { $this->matchStarted = false; $this->matchrecover = false; $this->pointstorecover = array(); $this->currentscore = array(); $this->preendroundscore = array(); $this->settingsloaded = false; $this->mapsshuffled = false; $this->mapshidden = false; $this->hidenextmaps = false; $this->maps = array(); $this->postmatch = true; $this->matchid = ""; $this->settings_nbroundsbymap = -1; $this->settings_nbwinners = 2; $this->settings_nbmapsbymatch = 0; $this->settings_pointlimit = 100; $this->currentgmbase = ""; $this->currentcustomgm = ""; $this->currentsettingmode = ""; } /** * Load Gamemode settings excluding not used settings in custom gamemodes * * @param array $gmsettings */ private function loadGMSettings($gmallsettings) { $currentgmsettings = $this->maniaControl->getClient()->getModeScriptSettings(); foreach ($gmallsettings as $gamemodename => $info) { if (isset($currentgmsettings[$gamemodename])) { $gmsettings[$gamemodename] = $info['value']; } } $this->maniaControl->getClient()->setModeScriptSettings($gmsettings); } /** * Get Array with all settings of the Gamemode * * @param String $gamemode */ public function getGMSettings(String $gamemodebase, String $customgamemode) { $gamesettings = []; foreach (self::GAMEMODES_LIST_SETTINGS as $gamesetting => $info) { if (in_array('Global', $info['gamemode']) || in_array($gamemodebase, $info['gamemode'])) { $gamesettings = array_merge($gamesettings , array($gamesetting => $info)); } } if ($customgamemode != "") { $filename = $this->maniaControl->getServer()->getDirectory()->getUserDataFolder() . DIRECTORY_SEPARATOR . "Scripts" . DIRECTORY_SEPARATOR . "Modes" . DIRECTORY_SEPARATOR . $customgamemode; if (file_exists($filename)) { $handle = fopen($filename, "r"); if ($handle) { while (($line = fgets($handle)) !== false) { if (preg_match('/^(\s*)\#Setting\s+(S_\S+)\s+(\S+)\s*(as\s|)(_\(|)("|\'|)([^\'"]*)("\)|\'\)|"|\'| |)/', $line, $matches)) { $gamesettingname = $matches[2]; $defaultvalue = $matches[3]; if (is_numeric($matches[3]) && is_float($matches[3]+0)) { $type = "float"; } else if (is_numeric($matches[3])) { $type = "integer"; } else if (strtolower($matches[3]) == "true" || strtolower($matches[3]) == "false") { $type = "boolean"; if (strtolower($matches[3]) == "false") $defaultvalue = ""; } else { $defaultvalue = str_replace(["'", '"'], "" , $matches[3]); $type = "string"; } $description = $matches[7]; settype($defaultvalue, $type); $gamesettings = array_merge($gamesettings , array($gamesettingname => [ 'type' => $type, 'default' => $defaultvalue, 'description' => $description ])); } else if (preg_match('/^\*\*\*/',$line)) { break; } } fclose($handle); } else { Logger::logError("Impossible to read custom gamemode file"); $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . " Impossible to read custom gamemode file"); } } } foreach ($gamesettings as $settingname => $info) { $gamesettings[$settingname]['value'] = $this->maniaControl->getSettingManager()->getSettingValue($this, $settingname); if ($gamesettings[$settingname]['value'] == null) { $gamesettings[$settingname]['value'] = $info['default']; } settype($gamesettings[$settingname]['value'], $info['type']); } return $gamesettings; } /** * Get Array with all settings of the Gamemode * * @param String $gamemode */ public function getModeSettings(String $mode) { $modesettings = []; foreach (self::SETTINGS_MODE_LIST as $setting => $info) { if (in_array('Global', $info['mode']) || in_array($mode, $info['mode'])) { $value = $this->maniaControl->getSettingManager()->getSettingValue($this, $setting); if ($value == null) { $value = $info['default']; } settype($value, $info['type']); $modesettings = array_merge($modesettings , array($setting => $value )); } } return $modesettings; } /** * 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]; } else { $this->settings_nbroundsbymap = -1; } if (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_DISABLEGOTOMAP])) { $this->settings_disablegotomap = (bool) $this->currentgmsettings[self::SETTING_MATCH_S_DISABLEGOTOMAP]; } } /** * Function called to list matches */ public function getMatchesList($limit = 10) { $mysqli = $this->maniaControl->getDatabase()->getMysqli(); $query = "SELECT `gamemodebase`,`started`,`ended` FROM `" . self::DB_MATCHESINDEX . "` ORDER BY `started` DESC LIMIT " . $limit; $result = $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error); return false; } while($row = $result->fetch_array()) { $array[] = $row; } return $array; } /** * Function called to start the match */ public function MatchStart() { if ($this->matchStarted) { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . " a match is already launched"); return; } try { $this->matchid = $this->maniaControl->getServer()->login . "-" . time(); $this->currentgmbase = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_GAMEMODE_BASE); $this->currentcustomgm = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_CUSTOM_GAMEMODE); $this->currentsettingmode = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_SETTINGS_MODE); $maplist = ""; if ($this->currentgmbase == "RoyalTimeAttack") { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . "No data are save in RoyalTimeAttack for the moment, it's not implemented on server side. Waiting a fix from NADEO"); Logger::Log("No data are save in RoyalTimeAttack for the moment, it's not implemented on server side. Waiting a fix from NADEO"); } // Prepare maps in case of "All from the plugin" mode if ($this->currentsettingmode == 'All from the plugin' && strlen($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MODE_MAPS)) >= 1) { $maps = explode(',', $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MODE_MAPS)); foreach ($maps as $map) { try { $mapInfo = $this->maniaControl->getMapManager()->initializeMap($this->maniaControl->getClient()->getMapInfo($map)); } catch (Exception $e) { throw new \Exception("Error with the map " . $map . ": " . $e->getMessage()); } } if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MODE_SHUFFLE)) { $this->mapsshuffled = true; shuffle($maps); } //Remove all maps foreach ($this->maniaControl->getMapManager()->getMaps() as $map) { $this->maniaControl->getClient()->removeMap($map->fileName); } $this->maps = $maps; $this->hidenextmaps = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MODE_HIDENEXTMAPS); } // Define Gamemode if ($this->currentsettingmode != 'All from file') { 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 . '!'); $this->maniaControl->getClient()->setScriptName($scriptName); } // Must be after loading the script in case of different MapType if ($this->currentsettingmode != 'All from the plugin') { Logger::log("Loading maplist + matchsettings"); $maplist = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MODE_MAPLIST_FILE); if (empty($maplist)) { $server = $this->maniaControl->getServer()->login; $maplist = 'MatchSettings' . DIRECTORY_SEPARATOR . $server . ".txt"; } else { $maplist = 'MatchSettings' . DIRECTORY_SEPARATOR . $maplist; } Logger::log("Load matchsettings: " . $maplist); if (!is_file($this->maniaControl->getServer()->getDirectory()->getMapsFolder() . $maplist)) { throw new \Exception("The Maplist file is not accessible or does not exist (the match has not started)"); } //Remove all maps foreach ($this->maniaControl->getMapManager()->getMaps() as $map) { $this->maniaControl->getClient()->removeMap($map->fileName); } $this->maniaControl->getClient()->InsertPlaylistFromMatchSettings($maplist); } elseif ($this->currentsettingmode == 'All from the plugin') { if ($this->hidenextmaps) { $this->maniaControl->getClient()->addMap($this->maps[0]); } else { foreach ($this->maps as $map) { $this->maniaControl->getClient()->addMap($map); } } } Logger::log("Restructure maplist"); $this->maniaControl->getMapManager()->restructureMapList(); $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); } // 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) { throw new \Exception("Error during the MySQL insert: " . $mysqli->error); } // Trigger Callback $settings = [ 'currentgmbase' => $this->currentgmbase, 'scriptName' => $scriptName, 'maplist' => $maplist, 'mapsshuffled' => $this->mapsshuffled, 'mapshidden' => $this->mapshidden, 'maps' => $this->maps]; $this->maniaControl->getCallbackManager()->triggerCallback(self::CB_MATCHMANAGER_STARTMATCH, $this->matchid, $settings); Logger::log("Skip map"); $this->maniaControl->getMapManager()->getMapActions()->skipMap(); } catch (Exception $e) { $this->resetMatchVariables(); Logger::log($e->getMessage()); $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . $e->getMessage()); } } /** * Function called to end the match */ public function MatchEnd() { try { // Load TimeAttack gamemode if possible $maplist = 'MatchSettings' . DIRECTORY_SEPARATOR . $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_POST_MATCH_MAPLIST); if (is_file($this->maniaControl->getServer()->getDirectory()->getMapsFolder() . $maplist)) { $this->maniaControl->getClient()->loadMatchSettings($maplist); } else { if ($this->currentmap->mapType == "TrackMania\TM_Race") { $scriptname = "Trackmania/TM_TimeAttack_Online.Script.txt" ; } else if ($this->currentmap->mapType == "TrackMania\TM_Royal") { $scriptname = "Trackmania/TM_RoyalTimeAttack_Online.Script.txt" ; } if (isset($scriptname)) { Logger::log("Loading script: " . $scriptname); $this->maniaControl->getClient()->setScriptName($scriptname); } } // MYSQL DATA INSERT $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("Match finished"); $this->resetMatchVariables(); // Teams Specifics variables $this->currentteamsscore = []; } 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"); if (!$this->matchStarted) { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . " No match launched"); return; } 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!'); // Load TimeAttack gamemode if possible $maplist = 'MatchSettings' . DIRECTORY_SEPARATOR . $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_POST_MATCH_MAPLIST); if (is_file($this->maniaControl->getServer()->getDirectory()->getMapsFolder() . $maplist)) { $this->maniaControl->getClient()->loadMatchSettings($maplist); } else { if ($this->currentmap->mapType == "TrackMania\TM_Race") { $scriptname = "Trackmania/TM_TimeAttack_Online.Script.txt" ; } else if ($this->currentmap->mapType == "TrackMania\TM_Royal") { $scriptname = "Trackmania/TM_RoyalTimeAttack_Online.Script.txt" ; } if (isset($scriptname)) { Logger::log("Loading script: " . $scriptname); $this->maniaControl->getClient()->setScriptName($scriptname); } } $this->resetMatchVariables(); } 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(); } /** * Function called to recover a match * @param integer $index */ public function MatchRecover(Int $index) { Logger::log("Match Recover"); $mysqli = $this->maniaControl->getDatabase()->getMysqli(); $query = "SELECT `matchid`,`gamemodebase` FROM `" . self::DB_MATCHESINDEX . "` ORDER BY `started` DESC LIMIT " . $index . ",1"; $result = $mysqli->query($query); $array = mysqli_fetch_array($result); if (isset($array[0])) { $gamemodebase = $array['gamemodebase']; $matchid = $array['matchid']; unset($array); $this->matchrecover = true; $query = "SELECT `timestamp`,`settings`,`nbmaps`,`nbrounds` FROM `" . self::DB_ROUNDSINDEX . "` WHERE `matchid` = '" . $matchid . "' ORDER BY `timestamp` DESC LIMIT 1"; $result = $mysqli->query($query); $array = mysqli_fetch_array($result); if (isset($array[0])) { $nbmaps=$array['nbmaps']; $nbrounds=$array['nbrounds']; $settings=$array['settings']; $timestamp=$array['timestamp']; unset($array); if ($gamemodebase == "Teams") { $query = "SELECT `id` AS login,`points` AS matchpoints FROM `" . self::DB_TEAMSDATA . "` WHERE `timestamp` = (SELECT `timestamp` FROM `" . self::DB_TEAMSDATA . "` WHERE `matchid` = '" . $matchid . "' ORDER BY `timestamp` DESC LIMIT 1)" ; } else { $query = "SELECT `login`,`matchpoints` FROM `" . self::DB_ROUNDSDATA . "` WHERE `timestamp` = '" . $timestamp . "'"; } $result = $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error); return false; } while($row = $result->fetch_array()) { $array[] = $row; } if (isset($array[0])) { $this->matchrecover = true; foreach ($array as $index => $value) { if (isset($value['login'])) { $this->pointstorecover[$value['login']] = $value['matchpoints']; } } $this->maniaControl->getChat()->sendSuccess($this->chatprefix . 'Recovering the match: ' . $matchid ); Logger::log('Recovering the match: ' . $matchid); $this->MatchStart(); } else { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'No data found from the last round'); } } else { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'No Rounds found for this match'); } } else { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . 'Match not found'); } } /** * Function called to recover points */ private function recoverPoints() { if (!empty($this->pointstorecover)) { if ($this->currentgmbase == "Teams") { // Blue Team $this->maniaControl->getModeScriptEventManager()->setTrackmaniaTeamPoints("0", "", $this->pointstorecover[0], $this->pointstorecover[0]); $this->maniaControl->getChat()->sendSuccess($this->chatprefix . '$<$ff0' . $this->pointstorecover[0] . '$> points recovered for the $<$00fBlue$> Team'); // Red Team $this->maniaControl->getModeScriptEventManager()->setTrackmaniaTeamPoints("1", "", $this->pointstorecover[1], $this->pointstorecover[1]); $this->maniaControl->getChat()->sendSuccess($this->chatprefix . '$<$ff0' . $this->pointstorecover[1] . '$> points recovered for the $<$f00Red$> Team'); Logger::log("Point recovered: Blue " . $this->pointstorecover[0] . " - Red " . $this->pointstorecover[1]); $this->pointstorecover = []; } else { foreach ($this->pointstorecover as $index => $value) { $player = $this->maniaControl->getPlayerManager()->getPlayer($index, true); if ($player) { if (!empty($this->currentscore)) { $key = array_search($index, array_column($this->currentscore, '1')); if (!($key === false)) { $points = $value + $this->currentscore[$key][2]; } else { $points = $value; } } else { $points = $value; } $this->maniaControl->getModeScriptEventManager()->setTrackmaniaPlayerPoints($player, "", "", $points); $this->maniaControl->getChat()->sendSuccess($this->chatprefix . 'Your $<$ff0' . $value . '$> points have been recovered', $player); unset($this->pointstorecover[$index]); Logger::log("Point recovered: " . $index . " " . $points . "(+" . $value . ")"); } } } } } /** * Set pause * * @param boolean $admin * @param integer $time */ public 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->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->displayPauseWidget(); $this->maniaControl->getTimerManager()->registerOneTimeListening($this, function () { $this->unsetNadeoPause(); }, $this->pausetimer * 1000); } } /** * Unset pause */ private function unsetNadeoPause() { if ($this->pauseon) { Logger::log("End Pause"); $this->closePauseWidget(); $this->pauseon = false; $this->skipround = true; $this->maniaControl->getModeScriptEventManager()->endPause(); } } /** * Display Pause Widget * */ public function displayPauseWidget() { $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 () { if ($this->pausetimer > 0 && $this->pauseon) { $this->pausetimer--; $this->displayPauseWidget(); } 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); } /** * Handle when a player connect * * @param \ManiaControl\Players\Player $player */ public function handlePlayerConnect(Player $player) { if ($this->pauseon) { $this->displayPauseWidget($player->login); } } /** * Handle when a player disconnects * * @param \ManiaControl\Players\Player $player */ public function handlePlayerDisconnect(Player $player) { $this->closePauseWidget($player->login); } /** * Handle XMLRPC callback "Maniaplanet.StartMatch_Start" */ public function handleStartMatchStartCallback() { Logger::log("handleStartMatchStartCallback"); if ($this->matchStarted) { Logger::log("Loading settings"); $this->settingsloaded = true; if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_SETTINGS_MODE) != 'All from file') { Logger::log("Load Script Settings"); $this->loadGMSettings($this->getGMSettings($this->currentgmbase, $this->currentcustomgm)); } $this->updateGMvariables(); } else if ($this->postmatch) { $this->postmatch = false; Logger::log("Load PostMatch Gamemode Settings"); $maplist = 'MatchSettings' . DIRECTORY_SEPARATOR . $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_POST_MATCH_MAPLIST); if (is_file($this->maniaControl->getServer()->getDirectory()->getMapsFolder() . $maplist)) { $this->maniaControl->getClient()->loadMatchSettings($maplist); } else { $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 ]; $currentgmsettings = $this->maniaControl->getClient()->getModeScriptSettings(); foreach ($postmatchsettings as $gamesettingname => $value) { if (!array_key_exists($gamesettingname,$currentgmsettings)) { unset($postmatchsettings[$gamesettingname]); } } $this->maniaControl->getClient()->setModeScriptSettings($postmatchsettings); } } } /** * Handle Maniacontrol callback "BeginMatch" */ public function handleBeginMatchCallback() { Logger::log("handleBeginMatchCallback"); if ($this->matchStarted && !$this->settingsloaded) { Logger::log("Restarting map to restart match data"); $this->maniaControl->getClient()->restartMap(); } else if ($this->matchStarted && $this->settingsloaded && $this->nbrounds == 0) { Logger::Log("Check if Points Repartition need to be re-applied"); $this->maniaControl->getModeScriptEventManager()->getTrackmaniaPointsRepartition()->setCallable(function (OnPointsRepartitionStructure $structure) { $currentgmsettings = $this->maniaControl->getClient()->getModeScriptSettings(); if (!is_null($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_S_POINTSREPARTITION)) && isset($currentgmsettings[self::SETTING_MATCH_S_POINTSREPARTITION])) { $pointrepartitionarray = explode(",", $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_S_POINTSREPARTITION)); if ($structure->getPointsRepartition() != $pointrepartitionarray) { Logger::Log("re-applying Points Repartition for workaround"); $newpoints = array(self::SETTING_MATCH_S_POINTSREPARTITION => $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_S_POINTSREPARTITION) . ',' . end($pointrepartitionarray)); $this->maniaControl->getClient()->setModeScriptSettings($newpoints); } } }); } } /** * Handle Maniacontrol callback "BeginMap" */ public function handleBeginMapCallback() { Logger::log("handleBeginMapCallback"); if ($this->matchStarted) { $this->nbmaps++; $this->nbrounds = 0; if ($this->nbmaps > 0) { $maps = $this->maniaControl->getMapManager()->getMaps(); $totalnbmaps = $this->maniaControl->getMapManager()->getMapsCount(); $this->currentmap = $this->maniaControl->getMapManager()->getCurrentMap(); Logger::log("Current Map: " . Formatter::stripCodes($this->currentmap->name)); $message = $this->chatprefix . '$<$o$iCurrent Map:$>' . "\n"; $message .= Formatter::stripCodes($this->currentmap->name); $this->maniaControl->getChat()->sendInformation($message); if (!in_array($this->currentgmbase, ["Laps", "TimeAttack", "RoyalTimeAttack"]) && !$this->settings_disablegotomap) { $message = ""; $i = 0; foreach ($maps as $map) { if ($this->currentmap->uid == $map->uid) { break; } $i++; } if (($this->settings_nbmapsbymatch > 0 && $i < $this->settings_nbmapsbymatch - 1 && $this->nbmaps < $this->settings_nbmapsbymatch) || ($this->settings_nbmapsbymatch <= 0 && ($totalnbmaps >= 2 || count($this->maps) >= 2))) { // TODO manage maps in queue added by an admin $message = $this->chatprefix . '$<$o$iNext Maps:$>'; $nbhiddenmaps = 0; if ($this->hidenextmaps) { if ($totalnbmaps < count($this->maps)) { if ($this->settings_nbmapsbymatch > 0) { $nbhiddenmaps = min(count($this->maps) - $totalnbmaps, $this->settings_nbmapsbymatch - 1); } else { $nbhiddenmaps = count($this->maps) - $totalnbmaps; } $message .= "\nThen " . $nbhiddenmaps . " hidden maps"; Logger::log("Then " . $nbhiddenmaps . " hidden maps"); } } for ($j = 1; $j + $nbhiddenmaps <= 4 && (($this->settings_nbmapsbymatch > 0 && $j + $nbhiddenmaps <= $this->settings_nbmapsbymatch - $this->nbmaps) || ($this->settings_nbmapsbymatch <= 0 && $j + $nbhiddenmaps <= $totalnbmaps)) ; $j++ ) { $index = $i + $j; while ($index >= $totalnbmaps) { // return to the start of the array if end of array $index = $index - $totalnbmaps; } if ($index != $i) { $message .= "\n" . $j . ": " . Formatter::stripCodes($maps[$index]->name); Logger::log(Formatter::stripCodes($index . ": " . $maps[$index]->name)); } else { $message .= "\nThen we will return to this map"; Logger::log("Then we will return to this map"); $j = 0; break; } } if ($j + $nbhiddenmaps >= 4) { if ($this->settings_nbmapsbymatch > 0 && $this->settings_nbmapsbymatch - $j - $nbhiddenmaps - $this->nbmaps + 1 > 0) { $message .= "\n" . "And " . ($this->settings_nbmapsbymatch - $j - $nbhiddenmaps - $this->nbmaps + 1) . " more maps"; Logger::log("And " . ($this->settings_nbmapsbymatch - $j - $nbhiddenmaps - $this->nbmaps + 1) . " more maps"); } elseif ($this->settings_nbmapsbymatch <= 0 && ($totalnbmaps - $j - $nbhiddenmaps > 0 || count($this->maps) - $j - $nbhiddenmaps > 0)) { $n = max($totalnbmaps - $j - $nbhiddenmaps, count($this->maps) - $j - $nbhiddenmaps); $message .= "\n" . "And " . $n . " more maps"; Logger::log("And " . $n . " more maps"); } } $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); } } /** * Handle callback "WarmUp.StartRound" */ public function handleStartWarmUpCallback() { Logger::log("handleStartWarmUpCallback"); // Match Recover if ($this->matchrecover) { $this->recoverPoints(); } } /** * Handle callback "BeginRound" */ public function handleBeginRoundCallback(StartEndStructure $structure) { Logger::log("handleBeginRoundCallback"); if ($this->matchStarted && $this->nbmaps > 0) { if (defined("\ManiaControl\ManiaControl::ISTRACKMANIACONTROL") && method_exists($structure, "getValidRoundCount")) { $this->nbrounds = $structure->getValidRoundCount(); } else if (property_exists($structure->getPlainJsonObject(), "valid")) { $this->nbrounds = $structure->getPlainJsonObject()->valid; } else { $this->nbrounds = $structure->getCount(); } 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->settings_nbroundsbymap > 1) { $this->maniaControl->getChat()->sendInformation($this->chatprefix . '$o$iRound: ' . $this->nbrounds . ' / ' . $this->settings_nbroundsbymap); Logger::log("Round: " . $this->nbrounds . ' / ' . $this->settings_nbroundsbymap); } } }); } // Match Recover if ($this->matchrecover) { $this->recoverPoints(); } } } /** * Handle callback "EndRound" * * @param OnScoresStructure $structure */ public function handleTrackmaniaScore(OnScoresStructure $structure) { Logger::log("handleTrackmaniaScore-" . $structure->getSection()); if ($this->matchStarted && $this->settingsloaded && !$this->postmatch) { Logger::log("Section: " . $structure->getSection()); if ($structure->getSection() == "EndMatchEarly") { $this->MatchEnd(); } elseif ($structure->getSection() == "EndMap" && $this->hidenextmaps && isset($this->maps[$this->nbmaps])) { $this->maniaControl->getClient()->addMap($this->maps[$this->nbmaps]); } elseif ($structure->getSection() == "PreEndRound") { $this->preendroundscore = $structure; } elseif ($structure->getSection() == "EndRound") { $timestamp = time(); if ($this->nbmaps != 0 && ($this->nbrounds <= $this->settings_nbroundsbymap || $this->settings_nbroundsbymap <= 0)) { // // Players Scores // $this->currentscore = array(); $results = $structure->getPlayerScores(); if ($this->currentgmbase == "RoyalTimeAttack") { $this->maniaControl->getChat()->sendErrorToAdmins($this->chatprefix . "No data are save in RoyalTimeAttack for the moment, it's not implemented on server side. Waiting a fix from NADEO"); Logger::Log("No data are save in RoyalTimeAttack for the moment, it's not implemented on server side. Waiting a fix from NADEO"); } $preendroundplayersscore = []; $preendroundteamsscore = []; if ($this->preendroundscore !== null) { $preendroundplayersscore = $this->preendroundscore->getPlayerScores(); $preendroundteamsscore = $this->preendroundscore->getTeamScores();; } $this->preendroundscore = null; //$rank = 1; foreach ($results as $result) { /** @var \ManiaControl\Callbacks\Structures\TrackMania\Models\PlayerScore $result */ $rank = $result->getRank(); $player = $result->getPlayer(); $matchpoints = $result->getMatchPoints(); $mappoints = $result->getMapPoints(); $roundpoints = $result->getRoundPoints(); $bestracetime = $result->getBestRaceTime(); $bestracecheckpoints = implode(",", $result->getBestRaceCheckpoints()); $bestlaptime = $result->getBestLapTime(); $bestlapcheckpoints = implode(",", $result->getBestLapCheckpoints()); $prevracetime = $result->getPrevRaceTime(); $prevracecheckpoints = implode(",", $result->getPrevRaceCheckpoints()); if (count($preendroundplayersscore) > 0) { $preendroundarray = array_filter($preendroundplayersscore, function ($e) use ($player) { return $e->getPlayer() === $player ; }); foreach ($preendroundarray as $key => $preendround) { if ($roundpoints == 0 && $preendround->getRoundPoints() != 0) { $roundpoints = $preendround->getRoundPoints(); } if ($mappoints == 0 && $preendround->getMapPoints() != 0) { $mappoints = $preendround->getMapPoints(); } unset($preendroundplayersscore[$key]); break; } } $this->currentscore = array_merge($this->currentscore, array( array($rank, $player->login, $matchpoints, $mappoints, $roundpoints, $bestracetime, $bestracecheckpoints, $bestlaptime, $bestlapcheckpoints, $prevracetime, $prevracecheckpoints, $player->teamId) )); } // // Teams Scores // $this->currentteamsscore = array(); $teamresults = $structure->getTeamScores(); if (count($teamresults) > 1) { // Resort scores usort($teamresults, function ($a, $b) { return -($a->getMatchPoints() <=> $b->getMatchPoints()); }); $rank = 1; foreach ($teamresults as $teamresult) { $teamid = $teamresult->getTeamId(); $teamname = $teamresult->getName(); $matchpoints = $teamresult->getMatchPoints(); $mappoints = $teamresult->getMapPoints(); $roundpoints = $teamresult->getRoundPoints(); if (count($preendroundteamsscore) > 0) { $preendroundarray = array_filter($preendroundteamsscore, function ($e) use ($teamid) { return $e->getTeamId() === $teamid ; }); foreach ($preendroundarray as $key => $preendround) { if ($roundpoints == 0 && $preendround->getRoundPoints() != 0) { $roundpoints = $preendround->getRoundPoints(); } if ($mappoints == 0 && $preendround->getMapPoints() != 0) { $mappoints = $preendround->getMapPoints(); } unset($preendroundteamsscore[$key]); break; } } $this->currentteamsscore = array_merge($this->currentteamsscore, array( array($rank, $teamid, $teamname, $matchpoints, $mappoints, $roundpoints) )); $rank++; } } // // MySQL queries // $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 $dbquery = 'INSERT INTO `' . self::DB_ROUNDSDATA . '` (`matchid`,`timestamp`,`rank`,`login`,`matchpoints`,`mappoints`,`roundpoints`,`bestracetime`,`bestracecheckpoints`,`bestlaptime`,`bestlapcheckpoints`,`prevracetime`,`prevracecheckpoints`,`teamid`) VALUES '; 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); } // Teams Rounds data if (count($teamresults) > 1) { $teamdbquery = 'INSERT INTO `' . self::DB_TEAMSDATA . '` (`matchid`,`timestamp`,`rank`,`id`,`team`,`matchpoints`,`mappoints`,`roundpoints`) VALUES '; foreach ($this->currentteamsscore as $value) { $teamdbquery .= '("' . $this->matchid . '","' . $timestamp . '","' . implode('","',$value) . '"),'; } $teamdbquery = substr($teamdbquery, 0, -1); $mysqli = $this->maniaControl->getDatabase()->getMysqli(); // Teams data $mysqli->query($teamdbquery); if ($mysqli->error) { trigger_error($mysqli->error); } } Logger::log("Rounds finished: " . $this->nbrounds); $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 //matchrecover for admins * * @param array $chatCallback * @param \ManiaControl\Players\Player $player */ public function onCommandMatchRecover(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; } $text = $chatCallback[1][2]; $text = explode(" ", $text); if (is_numeric($text[1])) { $this->MatchRecover($text[1]); } elseif ($text[1] == "latest") { $this->MatchRecover(0); } else { $lastmatches = $this->getMatchesList(3); $message = $this->chatprefix . '$' . "\n"; foreach ($lastmatches as $index => $value) { if ($index >= 3) { break; } $message .= '$<' . $index . ' - ' . $value['gamemodebase'] . ' started at ' . date("H:i:s", $value['started']); if ($value['ended'] == "0") { $message .= " (Not finished)$>\n"; } else { $message .= " (Finished at " . date("H:i:s", $value['ended'] ). ")$>\n"; } } $this->maniaControl->getChat()->sendSuccess($message, $player); $this->maniaControl->getChat()->sendError($this->chatprefix . 'For the moment, only point recovery is supported, you have to manage maps and rounds manually'); } } /** * 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) && (!in_array($this->currentgmbase, ["Laps", "TimeAttack", "RoyalTimeAttack"]) || ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_SETTINGS_MODE) != 'All from file' && !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 $<$ff0' . $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) && (!in_array($this->currentgmbase, ["Laps", "TimeAttack", "RoyalTimeAttack"]) || ( $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_MATCH_SETTINGS_MODE) != 'All from file' && !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(); } } /** * 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") { $this->maniaControl->getModeScriptEventManager()->setTrackmaniaTeamPoints("0", "", $text[2], $text[2]); $this->maniaControl->getChat()->sendSuccess($this->chatprefix . '$<$00fBlue$> Team now has $<$ff0' . $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 $<$ff0' . $text[2] . '$> points!'); } elseif (is_numeric($text[1])) {//TODO: add support of name of teams (need update from NADEO) $this->maniaControl->getModeScriptEventManager()->setTrackmaniaTeamPoints($text[1], "", $text[2] , $text[2]); $this->maniaControl->getChat()->sendSuccess($this->chatprefix . 'Team ' . $text[1] . ' now has $<$ff0' . $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($text[1]) == 22) { $login = $text[1]; } if ($mysqli->error) { trigger_error($mysqli->error, E_USER_ERROR); } if (isset($login)) { $player = $this->maniaControl->getPlayerManager()->getPlayer($login,true); if ($player) { $this->maniaControl->getModeScriptEventManager()->setTrackmaniaPlayerPoints($player, "", "", $text[2]); $this->maniaControl->getChat()->sendSuccess($this->chatprefix . 'Player $<$ff0' . $player->nickname . '$> now has $<$ff0' . $text[2] . '$> points!'); } else { $this->maniaControl->getChat()->sendError($this->chatprefix . 'Player ' . $text[1] . " isn't connected", $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); } } }