Compare commits

..

11 Commits

16 changed files with 751 additions and 252 deletions

View File

@@ -3,8 +3,10 @@
namespace ManiaControl\Admin; namespace ManiaControl\Admin;
use FML\Controls\Frame; use FML\Controls\Frame;
use FML\Controls\Label;
use FML\Controls\Labels\Label_Button; use FML\Controls\Labels\Label_Button;
use FML\Controls\Labels\Label_Text; use FML\Controls\Labels\Label_Text;
use FML\Controls\Quad;
use FML\Controls\Quads\Quad_BgRaceScore2; use FML\Controls\Quads\Quad_BgRaceScore2;
use FML\Controls\Quads\Quad_BgsPlayerCard; use FML\Controls\Quads\Quad_BgsPlayerCard;
use FML\Controls\Quads\Quad_UIConstruction_Buttons; use FML\Controls\Quads\Quad_UIConstruction_Buttons;
@@ -20,6 +22,7 @@ use ManiaControl\Manialinks\LabelLine;
use ManiaControl\Manialinks\ManialinkManager; use ManiaControl\Manialinks\ManialinkManager;
use ManiaControl\Manialinks\ManialinkPageAnswerListener; use ManiaControl\Manialinks\ManialinkPageAnswerListener;
use ManiaControl\Players\Player; use ManiaControl\Players\Player;
use ManiaControl\Utils\Formatter;
/** /**
* Widget Class listing Authorized Players * Widget Class listing Authorized Players
@@ -118,11 +121,14 @@ class AdminLists implements ManialinkPageAnswerListener, CallbackListener, Usage
$frame->addChild($headFrame); $frame->addChild($headFrame);
$headFrame->setY($posY - 5); $headFrame->setY($posY - 5);
$mainFieldWidth = (($width - 45) / 3) - 2;
$labelLine = new LabelLine($headFrame); $labelLine = new LabelLine($headFrame);
$labelLine->addLabelEntryText('Id', $posX + 5); $labelLine->addLabelEntryText('Id', $posX + 5);
$labelLine->addLabelEntryText('Nickname', $posX + 18); $labelLine->addLabelEntryText('Nickname', $posX + 18);
$labelLine->addLabelEntryText('Login', $posX + 70); $labelLine->addLabelEntryText('Login', $posX + 18 + $mainFieldWidth + 2);
$labelLine->addLabelEntryText('Actions', $posX + 120); $labelLine->addLabelEntryText('Location', $posX + 18 + ($mainFieldWidth + 2) * 2);
$labelLine->addLabelEntryText('Actions', $posX + $width - 18);
$labelLine->render(); $labelLine->render();
$index = 1; $index = 1;
@@ -151,10 +157,13 @@ class AdminLists implements ManialinkPageAnswerListener, CallbackListener, Usage
$lineQuad->setZ(-0.1); $lineQuad->setZ(-0.1);
} }
$path = $admin->getProvince();
$labelLine = new LabelLine($playerFrame); $labelLine = new LabelLine($playerFrame);
$labelLine->addLabelEntryText($index, $posX + 5, 13); $labelLine->addLabelEntryText($index, $posX + 5, 13);
$labelLine->addLabelEntryText($admin->nickname, $posX + 18, 52); $labelLine->addLabelEntryText($admin->nickname, $posX + 18, $mainFieldWidth - 10);
$labelLine->addLabelEntryText($admin->login, $posX + 70, 48); $labelLine->addLabelEntryText($admin->login, $posX + 18 + $mainFieldWidth + 2, $mainFieldWidth - 6);
$labelLine->addLabelEntryText($path, $posX + 18 + ($mainFieldWidth + 2) * 2 + 5, $mainFieldWidth - 2, '', true);
$labelLine->render(); $labelLine->render();
// Level Quad // Level Quad
@@ -174,6 +183,52 @@ class AdminLists implements ManialinkPageAnswerListener, CallbackListener, Usage
$description = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($admin) . " " . $admin->nickname; $description = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($admin) . " " . $admin->nickname;
$rightLabel->addTooltipLabelFeature($descriptionLabel, $description); $rightLabel->addTooltipLabelFeature($descriptionLabel, $description);
// Copy admin name
$quad = new Quad();
$playerFrame->addChild($quad);
$quad->setX($posX + 18 + $mainFieldWidth - 3);
$quad->setSize(3., 3.);
$quad->setStyle('UICommon64_1');
$quad->setSubStyle('Copy_light');
$quad->addClipboardFeature($admin->nickname);
$description = 'Copy player name';
$quad->addTooltipLabelFeature($descriptionLabel, $description);
// Trackmania.io button
$label = new Label();
$playerFrame->addChild($label);
$label->setX($posX + 18 + ($mainFieldWidth + 2) * 2 - 3);
$label->setSize(3., 3.);
$label->setText('$28d');
$label->setTextSize(.8);
$label->setAreaColor('00000000');
$label->setUrl('https://trackmania.io/#/player/'. $admin->login);
$description = 'Open player profile on Trackmania.io';
$label->addTooltipLabelFeature($descriptionLabel, $description);
// Copy admin login
$quad = new Quad();
$playerFrame->addChild($quad);
$quad->setX($posX + 18 + ($mainFieldWidth + 2) * 2 - 6);
$quad->setSize(3., 3.);
$quad->setStyle('UICommon64_1');
$quad->setSubStyle('Copy_light');
$quad->addClipboardFeature($admin->login);
$description = 'Copy player login';
$quad->addTooltipLabelFeature($descriptionLabel, $description);
$countryCode = Formatter::mapCountry($admin->getCountry());
if ($countryCode !== 'OTH') {
// Nation Quad
$countryQuad = new Quad();
$playerFrame->addChild($countryQuad);
$countryQuad->setImageUrl("file://ZoneFlags/Login/{$admin->login}/country");
$countryQuad->setX($posX + 18 + ($mainFieldWidth + 2) * 2 + 2);
$countryQuad->setSize(4, 4);
$countryQuad->addTooltipLabelFeature($descriptionLabel, '$<' . $admin->nickname . '$> from ' . $admin->path);
}
//Revoke Button //Revoke Button
if ($admin->authLevel > 0 if ($admin->authLevel > 0
&& $this->maniaControl->getAuthenticationManager()->checkRight($player, $admin->authLevel + 1) && $this->maniaControl->getAuthenticationManager()->checkRight($player, $admin->authLevel + 1)
@@ -188,7 +243,7 @@ class AdminLists implements ManialinkPageAnswerListener, CallbackListener, Usage
$quad = new Quad_BgsPlayerCard(); $quad = new Quad_BgsPlayerCard();
$playerFrame->addChild($quad); $playerFrame->addChild($quad);
$quad->setZ(11); $quad->setZ(11);
$quad->setX($posX + 130); $quad->setX($posX + $width - 12.5);
$quad->setSubStyle($quad::SUBSTYLE_BgPlayerCardBig); $quad->setSubStyle($quad::SUBSTYLE_BgPlayerCardBig);
$quad->setSize($quadWidth, $quadHeight); $quad->setSize($quadWidth, $quadHeight);
$quad->setAction(self::ACTION_REVOKE_RIGHTS . "." . $admin->login); $quad->setAction(self::ACTION_REVOKE_RIGHTS . "." . $admin->login);
@@ -196,7 +251,7 @@ class AdminLists implements ManialinkPageAnswerListener, CallbackListener, Usage
//Label //Label
$label = new Label_Button(); $label = new Label_Button();
$playerFrame->addChild($label); $playerFrame->addChild($label);
$label->setX($posX + 130); $label->setX($posX + $width - 12.5);
$quad->setZ(12); $quad->setZ(12);
$label->setStyle($style); $label->setStyle($style);
$label->setTextSize(1); $label->setTextSize(1);

View File

@@ -3,6 +3,7 @@
namespace ManiaControl\Commands; namespace ManiaControl\Commands;
use FML\Controls\Frame; use FML\Controls\Frame;
use FML\Controls\Quad;
use FML\Controls\Quads\Quad_BgsPlayerCard; use FML\Controls\Quads\Quad_BgsPlayerCard;
use FML\Controls\Quads\Quad_UIConstruction_Buttons; use FML\Controls\Quads\Quad_UIConstruction_Buttons;
use FML\ManiaLink; use FML\ManiaLink;
@@ -232,7 +233,7 @@ class HelpManager implements CommandListener, CallbackListener, ManialinkPageAns
$labelLine = new LabelLine($headFrame); $labelLine = new LabelLine($headFrame);
$labelLine->addLabelEntryText('Command', $posX + 5); $labelLine->addLabelEntryText('Command', $posX + 5);
$labelLine->addLabelEntryText('Description', $posX + 50); $labelLine->addLabelEntryText('Description', $posX + 5 + $width / 3 + 5);
$labelLine->render(); $labelLine->render();
$index = 1; $index = 1;
@@ -261,10 +262,27 @@ class HelpManager implements CommandListener, CallbackListener, ManialinkPageAns
} }
$labelLine = new LabelLine($playerFrame); $labelLine = new LabelLine($playerFrame);
$labelLine->addLabelEntryText($command['Name'], $posX + 5, 45); $labelLine->addLabelEntryText($command['Name'], $posX + 5, $width / 3 - 5);
$labelLine->addLabelEntryText($command['Description'], $posX + 50, $width / 2 - $posX + 50); $labelLine->addLabelEntryText($command['Description'], $posX + 5 + $width / 3 + 5, $width / 3 * 2 - 15);
$labelLine->render(); $labelLine->render();
$clipboardValue = '/';
if ($command['IsAdminCommand']) {
$clipboardValue .= '/';
}
$clipboardValue .= explode('|', $command['Name'])[0] . ' ';
// Copy command
$playerQuad = new Quad();
$playerFrame->addChild($playerQuad);
$playerQuad->setX($posX + 5 + $width / 3);
$playerQuad->setSize(3., 3.);
$playerQuad->setStyle('UICommon64_1');
$playerQuad->setSubStyle('Copy_light');
$playerQuad->addClipboardFeature($clipboardValue);
$description = 'Copy Command';
$playerQuad->addTooltipLabelFeature($descriptionLabel, $description);
$posY -= 4; $posY -= 4;
$index++; $index++;
} }
@@ -284,9 +302,9 @@ class HelpManager implements CommandListener, CallbackListener, ManialinkPageAns
public function registerCommand($name, $adminCommand = false, $description = '', $method = '') { public function registerCommand($name, $adminCommand = false, $description = '', $method = '') {
// TODO replace with new class Command // TODO replace with new class Command
if ($adminCommand) { if ($adminCommand) {
array_push($this->adminCommands, array("Name" => $name, "Description" => $description, "Method" => $method)); array_push($this->adminCommands, array("Name" => $name, "Description" => $description, "Method" => $method, "IsAdminCommand" => true));
} else { } else {
array_push($this->playerCommands, array("Name" => $name, "Description" => $description, "Method" => $method)); array_push($this->playerCommands, array("Name" => $name, "Description" => $description, "Method" => $method, "IsAdminCommand" => false));
} }
} }
} }

View File

@@ -2,6 +2,8 @@
namespace ManiaControl\Database; namespace ManiaControl\Database;
use ManiaControl\Callbacks\CallbackListener;
use ManiaControl\Callbacks\Callbacks;
use ManiaControl\Callbacks\TimerListener; use ManiaControl\Callbacks\TimerListener;
use ManiaControl\Logger; use ManiaControl\Logger;
use ManiaControl\ManiaControl; use ManiaControl\ManiaControl;
@@ -13,7 +15,7 @@ use ManiaControl\ManiaControl;
* @copyright 2014-2020 ManiaControl Team * @copyright 2014-2020 ManiaControl Team
* @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3
*/ */
class Database implements TimerListener { class Database implements CallbackListener, TimerListener {
/* /*
* Public properties * Public properties
*/ */
@@ -56,12 +58,14 @@ class Database implements TimerListener {
return; return;
} }
$this->getMysqli()->set_charset("utf8"); $this->getMysqli()->set_charset("utf8");
$this->reduceLockWaitTimeout();
$this->initDatabase(); $this->initDatabase();
// $this->optimizeTables(); // $this->optimizeTables();
// Register Method which checks the Database Connection every 5 seconds // Register Method which checks the Database Connection every 5 seconds
$this->maniaControl->getTimerManager()->registerTimerListening($this, 'checkConnection', 5000); $this->maniaControl->getTimerManager()->registerTimerListening($this, 'checkConnection', 5000);
$this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::AFTERINIT, $this, 'handleAfterInit');
// Children // Children
$this->migrationHelper = new MigrationHelper($maniaControl); $this->migrationHelper = new MigrationHelper($maniaControl);
@@ -201,6 +205,24 @@ class Database implements TimerListener {
return true; return true;
} }
/**
* Reduce session lock wait timeout value to between 5 and 10 seconds
* designed to be used during the initialization to prevent maniacontrol to be stuck when launched in parallel with other instances
*/
public function reduceLockWaitTimeout() {
// limit session lock during initialization
$this->getMysqli()->query("SET SESSION lock_wait_timeout = ". rand(5, 10) .";");
}
/**
* Reset session lock wait timeout value to the default one
* designed to be used during the initialization to prevent maniacontrol to be stuck when launched in parallel with other instances
*/
public function resetLockWaitTimeout() {
// limit session lock during initialization
$this->getMysqli()->query("SET SESSION lock_wait_timeout = @@GLOBAL.lock_wait_timeout;");
}
/** /**
* Return the database config * Return the database config
* *
@@ -228,6 +250,10 @@ class Database implements TimerListener {
} }
} }
public function handleAfterInit() {
$this->resetLockWaitTimeout();
}
/** /**
* Destruct Database Connection * Destruct Database Connection
*/ */

View File

@@ -36,6 +36,7 @@ class AsyncHttpRequest implements UsageInformationAble {
private $contentType = 'text/xml; charset=UTF-8;'; private $contentType = 'text/xml; charset=UTF-8;';
private $timeout = 60; private $timeout = 60;
private $headers = array(); private $headers = array();
private $handle = null;
public function __construct($maniaControl, $url) { public function __construct($maniaControl, $url) {
$this->maniaControl = $maniaControl; $this->maniaControl = $maniaControl;
@@ -57,8 +58,7 @@ class AsyncHttpRequest implements UsageInformationAble {
->set(CURLOPT_USERAGENT, 'ManiaControl v' . ManiaControl::VERSION)// user-agent ->set(CURLOPT_USERAGENT, 'ManiaControl v' . ManiaControl::VERSION)// user-agent
->set(CURLOPT_RETURNTRANSFER, true)// ->set(CURLOPT_RETURNTRANSFER, true)//
->set(CURLOPT_FOLLOWLOCATION, true)// support redirect ->set(CURLOPT_FOLLOWLOCATION, true)// support redirect
->set(CURLOPT_SSL_VERIFYPEER, false) ->set(CURLOPT_SSL_VERIFYPEER, false);
->set(CURLOPT_HEADER, true);
return $request; return $request;
} }
@@ -76,8 +76,14 @@ class AsyncHttpRequest implements UsageInformationAble {
array_push($this->headers, 'Accept-Charset: utf-8'); array_push($this->headers, 'Accept-Charset: utf-8');
$request = $this->newRequest($this->url, $this->timeout); $request = $this->newRequest($this->url, $this->timeout);
$request->getOptions()->set(CURLOPT_AUTOREFERER, true)// accept link reference $request->getOptions()
->set(CURLOPT_HTTPHEADER, $this->headers); // headers ->set(CURLOPT_AUTOREFERER, true)// accept link reference
->set(CURLOPT_HTTPHEADER, $this->headers); // headers
if ($this->handle !== null) {
$request->getOptions()
->set(CURLOPT_FILE, $this->handle);
}
$this->processRequest($request); $this->processRequest($request);
} }
@@ -287,4 +293,22 @@ class AsyncHttpRequest implements UsageInformationAble {
public function setTimeout($timeout) { public function setTimeout($timeout) {
$this->timeout = $timeout; $this->timeout = $timeout;
} }
/**
* Gets the File Resource handle
*
* @return int
*/
public function getHandle() {
return $this->handle;
}
/**
* Sets the File Resource handle
*
* @param int $handle
*/
public function setHandle($handle) {
$this->handle = $handle;
}
} }

View File

@@ -629,137 +629,156 @@ class DirectoryBrowser implements ManialinkPageAnswerListener {
if ($url === "") return; if ($url === "") return;
$folderPath = $player->getCache($this, self::CACHE_FOLDER_PATH); $folderPath = $player->getCache($this, self::CACHE_FOLDER_PATH);
if (filter_var($url, FILTER_VALIDATE_URL)) { if (filter_var($url, FILTER_VALIDATE_URL)) {
$asyncHttpRequest = new AsyncHttpRequest($this->maniaControl, $url);
$asyncHttpRequest->setCallable(function ($file, $error, $headers) use ($url, $folderPath, $player) {
if (!$file || $error) {
$message = "Impossible to download the file: " . $error;
$this->maniaControl->getChat()->sendError($message, $player);
Logger::logError(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') encountered an error during the download of the zip file "'. $url .'": '. $error);
return;
}
$filePath = "";
$finfo = new finfo(FILEINFO_MIME_TYPE); try {
if ($finfo->buffer($file) === "application/zip") { $tempFile = tempnam(sys_get_temp_dir(), 'map_');
$zip = new ZipArchive(); $fp = fopen($tempFile, 'w+');
// Create a temporary file $this->maniaControl->getChat()->sendSuccess('Starting download...', $player);
$tempFile = tempnam(sys_get_temp_dir(), 'zip');
file_put_contents($tempFile, $file);
$open = $zip->open($tempFile); $asyncHttpRequest = new AsyncHttpRequest($this->maniaControl, $url);
$asyncHttpRequest->setHandle($fp);
if ($open === true) { $asyncHttpRequest->setCallable(function ($file, $error, $headers) use ($url, $folderPath, $tempFile, $fp, $player) {
$zip->extractTo($folderPath); // closing file handle
$zip->close(); fclose($fp);
$message = "Successfully extracted zip archive from ". $url; if ($error) {
$this->maniaControl->getChat()->sendSuccess($message, $player); $message = "Impossible to download the file: " . $error;
Logger::log(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') downloaded the zip file "'. $url .'"');
} else {
$message = "Cannot extract archive from ". $url;
$this->maniaControl->getChat()->sendError($message, $player); $this->maniaControl->getChat()->sendError($message, $player);
Logger::logError(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') encountered an error when downloading the zip file "'. $url .'": Cannot extract the archive'); Logger::logError(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') encountered an error during the download of the zip file "'. $url .'": '. $error);
return;
} }
// Clean up the temporary file $filePath = "";
unlink($tempFile);
} else {
$fileName = "";
$contentdispositionheader = ""; $finfo = new finfo(FILEINFO_MIME_TYPE);
foreach ($headers as $key => $value) {
if (strtolower($key) === "content-disposition") {
$contentdispositionheader = urldecode($value);
break;
}
}
if ($contentdispositionheader !== "") {
$value = $contentdispositionheader;
if (strpos($value, ';') !== false) {
list($type, $attr_parts) = explode(';', $value, 2);
$attr_parts = explode(';', $attr_parts); if ($finfo->file($tempFile) === "application/zip") {
$attributes = array(); $zip = new ZipArchive();
foreach ($attr_parts as $part) {
if (strpos($part, '=') === false) {
continue;
}
list($key, $value) = explode('=', $part, 2);
$attributes[trim($key)] = trim($value);
}
$fileName = null;
if (array_key_exists('filename*', $attributes)) { $open = $zip->open($tempFile);
$fileName = trim($attributes['filename*']);
// remove prefix if needed if ($open === true) {
if (strpos(strtolower($fileName), "utf-8''") === 0) { $zip->extractTo($folderPath);
$fileName = substr($fileName, strlen("utf-8''")); $zip->close();
} $message = "Successfully extracted zip archive from ". $url;
} else if (array_key_exists('filename', $attributes)) { $this->maniaControl->getChat()->sendSuccess($message, $player);
$fileName = trim($attributes['filename']); Logger::log(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') downloaded the zip file "'. $url .'"');
} } else {
$message = "Cannot extract archive from ". $url;
if ($fileName !== null) {
if (substr($fileName, 0, 1) === '"' && substr($fileName, -1, 1) === '"') {
$fileName = substr($fileName, 1, -1);
}
$filePath = $folderPath . FileUtil::getClearedFileName($fileName);
}
}
if (!$this->isMapFileName($filePath)) {
$message = "File is not a map: " . $fileName;
$this->maniaControl->getChat()->sendError($message, $player); $this->maniaControl->getChat()->sendError($message, $player);
Logger::logError(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') encountered an error when downloadeding the map file "'. $fileName .'": File is not a map'); Logger::logError(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') encountered an error when downloading the zip file "'. $url .'": Cannot extract the archive');
return;
} }
// Clean up the temporary file
unlink($tempFile);
} else { } else {
$path = parse_url($url, PHP_URL_PATH); $fileName = "";
// extracted basename $contentdispositionheader = "";
$fileName = basename($path); foreach ($headers as $key => $value) {
if (strtolower($key) === "content-disposition") {
if (!$this->isMapFileName($fileName)) { $contentdispositionheader = urldecode($value);
$fileName .= ".Map.Gbx"; break;
}
$filePath = $folderPath . $fileName;
}
if ($filePath != "") {
if (file_exists($filePath)) {
$index = 1;
while (file_exists(substr($filePath, 0, -8) . "-" . $index . ".Map.Gbx")) {
$index++;
} }
$filePath = substr($filePath, 0, -8) . "-" . $index . ".Map.Gbx";
}
$bytes = file_put_contents($filePath, $file);
if (!$bytes || $bytes <= 0) {
$message = "Failed to write file " . $filePath;
$this->maniaControl->getChat()->sendError($message, $player);
Logger::logError(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') encountered an error when downloadeding the map file "'. $fileName .'": Failed to write the file');
return;
} }
if ($contentdispositionheader !== "") {
$value = $contentdispositionheader;
if (strpos($value, ';') !== false) {
list($type, $attr_parts) = explode(';', $value, 2);
$attr_parts = explode(';', $attr_parts);
$attributes = array();
foreach ($attr_parts as $part) {
if (strpos($part, '=') === false) {
continue;
}
list($key, $value) = explode('=', $part, 2);
$attributes[trim($key)] = trim($value);
}
$fileName = null;
$message = "Successfully downloaded the map ". $fileName; if (array_key_exists('filename*', $attributes)) {
$this->maniaControl->getChat()->sendSuccess($message, $player); $fileName = trim($attributes['filename*']);
Logger::log(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') downloaded the map file "'. $filePath .'"');
// remove prefix if needed
if (strpos(strtolower($fileName), "utf-8''") === 0) {
$fileName = substr($fileName, strlen("utf-8''"));
}
} else if (array_key_exists('filename', $attributes)) {
$fileName = trim($attributes['filename']);
}
if ($fileName !== null) {
if (substr($fileName, 0, 1) === '"' && substr($fileName, -1, 1) === '"') {
$fileName = substr($fileName, 1, -1);
}
$filePath = $folderPath . FileUtil::getClearedFileName($fileName);
}
}
if (!$this->isMapFileName($filePath)) {
$message = "File is not a map: " . $fileName;
$this->maniaControl->getChat()->sendError($message, $player);
Logger::logError(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') encountered an error when downloadeding the map file "'. $fileName .'": File is not a map');
// Clean up the temporary file
unlink($tempFile);
return;
}
} else {
$path = parse_url($url, PHP_URL_PATH);
// extracted basename
$fileName = basename($path);
if (!$this->isMapFileName($fileName)) {
$fileName .= ".Map.Gbx";
}
$filePath = $folderPath . $fileName;
}
if ($filePath != "") {
if (file_exists($filePath)) {
$index = 1;
while (file_exists(substr($filePath, 0, -8) . "-" . $index . ".Map.Gbx")) {
$index++;
}
$filePath = substr($filePath, 0, -8) . "-" . $index . ".Map.Gbx";
}
$renamed = rename($tempFile, $filePath);
if (!$renamed) {
$message = "Failed to write file " . $filePath;
$this->maniaControl->getChat()->sendError($message, $player);
Logger::logError(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') encountered an error when downloadeding the map file "'. $fileName .'": Failed to write the file');
// Clean up the temporary file
unlink($tempFile);
return;
}
$message = "Successfully downloaded the map ". $fileName;
$this->maniaControl->getChat()->sendSuccess($message, $player);
Logger::log(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') downloaded the map file "'. $filePath .'"');
}
} }
}
$this->showManiaLink($player); $this->showManiaLink($player);
}); });
$asyncHttpRequest->getData(); $asyncHttpRequest->getData();
} catch (\Throwable $th) {
Logger::logError('Error when downloading file: '. $th->getMessage());
$this->maniaControl->getChat()->sendError('Error when downloading file: '. $th->getMessage(), $player);
}
} }
} }
} }

View File

@@ -210,12 +210,15 @@ class MapList implements ManialinkPageAnswerListener, CallbackListener {
$headFrame->setY($height / 2 - 5); $headFrame->setY($height / 2 - 5);
$posX = -$width / 2; $posX = -$width / 2;
$mainFieldTotalWidth = $width - 45;
$labelLine = new LabelLine($headFrame); $labelLine = new LabelLine($headFrame);
$labelLine->addLabelEntryText('Id', $posX + 5); $labelLine->addLabelEntryText('Id', $posX + 5);
$labelLine->addLabelEntryText('Mx Id', $posX + 10); $labelLine->addLabelEntryText('Mx Id', $posX + 10);
$labelLine->addLabelEntryText('Map Name', $posX + 20); $labelLine->addLabelEntryText('Map Name', $posX + 20);
$labelLine->addLabelEntryText('Author', $width / 2 - 56); $labelLine->addLabelEntryText('Map Uid', $posX + 20 + $mainFieldTotalWidth * 0.4);
$labelLine->addLabelEntryText('Actions', $width / 2 - 16); $labelLine->addLabelEntryText('Author', $posX + 20 + $mainFieldTotalWidth * 0.4 + $mainFieldTotalWidth * 0.35);
$labelLine->addLabelEntryText('Actions', $posX + $width - 16);
$labelLine->setY(-7); $labelLine->setY(-7);
$labelLine->render(); $labelLine->render();
@@ -285,7 +288,7 @@ class MapList implements ManialinkPageAnswerListener, CallbackListener {
$mxQuad->setSize(3, 3); $mxQuad->setSize(3, 3);
$mxQuad->setImageUrl($mxIcon); $mxQuad->setImageUrl($mxIcon);
$mxQuad->setImageFocusUrl($mxIconHover); $mxQuad->setImageFocusUrl($mxIconHover);
$mxQuad->setX($width / 2 - 63); $mxQuad->setX($posX + $width - 16);
$mxQuad->setUrl($map->mx->pageurl); $mxQuad->setUrl($map->mx->pageurl);
$mxQuad->setZ(0.01); $mxQuad->setZ(0.01);
$description = 'View ' . $map->getEscapedName() . ' on Mania-Exchange'; $description = 'View ' . $map->getEscapedName() . ' on Mania-Exchange';
@@ -297,7 +300,7 @@ class MapList implements ManialinkPageAnswerListener, CallbackListener {
$mxQuad->setSize(3, 3); $mxQuad->setSize(3, 3);
$mxQuad->setImageUrl($mxIconGreen); $mxQuad->setImageUrl($mxIconGreen);
$mxQuad->setImageFocusUrl($mxIconGreenHover); $mxQuad->setImageFocusUrl($mxIconGreenHover);
$mxQuad->setX($width / 2 - 60); $mxQuad->setX($posX + $width - 19);
$mxQuad->setUrl($map->mx->pageurl); $mxQuad->setUrl($map->mx->pageurl);
$mxQuad->setZ(0.01); $mxQuad->setZ(0.01);
$description = 'Update for ' . $map->getEscapedName() . ' available on Mania-Exchange!'; $description = 'Update for ' . $map->getEscapedName() . ' available on Mania-Exchange!';
@@ -310,17 +313,31 @@ class MapList implements ManialinkPageAnswerListener, CallbackListener {
} }
} }
// Display Karma bar
$karmaGauge = $this->maniaControl->getManialinkManager()->getElementBuilder()->buildKarmaGauge(
$map,
17,
10
);
$karmaGaugeWidth = 0.;
if ($karmaGauge) {
$mapFrame->addChild($karmaGauge);
$karmaGauge->setX($posX + $width - 25);
$karmaGaugeWidth = 12.;
}
// Display Maps // Display Maps
$labelLine = new LabelLine($mapFrame); $labelLine = new LabelLine($mapFrame);
$labelLine->addLabelEntryText($mapListId, $posX + 5, 5); $labelLine->addLabelEntryText($mapListId, $posX + 5, 4);
$labelLine->addLabelEntryText($mxId, $posX + 10, 10); $labelLine->addLabelEntryText($mxId, $posX + 10, 9);
$labelLine->addLabelEntryText(Formatter::stripDirtyCodes($map->name), $posX + 20, $width - 20 - 56 - 5); $labelLine->addLabelEntryText(Formatter::stripDirtyCodes($map->name), $posX + 20, $mainFieldTotalWidth * 0.4 - 5);
$labelLine->addLabelEntryText($map->uid, $posX + 20 + $mainFieldTotalWidth * 0.4, $mainFieldTotalWidth * 0.35 - 8);
$label = new Label_Text(); $label = new Label_Text();
$mapFrame->addChild($label); $mapFrame->addChild($label);
$label->setText($map->authorNick); $label->setText($map->authorNick);
$label->setX($width / 2 - 56); $label->setX($posX + 20 + $mainFieldTotalWidth * 0.4 + $mainFieldTotalWidth * 0.35);
$label->setSize(47, 0); $label->setSize($mainFieldTotalWidth * 0.25 - $karmaGaugeWidth, 0);
$label->setAction(MapCommands::ACTION_SHOW_AUTHOR . $map->authorLogin); $label->setAction(MapCommands::ACTION_SHOW_AUTHOR . $map->authorLogin);
$description = 'Click to checkout all maps by $<' . $map->authorLogin . '$>!'; $description = 'Click to checkout all maps by $<' . $map->authorLogin . '$>!';
$label->addTooltipLabelFeature($descriptionLabel, $description); $label->addTooltipLabelFeature($descriptionLabel, $description);
@@ -328,13 +345,47 @@ class MapList implements ManialinkPageAnswerListener, CallbackListener {
$labelLine->render(); $labelLine->render();
// Copy Map Uid
$label = new Label();
$mapFrame->addChild($label);
$label->setX($posX + 20 + $mainFieldTotalWidth * 0.4 + $mainFieldTotalWidth * 0.35 - 3);
$label->setSize(3., 3.);
$label->setText('$28d');
$label->setTextSize(.8);
$label->setAreaColor('00000000');
$label->setUrl('https://trackmania.io/#/leaderboard/'. $map->uid);
$description = 'Open map leaderboard on Trackmania.io';
$label->addTooltipLabelFeature($descriptionLabel, $description);
// Copy Map Uid
$quad = new Quad();
$mapFrame->addChild($quad);
$quad->setX($posX + 20 + $mainFieldTotalWidth * 0.4 + $mainFieldTotalWidth * 0.35 - 6);
$quad->setSize(3., 3.);
$quad->setStyle('UICommon64_1');
$quad->setSubStyle('Copy_light');
$quad->addClipboardFeature($map->uid);
$description = 'Copy Map Uid';
$quad->addTooltipLabelFeature($descriptionLabel, $description);
// Copy Author Login
$quad = new Quad();
$mapFrame->addChild($quad);
$quad->setX($posX + $width - 23 - $karmaGaugeWidth);
$quad->setSize(3., 3.);
$quad->setStyle('UICommon64_1');
$quad->setSubStyle('Copy_light');
$quad->addClipboardFeature($map->authorLogin);
$description = 'Copy Author login';
$quad->addTooltipLabelFeature($descriptionLabel, $description);
// TODO action detailed map info including mx info // TODO action detailed map info including mx info
// Map-Queue-Map-Label // Map-Queue-Map-Label
if (isset($queuedMaps[$map->uid])) { if (isset($queuedMaps[$map->uid])) {
$label = new Label_Text(); $label = new Label_Text();
$mapFrame->addChild($label); $mapFrame->addChild($label);
$label->setX($width / 2 - 13); $label->setX($posX + $width - 13);
$label->setZ(0.2); $label->setZ(0.2);
$label->setTextSize(1.5); $label->setTextSize(1.5);
$label->setText($queuedMaps[$map->uid]); $label->setText($queuedMaps[$map->uid]);
@@ -378,7 +429,7 @@ class MapList implements ManialinkPageAnswerListener, CallbackListener {
// remove map button // remove map button
$removeButton = new Label_Button(); $removeButton = new Label_Button();
$mapFrame->addChild($removeButton); $mapFrame->addChild($removeButton);
$removeButton->setX($width / 2 - 5); $removeButton->setX($posX + $width - 5);
$removeButton->setZ(0.2); $removeButton->setZ(0.2);
$removeButton->setSize(3, 3); $removeButton->setSize(3, 3);
$removeButton->setTextSize(1); $removeButton->setTextSize(1);
@@ -395,7 +446,7 @@ class MapList implements ManialinkPageAnswerListener, CallbackListener {
// Switch to button // Switch to button
$switchLabel = new Label_Button(); $switchLabel = new Label_Button();
$mapFrame->addChild($switchLabel); $mapFrame->addChild($switchLabel);
$switchLabel->setX($width / 2 - 9); $switchLabel->setX($posX + $width - 9);
$switchLabel->setZ(0.2); $switchLabel->setZ(0.2);
$switchLabel->setSize(3, 3); $switchLabel->setSize(3, 3);
$switchLabel->setTextSize(2); $switchLabel->setTextSize(2);
@@ -413,7 +464,7 @@ class MapList implements ManialinkPageAnswerListener, CallbackListener {
// Switch Map Voting for Admins // Switch Map Voting for Admins
$switchQuad = new Quad_UIConstruction_Buttons(); $switchQuad = new Quad_UIConstruction_Buttons();
$mapFrame->addChild($switchQuad); $mapFrame->addChild($switchQuad);
$switchQuad->setX($width / 2 - 17); $switchQuad->setX($posX + $width - 21);
$switchQuad->setZ(0.2); $switchQuad->setZ(0.2);
$switchQuad->setSubStyle($switchQuad::SUBSTYLE_Validate_Step2); $switchQuad->setSubStyle($switchQuad::SUBSTYLE_Validate_Step2);
$switchQuad->setSize(3.8, 3.8); $switchQuad->setSize(3.8, 3.8);
@@ -424,7 +475,7 @@ class MapList implements ManialinkPageAnswerListener, CallbackListener {
// Switch Map Voting for Player // Switch Map Voting for Player
$switchLabel = new Label_Button(); $switchLabel = new Label_Button();
$mapFrame->addChild($switchLabel); $mapFrame->addChild($switchLabel);
$switchLabel->setX($width / 2 - 7); $switchLabel->setX($posX + $width - 7);
$switchLabel->setZ(0.2); $switchLabel->setZ(0.2);
$switchLabel->setSize(3, 3); $switchLabel->setSize(3, 3);
$switchLabel->setTextSize(2); $switchLabel->setTextSize(2);
@@ -436,17 +487,6 @@ class MapList implements ManialinkPageAnswerListener, CallbackListener {
} }
} }
// Display Karma bar
$karmaGauge = $this->maniaControl->getManialinkManager()->getElementBuilder()->buildKarmaGauge(
$map,
20,
10
);
if ($karmaGauge) {
$mapFrame->addChild($karmaGauge);
$karmaGauge->setX($posX + 120);
}
$posY -= 4; $posY -= 4;
$mapListId++; $mapListId++;
$index++; $index++;

View File

@@ -69,6 +69,10 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
const SETTING_PERMISSION_KICK_PLAYER = 'Kick Player'; const SETTING_PERMISSION_KICK_PLAYER = 'Kick Player';
const SETTING_PERMISSION_BAN_PLAYER = 'Ban Player'; const SETTING_PERMISSION_BAN_PLAYER = 'Ban Player';
/*
* Settings Constants
*/
const SETTING_SEND_MESSAGES_TO_ADMINS_ONLY = 'Send chat messages to admin only';
/* /*
* Private properties * Private properties
@@ -93,6 +97,10 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$this->maniaControl->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_FORCE_PLAYER_TEAM, AuthenticationManager::AUTH_LEVEL_MODERATOR); $this->maniaControl->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_FORCE_PLAYER_TEAM, AuthenticationManager::AUTH_LEVEL_MODERATOR);
$this->maniaControl->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_FORCE_PLAYER_SPEC, AuthenticationManager::AUTH_LEVEL_MODERATOR); $this->maniaControl->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_FORCE_PLAYER_SPEC, AuthenticationManager::AUTH_LEVEL_MODERATOR);
// Settings
$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_SEND_MESSAGES_TO_ADMINS_ONLY, false);
// Echo Warn Command (Usage: sendEcho json_encode("player" => "loginName") // Echo Warn Command (Usage: sendEcho json_encode("player" => "loginName")
$this->maniaControl->getEchoManager()->registerEchoListener(self::ECHO_WARN_PLAYER, $this, function ($params) { $this->maniaControl->getEchoManager()->registerEchoListener(self::ECHO_WARN_PLAYER, $this, function ($params) {
$this->warnPlayer(null, $params->player, false); $this->warnPlayer(null, $params->player, false);
@@ -186,6 +194,7 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
} }
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); $target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin);
if (!$target) { if (!$target) {
if ($calledByAdmin) $this->maniaControl->getChat()->sendError('Player not found', $adminLogin);
return false; return false;
} }
@@ -241,7 +250,11 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
} }
if ($message) { if ($message) {
$this->maniaControl->getChat()->sendInformation($message); if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SEND_MESSAGES_TO_ADMINS_ONLY)) {
$this->maniaControl->getChat()->sendInformationToAdmins($message);
} else {
$this->maniaControl->getChat()->sendInformation($message);
}
Logger::logInfo($message, true); Logger::logInfo($message, true);
} }
@@ -270,6 +283,7 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); $target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin);
if (!$target) { if (!$target) {
if ($calledByAdmin) $this->maniaControl->getChat()->sendError('Player not found', $adminLogin);
return false; return false;
} }
@@ -312,7 +326,11 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
); );
} }
$this->maniaControl->getChat()->sendInformation($message); if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SEND_MESSAGES_TO_ADMINS_ONLY)) {
$this->maniaControl->getChat()->sendInformationToAdmins($message);
} else {
$this->maniaControl->getChat()->sendInformation($message);
}
} }
return true; return true;
@@ -344,10 +362,17 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); $target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin);
if (!$target || $target->isSpectator) { if (!$target) {
if ($calledByAdmin) $this->maniaControl->getChat()->sendError('Player not found', $adminLogin);
return false; return false;
} }
if ($target->isSpectator) {
if ($calledByAdmin) $this->maniaControl->getChat()->sendError('Player is already spectator', $adminLogin);
return false;
}
try { try {
$this->maniaControl->getClient()->forceSpectator($target->login, $spectatorState); $this->maniaControl->getClient()->forceSpectator($target->login, $spectatorState);
} catch (ServerOptionsException $e) { } catch (ServerOptionsException $e) {
@@ -406,6 +431,7 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); $target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin);
if (!$target) { if (!$target) {
if ($calledByAdmin) $this->maniaControl->getChat()->sendError('Player not found', $adminLogin);
return false; return false;
} }
@@ -434,7 +460,11 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
); );
} }
$this->maniaControl->getChat()->sendInformation($message); if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SEND_MESSAGES_TO_ADMINS_ONLY)) {
$this->maniaControl->getChat()->sendInformationToAdmins($message);
} else {
$this->maniaControl->getChat()->sendInformation($message);
}
Logger::logInfo($message, true); Logger::logInfo($message, true);
return true; return true;
@@ -460,6 +490,7 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); $target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin);
if (!$target) { if (!$target) {
if ($calledByAdmin) $this->maniaControl->getChat()->sendError('Player not found', $adminLogin);
return false; return false;
} }
@@ -493,7 +524,11 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
); );
} }
$this->maniaControl->getChat()->sendInformation($message); if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SEND_MESSAGES_TO_ADMINS_ONLY)) {
$this->maniaControl->getChat()->sendInformationToAdmins($message);
} else {
$this->maniaControl->getChat()->sendInformation($message);
}
Logger::logInfo($message, true); Logger::logInfo($message, true);
return true; return true;
@@ -519,6 +554,7 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); $target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin);
if (!$target) { if (!$target) {
if ($calledByAdmin) $this->maniaControl->getChat()->sendError('Player not found', $adminLogin);
return false; return false;
} }
@@ -596,7 +632,11 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
); );
} }
$this->maniaControl->getChat()->sendInformation($message); if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SEND_MESSAGES_TO_ADMINS_ONLY)) {
$this->maniaControl->getChat()->sendInformationToAdmins($message);
} else {
$this->maniaControl->getChat()->sendInformation($message);
}
Logger::log($message, true); Logger::log($message, true);
return true; return true;
@@ -624,6 +664,7 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); $target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin);
if (!$target) { if (!$target) {
if ($calledByAdmin) $this->maniaControl->getChat()->sendError('Player not found', $adminLogin);
return false; return false;
} }
@@ -662,7 +703,11 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
); );
} }
$this->maniaControl->getChat()->sendInformation($message); if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SEND_MESSAGES_TO_ADMINS_ONLY)) {
$this->maniaControl->getChat()->sendInformationToAdmins($message);
} else {
$this->maniaControl->getChat()->sendInformation($message);
}
Logger::logInfo($message, true); Logger::logInfo($message, true);
return true; return true;
@@ -686,6 +731,7 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); $target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin);
if (!$target) { if (!$target) {
$this->maniaControl->getChat()->sendError('Player not found', $adminLogin);
return; return;
} }
@@ -710,7 +756,11 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$admin, $admin,
$target $target
); );
$this->maniaControl->getChat()->sendInformation($message); if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SEND_MESSAGES_TO_ADMINS_ONLY)) {
$this->maniaControl->getChat()->sendInformationToAdmins($message);
} else {
$this->maniaControl->getChat()->sendInformation($message);
}
Logger::logInfo($message, true); Logger::logInfo($message, true);
} }
@@ -730,6 +780,7 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); $target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin);
if (!$target) { if (!$target) {
$this->maniaControl->getChat()->sendError('Player not found', $adminLogin);
return; return;
} }
@@ -752,7 +803,11 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$admin, $admin,
$target $target
); );
$this->maniaControl->getChat()->sendInformation($message); if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SEND_MESSAGES_TO_ADMINS_ONLY)) {
$this->maniaControl->getChat()->sendInformationToAdmins($message);
} else {
$this->maniaControl->getChat()->sendInformation($message);
}
Logger::logInfo($message, true); Logger::logInfo($message, true);
} }
@@ -781,6 +836,7 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); $admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin);
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); $target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin);
if (!$admin || !$target) { if (!$admin || !$target) {
$this->maniaControl->getChat()->sendError('Player not found', $adminLogin);
return; return;
} }
@@ -807,7 +863,11 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$admin, $admin,
$target $target
); );
$this->maniaControl->getChat()->sendInformation($message); if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SEND_MESSAGES_TO_ADMINS_ONLY)) {
$this->maniaControl->getChat()->sendInformationToAdmins($message);
} else {
$this->maniaControl->getChat()->sendInformation($message);
}
Logger::logInfo($message, true); Logger::logInfo($message, true);
} }
@@ -822,6 +882,7 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); $admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin);
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); $target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin);
if (!$admin || !$target) { if (!$admin || !$target) {
$this->maniaControl->getChat()->sendError('Player not found', $adminLogin);
return; return;
} }
@@ -847,7 +908,11 @@ class PlayerActions implements EchoListener, CommunicationListener, UsageInforma
$admin, $admin,
$target $target
); );
$this->maniaControl->getChat()->sendInformation($message); if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SEND_MESSAGES_TO_ADMINS_ONLY)) {
$this->maniaControl->getChat()->sendInformationToAdmins($message);
} else {
$this->maniaControl->getChat()->sendInformation($message);
}
Logger::logInfo($message, true); Logger::logInfo($message, true);
} }
} }

View File

@@ -132,7 +132,7 @@ class PlayerCommands implements CommandListener, ManialinkPageAnswerListener, Ca
return; return;
} }
$params = explode(' ', $chat[1][2], 3); $params = explode(' ', trim($chat[1][2]), 3);
if (count($params) <= 1) { if (count($params) <= 1) {
$message = $this->maniaControl->getChat()->formatMessage( $message = $this->maniaControl->getChat()->formatMessage(
'No Login given! Example: %s', 'No Login given! Example: %s',
@@ -162,7 +162,7 @@ class PlayerCommands implements CommandListener, ManialinkPageAnswerListener, Ca
return; return;
} }
$params = explode(' ', $chat[1][2], 3); $params = explode(' ', trim($chat[1][2]), 3);
if (count($params) <= 1) { if (count($params) <= 1) {
$message = $this->maniaControl->getChat()->formatMessage( $message = $this->maniaControl->getChat()->formatMessage(
'No Login given! Example: %s', 'No Login given! Example: %s',
@@ -192,7 +192,7 @@ class PlayerCommands implements CommandListener, ManialinkPageAnswerListener, Ca
return; return;
} }
$params = explode(' ', $chat[1][2], 3); $params = explode(' ', trim($chat[1][2]), 3);
if (count($params) <= 1) { if (count($params) <= 1) {
$message = $this->maniaControl->getChat()->formatMessage( $message = $this->maniaControl->getChat()->formatMessage(
'No Login given! Example: %s', 'No Login given! Example: %s',
@@ -218,7 +218,7 @@ class PlayerCommands implements CommandListener, ManialinkPageAnswerListener, Ca
return; return;
} }
$params = explode(' ', $chatCallback[1][2], 3); $params = explode(' ', trim($chatCallback[1][2]), 3);
if (count($params) <= 1) { if (count($params) <= 1) {
$message = $this->maniaControl->getChat()->formatMessage( $message = $this->maniaControl->getChat()->formatMessage(
'No Login given! Example: %s', 'No Login given! Example: %s',
@@ -244,7 +244,7 @@ class PlayerCommands implements CommandListener, ManialinkPageAnswerListener, Ca
return; return;
} }
$params = explode(' ', $chat[1][2]); $params = explode(' ', trim($chat[1][2]));
if (count($params) <= 1) { if (count($params) <= 1) {
$message = $this->maniaControl->getChat()->formatMessage( $message = $this->maniaControl->getChat()->formatMessage(
'No Login given! Example: %s', 'No Login given! Example: %s',
@@ -275,7 +275,7 @@ class PlayerCommands implements CommandListener, ManialinkPageAnswerListener, Ca
return; return;
} }
$params = explode(' ', $chat[1][2]); $params = explode(' ', trim($chat[1][2]));
if (!isset($params[1])) { if (!isset($params[1])) {
$message = $this->maniaControl->getChat()->formatMessage( $message = $this->maniaControl->getChat()->formatMessage(
'No Login given! Example: %s', 'No Login given! Example: %s',
@@ -307,7 +307,7 @@ class PlayerCommands implements CommandListener, ManialinkPageAnswerListener, Ca
return; return;
} }
$params = explode(' ', $chat[1][2]); $params = explode(' ', trim($chat[1][2]));
if (!isset($params[1])) { if (!isset($params[1])) {
$message = $this->maniaControl->getChat()->formatMessage( $message = $this->maniaControl->getChat()->formatMessage(
'No Login given! Example: %s', 'No Login given! Example: %s',
@@ -333,7 +333,7 @@ class PlayerCommands implements CommandListener, ManialinkPageAnswerListener, Ca
return; return;
} }
$params = explode(' ', $chat[1][2]); $params = explode(' ', trim($chat[1][2]));
if (!isset($params[1])) { if (!isset($params[1])) {
$message = $this->maniaControl->getChat()->formatMessage( $message = $this->maniaControl->getChat()->formatMessage(
'No Login given! Example: %s', 'No Login given! Example: %s',
@@ -360,7 +360,7 @@ class PlayerCommands implements CommandListener, ManialinkPageAnswerListener, Ca
} }
$amount = 1; $amount = 1;
$messageParts = explode(' ', $chatCallback[1][2]); $messageParts = explode(' ', trim($chatCallback[1][2]));
if (isset($messageParts[1]) && is_numeric($messageParts[1])) { if (isset($messageParts[1]) && is_numeric($messageParts[1])) {
$amount = intval($messageParts[1]); $amount = intval($messageParts[1]);
} }
@@ -403,7 +403,7 @@ class PlayerCommands implements CommandListener, ManialinkPageAnswerListener, Ca
return; return;
} }
$commandParts = explode(' ', $chatCallback[1][2]); $commandParts = explode(' ', trim($chatCallback[1][2]));
if (count($commandParts) <= 1) { if (count($commandParts) <= 1) {
$message = $this->maniaControl->getChat()->formatMessage( $message = $this->maniaControl->getChat()->formatMessage(
'No Login given! Example: %s', 'No Login given! Example: %s',
@@ -429,7 +429,7 @@ class PlayerCommands implements CommandListener, ManialinkPageAnswerListener, Ca
return; return;
} }
$commandParts = explode(' ', $chatCallback[1][2]); $commandParts = explode(' ', trim($chatCallback[1][2]));
if (count($commandParts) <= 1) { if (count($commandParts) <= 1) {
$message = $this->maniaControl->getChat()->formatMessage( $message = $this->maniaControl->getChat()->formatMessage(
'No Login given! Example: %s', 'No Login given! Example: %s',

View File

@@ -3,6 +3,7 @@
namespace ManiaControl\Players; namespace ManiaControl\Players;
use FML\Controls\Frame; use FML\Controls\Frame;
use FML\Controls\Label;
use FML\Controls\Labels\Label_Text; use FML\Controls\Labels\Label_Text;
use FML\Controls\Quad; use FML\Controls\Quad;
use FML\Controls\Quads\Quad_BgRaceScore2; use FML\Controls\Quads\Quad_BgRaceScore2;
@@ -189,13 +190,15 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer
$frame->addChild($headFrame); $frame->addChild($headFrame);
$headFrame->setY($posY - 5); $headFrame->setY($posY - 5);
$mainFieldWidth = (($width - 30) / 3) - 2;
$labelLine = new LabelLine($headFrame); $labelLine = new LabelLine($headFrame);
$labelLine->addLabelEntryText('Id', $posX + 5); $labelLine->addLabelEntryText('Id', $posX + 5);
$labelLine->addLabelEntryText('Nickname', $posX + 18); $labelLine->addLabelEntryText('Nickname', $posX + 18);
$labelLine->addLabelEntryText('Login', $posX + 70); $labelLine->addLabelEntryText('Login', $posX + 18 + $mainFieldWidth + 2);
$labelLine->addLabelEntryText('Location', $posX + 101); $labelLine->addLabelEntryText('Location', $posX + 18 + ($mainFieldWidth + 2) * 2);
if ($this->maniaControl->getAuthenticationManager()->checkRight($player, AuthenticationManager::AUTH_LEVEL_MODERATOR)) { if ($this->maniaControl->getAuthenticationManager()->checkRight($player, AuthenticationManager::AUTH_LEVEL_MODERATOR)) {
$labelLine->addLabelEntryText('Actions', $posX + 135); $labelLine->addLabelEntryText('Actions', $posX + $width - 15);
} }
$labelLine->render(); $labelLine->render();
@@ -220,6 +223,7 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer
} }
$path = $listPlayer->getProvince(); $path = $listPlayer->getProvince();
$playerFrame = new Frame(); $playerFrame = new Frame();
$pageFrame->addChild($playerFrame); $pageFrame->addChild($playerFrame);
@@ -233,16 +237,16 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer
$labelLine = new LabelLine($playerFrame); $labelLine = new LabelLine($playerFrame);
$labelLine->addLabelEntryText($playerIndex, $posX + 5, 13); $labelLine->addLabelEntryText($playerIndex, $posX + 5, 13);
$labelLine->addLabelEntryText($listPlayer->nickname, $posX + 18, 43); $labelLine->addLabelEntryText($listPlayer->nickname, $posX + 18, $mainFieldWidth - 10);
$labelLine->addLabelEntryText($listPlayer->login, $posX + 70, 26); $labelLine->addLabelEntryText($listPlayer->login, $posX + 18 + $mainFieldWidth + 2, $mainFieldWidth - 6);
$labelLine->addLabelEntryText($path, $posX + 101, 27); $labelLine->addLabelEntryText($path, $posX + 18 + ($mainFieldWidth + 2) * 2 + 5, $mainFieldWidth - 8);
$labelLine->render(); $labelLine->render();
$playerFrame->setY($posY); $playerFrame->setY($posY);
// Show current Player Arrow // Show current Player Arrow
if ($listPlayer->index === $player->index) { if ($listPlayer->index === $player->index) {
$currentQuad = new Quad_Icons64x64_1(); $currentQuad = new Quad_Icons64x64_1();
$playerFrame->addChild($currentQuad); $playerFrame->addChild($currentQuad);
$currentQuad->setX($posX + 3.5); $currentQuad->setX($posX + 3.5);
@@ -281,7 +285,7 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer
$countryQuad = new Quad(); $countryQuad = new Quad();
$playerFrame->addChild($countryQuad); $playerFrame->addChild($countryQuad);
$countryQuad->setImageUrl("file://ZoneFlags/Login/{$listPlayer->login}/country"); $countryQuad->setImageUrl("file://ZoneFlags/Login/{$listPlayer->login}/country");
$countryQuad->setX($posX + 98); $countryQuad->setX($posX + 18 + ($mainFieldWidth + 2) * 2 + 2);
$countryQuad->setSize(4, 4); $countryQuad->setSize(4, 4);
$countryQuad->addTooltipLabelFeature($descriptionLabel, '$<' . $listPlayer->nickname . '$> from ' . $listPlayer->path); $countryQuad->addTooltipLabelFeature($descriptionLabel, '$<' . $listPlayer->nickname . '$> from ' . $listPlayer->path);
@@ -305,10 +309,21 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer
$description = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($listPlayer) . ' ' . $listPlayer->nickname; $description = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($listPlayer) . ' ' . $listPlayer->nickname;
$rightLabel->addTooltipLabelFeature($descriptionLabel, $description); $rightLabel->addTooltipLabelFeature($descriptionLabel, $description);
// Copy player name
$playerQuad = new Quad();
$playerFrame->addChild($playerQuad);
$playerQuad->setX($posX + 18 + $mainFieldWidth - 10);
$playerQuad->setSize(3., 3.);
$playerQuad->setStyle('UICommon64_1');
$playerQuad->setSubStyle('Copy_light');
$playerQuad->addClipboardFeature($listPlayer->nickname);
$description = 'Copy player name';
$playerQuad->addTooltipLabelFeature($descriptionLabel, $description);
// Player Statistics // Player Statistics
$playerQuad = new Quad_Icons64x64_1(); $playerQuad = new Quad_Icons64x64_1();
$playerFrame->addChild($playerQuad); $playerFrame->addChild($playerQuad);
$playerQuad->setX($posX + 61); $playerQuad->setX($posX + 18 + $mainFieldWidth - 7);
$playerQuad->setSize(2.7, 2.7); $playerQuad->setSize(2.7, 2.7);
$playerQuad->setSubStyle($playerQuad::SUBSTYLE_TrackInfo); $playerQuad->setSubStyle($playerQuad::SUBSTYLE_TrackInfo);
$playerQuad->setAction(self::ACTION_OPEN_PLAYER_DETAILED . '.' . $listPlayer->login); $playerQuad->setAction(self::ACTION_OPEN_PLAYER_DETAILED . '.' . $listPlayer->login);
@@ -316,32 +331,57 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer
$playerQuad->addTooltipLabelFeature($descriptionLabel, $description); $playerQuad->addTooltipLabelFeature($descriptionLabel, $description);
// Camera Quad // Camera Quad
$playerQuad = new Quad_UIConstruction_Buttons(); $playerQuad = new Quad();
$playerFrame->addChild($playerQuad); $playerFrame->addChild($playerQuad);
$playerQuad->setX($posX + 64.5); $playerQuad->setX($posX + 18 + $mainFieldWidth - 4);
$playerQuad->setSize(3.8, 3.8); $playerQuad->setSize(3.8, 3.8);
$playerQuad->setSubStyle($playerQuad::SUBSTYLE_Camera); $playerQuad->setStyle('UICommon64_1');
$playerQuad->setSubStyle('Camera_light');
$description = 'Spectate $<' . $listPlayer->nickname . '$>'; $description = 'Spectate $<' . $listPlayer->nickname . '$>';
$playerQuad->addTooltipLabelFeature($descriptionLabel, $description); $playerQuad->addTooltipLabelFeature($descriptionLabel, $description);
$playerQuad->setAction(self::ACTION_SPECTATE_PLAYER . '.' . $listPlayer->login); $playerQuad->setAction(self::ACTION_SPECTATE_PLAYER . '.' . $listPlayer->login);
// Player Profile Quad // Player Profile Quad
$playerQuad = new Quad_UIConstruction_Buttons(); $playerQuad = new Quad();
$playerFrame->addChild($playerQuad); $playerFrame->addChild($playerQuad);
$playerQuad->setX($posX + 68); $playerQuad->setX($posX + 18 + $mainFieldWidth - 1);
$playerQuad->setSize(3.8, 3.8); $playerQuad->setSize(3.8, 3.8);
$playerQuad->setSubStyle($playerQuad::SUBSTYLE_Author); $playerQuad->setStyle('UICommon64_1');
$playerQuad->setSubStyle('User_light');
$playerQuad->addPlayerProfileFeature($listPlayer->login); $playerQuad->addPlayerProfileFeature($listPlayer->login);
// Description Label // Description Label
$description = 'View Player Profile of $<' . $listPlayer->nickname . '$>'; $description = 'View Player Profile of $<' . $listPlayer->nickname . '$>';
$playerQuad->addTooltipLabelFeature($descriptionLabel, $description); $playerQuad->addTooltipLabelFeature($descriptionLabel, $description);
// Trackmania.io button
$label = new Label();
$playerFrame->addChild($label);
$label->setX($posX + 18 + ($mainFieldWidth + 2) * 2 - 3);
$label->setSize(3., 3.);
$label->setText('$28d');
$label->setTextSize(.8);
$label->setAreaColor('00000000');
$label->setUrl('https://trackmania.io/#/player/'. $listPlayer->login);
$description = 'Open player profile on Trackmania.io';
$label->addTooltipLabelFeature($descriptionLabel, $description);
// Copy player login
$playerQuad = new Quad();
$playerFrame->addChild($playerQuad);
$playerQuad->setX($posX + 18 + ($mainFieldWidth + 2) * 2 - 6);
$playerQuad->setSize(3., 3.);
$playerQuad->setStyle('UICommon64_1');
$playerQuad->setSubStyle('Copy_light');
$playerQuad->addClipboardFeature($listPlayer->login);
$description = 'Copy player login';
$playerQuad->addTooltipLabelFeature($descriptionLabel, $description);
if ($this->maniaControl->getAuthenticationManager()->checkRight($player, AuthenticationManager::AUTH_LEVEL_MODERATOR)) { if ($this->maniaControl->getAuthenticationManager()->checkRight($player, AuthenticationManager::AUTH_LEVEL_MODERATOR)) {
// Further Player actions Quad // Further Player actions Quad
$playerQuad = new Quad_Icons64x64_1(); $playerQuad = new Quad_Icons64x64_1();
$playerFrame->addChild($playerQuad); $playerFrame->addChild($playerQuad);
$playerQuad->setX($posX + 132); $playerQuad->setX($posX + $width - 15);
$playerQuad->setSize(3.8, 3.8); $playerQuad->setSize(3.8, 3.8);
$playerQuad->setSubStyle($playerQuad::SUBSTYLE_Buddy); $playerQuad->setSubStyle($playerQuad::SUBSTYLE_Buddy);
$playerQuad->setAction(self::ACTION_PLAYER_ADV . '.' . $listPlayer->login); $playerQuad->setAction(self::ACTION_PLAYER_ADV . '.' . $listPlayer->login);
@@ -356,7 +396,7 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer
// Force to Red-Team Quad // Force to Red-Team Quad
$redQuad = new Quad_Emblems(); $redQuad = new Quad_Emblems();
$playerFrame->addChild($redQuad); $playerFrame->addChild($redQuad);
$redQuad->setX($posX + 144); $redQuad->setX($posX + $width - 15 + 12);
$redQuad->setSize(3.8, 3.8); $redQuad->setSize(3.8, 3.8);
$redQuad->setSubStyle($redQuad::SUBSTYLE_2); $redQuad->setSubStyle($redQuad::SUBSTYLE_2);
$redQuad->setAction(self::ACTION_FORCE_RED . '.' . $listPlayer->login); $redQuad->setAction(self::ACTION_FORCE_RED . '.' . $listPlayer->login);
@@ -368,7 +408,7 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer
// Force to Blue-Team Quad // Force to Blue-Team Quad
$blueQuad = new Quad_Emblems(); $blueQuad = new Quad_Emblems();
$playerFrame->addChild($blueQuad); $playerFrame->addChild($blueQuad);
$blueQuad->setX($posX + 140); $blueQuad->setX($posX + $width - 15 + 8);
$blueQuad->setSize(3.8, 3.8); $blueQuad->setSize(3.8, 3.8);
$blueQuad->setSubStyle($blueQuad::SUBSTYLE_1); $blueQuad->setSubStyle($blueQuad::SUBSTYLE_1);
$blueQuad->setAction(self::ACTION_FORCE_BLUE . '.' . $listPlayer->login); $blueQuad->setAction(self::ACTION_FORCE_BLUE . '.' . $listPlayer->login);
@@ -381,7 +421,7 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer
// Kick Player Vote // Kick Player Vote
$kickQuad = new Quad_UIConstruction_Buttons(); $kickQuad = new Quad_UIConstruction_Buttons();
$playerFrame->addChild($kickQuad); $playerFrame->addChild($kickQuad);
$kickQuad->setX($posX + 140); $kickQuad->setX($posX + $width - 15 + 8);
$kickQuad->setSize(3.8, 3.8); $kickQuad->setSize(3.8, 3.8);
$kickQuad->setSubStyle($kickQuad::SUBSTYLE_Validate_Step2); $kickQuad->setSubStyle($kickQuad::SUBSTYLE_Validate_Step2);
$kickQuad->setAction(self::ACTION_KICK_PLAYER_VOTE . '.' . $listPlayer->login); $kickQuad->setAction(self::ACTION_KICK_PLAYER_VOTE . '.' . $listPlayer->login);
@@ -394,7 +434,7 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer
// Force to Play // Force to Play
$playQuad = new Quad_Emblems(); $playQuad = new Quad_Emblems();
$playerFrame->addChild($playQuad); $playerFrame->addChild($playQuad);
$playQuad->setX($posX + 142); $playQuad->setX($posX + $width - 15 + 8);
$playQuad->setSize(3.8, 3.8); $playQuad->setSize(3.8, 3.8);
$playQuad->setSubStyle($playQuad::SUBSTYLE_2); $playQuad->setSubStyle($playQuad::SUBSTYLE_2);
$playQuad->setAction(self::ACTION_FORCE_PLAY . '.' . $listPlayer->login); $playQuad->setAction(self::ACTION_FORCE_PLAY . '.' . $listPlayer->login);
@@ -408,7 +448,7 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer
// Force to Spectator Quad // Force to Spectator Quad
$spectatorQuad = new Quad_BgRaceScore2(); $spectatorQuad = new Quad_BgRaceScore2();
$playerFrame->addChild($spectatorQuad); $playerFrame->addChild($spectatorQuad);
$spectatorQuad->setX($posX + 136); $spectatorQuad->setX($posX + $width - 15 + 4);
$spectatorQuad->setSize(3.8, 3.8); $spectatorQuad->setSize(3.8, 3.8);
$spectatorQuad->setSubStyle($spectatorQuad::SUBSTYLE_Spectator); $spectatorQuad->setSubStyle($spectatorQuad::SUBSTYLE_Spectator);
$spectatorQuad->setAction(self::ACTION_FORCE_SPEC . '.' . $listPlayer->login); $spectatorQuad->setAction(self::ACTION_FORCE_SPEC . '.' . $listPlayer->login);
@@ -420,7 +460,7 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer
// Force to Spectator Quad // Force to Spectator Quad
$spectatorQuad = new Quad_BgRaceScore2(); $spectatorQuad = new Quad_BgRaceScore2();
$playerFrame->addChild($spectatorQuad); $playerFrame->addChild($spectatorQuad);
$spectatorQuad->setX($posX + 136); $spectatorQuad->setX($posX + $width - 15 + 4);
$spectatorQuad->setSize(3.8, 3.8); $spectatorQuad->setSize(3.8, 3.8);
$spectatorQuad->setSubStyle($spectatorQuad::SUBSTYLE_Spectator); $spectatorQuad->setSubStyle($spectatorQuad::SUBSTYLE_Spectator);
$spectatorQuad->setAction(self::ACTION_FORCE_SPEC_VOTE . '.' . $listPlayer->login); $spectatorQuad->setAction(self::ACTION_FORCE_SPEC_VOTE . '.' . $listPlayer->login);
@@ -736,58 +776,63 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer
$this->maniaControl->getPlayerManager()->getPlayerActions()->revokeAuthLevel($adminLogin, $targetLogin); $this->maniaControl->getPlayerManager()->getPlayerActions()->revokeAuthLevel($adminLogin, $targetLogin);
break; break;
case self::ACTION_FORCE_SPEC_VOTE: case self::ACTION_FORCE_SPEC_VOTE:
/** @var $votesPlugin CustomVotesPlugin */ /** @var ?CustomVotesPlugin $votesPlugin */
$votesPlugin = $this->maniaControl->getPluginManager()->getPlugin(self::DEFAULT_CUSTOM_VOTE_PLUGIN); $votesPlugin = $this->maniaControl->getPluginManager()->getPlugin(self::DEFAULT_CUSTOM_VOTE_PLUGIN);
if ($votesPlugin !== null) {
$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin);
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin);
$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); $startMessage = $admin->getEscapedNickname() . '$s started a vote to force $<' . $target->nickname . '$> into spectator!';
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin);
$startMessage = $admin->getEscapedNickname() . '$s started a vote to force $<' . $target->nickname . '$> into spectator!'; $votesPlugin->defineVote('forcespec', 'Force ' . $target->getEscapedNickname() . ' Spec', true, $startMessage);
$votesPlugin->defineVote('forcespec', 'Force ' . $target->getEscapedNickname() . ' Spec', true, $startMessage); $votesPlugin->startVote($admin, 'forcespec', function ($result) use (&$votesPlugin, &$target) {
$message = $this->maniaControl->getChat()->formatMessage(
'Vote successful -> %s forced to Spectator!',
$target
);
$this->maniaControl->getChat()->sendSuccess($message);
$votesPlugin->undefineVote('forcespec');
$votesPlugin->startVote($admin, 'forcespec', function ($result) use (&$votesPlugin, &$target) { try {
$message = $this->maniaControl->getChat()->formatMessage( $this->maniaControl->getClient()->forceSpectator($target->login, PlayerActions::SPECTATOR_BUT_KEEP_SELECTABLE);
'Vote successful -> %s forced to Spectator!', $this->maniaControl->getClient()->spectatorReleasePlayerSlot($target->login);
$target } catch (PlayerStateException $e) {
); } catch (UnknownPlayerException $e) {
$this->maniaControl->getChat()->sendSuccess($message); }
$votesPlugin->undefineVote('forcespec'); });
}
try {
$this->maniaControl->getClient()->forceSpectator($target->login, PlayerActions::SPECTATOR_BUT_KEEP_SELECTABLE);
$this->maniaControl->getClient()->spectatorReleasePlayerSlot($target->login);
} catch (PlayerStateException $e) {
} catch (UnknownPlayerException $e) {
}
});
break; break;
case self::ACTION_KICK_PLAYER_VOTE: case self::ACTION_KICK_PLAYER_VOTE:
/** @var $votesPlugin CustomVotesPlugin */ /** @var ?CustomVotesPlugin $votesPlugin */
$votesPlugin = $this->maniaControl->getPluginManager()->getPlugin(self::DEFAULT_CUSTOM_VOTE_PLUGIN); $votesPlugin = $this->maniaControl->getPluginManager()->getPlugin(self::DEFAULT_CUSTOM_VOTE_PLUGIN);
$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); if ($votesPlugin !== null) {
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); $admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin);
$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin);
$startMessage = $admin->getEscapedNickname() . '$s started a vote to kick $<' . $target->nickname . '$>!'; $startMessage = $admin->getEscapedNickname() . '$s started a vote to kick $<' . $target->nickname . '$>!';
$votesPlugin->defineVote('kick', 'Kick ' . $target->getEscapedNickname(), true, $startMessage); $votesPlugin->defineVote('kick', 'Kick ' . $target->getEscapedNickname(), true, $startMessage);
$votesPlugin->startVote($admin, 'kick', function ($result) use (&$votesPlugin, &$target) { $votesPlugin->startVote($admin, 'kick', function ($result) use (&$votesPlugin, &$target) {
$message = $this->maniaControl->getChat()->formatMessage( $message = $this->maniaControl->getChat()->formatMessage(
'Vote successful -> %s got kicked!', 'Vote successful -> %s got kicked!',
$target $target
); );
$this->maniaControl->getChat()->sendSuccess($message); $this->maniaControl->getChat()->sendSuccess($message);
$votesPlugin->undefineVote('kick'); $votesPlugin->undefineVote('kick');
$message = '$39FYou got kicked due to a Public Vote!'; $message = '$39FYou got kicked due to a Public Vote!';
try { try {
$this->maniaControl->getClient()->kick($target->login, $message); $this->maniaControl->getClient()->kick($target->login, $message);
} catch (UnknownPlayerException $e) { } catch (UnknownPlayerException $e) {
} }
}); });
}
break; break;
} }
} else if (count($actionArray) == 2) { } else if (count($actionArray) == 2) {

View File

@@ -380,6 +380,15 @@ class ServerOptionsMenu implements CallbackListener, ConfiguratorMenu, TimerList
} }
}"); }");
$optionsFrame->addChild($checkBox); $optionsFrame->addChild($checkBox);
// Copy player name
$quad = new Quad();
$quad->setX($width - $width * 0.3 - 7);
$quad->setSize(3., 3.);
$quad->setStyle('UICommon64_1');
$quad->setSubStyle('Copy_light');
$quad->addClipboardFeature($value);
$optionsFrame->addChild($quad);
} }
} }

View File

@@ -47,8 +47,7 @@ abstract class WebReader {
->set(CURLOPT_USERAGENT, 'ManiaControl v' . ManiaControl::VERSION)// user-agent ->set(CURLOPT_USERAGENT, 'ManiaControl v' . ManiaControl::VERSION)// user-agent
->set(CURLOPT_RETURNTRANSFER, true)// return instead of output content ->set(CURLOPT_RETURNTRANSFER, true)// return instead of output content
->set(CURLOPT_AUTOREFERER, true)// follow redirects ->set(CURLOPT_AUTOREFERER, true)// follow redirects
->set(CURLOPT_SSL_VERIFYPEER, false) ->set(CURLOPT_SSL_VERIFYPEER, false);
->set(CURLOPT_HEADER, true);;
return $request; return $request;
} }

View File

@@ -3,6 +3,7 @@
namespace FML\Controls; namespace FML\Controls;
use FML\Script\Features\ActionTrigger; use FML\Script\Features\ActionTrigger;
use FML\Script\Features\Clipboard;
use FML\Script\Features\ControlScript; use FML\Script\Features\ControlScript;
use FML\Script\Features\MapInfo; use FML\Script\Features\MapInfo;
use FML\Script\Features\PlayerProfile; use FML\Script\Features\PlayerProfile;
@@ -919,6 +920,21 @@ abstract class Control implements Identifiable, Renderable, ScriptFeatureable
return $this; return $this;
} }
/**
* Add a custom Control Script text part
*
* @api
* @param string $scriptText Script text
* @param string $label (optional) Script label name
* @return static
*/
public function addClipboardFeature(mixed $value, ?Label $tooltipLabel = null)
{
$clipboard = new Clipboard($this, $value, $tooltipLabel);
$this->addScriptFeature($clipboard);
return $this;
}
/** /**
* Add a custom Control Script text part * Add a custom Control Script text part
* *

View File

@@ -0,0 +1,137 @@
<?php
namespace FML\Script\Features;
use FML\Controls\Control;
use FML\Controls\Label;
use FML\Script\Builder;
use FML\Script\Script;
use FML\Script\ScriptLabel;
use FML\Types\Scriptable;
/**
* Script Feature for showing Tooltips
*
* @author steeffeen <mail@steeffeen.com>
* @copyright FancyManiaLinks Copyright © 2017 Steffen Schröder
* @license http://www.gnu.org/licenses/ GNU General Public License, Version 3
*/
class Clipboard extends ScriptFeature
{
public const DATASET_PROPERTY = 'clipboard-data';
/**
* @var Control $control
*/
protected $control = null;
/**
* @var string $value value
*/
protected $value = null;
/**
* @var Control $tooltipControl Tooltip Control
*/
protected $tooltipControl = null;
/**
* Construct a new Tooltip
*
* @api
* @param Control $hoverControl Control
* @param string $value Value to set in the Clipboard
* @param Control $tooltipControl (optional) If tooltip is used
*/
public function __construct(Control $control, mixed $value, ?Control $tooltipControl = null)
{
$this->setControl($control);
$this->setValue($value);
if ($tooltipControl) {
$this->setTooltipControl($tooltipControl);
}
}
/**
* Set the Control
*
* @api
* @param Control $control Control
* @return static
*/
public function setControl(Control $control)
{
$control->checkId();
if ($this->control !== null) {
$this->control->removeDataAttribute(self::DATASET_PROPERTY);
}
$this->control = $control;
if ($this->control instanceof Scriptable) {
$this->control->setScriptEvents(true);
}
if ($this->value !== null) {
$this->setValue($this->value);
}
return $this;
}
/**
* Set the value to copy
*
* @api
* @param mixed $value value
* @return static
*/
public function setValue(mixed $value)
{
$this->value = (string) $value;
$this->control->addDataAttribute(self::DATASET_PROPERTY, $this->value);
return $this;
}
/**
* Set the Tooltip Control
*
* @api
* @param Control $tooltipControl Tooltip Control
* @return static
*/
public function setTooltipControl(Control $tooltipControl)
{
$tooltipControl->checkId();
$this->tooltipControl = $tooltipControl;
$tooltip = new Tooltip($this->control, $tooltipControl, false, false, "Click to copy");
$this->control->addScriptFeature($tooltip);
return $this;
}
/**
* @see ScriptFeature::prepare()
*/
public function prepare(Script $script)
{
$controlId = Builder::escapeText($this->control->getId());
$datasetProperty = Builder::escapeText(self::DATASET_PROPERTY);
$scriptText = "
if (Event.Control.ControlId == {$controlId}) {
log(\"clipboard \"^ Event.Control.DataAttributeExists({$datasetProperty}));
if (System != Null && Event.Control.DataAttributeExists({$datasetProperty})) {
System.ClipboardSet(Event.Control.DataAttributeGet({$datasetProperty}));
}
}";
$script->appendGenericScriptLabel(ScriptLabel::MOUSECLICK, $scriptText);
return $this;
}
}

View File

@@ -6,7 +6,7 @@ use Symfony\Component\EventDispatcher\EventDispatcher;
class Request extends EventDispatcher implements RequestInterface class Request extends EventDispatcher implements RequestInterface
{ {
/** /**
* @var resource cURL handler * @var \CurlHandle cURL handler
*/ */
protected $ch; protected $ch;
@@ -19,6 +19,11 @@ class Request extends EventDispatcher implements RequestInterface
* @var Options Object containing options for current request * @var Options Object containing options for current request
*/ */
protected $options = null; protected $options = null;
/**
* @var array Response Headers feed by the CURLOPT_HEADERFUNCTION callback
*/
protected $responseHeaders;
/** /**
* Create new cURL handle * Create new cURL handle
@@ -30,6 +35,35 @@ class Request extends EventDispatcher implements RequestInterface
if ($url !== null) { if ($url !== null) {
$this->getOptions()->set(CURLOPT_URL, $url); $this->getOptions()->set(CURLOPT_URL, $url);
} }
$this->getOptions()->set(CURLOPT_HEADERFUNCTION, function($ch, $headerLine) {
$len = strlen($headerLine);
// Handle HTTP status lines (e.g., HTTP/1.1 200 OK)
if (preg_match('/^HTTP\/\d\.\d\s+\d+/', $headerLine)) {
$this->responseHeaders = []; // Reset on redirect or multiple responses
}
$parts = explode(':', $headerLine, 2);
if (count($parts) === 2) {
$key = strtolower(trim($parts[0]));
$value = trim($parts[1]);
// Handle multiple headers with same name
if (!isset($this->responseHeaders[$key])) {
$this->responseHeaders[$key] = $value;
} else {
if (is_array($this->responseHeaders[$key])) {
$this->responseHeaders[$key][] = $value;
} else {
$this->responseHeaders[$key] = [$this->responseHeaders[$key], $value];
}
}
}
return $len;
});
$this->ch = curl_init(); $this->ch = curl_init();
} }
@@ -72,7 +106,7 @@ class Request extends EventDispatcher implements RequestInterface
/** /**
* Returns cURL raw resource * Returns cURL raw resource
* *
* @return resource cURL handle * @return \CurlHandle cURL handle
*/ */
public function getHandle() public function getHandle()
{ {
@@ -89,6 +123,16 @@ class Request extends EventDispatcher implements RequestInterface
{ {
return (int)$this->ch; return (int)$this->ch;
} }
/**
* Get the response headers
*
* @return array
*/
public function getResponseHeaders()
{
return $this->responseHeaders;
}
/** /**
* Perform a cURL session. * Perform a cURL session.
@@ -108,6 +152,7 @@ class Request extends EventDispatcher implements RequestInterface
$content = curl_exec($this->ch); $content = curl_exec($this->ch);
$response = new Response($this, $content); $response = new Response($this, $content);
$response->setHeaders($this->responseHeaders);
$errorCode = curl_errno($this->ch); $errorCode = curl_errno($this->ch);
if ($errorCode !== CURLE_OK) { if ($errorCode !== CURLE_OK) {
$response->setError(new Error(curl_error($this->ch), $errorCode)); $response->setError(new Error(curl_error($this->ch), $errorCode));

View File

@@ -11,7 +11,7 @@ class RequestsQueue extends EventDispatcher implements RequestsQueueInterface, \
protected $defaultOptions = null; protected $defaultOptions = null;
/** /**
* @var resource cURL multi handler * @var \CurlMultiHandle cURL multi handler
*/ */
protected $mh; protected $mh;
@@ -115,6 +115,7 @@ class RequestsQueue extends EventDispatcher implements RequestsQueueInterface, \
$event = new Event(); $event = new Event();
$event->request = $request; $event->request = $request;
$event->response = new Response($request, curl_multi_getcontent($request->getHandle())); $event->response = new Response($request, curl_multi_getcontent($request->getHandle()));
$event->response->setHeaders($event->request->getResponseHeaders());
if ($result !== CURLE_OK) { if ($result !== CURLE_OK) {
$event->response->setError(new Error(curl_error($request->getHandle()), $result)); $event->response->setError(new Error(curl_error($request->getHandle()), $result));
} }

View File

@@ -19,18 +19,7 @@ class Response
$this->ch = $request->getHandle(); $this->ch = $request->getHandle();
if ($content != null) { if ($content != null) {
$header_size = $this->getInfo(CURLINFO_HEADER_SIZE); $this->content = $content;
foreach (explode("\r\n", substr($content, 0, $header_size)) as $value) {
if(false !== ($matches = explode(':', $value, 2))) {
if (count($matches) === 2) {
$headers_arr["{$matches[0]}"] = trim($matches[1]);
}
}
}
$this->headers = $headers_arr;
$this->content = substr($content, $header_size);
} }
} }
@@ -89,6 +78,17 @@ class Response
return isset($this->error); return isset($this->error);
} }
/**
* Sets headers
*
* @param array|null $headers headers to set
* @return void
*/
public function setHeaders(?array $headers)
{
$this->headers = $headers;
}
/** /**
* Returns headers of request * Returns headers of request
* *