diff --git a/application/core/Maniaplanet/DedicatedServer/Connection.php b/application/core/Maniaplanet/DedicatedServer/Connection.php new file mode 100644 index 00000000..e55ff14c --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Connection.php @@ -0,0 +1,4419 @@ +terminate(); + unset(self::$instances[$key]); + } + } + + /** + * @param string $host + * @param int $port + * @param int $timeout + * @param string $user + * @param string $password + */ + protected function __construct($host, $port, $timeout, $user, $password) + { + $this->xmlrpcClient = new Xmlrpc\ClientMulticall($host, $port, $timeout); + $this->authenticate($user, $password); + $this->setApiVersion('2013-04-16'); + } + + /** + * Close the current socket connexion + * Never call this method, use instead DedicatedApi::delete($host, $port) + */ + protected function terminate() + { + $this->xmlrpcClient->terminate(); + } + + /** + * + * Read a Call back on the DedicatedServer and call the method if handle + * @param array $methods if empty, every methods will be called on call back, otherwise only the method declared inside. The metho name must be the name of the interface's method + */ + function executeCallbacks() + { + $this->xmlrpcClient->readCallbacks(); + $calls = $this->xmlrpcClient->getCallbackResponses(); + return $calls; + } + + /** + * Execute the calls in queue and return the result + * TODO Prendre en compte les retours du mutliQuery (via un handler ?) + */ + function executeMulticall() + { + $this->xmlrpcClient->multiqueryIgnoreResult(); + } + + /** + * Add a call in queur. It will be executed by the next Call from the user to executemulticall + * @param string $methodName + * @param string $authLevel + * @param array $params + */ + protected function execute($methodName, $params = array(), $multicall = false) + { + if($multicall) + { + $this->xmlrpcClient->addCall($methodName, $params); + } + else + { + array_unshift($params, $methodName); + call_user_func_array(array($this->xmlrpcClient, 'query'), $params); + return $this->xmlrpcClient->getResponse(); + } + } + + /** + * Given the name of a method, return an array of legal signatures. + * Each signature is an array of strings. + * The first item of each signature is the return type, and any others items are parameter types. + * @param string $methodName + * @return array + */ + function methodSignature($methodName) + { + return $this->execute('system.methodSignature', array($methodName)); + } + + /** + * Change the password for the specified login/user. + * @param string $username + * @param string $password + * @return bool + * @throws InvalidArgumentException + */ + function changeAuthPassword($username, $password) + { + if(!is_string($password)) + { + throw new InvalidArgumentException('password = '.print_r($password, true)); + } + if($username != 'User' && $username != 'Admin' && $username != 'SuperAdmin') + { + throw new InvalidArgumentException('username = '.print_r($username, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($username, $password), false); + } + + /** + * Allow the GameServer to call you back. + * @param bool $enable + * @param bool $multicall + * @return bool + */ + function enableCallbacks($enable, $multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array((bool) $enable), $multicall); + } + + /** + * Define the wanted api. + * @param string $version + * @param bool $multicall + * @return bool + */ + function setApiVersion($version, $multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array((string) $version), $multicall); + } + + /** + * Returns a struct with the Name, Version, Build and ApiVersion of the application remotely controled. + * @return Structures\Version + * @throws InvalidArgumentException + */ + function getVersion() + { + $result = $this->execute(ucfirst(__FUNCTION__)); + return Structures\Version::fromArray($result); + } + + function authenticate($username, $password) + { + return $this->execute(ucfirst(__FUNCTION__), array($username, $password), false); + } + + /** + * Call a vote for a cmd. The command is a XML string corresponding to an XmlRpc request. + * You can additionally specifiy specific parameters for this vote: a ratio, a time out + * and who is voting. Special timeout values: a timeout of '0' means default, '1' means + * indefinite; a ratio of '-1' means default; Voters values: '0' means only active players, + * '1' means any player, '2' is for everybody, pure spectators included. + * @param Structures\Vote $vote + * @param double $ratio -1 means default, else ration should be between 0 and 1 + * @param int $timeout time to vote in millisecondes, '0' means default + * @param int $voters Voters values: '0' means only active players, '1' means any player, '2' is for everybody, pure spectators included + * @param bool $multicall + * @throws InvalidArgumentException + */ + function callVote(Structures\Vote $vote, $ratio = 0.5, $timeout = 0, $voters = 1, $multicall = false) + { + if(is_null($vote)) + { + throw new InvalidArgumentException('vote must be set'); + } + if(!is_float($ratio)) + { + throw new InvalidArgumentException('ratio = '.print_r($ratio, true)); + } + if(!is_int($timeout)) + { + throw new InvalidArgumentException('timeout = '.print_r($timeout, true)); + } + if(!is_int($voters)) + { + throw new InvalidArgumentException('voters = '.print_r($voters, true)); + } + if(!is_array($vote->cmdParam)) + { + throw new InvalidArgumentException('vote->cmdParam = '.print_r($vote->cmdParam, true)); + } + + $tmpCmd = new Xmlrpc\Request($vote->cmdName, $vote->cmdParam); + + return $this->execute(ucfirst(__FUNCTION__).'Ex', array($tmpCmd->getXml(), $ratio, $timeout, $voters), $multicall); + } + + /** + * Call a vote to kick a player. + * You can additionally specifiy specific parameters for this vote: a ratio, a time out + * and who is voting. Special timeout values: a timeout of '0' means default, '1' means + * indefinite; a ratio of '-1' means default; Voters values: '0' means only active players, + * '1' means any player, '2' is for everybody, pure spectators included. + * @param Structures\Player|string $player Structures\Player or string + * @param double $ratio -1 means default, else ration should be between 0 and 1 + * @param int $timeout time to vote in millisecondes, '0' means default + * @param int $voters Voters values: '0' means only active players, '1' means any player, '2' is for everybody, pure spectators included + * @param bool $multicall + * @throws InvalidArgumentException + */ + function callVoteKick($player, $ratio = 0.5, $timeout = 0, $voters = 1, $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + if(!is_float($ratio)) + { + throw new InvalidArgumentException('ratio = '.print_r($ratio, true)); + } + if(!is_int($timeout)) + { + throw new InvalidArgumentException('timeout = '.print_r($timeout, true)); + } + if(!is_int($voters)) + { + throw new InvalidArgumentException('voters = '.print_r($voters, true)); + } + + $tmpCmd = new Xmlrpc\Request('Kick', array($login)); + + return $this->execute('CallVoteEx', array($tmpCmd->getXml(), $ratio, $timeout, $voters), $multicall); + } + + /** + * Call a vote to ban a player. + * You can additionally specifiy specific parameters for this vote: a ratio, a time out + * and who is voting. Special timeout values: a timeout of '0' means default, '1' means + * indefinite; a ratio of '-1' means default; Voters values: '0' means only active players, + * '1' means any player, '2' is for everybody, pure spectators included. + * @param Structures\Player|string $player + * @param double $ratio -1 means default, else ration should be between 0 and 1 + * @param int $timeout time to vote in millisecondes, '0' means default + * @param int $voters Voters values: '0' means only active players, '1' means any player, '2' is for everybody, pure spectators included + * @param bool $multicall + * @throws InvalidArgumentException + */ + function callVoteBan($player, $ratio = 0.6, $timeout = 0, $voters = 1, $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + if(!is_float($ratio)) + { + throw new InvalidArgumentException('ratio = '.print_r($ratio, true)); + } + if(!is_int($timeout)) + { + throw new InvalidArgumentException('timeout = '.print_r($timeout, true)); + } + if(!is_int($voters)) + { + throw new InvalidArgumentException('voters = '.print_r($voters, true)); + } + + $tmpCmd = new Xmlrpc\Request('Ban', array($login)); + + return $this->execute('CallVoteEx', array($tmpCmd->getXml(), $ratio, $timeout, $voters), $multicall); + } + + /** + * Call a vote to restart the current Map. + * You can additionally specifiy specific parameters for this vote: a ratio, a time out + * and who is voting. Special timeout values: a timeout of '0' means default, '1' means + * indefinite; a ratio of '-1' means default; Voters values: '0' means only active players, + * '1' means any player, '2' is for everybody, pure spectators included. + * @param double $ratio -1 means default, else ration should be between 0 and 1 + * @param int $timeout time to vote in millisecondes, '0' means default + * @param int $voters Voters values: '0' means only active players, '1' means any player, '2' is for everybody, pure spectators included + * @param bool $multicall + * @throws InvalidArgumentException + */ + function callVoteRestartMap($ratio = 0.5, $timeout = 0, $voters = 1, $multicall = false) + { + if(!is_float($ratio)) + { + throw new InvalidArgumentException('ratio = '.print_r($ratio, true)); + } + if(!is_int($timeout)) + { + throw new InvalidArgumentException('timeout = '.print_r($timeout, true)); + } + if(!is_int($voters)) + { + throw new InvalidArgumentException('voters = '.print_r($voters, true)); + } + + $tmpCmd = new Xmlrpc\Request('RestartMap', array()); + + return $this->execute('CallVoteEx', array($tmpCmd->getXml(), $ratio, $timeout, $voters), $multicall); + } + + /** + * Call a vote to go to the next Map. + * You can additionally specifiy specific parameters for this vote: a ratio, a time out + * and who is voting. Special timeout values: a timeout of '0' means default, '1' means + * indefinite; a ratio of '-1' means default; Voters values: '0' means only active players, + * '1' means any player, '2' is for everybody, pure spectators included. + * @param double $ratio -1 means default, else ration should be between 0 and 1 + * @param int $timeout time to vote in millisecondes, '0' means default + * @param int $voters Voters values: '0' means only active players, '1' means any player, '2' is for everybody, pure spectators included + * @param bool $multicall + * @throws InvalidArgumentException + */ + function callVoteNextMap($ratio = 0.5, $timeout = 0, $voters = 1, $multicall = false) + { + if(!is_float($ratio)) + { + throw new InvalidArgumentException('ratio = '.print_r($ratio, true)); + } + if(!is_int($timeout)) + { + throw new InvalidArgumentException('timeout = '.print_r($timeout, true)); + } + if(!is_int($voters)) + { + throw new InvalidArgumentException('voters = '.print_r($voters, true)); + } + + $tmpCmd = new Xmlrpc\Request('NextMap', array()); + + return $this->execute('CallVoteEx', array($tmpCmd->getXml(), $ratio, $timeout, $voters), $multicall); + } + + /** + * Used internaly by game. + * @param bool $multicall + * @return bool + */ + protected function internalCallVote($multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array(), $multicall); + } + + /** + * Cancel the current vote. + * @param bool $multicall + * @return bool + */ + function cancelVote($multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array(), $multicall); + } + + /** + * Returns the vote currently in progress. + * The returned structure is { CallerLogin, CmdName, CmdParam }. + * @return Structures\Vote + */ + function getCurrentCallVote() + { + return Structures\Vote::fromArray($this->execute(ucfirst(__FUNCTION__))); + } + + /** + * Set a new timeout for waiting for votes. A zero value disables callvote. + * Requires a map restart to be taken into account + * @param int $timeout time to vote in millisecondes, '0' disables callvote + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setCallVoteTimeOut($timeout, $multicall = false) + { + if(!is_int($timeout)) + { + throw new InvalidArgumentException('timeout = '.print_r($timeout, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($timeout), $multicall); + } + + /** + * Get the current and next timeout for waiting for votes. + * The struct returned contains two fields 'CurrentValue' and 'NextValue'. + * @return array + */ + function getCallVoteTimeOut() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new default ratio for passing a vote. + * Must lie between 0 and 1. + * @param double $ratio + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setCallVoteRatio($ratio, $multicall = false) + { + if($ratio !== -1. && !(is_float($ratio) && $ratio >= 0 && $ratio <= 1)) + { + throw new InvalidArgumentException('ratio = '.print_r($ratio, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($ratio), $multicall); + } + + /** + * Get the current default ratio for passing a vote. + * This value lies between 0 and 1. + * @return double + */ + function getCallVoteRatio() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set new ratios for passing specific votes. + * The parameter is an array of associative arrays + * {string votecommand, double ratio}, ratio is in [0,1] or -1. for vote disabled. + * @example setCallVoteRatios(array(array('Command' => 'Kick', 'Ratio' => -1. )); + * @param array $ratios + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setCallVoteRatios(array $ratios, $multicall = false) + { + return $this->setCallVoteRatiosEx(true, $ratios, $multicall); + } + + /** + * Get the current ratios for passing votes. + * @return array + */ + function getCallVoteRatios() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set the ratios list for passing specific votes, extended version with parameters matching. + * The parameters, a boolean ReplaceAll (or else, only modify specified ratios, leaving the previous ones unmodified) + * and an array of structs {string Command, string Param, double Ratio}, + * ratio is in [0,1] or -1 for vote disabled. + * Param is matched against the vote parameters to make more specific ratios, leave empty to match all votes for the command. + * Only available to Admin. + * @param bool $replaceAll + * @param array[array[]]|Structures\VoteRatio[] $ratios + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setCallVoteRatiosEx($replaceAll, array $ratios, $multicall = false) + { + if(!is_array($ratios)) + { + throw new InvalidArgumentException('ratios = '.print_r($ratios, true)); + } + + foreach($ratios as $i => $ratio) + { + if($ratio instanceof Structures\VoteRatio) + { + $ratios[$i] = $ratio->toArray(); + } + else + { + if(!is_array($ratio) && !array_key_exists('Command', $ratio) && !array_key_exists('Ratio', $ratio)) + { + throw new InvalidArgumentException('ratios['.$i.'] = '.print_r($ratio, true)); + } + if(!is_string($ratio['Command'])) + { + throw new InvalidArgumentException('ratios['.$i.'][Command] = '.print_r($ratios['Command'], true)); + } + if($ratio['Ratio'] !== -1. && !(is_float($ratio['Ratio']) && $ratio['Ratio'] >= 0 && $ratio['Ratio'] <= 1)) + { + throw new InvalidArgumentException('ratios['.$i.'][Ratio] = '.print_r($ratio['Ratio'], true)); + } + if(array_key_exists('Param', $ratio) && !is_string($ratio['Param'])) + { + throw new InvalidArgumentException('ratios['.$i.'][Param] = '.print_r($ratio['Param'], true)); + } + elseif(!array_key_exists('Param', $ratio)) + { + $ratio['Param'] = ''; + $ratios[$i] = $ratio; + } + } + } + + return $this->execute(ucfirst(__FUNCTION__), array($replaceAll, $ratios), $multicall); + } + + /** + * Get the current ratios for passing votes, extended version with parameters matching. + * @return Structures\VoteRatio[] + */ + function getCallVoteRatiosEx() + { + return Structures\VoteRatio::fromArrayOfArray($this->execute(ucfirst(__FUNCTION__))); + } + + /** + * Send a localised text message to specied clients. + * The parameter is an array of structures {Lang='??', Text='...'}. + * If no matching language is found, the last text in the array is used. + * @param array $messages + * @param Structures\Player|string|mixed[] $receiver Structures\Player(s) who will receive the message, put null to send the message to everyone + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function chatSendServerMessageToLanguage(array $messages, $receiver = null, $multicall = false) + { + if(!is_array($messages)) + { + throw new InvalidArgumentException('messages = '.print_r($messages, true)); + } + if(is_null($receiver)) + { + $receiverString = ''; + } + else if(!($receiverString = $this->getLogins($receiver))) + { + throw new InvalidArgumentException('receiver = '.print_r($receiver, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($messages, $receiverString), $multicall); + } + + /** + * Send a text message without the server login to everyone if players is null. + * Players can be a Structures\Player object or an array of Structures\Player + * @param string $message + * @param Structures\Player|string|mixed[] $receiver Structures\Player(s) who will receive the message, put null to send the message to everyone + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function chatSendServerMessage($message, $receiver = null, $multicall = false) + { + if(!is_string($message)) + { + throw new InvalidArgumentException('message = '.print_r($message, true)); + } + + $params = array($message); + $method = 'ChatSendServerMessage'; + if(!is_null($receiver)) + { + if(!($logins = $this->getLogins($receiver))) + { + throw new InvalidArgumentException('receiver = '.print_r($receiver, true)); + } + $params[] = $logins; + $method .= 'ToLogin'; + } + + return $this->execute($method, $params, $multicall); + } + + /** + * Send a localised text message to selected clients. + * The parameter is an array of structures {Lang='??', Text='...'}. + * If no matching language is found, the last text in the array is used. + * @param array $messages + * @param Structures\Player|string|mixed[] $receiver Structures\Player(s) who will receive the message, put null to send the message to everyone + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function chatSendToLanguage(array $messages, $receiver = null, $multicall = false) + { + if(!is_array($messages)) throw new InvalidArgumentException('messages = '.print_r($messages, true)); + + if($receiver == null) + { + $receiverString = ''; + } + else if(!($receiverString = $this->getLogins($receiver))) + { + throw new InvalidArgumentException('receiver = '.print_r($receiver, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($messages, $receiverString), $multicall); + } + + /** + * Send a text message to every Structures\Player or the a specified player(s). + * If Structures\Player is null, the message will be delivered to every Structures\Player + * @param string $message + * @param Structures\Player|string|mixed[] $receiver Structures\Player(s) who will receive the message, put null to send the message to everyone + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function chatSend($message, $receiver, $multicall = false) + { + if(!is_string($message)) throw new InvalidArgumentException('message = '.print_r($message, true)); + + $params = array($message); + $method = 'ChatSend'; + if(!is_null($receiver)) + { + if(!($logins = $this->getLogins($receiver))) + { + throw new InvalidArgumentException('players = '.print_r($receiver, true)); + } + $params[] = $logins; + $method .= 'ToLogin'; + } + + return $this->execute($method, $params, $multicall); + } + + /** + * Returns the last chat lines. Maximum of 40 lines. + * @return array + */ + function getChatLines() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * The chat messages are no longer dispatched to the players, they only go to the rpc callback + * and the controller has to manually forward them. The second (optional) parameter allows all + * messages from the server to be automatically forwarded. + * @param bool $enable + * @param bool $serverAutomaticForward + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function chatEnableManualRouting($enable, $serverAutomaticForward = false, $multicall = false) + { + if(!is_bool($enable)) + { + throw new InvalidArgumentException('enable = '.print_r($enable, true)); + } + if(!is_bool($serverAutomaticForward)) + { + throw new InvalidArgumentException('serverAutomaticForward = '.print_r($serverAutomaticForward, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($enable, $serverAutomaticForward), $multicall); + } + + /** + * (Text, SenderLogin, DestLogin) Send a text message to the specified DestLogin (or everybody if empty) + * on behalf of SenderLogin. DestLogin can be a single login or a list of comma-separated logins. + * Only available if manual routing is enabled. + * @param string $message + * @param Structures\Player|string $sender + * @param Structures\Player|string $receiver + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function chatForwardToLogin($message, $sender, $receiver = null, $multicall = false) + { + if(!is_string($message)) + { + throw new InvalidArgumentException('message = '.print_r($message, true)); + } + if(!($senderLogin = $this->getLogin($sender))) + { + throw new InvalidArgumentException('sender must be set'); + } + $receiverLogin = $this->getLogin($receiver) ? : ''; + + return $this->execute(ucfirst(__FUNCTION__), array($message, $senderLogin, $receiverLogin), $multicall); + } + + /** + * Display a notice on the client with the specified UId. + * The parameters are : + * the Uid of the client to whom the notice is sent, + * the text message to display, + * the UId of the avatar to display next to it (or '255' for no avatar), + * an optional 'max duration' in seconds (default: 3). + * @param string $message + * @param Structures\Player|string|mixed[] $receiver + * @param Structures\Player|string $player + * @param int $variant 0, 1 or 2 + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function sendNotice($receiver, $message, $player = null, $variant = 0, $multicall = false) + { + if(!is_string($message)) + { + throw new InvalidArgumentException('message = '.print_r($message, true)); + } + + $params = array(); + $method = 'SendNotice'; + if(!is_null($receiver)) + { + if(!($login = $this->getLogins($receiver))) + throw new InvalidArgumentException('receiver = '.print_r($receiver, true)); + else $params[] = $login; + + $method .= 'ToLogin'; + } + + $params[] = $message; + $params[] = $this->getLogin($player) ? : ''; + $params[] = $variant; + return $this->execute($method, $params, $multicall); + } + + /** + * Display a manialink page on the client of the specified Structures\Player(s). + * The first parameter is the login of the player, + * the other are identical to 'SendDisplayManialinkPage'. + * The players can be an object of player Type or an array of Structures\Player object + * @param null|Structures\Player|string|mixed[] $playerLogin + * @param string $manialink + * @param int $timeout + * @param bool $hideOnClick + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function sendDisplayManialinkPage($players, $manialink, $timeout, $hideOnClick, $multicall = false) + { + $params = array(); + $method = 'SendDisplayManialinkPage'; + if(!is_null($players)) + { + if(!($login = $this->getLogins($players))) throw new InvalidArgumentException('players = '.print_r($players, true)); + else $params[] = $login; + + $method .= 'ToLogin'; + } + + if(!is_string($manialink)) + { + throw new InvalidArgumentException('manialink = '.print_r($manialink, true)); + } + if(!is_int($timeout)) + { + throw new InvalidArgumentException('timeout = '.print_r($timeout, true)); + } + if(!is_bool($hideOnClick)) + { + throw new InvalidArgumentException('hideOnClick = '.print_r($hideOnClick, true)); + } + $params[] = $manialink; + $params[] = $timeout; + $params[] = $hideOnClick; + + return $this->execute($method, $params, $multicall); + } + + /** + * Hide the displayed manialink page on the client with the specified login. + * Login can be a single login or a list of comma-separated logins. + * @param null|Structures\Player|string|mixed[] $players + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function sendHideManialinkPage($players = null, $multicall = false) + { + $params = array(); + $method = 'SendHideManialinkPage'; + if(!is_null($players)) + { + if(!($login = $this->getLogins($players))) throw new InvalidArgumentException('players = '.print_r($players, true)); + else $params[] = $login; + + $method .= 'ToLogin'; + } + + return $this->execute($method, $params, $multicall); + } + + /** + * Returns the latest results from the current manialink page, + * as an array of structs {string Login, int PlayerId, int Result} + * Result==0 -> no answer, Result>0.... -> answer from the player. + * @return array + */ + function getManialinkPageAnswers() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Opens a link in the client with the specified players. + * The parameters are the login of the client to whom the link to open is sent, the link url, and the 'LinkType' + * (0 in the external browser, 1 in the internal manialink browser). + * Login can be a single login or a list of comma-separated logins. Only available to + * @param Structures\Player|string|mixed[] $player + * @param string $link + * @param int $linkType + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function sendOpenLink($player, $link, $linkType, $multicall = false) + { + if(!($login = $this->getLogins($player))) + { + throw new InvalidArgumentException('player must be set'); + } + if(!is_string($link)) + { + throw new InvalidArgumentException('link = '.print_r($link, true)); + } + if($linkType !== 0 && $linkType !== 1) + { + throw new InvalidArgumentException('linkType = '.print_r($linkType, true)); + } + + return $this->execute('SendOpenLinkToLogin', array($login, $link, $linkType), $multicall); + } + + /** + * Kick the player with an optional message. + * @param Structures\Player|string $playerLogin + * @param string $message + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function kick($player, $message = '', $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + if(!is_string($message)) + { + throw new InvalidArgumentException('message = '.print_r($message, true)); + } + + return $this->execute('Kick', array($login, $message), $multicall); + } + + /** + * Ban the player with an optional message. + * @param Structures\Player|string $player + * @param string $message + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function ban($player, $message = '', $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + if(!is_string($message)) + { + throw new InvalidArgumentException('message = '.print_r($message, true)); + } + + return $this->execute('Ban', array($login, $message), $multicall); + } + + /** + * Ban the player with a message. + * Add it to the black list, and optionally save the new list. + * @param Structures\Player|string $player + * @param string $message + * @param bool $saveList + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function banAndBlackList($player, $message, $saveList = false, $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + if(!is_string($message) || !$message) + { + throw new InvalidArgumentException('message = '.print_r($message, true)); + } + if(!is_bool($saveList)) + { + throw new InvalidArgumentException('saveList = '.print_r($saveList, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($login, $message, $saveList), $multicall); + } + + /** + * Unban the player + * @param Structures\Player|string $player + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function unBan($player, $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + + return $this->execute(ucfirst(__FUNCTION__), array($login), $multicall); + } + + /** + * Clean the ban list of the server. + * @param bool $multicall + * @return bool + */ + function cleanBanList($multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array(), $multicall); + } + + /** + * Returns the list of banned players. This method takes two parameters. + * The first parameter specifies the maximum number of infos to be returned, + * the second one the starting index in the list. The list is an array of structures. + * Each structure contains the following fields : Login, ClientName and IPAddress. + * @param int $length specifies the maximum number of infos to be returned + * @param int $offset specifies the starting index in the list + * @return Structures\Player[] The list is an array of Structures\Player + * @throws InvalidArgumentException + */ + function getBanList($length, $offset) + { + if(!is_int($length)) throw new InvalidArgumentException('length = '.print_r($length, true)); + if(!is_int($offset)) throw new InvalidArgumentException('offset = '.print_r($offset, true)); + + $result = $this->execute(ucfirst(__FUNCTION__), array($length, $offset)); + return Structures\Player::fromArrayOfArray($result); + } + + /** + * Blacklist the player + * @param Structures\Player|string $player + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function blackList($player, $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + return $this->execute(ucfirst(__FUNCTION__), array($login), $multicall); + } + + /** + * UnBlackList the player + * @param Structures\Player|string $player + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function unBlackList($player, $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + return $this->execute(ucfirst(__FUNCTION__), array($login), $multicall); + } + + /** + * Clean the blacklist of the server. + * @param bool $multicall + * @return bool + */ + function cleanBlackList($multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array(), $multicall); + } + + /** + * Returns the list of blacklisted players. + * This method takes two parameters. + * The first parameter specifies the maximum number of infos to be returned, + * the second one the starting index in the list. The list is an array of structures. + * Each structure contains the following fields : Login. + * @param int $length specifies the maximum number of infos to be returned + * @param int $offset specifies the starting index in the list + * @return Structures\Player[] The list is an array of structures. Each structure contains the following fields : Login. + * @throws InvalidArgumentException + */ + function getBlackList($length, $offset) + { + if(!is_int($length)) throw new InvalidArgumentException('length = '.print_r($length, true)); + if(!is_int($offset)) throw new InvalidArgumentException('offset = '.print_r($offset, true)); + + $result = $this->execute(ucfirst(__FUNCTION__), array($length, $offset)); + return Structures\Player::fromArrayOfArray($result); + } + + /** + * Load the black list file with the specified file name. + * @param string $filename blackList file name + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function loadBlackList($filename, $multicall = false) + { + if(!is_string($filename)) throw new InvalidArgumentException('filename = '.print_r($filename, true)); + + return $this->execute(ucfirst(__FUNCTION__), array($filename), $multicall); + } + + /** + * Save the black list in the file with specified file name. + * @param string $filename blackList filename + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function saveBlackList($filename, $multicall = false) + { + if(!is_string($filename)) throw new InvalidArgumentException('filename = '.print_r($filename, true)); + + return $this->execute(ucfirst(__FUNCTION__), array($filename), $multicall); + } + + /** + * Add the player to the guest list. + * @param Structures\Player|string $player + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function addGuest($player, $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + return $this->execute(ucfirst(__FUNCTION__), array($login), $multicall); + } + + /** + * Remove the player from the guest list. + * @param Structures\Player|string $player + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function removeGuest($player, $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + return $this->execute(ucfirst(__FUNCTION__), array($login), $multicall); + } + + /** + * Clean the guest list of the server. + * @param bool $multicall + * @return bool + */ + function cleanGuestList($multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array(), $multicall); + } + + /** + * Returns the list of players on the guest list. + * This method takes two parameters. + * The first parameter specifies the maximum number of infos to be returned, + * the second one the starting index in the list. The list is an array of structures. + * Each structure contains the following fields : Login. + * @param int $length specifies the maximum number of infos to be returned + * @param int $offset specifies the starting index in the list + * @return Structures\Player[] The list is an array of structures. Each structure contains the following fields : Login. + * @throws InvalidArgumentException + */ + function getGuestList($length, $offset) + { + if(!is_int($length)) + { + throw new InvalidArgumentException('length = '.print_r($length, true)); + } + if(!is_int($offset)) + { + throw new InvalidArgumentException('offset = '.print_r($offset, true)); + } + + $result = $this->execute(ucfirst(__FUNCTION__), array($length, $offset)); + return Structures\Player::fromArrayOfArray($result); + } + + /** + * + * Load the guest list file with the specified file name. + * @param string $filename blackList file name + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function loadGuestList($filename, $multicall = false) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filename), $multicall); + } + + /** + * Save the guest list in the file with specified file name. + * @param string $filename blackList file name + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function saveGuestList($filename, $multicall = false) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filename), $multicall); + } + + /** + * Sets whether buddy notifications should be sent in the chat. + * login is the login of the player, or '' for global setting, + * enabled is the value. + * @param null|Structures\Player|string $player the player, or null for global setting + * @param bool $enable the value. + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setBuddyNotification($player, $enable, $multicall = false) + { + if(!is_bool($enable)) + { + throw new InvalidArgumentException('enable = '.print_r($enable, true)); + } + + $player = $this->getLogin($player) ? : ''; + + return $this->execute(ucfirst(__FUNCTION__), array($player, $enable), $multicall); + } + + /** + * Gets whether buddy notifications are enabled for login, or '' to get the global setting. + * @param null|Structures\Player|string $player the player, or null for global setting + * @return bool + * @throws InvalidArgumentException + */ + function getBuddyNotification($player) + { + $player = $this->getLogin($player) ? : ''; + + return $this->execute(ucfirst(__FUNCTION__), array($player)); + } + + /** + * Write the data to the specified file. The filename is relative to the Tracks path + * @param string $filename The file to be written + * @param string $localFilename The file to be read to obtain the data + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function writeFile($filename, $localFilename, $multicall = false) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + if(!file_exists($localFilename)) + { + throw new InvalidArgumentException('localFilename = '.print_r($localFilename, true)); + } + + $inputData = file_get_contents($localFilename); + + $data = new Xmlrpc\Base64($inputData); + + if(strlen($data->getXml()) > 1024 * 1024 - 15) + { + throw new InvalidArgumentException('file is too big'); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filename, $data), $multicall); + } + + /** + * Write the data to the specified file. The filename is relative to the Tracks path + * @param string $filename The file to be written + * @param string $data the data to be written + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function writeFileFromString($filename, $data, $multicall = false) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + $data = new Xmlrpc\Base64($data); + + if(strlen($data->getXml()) > 1024 * 1024 - 15) + { + throw new InvalidArgumentException('data are too big'); + } + + return $this->execute('WriteFile', array($filename, $data), $multicall); + } + + /** + * Send the data to the specified player. + * Login can be a single login or a list of comma-separated logins. + * @param Structures\Player|string|mixed[] $players + * @param string $filename + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function tunnelSendData($players, $filename, $multicall = false) + { + if(!($login = $this->getLogins($players))) + { + throw new InvalidArgumentException('players = '.print_r($players, true)); + } + if(!file_exists($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + if(filesize($filename) > 4 * 1024) + { + throw new InvalidArgumentException('file is too big'); + } + + $inputData = file_get_contents($filename); + + $data = new Xmlrpc\Base64($inputData); + + return $this->execute('TunnelSendDataToLogin', array($login, $data), $multicall); + } + + /** + * Send the data to the specified player. + * Login can be a single login or a list of comma-separated logins. + * @param Structures\Player|string|mixed[] $players + * @param string $data + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function tunnelSendDataFromString($players, $data, $multicall = false) + { + if(!($login = $this->getLogins($players))) + { + throw new InvalidArgumentException('players = '.print_r($players, true)); + } + + $data = new Xmlrpc\Base64($data); + + return $this->execute('TunnelSendDataToLogin', array($login, $data), $multicall); + } + + /** + * Just log the parameters and invoke a callback. + * Can be used to talk to other xmlrpc clients connected, or to make custom votes. + * If used in a callvote, the first parameter will be used as the vote message on the clients. + * @param string $message the message to log + * @param string $callback optionnal callback name + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function dedicatedEcho($message, $callback = '', $multicall = false) + { + if(!is_string($message)) + { + throw new InvalidArgumentException('message = '.print_r($message, true)); + } + if(!is_string($callback)) + { + throw new InvalidArgumentException('callback = '.print_r($callback, true)); + } + + return $this->execute('Echo', array($message, $callback), $multicall); + } + + /** + * Ignore the specified Structures\Player. + * @param Structures\Player|string $player + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function ignore($player, $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + return $this->execute(ucfirst(__FUNCTION__), array($login), $multicall); + } + + /** + * Unignore the specified player. + * @param Structures\Player|string $player + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function unIgnore($player, $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + return $this->execute(ucfirst(__FUNCTION__), array($login), $multicall); + } + + /** + * Clean the ignore list of the server. + * @param bool $multicall + * @return bool + */ + function cleanIgnoreList($multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array(), $multicall); + } + + /** + * Returns the list of ignored players. This method takes two parameters. + * The first parameter specifies the maximum number of infos to be returned, + * the second one the starting index in the list. The list is an array of structures. + * Each structure contains the following fields : Login. + * @param int $length specifies the maximum number of infos to be returned + * @param int $offset specifies the starting index in the list + * @return Structures\Player[] The list is an array of structures. Each structure contains the following fields : Login. + * @throws InvalidArgumentException + */ + function getIgnoreList($length, $offset) + { + if(!is_int($length)) + { + throw new InvalidArgumentException('length = '.print_r($length, true)); + } + if(!is_int($offset)) + { + throw new InvalidArgumentException('offset = '.print_r($offset, true)); + } + + $result = $this->execute(ucfirst(__FUNCTION__), array($length, $offset)); + return Structures\Player::fromArrayOfArray($result); + } + + /** + * Pay coppers from the server account to a player, returns the BillId. + * This method takes three parameters: + * Login of the payee, + * Coppers to pay and + * Label to send with the payment. + * The creation of the transaction itself may cost coppers, + * so you need to have coppers on the server account. + * @param Structures\Player|string $player + * @param int $amount + * @param string $label + * @param bool $multicall + * @return int The Bill Id + * @throws InvalidArgumentException + */ + function pay($player, $amount, $label, $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + if(!is_int($amount) || $amount < 1) + { + throw new InvalidArgumentException('amount = '.print_r($amount, true)); + } + if(!is_string($label)) + { + throw new InvalidArgumentException('label = '.print_r($label, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($login, $amount, $label), $multicall); + } + + /** + * Create a bill, send it to a player, and return the BillId. + * This method takes four parameters: + * LoginFrom of the payer, + * Coppers the player has to pay, + * Label of the transaction and + * optional LoginTo of the payee (if empty string, then the server account is used). + * The creation of the transaction itself may cost coppers, + * so you need to have coppers on the server account. + * @param Structures\Player|string $fromPlayer + * @param int $amount + * @param string $label + * @param Structures\Player|string|null $toPlayer + * @param bool $multicall + * @return int + * @throws InvalidArgumentException + */ + function sendBill($fromPlayer, $amount, $label, $toPlayer = null, $multicall = false) + { + + if(!is_int($amount) || $amount < 1) + { + throw new InvalidArgumentException('amount = '.print_r($amount, true)); + } + if(!is_string($label)) + { + throw new InvalidArgumentException('label = '.print_r($label, true)); + } + if(!($from = $this->getLogin($fromPlayer))) + { + throw new InvalidArgumentException('fromPlayer must be set'); + } + + $to = $this->getLogin($toPlayer) ? : ''; + + return $this->execute(ucfirst(__FUNCTION__), array($from, $amount, $label, $to), $multicall); + } + + /** + * Returns the current state of a bill. + * This method takes one parameter, the BillId. + * Returns a struct containing + * State, StateName and TransactionId. + * Possible enum values are: CreatingTransaction, Issued, ValidatingPayement, Payed, Refused, Error. + * @param int $billId + * @return Structures\Bill + * @throws InvalidArgumentException + */ + function getBillState($billId) + { + if(!is_int($billId)) + { + throw new InvalidArgumentException('billId = '.print_r($billId, true)); + } + + $result = $this->execute(ucfirst(__FUNCTION__), array($billId)); + return Structures\Bill::fromArray($result); + } + + /** + * Returns the current number of planets on the server account. + * @return int + */ + function getServerPlanets() + { + return $this->execute('GetServerPlanets'); + } + + /** + * Get some system infos. + * Return a struct containing: + * PublishedIp, Port, P2PPort, ServerLogin, ServerPlayerId + * @return Structures\SystemInfos + */ + function getSystemInfo() + { + $result = $this->execute(ucfirst(__FUNCTION__)); + return Structures\SystemInfos::fromArray($result); + } + + /** + * Sets up- and download speed for the server in kbps. + * @param int $downloadRate the download rate in kbps + * @param int $uploadRate the upload rate in kbps + * @param bool $multicall + * @return bool + */ + function setConnectionRates($downloadRate, $uploadRate, $multicall = false) + { + if(!is_int($downloadRate)) + { + throw new InvalidArgumentException('downloadRate = '.print_r($downloadRate, true)); + } + if(!is_int($uploadRate)) + { + throw new InvalidArgumentException('uploadRate = '.print_r($uploadRate, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($downloadRate, $uploadRate), $multicall); + } + + /** + * Returns the list of tags and associated values set on this server. + * The list is an array of structures {string Name, string Value}. + * Only available to Admin. + * @return array + */ + function getServerTags() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a tag and its value on the server. This method takes two parameters. + * The first parameter specifies the name of the tag, and the second one its value. + * Only available to Admin. + * @param string $key + * @param string $value + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setServerTag($key, $value, $multicall = false) + { + if(!is_string($key)) + { + throw new InvalidArgumentException('key = '.print_r($key, true)); + } + if(!is_string($value)) + { + throw new InvalidArgumentException('value = '.print_r($value, true)); + } + return $this->execute(ucfirst(__FUNCTION__), array($key, $value), $multicall); + } + + /** + * Unset the tag with the specified name on the server. + * Only available to Admin. + * @param string $key + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function unsetServerTag($key, $multicall = false) + { + if(!is_string($key)) + { + throw new InvalidArgumentException('key = '.print_r($key, true)); + } + return $this->execute(ucfirst(__FUNCTION__), array($key), $multicall); + } + + /** + * Reset all tags on the server. + * Only available to Admin. + * @param bool $multicall + * @return bool + */ + function resetServerTags($multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array(), $multicall); + } + + /** + * Set a new server name in utf8 format. + * @param string $serverName + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setServerName($serverName, $multicall = false) + { + if(!is_string($serverName)) + { + throw new InvalidArgumentException('serverName = '.print_r($serverName, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($serverName), $multicall); + } + + /** + * Get the server name in utf8 format. + * @return string + */ + function getServerName() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new server comment in utf8 format. + * @param string $serverComment + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setServerComment($serverComment, $multicall = false) + { + if(!is_string($serverComment)) + { + throw new InvalidArgumentException('serverComment = '.print_r($serverComment, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($serverComment), $multicall); + } + + /** + * Get the server comment in utf8 format. + * @return string + */ + function getServerComment() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set whether the server should be hidden from the public server list + * (0 = visible, 1 = always hidden, 2 = hidden from nations). + * @param int $visibility + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setHideServer($visibility, $multicall = false) + { + if($visibility !== 0 && $visibility !== 1 && $visibility !== 2) + { + throw new InvalidArgumentException('visibility = '.print_r($visibility, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($visibility), $multicall); + } + + /** + * Get whether the server wants to be hidden from the public server list. + * @return string + */ + function getHideServer() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Returns true if this is a relay server. + * @return bool + */ + function isRelayServer() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new password for the server. + * @param string $serverPassword + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setServerPassword($serverPassword, $multicall = false) + { + if(!is_string($serverPassword)) + { + throw new InvalidArgumentException('serverPassword = '.print_r($serverPassword, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($serverPassword), $multicall); + } + + /** + * Get the server password if called as Admin or Super Admin, else returns if a password is needed or not. + * Get the server name in utf8 format. + * @return bool|string + */ + function getServerPassword() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new password for the spectator mode. + * @param string $serverPassword + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setServerPasswordForSpectator($serverPassword, $multicall = false) + { + if(!is_string($serverPassword)) + { + throw new InvalidArgumentException('serverPassword = '.print_r($serverPassword, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($serverPassword), $multicall); + } + + /** + * Get the password for spectator mode if called as Admin or Super Admin, else returns if a password is needed or not. + * @return bool|string + */ + function getServerPasswordForSpectator() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new maximum number of players. + * Requires a map restart to be taken into account. + * @param int $maxPlayers + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setMaxPlayers($maxPlayers, $multicall = false) + { + if(!is_int($maxPlayers)) + { + throw new InvalidArgumentException('maxPlayers = '.print_r($maxPlayers, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($maxPlayers), $multicall); + } + + /** + * Get the current and next maximum number of players allowed on server. + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getMaxPlayers() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new maximum number of spectators. + * Requires a map restart to be taken into account. + * @param int $maxSpectators + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setMaxSpectators($maxSpectators, $multicall = false) + { + if(!is_int($maxSpectators)) + { + throw new InvalidArgumentException('maxPlayers = '.print_r($maxSpectators, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($maxSpectators), $multicall); + } + + /** + * Get the current and next maximum number of spectators allowed on server. + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getMaxSpectators() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Declare if the server is a lobby, the number and maximum number of players currently managed by it, and the average level of the players. + * Only available to Admin. + * @param bool $isLobby + * @param int $lobbyPlayers + * @param int $maxPlayers + * @param double $lobbyPlayersLevel + * @param bool $multicall + * @return bool + */ + function setLobbyInfo($isLobby, $lobbyPlayers, $maxPlayers, $lobbyPlayersLevel, $multicall = false) + { + if(!is_bool($isLobby)) + { + throw new InvalidArgumentException('isLobby = '.print_r($isLobby, true)); + } + if(!is_int($lobbyPlayers)) + { + throw new InvalidArgumentException('lobbyPlayers = '.print_r($lobbyPlayers, true)); + } + if(!is_int($maxPlayers)) + { + throw new InvalidArgumentException('maxPlayers = '.print_r($maxPlayers, true)); + } + if(!is_double($lobbyPlayersLevel)) + { + throw new InvalidArgumentException('lobbyPlayersLevel = '.print_r($lobbyPlayersLevel, true)); + } + return $this->execute(ucfirst(__FUNCTION__), array($isLobby, $lobbyPlayers, $maxPlayers, $lobbyPlayersLevel), $multicall); + } + + /** + * Get whether the server if a lobby, the number and maximum number of players currently managed by it. + * The struct returned contains 4 fields IsLobby, LobbyPlayers, LobbyMaxPlayers, and LobbyPlayersLevel. + * @return Structures\LobbyInfo + */ + function getLobbyInfo() + { + $result = $this->execute(ucfirst(__FUNCTION__)); + return Structures\LobbyInfo::fromArray($result); + } + + /** + * Customize the clients 'leave server' dialog box. + * Parameters are: ManialinkPage, SendToServer url '#qjoin=login@title', + * ProposeAddToFavorites and DelayQuitButton (in milliseconds). + * Only available to Admin. + * @param string $manialinkPage + * @param string $sendToServer + * @param bool $proposeAddToFavorites + * @param bool $multicall + * @return bool + */ + function customizeQuitDialog($manialinkPage, $sendToServer, $proposeAddToFavorites, $delayQuitButton, $multicall = false) + { + if(!is_string($manialinkPage)) + { + throw new InvalidArgumentException('manialinkPage = '.print_r($manialinkPage, true)); + } + if(!is_string($sendToServer)) + { + throw new InvalidArgumentException('sendToServer = '.print_r($sendToServer, true)); + } + if(!is_bool($proposeAddToFavorites)) + { + throw new InvalidArgumentException('proposeAddToFavorites = '.print_r($proposeAddToFavorites, true)); + } + if(!is_int($delayQuitButton)) + { + throw new InvalidArgumentException('delayQuitButton = '.print_r($delayQuitButton, true)); + } + return $this->execute(ucfirst(__FUNCTION__), array($manialinkPage, $sendToServer, $proposeAddToFavorites, $delayQuitButton), $multicall); + } + + /** + * Set whether, when a player is switching to spectator, the server should still consider him a player + * and keep his player slot, or not. Only available to Admin. + * @param bool $keep + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function keepPlayerSlots($keep, $multicall = false) + { + if(!is_bool($keep)) + { + throw new InvalidArgumentException('keep = '.print_r($keep, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($keep), $multicall); + } + + /** + * Get whether the server keeps player slots when switching to spectator. + * @return bool + */ + function isKeepingPlayerSlots() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Enable or disable peer-to-peer upload from server. + * @param bool $enable + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function enableP2PUpload($enable, $multicall = false) + { + if(!is_bool($enable)) + { + throw new InvalidArgumentException('enable = '.print_r($enable, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($enable), $multicall); + } + + /** + * Returns if the peer-to-peer upload from server is enabled. + * @return bool + */ + function isP2PUpload() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Enable or disable peer-to-peer download from server. + * @param bool $enable + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function enableP2PDownload($enable, $multicall = false) + { + if(!is_bool($enable)) + { + throw new InvalidArgumentException('enable = '.print_r($enable, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($enable), $multicall); + } + + /** + * Returns if the peer-to-peer download from server is enabled. + * @return bool + */ + function isP2PDownload() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Allow clients to download maps from the server. + * @param bool $allow + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function allowMapDownload($allow, $multicall = false) + { + if(!is_bool($allow)) + { + throw new InvalidArgumentException('allow = '.print_r($allow, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($allow), $multicall); + } + + /** + * Returns if clients can download maps from the server. + * @return bool + */ + function isMapDownloadAllowed() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Enable the autosaving of all replays (vizualisable replays with all players, + * but not validable) on the server. + * @param bool $enable + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function autoSaveReplays($enable, $multicall = false) + { + if(!is_bool($enable)) + { + throw new InvalidArgumentException('enable = '.print_r($enable, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($enable), $multicall); + } + + /** + * Returns if autosaving of all replays is enabled on the server. + * @return bool + */ + function isAutoSaveReplaysEnabled() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Enable the autosaving on the server of validation replays, every time a player makes a new time. + * @param bool $enable + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function autoSaveValidationReplays($enable, $multicall = false) + { + if(!is_bool($enable)) + { + throw new InvalidArgumentException('enable = '.print_r($enable, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($enable), $multicall); + } + + /** + * Returns if autosaving of validation replays is enabled on the server. + * @return bool + */ + function isAutoSaveValidationReplaysEnabled() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Saves the current replay (vizualisable replays with all players, but not validable). + * Pass a filename, or '' for an automatic filename. + * @param string $filename + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function saveCurrentReplay($filename = '', $multicall = false) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filename), $multicall); + } + + /** + * Saves a replay with the ghost of all the players' best race. + * First parameter is the player object(or null for all players), + * Second parameter is the filename, or '' for an automatic filename. + * @param null|Structures\Player|string $player the player (or null for all players) + * @param string $filename is the filename, or '' for an automatic filename + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function saveBestGhostsReplay($player = null, $filename = '', $multicall = false) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + $playerLogin = $this->getLogin($player) ? : ''; + + return $this->execute(ucfirst(__FUNCTION__), array($playerLogin, $filename), $multicall); + } + + /** + * Returns a replay containing the data needed to validate the current best time of the player. + * The parameter is the login of the player. + * @param Structures\Player|string $player + * @return string base64 encoded + * @throws InvalidArgumentException + */ + function getValidationReplay($player) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + return $this->execute(ucfirst(__FUNCTION__), array($login)); + } + + /** + * Set a new ladder mode between ladder disabled (0) and forced (1). + * Requires a map restart to be taken into account. + * @param int $mode + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setLadderMode($mode, $multicall = false) + { + if($mode !== 0 && $mode !== 1) + { + throw new InvalidArgumentException('mode = '.print_r($mode, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($mode), $multicall); + } + + /** + * Get the current and next ladder mode on server. + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getLadderMode() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Get the ladder points limit for the players allowed on this server. + * The struct returned contains two fields LadderServerLimitMin and LadderServerLimitMax. + * @return array + */ + function getLadderServerLimits() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set the network vehicle quality to Fast (0) or High (1). + * Requires a map restart to be taken into account. + * @param int $quality + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setVehicleNetQuality($quality, $multicall = false) + { + if($quality !== 0 && $quality !== 1) + { + throw new InvalidArgumentException('quality = '.print_r($quality, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($quality), $multicall); + } + + /** + * Get the current and next network vehicle quality on server. + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getVehicleNetQuality() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set new server options using the struct passed as parameters. This struct must contain the following fields : + * Name, Comment, Password, PasswordForSpectator, NextMaxPlayers, NextMaxSpectators, IsP2PUpload, IsP2PDownload, + * NextLadderMode, NextVehicleNetQuality, NextCallVoteTimeOut, CallVoteRatio, AllowMapDownload, AutoSaveReplays, + * + * and optionally for forever: + * RefereePassword, RefereeMode, AutoSaveValidationReplays, HideServer, UseChangingValidationSeed, + * ClientInputsMaxLatency, KeepPlayerSlots. + * + * Only available to Admin. + * A change of NextMaxPlayers, NextMaxSpectators, NextLadderMode, NextVehicleNetQuality, NextCallVoteTimeOut + * or UseChangingValidationSeed requires a map restart to be taken into account. + * @param array $options + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setServerOptions(array $options, $multicall = false) + { + if(!is_array($options) || !array_key_exists('Name', $options) || !array_key_exists('Comment', $options) + || !array_key_exists('Password', $options) || !array_key_exists('PasswordForSpectator', $options) + || !array_key_exists('NextCallVoteTimeOut', $options) || !array_key_exists('CallVoteRatio', $options) + || (array_key_exists('IsP2PUpload', $options) xor array_key_exists('IsP2PDownload', $options)) + || (array_key_exists('NextMaxPlayer', $options) xor array_key_exists('NextMaxSpectator', $options)) + || (array_key_exists('RefereePassword', $options) xor array_key_exists('RefereeMode', $options))) + { + throw new InvalidArgumentException('options = '.print_r($options, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($options), $multicall); + } + + /** + * Returns a struct containing the server options: + * Name, Comment, Password, PasswordForSpectator, CurrentMaxPlayers, NextMaxPlayers, CurrentMaxSpectators, + * NextMaxSpectators, KeepPlayerSlots, IsP2PUpload, IsP2PDownload, CurrentLadderMode, NextLadderMode, + * CurrentVehicleNetQuality, NextVehicleNetQuality, CurrentCallVoteTimeOut, NextCallVoteTimeOut, CallVoteRatio, + * AllowMapDownload, AutoSaveReplays, RefereePassword, RefereeMode, AutoSaveValidationReplays, HideServer, + * CurrentUseChangingValidationSeed, NextUseChangingValidationSeed, ClientInputsMaxLatency. + * @return Structures\ServerOptions + * @throws InvalidArgumentException + */ + function getServerOptions() + { + return Structures\ServerOptions::fromArray($this->execute(ucfirst(__FUNCTION__))); + } + + /** + * Set whether the players can choose their side or if the teams are forced by the server (using ForcePlayerTeam()). + * Only available to Admin. + * @param bool $enable + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setForcedTeams($enable, $multicall = false) + { + if(!is_bool($enable)) + { + throw new InvalidArgumentException('enable = '.print_r($enable, true)); + } + return $this->execute(ucfirst(__FUNCTION__), array($enable), $multicall); + } + + /** + * Returns whether the players can choose their side or if the teams are forced by the server. + * @return bool + */ + function getForcedTeams() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Defines the packmask of the server. Can be 'United', 'Nations', 'Sunrise', 'Original', + * or any of the environment names. (Only maps matching the packmask will be + * allowed on the server, so that player connecting to it know what to expect.) + * Only available when the server is stopped. + * @param string $packMask + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setServerPackMask($packMask, $multicall = false) + { + if(!is_string($packMask)) + { + throw new InvalidArgumentException('packMask = '.print_r($packMask, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($packMask), $multicall); + } + + /** + * Get the packmask of the server. + * @return string + */ + function getServerPackMask() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set the mods to apply on the clients. Parameters: + * Override, if true even the maps with a mod will be overridden by the server setting; + * Mods, an array of structures [{EnvName, Url}, ...]. + * Requires a map restart to be taken into account. + * @param bool $override + * @param array $mods + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setForcedMods($override, $mods, $multicall = false) + { + if(!is_bool($override)) + { + throw new InvalidArgumentException('override = '.print_r($override, true)); + } + if(is_array($mods)) + { + $modList = array(); + foreach($mods as $mod) + { + if(!($mod instanceof Structures\Mod)) throw new InvalidArgumentException('mods = '.print_r($mods, true)); + else $modList[] = $mod->toArray(); + } + } + elseif($mods instanceof Structures\Mod) $modList = array($mods->toArray()); + else throw new InvalidArgumentException('mods = '.print_r($mods, true)); + + return $this->execute(ucfirst(__FUNCTION__), array($override, $modList), $multicall); + } + + /** + * Get the mods settings. + * @return array the first value is a boolean which indicate if the mods override existing mods, the second is an array of objet of Structures\Mod type + */ + function getForcedMods() + { + $result = $this->execute(ucfirst(__FUNCTION__)); + $result['Mods'] = Structures\Mod::fromArrayOfArray($result['Mods']); + return $result; + } + + /** + * Set the music to play on the clients. Parameters: + * Override, if true even the maps with a custom music will be overridden by the server setting, + * UrlOrFileName for the music. + * Requires a map restart to be taken into account + * @param bool $override + * @param string $music + * @param bool $multicall + * @throws InvalidArgumentException + */ + function setForcedMusic($override, $music, $multicall = false) + { + if(!is_bool($override)) + { + throw new InvalidArgumentException('override = '.print_r($override, true)); + } + if(!is_string($music)) + { + throw new InvalidArgumentException('music = '.print_r($music, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($override, $music), $multicall); + } + + /** + * Get the music setting. + * @return Structures\Music + */ + function getForcedMusic() + { + return Structures\Music::fromArray($this->execute(ucfirst(__FUNCTION__))); + } + + /** + * Defines a list of remappings for player skins. It expects a list of structs Orig, Name, Checksum, Url. + * Orig is the name of the skin to remap, or '*' for any other. Name, Checksum, Url define the skin to use. + * (They are optional, you may set value '' for any of those. All 3 null means same as Orig). + * Will only affect players connecting after the value is set. + * @param Structures\Skin[] $skins + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setForcedSkins(array $skins, $multicall = false) + { + if(!is_array($skins)) + { + throw new InvalidArgumentException('skins = '.print_r($skins, true)); + } + + $skinParameter = array(); + foreach($skins as $key => $skin) + { + if($skin instanceof Structures\Skin) + { + $skinParameter[$key] = array(); + $skinParameter[$key]['Orig'] = $skin->orig; + $skinParameter[$key]['Name'] = $skin->name; + $skinParameter[$key]['Checksum'] = $skin->checksum; + $skinParameter[$key]['Url'] = $skin->url; + } + elseif(!is_array($skin) || !array_key_exists('Orig', $skin) && !array_key_exists('Name', $skin) && !array_key_exists('Checksum', + $skin) && !array_key_exists('Url', $skin)) + { + throw new InvalidArgumentException('skins['.$key.'] = '.print_r($skins[$key], true)); + } + else + { + $skinParameter[$key] = $skin; + } + } + + return $this->execute(ucfirst(__FUNCTION__), array($skinParameter), $multicall); + } + + /** + * Get the current forced skins. + * @return Structures\Skin[] + */ + function getForcedSkins() + { + return Structures\Skin::fromArrayOfArray($this->execute(ucfirst(__FUNCTION__))); + } + + /** + * Returns the last error message for an internet connection. + * @return string + */ + function getLastConnectionErrorMessage() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new password for the referee mode. + * @param string $refereePassword + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setRefereePassword($refereePassword, $multicall = false) + { + if(!is_string($refereePassword)) + { + throw new InvalidArgumentException('refereePassword = '.print_r($refereePassword, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($refereePassword), $multicall); + } + + /** + * Get the password for referee mode if called as Admin or Super Admin, + * else returns if a password is needed or not. + * @return bool|string + */ + function getRefereePassword() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set the referee validation mode. 0 = validate the top3 players, 1 = validate all players. Only available to Admin. + * @param int $refereeMode + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setRefereeMode($refereeMode, $multicall = false) + { + if($refereeMode !== 0 && $refereeMode !== 1) + { + throw new InvalidArgumentException('refereeMode = '.print_r($refereeMode, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($refereeMode), $multicall); + } + + /** + * Get the referee validation mode. + * @return bool|string + */ + function getRefereeMode() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set whether the game should use a variable validation seed or not. + * Requires a map restart to be taken into account. + * @param bool $enable + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setUseChangingValidationSeed($enable, $multicall = false) + { + if(!is_bool($enable)) + { + throw new InvalidArgumentException('enable = '.print_r($enable, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($enable), $multicall); + } + + /** + * Get the current and next value of UseChangingValidationSeed. + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getUseChangingValidationSeed() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set the maximum time the server must wait for inputs from the clients before dropping data, or '0' for auto-adaptation. + * Only used by ShootMania. Only available to Admin. + * @param int $latency + * @param bool $multicall + * @return bool + */ + function setClientInputsMaxLatency($latency, $multicall = false) + { + if(!is_int($latency)) + { + throw new InvalidArgumentException('latency = '.print_r($latency, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($latency), $multicall); + } + + /** + * Get the current ClientInputsMaxLatency. Only used by ShootMania. + * @return int + */ + function getClientInputsMaxLatency() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Sets whether the server is in warm-up phase or not. + * @param bool $enable + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setWarmUp($enable, $multicall = false) + { + if(!is_bool($enable)) + { + throw new InvalidArgumentException('enable = '.print_r($enable, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($enable), $multicall); + } + + /** + * Returns whether the server is in warm-up phase. + * @return bool + */ + function getWarmUp() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Get the current rules script. + * TODO Check if correct + * @return string + */ + function getModeScriptText() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set the rules script and restart. + * Only available to Admin. + * TODO Check if correct + * @param string $script + * @param bool $multicall + * @return bool + */ + function setModeScriptText($script, $multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array($script), $multicall); + } + + /** + * Get the xml-rpc variables of the mode script. + * Only available to Admin. + * @return array + */ + function getModeScriptVariables() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set the variables of the rules script. Only available to Admin. + * @param array $variables + * @param bool $multicall + */ + function setModeScriptVariables($variables, $multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array($variables), $multicall); + } + + /** + * Send an event to the mode script. Only available to Admin. + * @param string $param1 + * @param string $param2 + * @param bool $multicall + * @return bool + */ + function triggerModeScriptEvent($param1, $param2, $multicall = false) + { + if(!is_string($param1)) + { + throw new InvalidArgumentException('param1 = '.print_r($param1, true)); + } + if(!is_string($param2)) + { + throw new InvalidArgumentException('param2 = '.print_r($param2, true)); + } + return $this->execute(ucfirst(__FUNCTION__), array($param1, $param2), $multicall); + } + + /** + * Send an event to the mode script. Only available to Admin. + * @param string $param1 + * @param mixed[] $param2 + * @param bool $multicall + * @return bool + */ + function triggerModeScriptEventArray($param1, $param2, $multicall = false) + { + if(!is_string($param1)) + { + throw new InvalidArgumentException('param1 = '.print_r($param1, true)); + } + if(!is_array($param2)) + { + throw new InvalidArgumentException('param2 = '.print_r($param2, true)); + } + return $this->execute(ucfirst(__FUNCTION__), array($param1, $param2), $multicall); + } + + /** + * Returns the description of the current rules script, + * as a structure containing: Name, CompatibleTypes, + * Description and the settings available. + * @return Structures\ScriptInfo + */ + function getModeScriptInfo() + { + return Structures\ScriptInfo::fromArray($this->execute(ucfirst(__FUNCTION__))); + } + + /** + * Returns the current parameters of the mode script. + * @return array + */ + function getModeScriptSettings() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set the parameters of the rules script. Only available to Admin. + * @param array $rules + * @param bool $multicall + * @return bool + */ + function setModeScriptSettings($rules, $multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array($rules), $multicall); + } + + /** + * Send commands to the mode script. + * Only available to Admin. + * @param array $commands + * @param bool $multicall + * @return bool + */ + function sendModeScriptCommands(array $commands, $multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array($commands), $multicall); + } + + /** + * Change the settings and send commands to the mode script. + * Only available to Admin. + * @param array $settings + * @param array $commands + * @param bool $multicall + * @return bool + */ + function setModeScriptSettingsAndCommands(array $settings, array $commands, $multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array($settings, $commands), $multicall); + } + + /** + * Restarts the map, with an optional boolean parameter DontClearCupScores (only available in cup mode). + * @param bool $dontClearCupScores + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function restartMap($dontClearCupScores = false, $multicall = false) + { + if(!is_bool($dontClearCupScores)) + { + throw new InvalidArgumentException('dontClearCupScores = '.print_r($dontClearCupScores, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($dontClearCupScores), $multicall); + } + + /** + * Switch to next map, with an optional boolean parameter DontClearCupScores (only available in cup mode). + * @param bool $dontClearCupScores + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function nextMap($dontClearCupScores = false, $multicall = false) + { + if(!is_bool($dontClearCupScores)) + { + throw new InvalidArgumentException('dontClearCupScores = '.print_r($dontClearCupScores, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($dontClearCupScores), $multicall); + } + + /** + * Attempt to balance teams. Only available to Admin. + * @return bool + */ + function autoTeamBalance() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Stop the server. + * @param bool $multicall + * @return bool + */ + function stopServer($multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array(), $multicall); + } + + /** + * In Rounds or Laps mode, force the end of round without waiting for all players to giveup/finish. + * @param bool $multicall + * @return bool + */ + function forceEndRound($multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array(), $multicall); + } + + /** + * Set new game settings using the struct passed as parameters. + * This struct must contain the following fields : + * GameMode, ChatTime, RoundsPointsLimit, RoundsUseNewRules, RoundsForcedLaps, TimeAttackLimit, + * TimeAttackSynchStartPeriod, TeamPointsLimit, TeamMaxPoints, TeamUseNewRules, LapsNbLaps, LapsTimeLimit, + * FinishTimeout, and optionally: AllWarmUpDuration, DisableRespawn, ForceShowAllOpponents, RoundsPointsLimitNewRules, + * TeamPointsLimitNewRules, CupPointsLimit, CupRoundsPerMap, CupNbWinners, CupWarmUpDuration. + * Requires a map restart to be taken into account. + * @param Structures\GameInfos $gameInfos + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setGameInfos(Structures\GameInfos $gameInfos, $multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array($gameInfos->toArray()), $multicall); + } + + /** + * Optional parameter for compatibility: + * struct version (0 = united, 1 = forever). + * Returns a struct containing the current game settings, ie: + * GameMode, ChatTime, NbMap, RoundsPointsLimit, RoundsUseNewRules, RoundsForcedLaps, + * TimeAttackLimit, TimeAttackSynchStartPeriod, TeamPointsLimit, TeamMaxPoints, TeamUseNewRules, + * LapsNbLaps, LapsTimeLimit, FinishTimeout, + * additionally for version 1: AllWarmUpDuration, DisableRespawn, ForceShowAllOpponents, RoundsPointsLimitNewRules, + * TeamPointsLimitNewRules, CupPointsLimit, CupRoundsPerMap, CupNbWinners, CupWarmUpDuration. + * @param int $compatibility + * @return Structures\GameInfos + * @throws InvalidArgumentException + */ + function getCurrentGameInfo($compatibility = 1) + { + if($compatibility !== 1 && $compatibility != 0) + { + throw new InvalidArgumentException('compatibility = '.print_r($compatibility, true)); + } + + return Structures\GameInfos::fromArray($this->execute(ucfirst(__FUNCTION__), array($compatibility))); + } + + /** + * Optional parameter for compatibility: + * struct version (0 = united, 1 = forever). + * Returns a struct containing the game settings for the next map, ie: + * GameMode, ChatTime, NbMap, RoundsPointsLimit, RoundsUseNewRules, RoundsForcedLaps, + * TimeAttackLimit, TimeAttackSynchStartPeriod, TeamPointsLimit, TeamMaxPoints, TeamUseNewRules, + * LapsNbLaps, LapsTimeLimit, FinishTimeout, + * additionally for version 1: AllWarmUpDuration, DisableRespawn, ForceShowAllOpponents, RoundsPointsLimitNewRules, + * TeamPointsLimitNewRules, CupPointsLimit, CupRoundsPerMap, CupNbWinners, CupWarmUpDuration. + * @param int $compatibility + * @return Structures\GameInfos + * @throws InvalidArgumentException + */ + function getNextGameInfo($compatibility = 1) + { + if($compatibility !== 1 && $compatibility != 0) + { + throw new InvalidArgumentException('compatibility = '.print_r($compatibility, true)); + } + + return Structures\GameInfos::fromArray($this->execute(ucfirst(__FUNCTION__), array($compatibility))); + } + + /** + * Optional parameter for compatibility: struct version (0 = united, 1 = forever). + * Returns a struct containing two other structures, + * the first containing the current game settings and the second the game settings for next map. + * The first structure is named CurrentGameInfos and the second NextGameInfos. + * @param int $compatibility + * @return Structures\GameInfos[] + * @throws InvalidArgumentException + */ + function getGameInfos($compatibility = 1) + { + if($compatibility !== 1 && $compatibility != 0) + { + throw new InvalidArgumentException('compatibility = '.print_r($compatibility, true)); + } + + return Structures\GameInfos::fromArrayOfArray($this->execute(ucfirst(__FUNCTION__), array($compatibility))); + } + + /** + * Set a new game mode between Rounds (0), TimeAttack (1), Team (2), Laps (3), Stunts (4) and Cup (5). + * Requires a map restart to be taken into account. + * @param int $gameMode + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setGameMode($gameMode, $multicall = false) + { + if(!is_int($gameMode) && ($gameMode < 0 || $gameMode > 5)) + { + throw new InvalidArgumentException('gameMode = '.print_r($gameMode, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($gameMode), $multicall); + } + + /** + * Get the current game mode. + * @return int + */ + function getGameMode() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new chat time value in milliseconds (actually 'chat time' is the duration of the end race podium, 0 means no podium displayed.). + * @param int $chatTime + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setChatTime($chatTime, $multicall = false) + { + if(!is_int($chatTime)) + { + throw new InvalidArgumentException('chatTime = '.print_r($chatTime, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($chatTime), $multicall); + } + + /** + * Get the current and next chat time. The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getChatTime() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new finish timeout (for rounds/laps mode) value in milliseconds. + * 0 means default. 1 means adaptative to the duration of the map. + * Requires a map restart to be taken into account. + * @param int $finishTimeout + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setFinishTimeout($finishTimeout, $multicall = false) + { + if(!is_int($finishTimeout)) + { + throw new InvalidArgumentException('chatTime = '.print_r($finishTimeout, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($finishTimeout), $multicall); + } + + /** + * Get the current and next FinishTimeout. The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getFinishTimeout() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set whether to enable the automatic warm-up phase in all modes. + * 0 = no, otherwise it's the duration of the phase, expressed in number of rounds (in rounds/team mode), + * or in number of times the gold medal time (other modes). + * Requires a map restart to be taken into account. + * @param int $warmUpDuration + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setAllWarmUpDuration($warmUpDuration, $multicall = false) + { + if(!is_int($warmUpDuration)) + { + throw new InvalidArgumentException('warmUpDuration = '.print_r($warmUpDuration, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($warmUpDuration), $multicall); + } + + /** + * Get whether the automatic warm-up phase is enabled in all modes. The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getAllWarmUpDuration() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set whether to disallow players to respawn. + * Requires a map restart to be taken into account. + * @param bool $disableRespawn + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setDisableRespawn($disableRespawn, $multicall = false) + { + if(!is_bool($disableRespawn)) + { + throw new InvalidArgumentException('disableRespawn = '.print_r($disableRespawn, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($disableRespawn), $multicall); + } + + /** + * Get whether players are disallowed to respawn. The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getDisableRespawn() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set whether to override the players preferences and always display all opponents + * 0=no override, 1=show all, other value=minimum number of opponents. + * Requires a map restart to be taken into account. + * @param int $forceShowAllOpponents + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setForceShowAllOpponents($forceShowAllOpponents, $multicall = false) + { + if(!is_int($forceShowAllOpponents)) + { + throw new InvalidArgumentException('forceShowAllOpponents = '.print_r($forceShowAllOpponents, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($forceShowAllOpponents), $multicall); + } + + /** + * Get whether players are forced to show all opponents. The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getForceShowAllOpponents() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new rules script name for script mode. Only available to Admin. + * Requires a map restart to be taken into account. + * @param string $scriptName + * @param bool $multicall + * @return bool + */ + function setScriptName($scriptName, $multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array($scriptName), $multicall); + } + + /** + * Get the current and next rules script name for script mode. + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getScriptName() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new time limit for time attack mode. + * Requires a map restart to be taken into account. + * @param int $timeAttackLimit + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setTimeAttackLimit($timeAttackLimit, $multicall = false) + { + if(!is_int($timeAttackLimit)) + { + throw new InvalidArgumentException('timeAttackLimit = '.print_r($timeAttackLimit, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($timeAttackLimit), $multicall); + } + + /** + * Get the current and next time limit for time attack mode. The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getTimeAttackLimit() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new synchronized start period for time attack mode. + * Requires a map restart to be taken into account. + * @param int $timeAttackSynchPeriod + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setTimeAttackSynchStartPeriod($timeAttackSynchPeriod, $multicall = false) + { + if(!is_int($timeAttackSynchPeriod)) + { + throw new InvalidArgumentException('timeAttackSynchPeriod = '.print_r($timeAttackSynchPeriod, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($timeAttackSynchPeriod), $multicall); + } + + /** + * Get the current and synchronized start period for time attack mode. + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getTimeAttackSynchStartPeriod() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new time limit for laps mode. + * Requires a map restart to be taken into account. + * @param int $lapsTimeLimit + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setLapsTimeLimit($lapsTimeLimit, $multicall = false) + { + if(!is_int($lapsTimeLimit)) + { + throw new InvalidArgumentException('lapsTimeLimit = '.print_r($lapsTimeLimit, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($lapsTimeLimit), $multicall); + } + + /** + * Get the current and next time limit for laps mode. + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getLapsTimeLimit() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new number of laps for laps mode. + * Requires a map restart to be taken into account. + * @param int $nbLaps + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setNbLaps($nbLaps, $multicall = false) + { + if(!is_int($nbLaps)) + { + throw new InvalidArgumentException('nbLaps = '.print_r($nbLaps, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($nbLaps), $multicall); + } + + /** + * Get the current and next number of laps for laps mode. + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getNbLaps() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new number of laps for rounds mode + * 0 = default, use the number of laps from the maps, + * otherwise forces the number of rounds for multilaps maps. + * Requires a map restart to be taken into account. + * @param int $roundForcedLaps + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setRoundForcedLaps($roundForcedLaps, $multicall = false) + { + if(!is_int($roundForcedLaps)) + { + throw new InvalidArgumentException('roundForcedLaps = '.print_r($roundForcedLaps, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($roundForcedLaps), $multicall); + } + + /** + * Get the current and next number of laps for rounds mode. + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getRoundForcedLaps() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new points limit for rounds mode (value set depends on UseNewRulesRound). + * Requires a map restart to be taken into account. + * @param int $roundPointsLimit + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setRoundPointsLimit($roundPointsLimit, $multicall = false) + { + if(!is_int($roundPointsLimit)) + { + throw new InvalidArgumentException('roundPointsLimit = '.print_r($roundPointsLimit, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($roundPointsLimit), $multicall); + } + + /** + * Get the current and next points limit for rounds mode (values returned depend on UseNewRulesRound). + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getRoundPointsLimit() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set the points used for the scores in rounds mode. + * Points is an array of decreasing integers for the players from the first to last. + * And you can add an optional boolean to relax the constraint checking on the scores. + * @param array $roundCustomPoints + * @param bool $relaxChecking + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setRoundCustomPoints(array $roundCustomPoints, $relaxChecking = false, $multicall = false) + { + if(!is_array($roundCustomPoints)) + { + throw new InvalidArgumentException('roundCustomPoints = '.print_r($roundCustomPoints, true)); + } + if(!is_bool($relaxChecking)) + { + throw new InvalidArgumentException('relaxChecking = '.print_r($relaxChecking, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($roundCustomPoints, $relaxChecking), $multicall); + } + + /** + * Gets the points used for the scores in rounds mode. + * @param bool $multicall + * @return array + */ + function getRoundCustomPoints() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set the points used for the scores in rounds mode. + * Points is an array of decreasing integers for the players from the first to last. + * And you can add an optional boolean to relax the constraint checking on the scores. + * @param bool $useNewRulesRound + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setUseNewRulesRound($useNewRulesRound, $multicall = false) + { + if(!is_bool($useNewRulesRound)) + { + throw new InvalidArgumentException('useNewRulesRound = '.print_r($useNewRulesRound, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($useNewRulesRound), $multicall); + } + + /** + * Gets the points used for the scores in rounds mode. + * @return array + */ + function getUseNewRulesRound() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new points limit for team mode (value set depends on UseNewRulesTeam). + * Requires a map restart to be taken into account. + * @param int $teamPointsLimit + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setTeamPointsLimit($teamPointsLimit, $multicall = false) + { + if(!is_int($teamPointsLimit)) + { + throw new InvalidArgumentException('teamPointsLimit = '.print_r($teamPointsLimit, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($teamPointsLimit), $multicall); + } + + /** + * Get the current and next points limit for team mode (values returned depend on UseNewRulesTeam). + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getTeamPointsLimit() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set a new number of maximum points per round for team mode. + * Requires a map restart to be taken into account. + * @param int $maxPointsTeam + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setMaxPointsTeam($maxPointsTeam, $multicall = false) + { + if(!is_int($maxPointsTeam)) + { + throw new InvalidArgumentException('maxPointsTeam = '.print_r($maxPointsTeam, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($maxPointsTeam), $multicall); + } + + /** + * Get the current and next number of maximum points per round for team mode. + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getMaxPointsTeam() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set if new rules are used for team mode. + * Requires a map restart to be taken into account. + * @param bool $useNewRulesTeam + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setUseNewRulesTeam($useNewRulesTeam, $multicall = false) + { + if(!is_bool($useNewRulesTeam)) + { + throw new InvalidArgumentException('useNewRulesTeam = '.print_r($useNewRulesTeam, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($useNewRulesTeam), $multicall); + } + + /** + * Get if the new rules are used for team mode (Current and next values). + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getUseNewRulesTeam() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set the points needed for victory in Cup mode. + * Requires a map restart to be taken into account. + * @param int $pointsLimit + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setCupPointsLimit($pointsLimit, $multicall = false) + { + if(!is_int($pointsLimit)) + { + throw new InvalidArgumentException('pointsLimit = '.print_r($pointsLimit, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($pointsLimit), $multicall); + } + + /** + * Get the points needed for victory in Cup mode. + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getCupPointsLimit() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Sets the number of rounds before going to next map in Cup mode. + * Requires a map restart to be taken into account. + * @param int $roundsPerMap + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setCupRoundsPerMap($roundsPerMap, $multicall = false) + { + if(!is_int($roundsPerMap)) + { + throw new InvalidArgumentException('roundsPerMap = '.print_r($roundsPerMap, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($roundsPerMap), $multicall); + } + + /** + * Get the number of rounds before going to next map in Cup mode. + * The struct returned contains two fields CurrentValue and NextValue. + * @param bool $multicall + * @return array + */ + function getCupRoundsPerMap() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set whether to enable the automatic warm-up phase in Cup mode. + * 0 = no, otherwise it's the duration of the phase, expressed in number of rounds. + * Requires a map restart to be taken into account. + * @param int $warmUpDuration + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setCupWarmUpDuration($warmUpDuration, $multicall = false) + { + if(!is_int($warmUpDuration)) + { + throw new InvalidArgumentException('warmUpDuration = '.print_r($warmUpDuration, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($warmUpDuration), $multicall); + } + + /** + * Get whether the automatic warm-up phase is enabled in Cup mode. + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getCupWarmUpDuration() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Set the number of winners to determine before the match is considered over. + * Requires a map restart to be taken into account. + * @param int $nbWinners + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setCupNbWinners($nbWinners, $multicall = false) + { + if(!is_int($nbWinners)) + { + throw new InvalidArgumentException('nbWinners = '.print_r($nbWinners, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($nbWinners), $multicall); + } + + /** + * Get the number of winners to determine before the match is considered over. + * The struct returned contains two fields CurrentValue and NextValue. + * @return array + */ + function getCupNbWinners() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Returns the current map index in the selection, or -1 if the map is no longer in the selection. + * @return int + */ + function getCurrentMapIndex() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Returns the map index in the selection that will be played next (unless the current one is restarted...) + * @return int + */ + function getNextMapIndex() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Sets the map index in the selection that will be played next (unless the current one is restarted...) + * @param int $nextMapIndex + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function setNextMapIndex($nextMapIndex, $multicall = false) + { + if(!is_int($nextMapIndex)) + { + throw new InvalidArgumentException('nextMapIndex = '.print_r($nextMapIndex, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($nextMapIndex), $multicall); + } + + /** + * Immediately jumps to the map designated by the index in the selection + * @param int $nextMapIndex + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function jumpToMapIndex($mapIndex, $multicall = false) + { + if(!is_int($mapIndex)) + { + throw new InvalidArgumentException('mapIndex = '.print_r($mapIndex, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($mapIndex), $multicall); + } + + /** + * Set Team names and colors. Only available to Admin. + * @param string $teamName1 + * @param float $teamColor1 + * @param string $team1Country + * @param string $teamName2 + * @param float $teamColor2 + * @param string $team2Country + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + * @deprecated since version 2013-04-11 + */ + function setTeamInfo($teamName1, $teamColor1, $team1Country, $teamName2, $teamColor2, $team2Country, $multicall = false) + { + if(!is_float($teamColor1)) + { + throw new InvalidArgumentException('teamColor1 = '.print_r($teamColor1, true)); + } + if(!is_float($teamColor2)) + { + throw new InvalidArgumentException('teamColor2 = '.print_r($teamColor2, true)); + } + if(!is_string($teamName1)) + { + throw new InvalidArgumentException('teamName1 = '.print_r($teamName1, true)); + } + if(!is_string($teamName2)) + { + throw new InvalidArgumentException('teamName2 = '.print_r($teamName2, true)); + } + return $this->execute(ucfirst(__FUNCTION__), + array('unused', 0., 'World', $teamName1, $teamColor1, $team1Country, $teamName2, $teamColor2, $team2Country), + $multicall); + } + + /** + * Return Team info for a given clan (0 = no clan, 1, 2). + * The structure contains: name, zonePath, city, emblemUrl, huePrimary, hueSecondary, rGB, clubLinkUrl. + * Only available to Admin. + * @param int $teamId + * @return Structures\Team + * @throws InvalidArgumentException + */ + function getTeamInfo($teamId) + { + if(!is_int($teamId)) + { + throw new InvalidArgumentException('teamId = '.print_r($teamId, true)); + } + return Structures\Team::fromArray($this->execute(ucfirst(__FUNCTION__), array($teamId))); + } + + /** + * Set the clublinks to use for the two clans. + * Only available to Admin. + * @param string $team1ClubLink + * @param string $team2ClubLink + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function setForcedClubLinks($team1ClubLink, $team2ClubLink, $multicall = false) + { + if(!is_string($team1ClubLink)) + { + throw new InvalidArgumentException('team1ClubLink = '.print_r($team1ClubLink, true)); + } + if(!is_string($team2ClubLink)) + { + throw new InvalidArgumentException('team2ClubLink = '.print_r($team2ClubLink, true)); + } + return $this->execute(ucfirst(__FUNCTION__), array($team1ClubLink, $team2ClubLink), $multicall); + } + + /** + * Get the forced clublinks. + * @return array + */ + function getForcedClubLinks() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * (debug tool) Connect a fake player to the server and returns the login. + * Only available to Admin. + * @param bool $multicall + * @return string + */ + function connectFakePlayer($multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array(), $multicall); + } + + /** + * (debug tool) Disconnect a fake player, or all the fake players if login is '*'. + * Only available to Admin. + * @param string $fakePlayerLogin + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function disconnectFakePlayer($fakePlayerLogin, $multicall = false) + { + if(!is_string($fakePlayerLogin)) + { + throw new InvalidArgumentException('fakePlayerLogin = '.print_r($fakePlayerLogin, true)); + } + return $this->execute(ucfirst(__FUNCTION__), array($fakePlayerLogin), $multicall); + } + + /** + * Returns the token infos for a player. + * The returned structure is { TokenCost, CanPayToken }. + * @param Structures\Player|string $player + * @return array + */ + function getDemoTokenInfosForPlayer($player) + { + $login = $this->getLogin($player); + return (object) $this->execute(ucfirst(__FUNCTION__), array($login)); + } + + /** + * Disable player horns. Only available to Admin. + * @param bool $disable + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function disableHorns($disable, $multicall = false) + { + if(!is_bool($disable)) + { + throw new InvalidArgumentException('disable = '.print_r($disable, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($disable), $multicall); + } + + /** + * Returns whether the horns are disabled. + * @return bool + */ + function areHornsDisabled() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Disable the automatic mesages when a player connects/disconnects from the server. + * Only available to Admin. + * @param bool $disable + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function disableServiceAnnounces($disable = true, $multicall = false) + { + if(!is_bool($disable)) + { + throw new InvalidArgumentException('disable = '.print_r($disable, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($disable), $multicall); + } + + /** + * Returns whether the automatic mesages are disabled. + * @return bool + */ + function areServiceAnnouncesDisabled() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Returns a struct containing the infos for the current map. + * The struct contains the following fields : Name, UId, FileName, + * Author, Environnement, Mood, BronzeTime, SilverTime, GoldTime, + * AuthorTime, CopperPrice, LapRace, NbLaps and NbCheckpoints. + * @return Structures\Map + */ + function getCurrentMapInfo() + { + return Structures\Map::fromArray($this->execute(ucfirst(__FUNCTION__))); + } + + /** + * Returns a struct containing the infos for the next map. + * The struct contains the following fields : Name, UId, FileName, + * Author, Environnement, Mood, BronzeTime, SilverTime, GoldTime, + * AuthorTime, CopperPrice, LapRace, NbLaps and NbCheckpoints. + * (NbLaps and NbCheckpoints are also present but always set to -1) + * @return Structures\Map + */ + function getNextMapInfo() + { + return Structures\Map::fromArray($this->execute(ucfirst(__FUNCTION__))); + } + + /** + * Returns a struct containing the infos for the map with the specified filename. + * The struct contains the following fields : Name, UId, FileName, + * Author, Environnement, Mood, BronzeTime, SilverTime, GoldTime, + * AuthorTime, CopperPrice, LapRace, NbLaps and NbCheckpoints. + * (NbLaps and NbCheckpoints are also present but always set to -1) + * @param string $filename + * @return Structures\Map + * @throws InvalidArgumentException + */ + function getMapInfo($filename) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + $temp = $this->execute(ucfirst(__FUNCTION__), array($filename)); + return Structures\Map::fromArray($temp); + } + + /** + * Returns a boolean if the map with the specified filename matches the current server settings. + * @param string $filename + * @return bool + */ + function checkMapForCurrentServerParams($filename) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filename)); + } + + /** + * Returns a list of maps among the current selection of the server. + * This method take two parameters. + * The first parameter specifies the maximum number of infos to be returned, + * the second one the starting index in the selection. + * The list is an array of structures. Each structure contains the following fields : Name, UId, FileName, Environnement, Author, GoldTime and CopperPrice. + * @param int $length specifies the maximum number of infos to be returned + * @param int $offset specifies the starting index in the list + * @return Structures\Map[] The list is an array of Map + * @throws InvalidArgumentException + */ + function getMapList($length, $offset) + { + if(!is_int($length)) + { + throw new InvalidArgumentException('length = '.print_r($length, true)); + } + if(!is_int($offset)) + { + throw new InvalidArgumentException('offset = '.print_r($offset, true)); + } + + return Structures\Map::fromArrayOfArray($this->execute(ucfirst(__FUNCTION__), array($length, $offset))); + } + + /** + * Add the map with the specified filename at the end of the current selection. + * @param string $filename + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function addMap($filename, $multicall = false) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filename), $multicall); + } + + /** + * Add the list of maps with the specified filename at the end of the current selection. + * @param array $filenames + * @param bool $multicall + * @throws InvalidArgumentException + * @return int + */ + function addMapList(array $filenames, $multicall = false) + { + if(!is_array($filenames)) + { + throw new InvalidArgumentException('filenames = '.print_r($filenames, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filenames), $multicall); + } + + /** + * Remove the map with the specified filename from the current selection. + * @param string $filename + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function removeMap($filename, $multicall = false) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filename), $multicall); + } + + /** + * Remove the list of maps with the specified filenames from the current selection. + * The list of maps to remove is an array of strings. + * @param array $filenames + * @param bool $multicall + * @throws InvalidArgumentException + * @return int + */ + function removeMapList(array $filenames, $multicall = false) + { + if(!is_array($filenames)) + { + throw new InvalidArgumentException('filenames = '.print_r($filenames, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filenames), $multicall); + } + + /** + * Insert the map with the specified filename after the current map. + * @param string $filename + * @throws InvalidArgumentException + * @return bool + */ + function insertMap($filename, $multicall = false) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filename), $multicall); + } + + /** + * Insert the list of maps with the specified filenames after the current map. + * The list of maps to remove is an array of strings. + * @param array $filenames + * @throws InvalidArgumentException + * @return int + */ + function insertMapList(array $filenames, $multicall = false) + { + if(!is_array($filenames)) + { + throw new InvalidArgumentException('filenames = '.print_r($filenames, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filenames), $multicall); + } + + /** + * Set as next map the one with the specified filename, if it is present in the selection. + * @param string $filename + * @param bool $multicall + * @throws InvalidArgumentException + * @return bool + */ + function chooseNextMap($filename, $multicall = false) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filename), $multicall); + } + + /** + * Set as next maps the list of maps with the specified filenames, if they are present in the selection. + * The list of maps to remove is an array of strings. + * @param array $filenames + * @param bool $multicall + * @throws InvalidArgumentException + * @return int + */ + function chooseNextMapList(array $filenames, $multicall = false) + { + if(!is_array($filenames)) + { + throw new InvalidArgumentException('filenames = '.print_r($filenames, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filenames), $multicall); + } + + /** + * Set a list of maps defined in the playlist with the specified filename + * as the current selection of the server, and load the gameinfos from the same file. + * @param string $filename + * @throws InvalidArgumentException + * @return int + */ + function loadMatchSettings($filename, $multicall = false) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filename), $multicall); + } + + /** + * Add a list of maps defined in the playlist with the specified filename at the end of the current selection. + * @param string $filename + * @throws InvalidArgumentException + * @return int + */ + function appendPlaylistFromMatchSettings($filename, $multicall = false) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filename), $multicall); + } + + /** + * Save the current selection of map in the playlist with the specified filename, as well as the current gameinfos. + * @param string $filename + * @param bool $multicall + * @throws InvalidArgumentException + * @return int + */ + function saveMatchSettings($filename, $multicall = false) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filename), $multicall); + } + + /** + * Insert a list of maps defined in the playlist with the specified filename after the current map. + * @param string $filename + * @throws InvalidArgumentException + * @return int + */ + function insertPlaylistFromMatchSettings($filename, $multicall = false) + { + if(!is_string($filename)) + { + throw new InvalidArgumentException('filename = '.print_r($filename, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($filename), $multicall); + } + + /** + * Returns the list of players on the server. This method take two parameters. + * The first parameter specifies the maximum number of infos to be returned, + * the second one the starting index in the list, + * an optional 3rd parameter is used for compatibility: struct version (0 = united, 1 = forever, 2 = forever, including the servers). + * The list is an array of Structures\Player. + * LadderRanking is 0 when not in official mode, + * Flags = ForceSpectator(0,1,2) + IsReferee * 10 + IsPodiumReady * 100 + IsUsingStereoscopy * 1000 + + * IsManagedByAnOtherServer * 10000 + IsServer * 100000 + HasPlayerSlot * 1000000 + * SpectatorStatus = Spectator + TemporarySpectator * 10 + PureSpectator * 100 + AutoTarget * 1000 + CurrentTargetId * 10000 + * @param int $length specifies the maximum number of infos to be returned + * @param int $offset specifies the starting index in the list + * @param int $compatibility + * @return Structures\Player[] The list is an array of Structures\Player + * @throws InvalidArgumentException + */ + function getPlayerList($length, $offset, $compatibility = 1) + { + if(!is_int($length)) + { + throw new InvalidArgumentException('length = '.print_r($length, true)); + } + if(!is_int($offset)) + { + throw new InvalidArgumentException('offset = '.print_r($offset, true)); + } + if(!is_int($compatibility)) + { + throw new InvalidArgumentException('compatibility = '.print_r($compatibility, true)); + } + + return Structures\Player::fromArrayOfArray($this->execute(ucfirst(__FUNCTION__), array($length, $offset, $compatibility))); + } + + /** + * Returns a object of type Structures\Player containing the infos on the player with the specified login, + * with an optional parameter for compatibility: struct version (0 = united, 1 = forever). + * The structure is identical to the ones from GetPlayerList. Forever PlayerInfo struct is: + * Login, NickName, PlayerId, TeamId, SpectatorStatus, LadderRanking, and Flags. + * LadderRanking is 0 when not in official mode, + * Flags = ForceSpectator(0,1,2) + IsReferee * 10 + IsPodiumReady * 100 + IsUsingStereoscopy * 1000 + + * IsManagedByAnOtherServer * 10000 + IsServer * 100000 + HasPlayerSlot * 1000000 + * SpectatorStatus = Spectator + TemporarySpectator * 10 + PureSpectator * 100 + AutoTarget * 1000 + CurrentTargetId * 10000 + * @param int $playerLogin + * @param int $compatibility + * @return Structures\Player + * @throws InvalidArgumentException + */ + function getPlayerInfo($playerLogin, $compatibility = 1) + { + if(!is_string($playerLogin)) + { + throw new InvalidArgumentException('playerLogin = '.print_r($playerLogin, true)); + } + if(!is_int($compatibility)) + { + throw new InvalidArgumentException('compatibility = '.print_r($compatibility, true)); + } + + return Structures\Player::fromArray($this->execute(ucfirst(__FUNCTION__), array($playerLogin, $compatibility))); + } + + /** + * Returns an object of type Structures\Player containing the infos on the player with the specified login. + * The structure contains the following fields : + * Login, NickName, PlayerId, TeamId, IPAddress, DownloadRate, UploadRate, Language, IsSpectator, + * IsInOfficialMode, a structure named Avatar, an array of structures named Skins, a structure named LadderStats, + * HoursSinceZoneInscription and OnlineRights (0: nations account, 3: united account). + * Each structure of the array Skins contains two fields Environnement and a struct PackDesc. + * Each structure PackDesc, as well as the struct Avatar, contains two fields FileName and Checksum. + * @param int $playerLogin + * @return Structures\Player + * @throws InvalidArgumentException + */ + function getDetailedPlayerInfo($playerLogin) + { + if(!is_string($playerLogin)) + { + throw new InvalidArgumentException('playerLogin = '.print_r($playerLogin, true)); + } + + return Structures\Player::fromArray($this->execute(ucfirst(__FUNCTION__), array($playerLogin))); + } + + /** + * Returns an object of Structures\Player type containing the infos on the player with the specified login. + * The structure contains the following fields : Login, NickName, PlayerId, TeamId, IPAddress, DownloadRate, UploadRate, + * Language, IsSpectator, IsInOfficialMode, a structure named Avatar, an array of structures named Skins, a structure named LadderStats, + * HoursSinceZoneInscription and OnlineRights (0: nations account, 3: united account). + * Each structure of the array Skins contains two fields Environnement and a struct PackDesc. + * Each structure PackDesc, as well as the struct Avatar, contains two fields FileName and Checksum. + * @param int $compatibility + * @return Structures\Player + * @throws InvalidArgumentException + */ + function getMainServerPlayerInfo($compatibility = 1) + { + if(!is_int($compatibility)) + { + throw new InvalidArgumentException('compatibility = '.print_r($compatibility, true)); + } + + return Structures\Player::fromArray($this->execute(ucfirst(__FUNCTION__), array($compatibility))); + } + + /** + * Returns the current rankings for the race in progress. + * (in team mode, the scores for the two teams are returned. + * In other modes, it's the individual players' scores) This method take two parameters. + * The first parameter specifies the maximum number of infos to be returned, + * the second one the starting index in the ranking. + * The ranking returned is a list of Structures\Player. + * It also contains an array BestCheckpoints that contains the checkpoint times for the best race. + * @param int $length specifies the maximum number of infos to be returned + * @param int $offset specifies the starting index in the list + * @return Structures\Player[] The list is an array of Structures\Player. + * @throws InvalidArgumentException + */ + function getCurrentRanking($length, $offset) + { + if(!is_int($length)) + { + throw new InvalidArgumentException('length = '.print_r($length, true)); + } + if(!is_int($offset)) + { + throw new InvalidArgumentException('offset = '.print_r($offset, true)); + } + + return Structures\Player::fromArrayOfArray($this->execute(ucfirst(__FUNCTION__), array($length, $offset))); + } + + /** + * Returns the current ranking for the race in progressof the player with the specified login (or list of comma-separated logins). + * The ranking returned is a list of structures that contains the following fields : + * Login, NickName, PlayerId, Rank, BestTime, Score, NbrLapsFinished and LadderScore. + * It also contains an array BestCheckpoints that contains the checkpoint times for the best race. + * @param Structures\Player|Structures\Player[] $player + * @throws InvalidArgumentException + * @return Structures\Player[] The list is an array of Structures\Player. + */ + function getCurrentRankingForLogin($player = null) + { + $login = $this->getLogin($player) ? : ''; + + return Structures\Player::fromArrayOfArray($this->execute(ucfirst(__FUNCTION__), array($login))); + } + + /** + * Returns the current winning team for the race in progress. (-1: if not in team mode, or draw match) + * @return int -1, 0 or 1 + */ + function getCurrentWinnerTeam() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Force the scores of the current game. Only available in rounds and team mode. + * You have to pass an array of structs {int PlayerId, int Score}. And a boolean SilentMode - + * if true, the scores are silently updated (only available for SuperAdmin), allowing an external controller to do its custom counting... + * @param array $scores + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function forceScores(array $scores, $silentMode = false, $multicall = false) + { + if(!is_array($scores)) + { + throw new InvalidArgumentException('scores = '.print_r($scores, true)); + } + + for($i = 0; $i < count($scores); $i++) + { + if(!is_int($scores[$i]['PlayerId'])) + { + throw new InvalidArgumentException('score['.$i.'][\'PlayerId\'] = '.print_r($scores[$i]['PlayerId'], true)); + } + if(!is_int($scores[$i]['Score'])) + { + throw new InvalidArgumentException('score['.$i.'][\'Score\'] = '.print_r($scores[$i]['Score'], true)); + } + } + + return $this->execute(ucfirst(__FUNCTION__), array($scores, $silentMode), $multicall); + } + + /** + * Force the team of the player. Only available in team mode. You have to pass the login and the team number (0 or 1). + * @param Structures\Player|string $player + * @param int $teamNumber + * @param bool $multicall + * @return bool + */ + function forcePlayerTeam($player, $teamNumber, $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + if($teamNumber !== 0 && $teamNumber !== 1) + { + throw new InvalidArgumentException('teamNumber = '.print_r($teamNumber, true)); + } + + return $this->execute('ForcePlayerTeam', array($login, $teamNumber), $multicall); + } + + /** + * Force the spectating status of the player. + * You have to pass the login and the spectator mode + * (0: user selectable, 1: spectator, 2: player, 3: spectator but keep selectable). + * Only available to Admin. + * @param Structures\Player|string $player + * @param int $spectatorMode + * @param bool $multicall + * @return bool + */ + function forceSpectator($player, $spectatorMode, $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + if(array_search($spectatorMode, range(0, 3), true) === false) + { + throw new InvalidArgumentException('spectatorMode = '.print_r($spectatorMode, true)); + } + + return $this->execute('ForceSpectator', array($login, $spectatorMode), $multicall); + } + + /** + * Force spectators to look at a specific player. You have to pass the login of the spectator (or '' for all) and + * the login of the target (or '' for automatic), and an integer for the camera type to use (-1 = leave unchanged, 0 = replay, 1 = follow, 2 = free). + * @param Structures\Player|string $player + * @param Structures\Player|string $target + * @param int $cameraType + * @param bool $multicall + * @return bool + */ + function forceSpectatorTarget($player, $target, $cameraType, $multicall = false) + { + if(!($playerLogin = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + if(!($targetLogin = $this->getLogin($target))) + { + throw new InvalidArgumentException('target must be set'); + } + if($cameraType !== -1 && $cameraType !== 0 && $cameraType !== 1 && $cameraType !== 2) + { + throw new InvalidArgumentException('cameraType = '.print_r($cameraType, true)); + } + + return $this->execute('ForceSpectatorTarget', array($playerLogin, $targetLogin, $cameraType), $multicall); + } + + /** + * Pass the login of the spectator. A spectator that once was a player keeps his player slot, so that he can go back to race mode. + * Calling this function frees this slot for another player to connect. + * @param Structures\Player|string $player + * @param bool $multicall + * @return bool + */ + function spectatorReleasePlayerSlot($player, $multicall = false) + { + if(!($login = $this->getLogin($player))) + { + throw new InvalidArgumentException('player must be set'); + } + return $this->execute('SpectatorReleasePlayerSlot', array($login), $multicall); + } + + /** + * Enable control of the game flow: the game will wait for the caller to validate state transitions. + * @param bool $flowControlEnable + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function manualFlowControlEnable($flowControlEnable, $multicall = false) + { + if(!is_bool($flowControlEnable)) + { + throw new InvalidArgumentException('flowControlEnable = '.print_r($flowControlEnable, true)); + } + + return $this->execute(ucfirst(__FUNCTION__), array($flowControlEnable), $multicall); + } + + /** + * Allows the game to proceed. + * @param bool $multicall + * @return bool + */ + function manualFlowControlProceed($multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array(), $multicall); + } + + /** + * Returns whether the manual control of the game flow is enabled. 0 = no, 1 = yes by the xml-rpc client making the call, 2 = yes, by some other xml-rpc client. + * @return int + */ + function manualFlowControlIsEnabled() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Returns the transition that is currently blocked, or '' if none. (That's exactly the value last received by the callback.) + * @return string + */ + function manualFlowControlGetCurTransition() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Returns the current match ending condition. + * Return values are: 'Playing', 'ChangeMap' or 'Finished'. + * @param bool $multicall + * @return string + */ + function checkEndMatchCondition() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Returns an object Structures\NetworkStats. + * The structure contains the following fields : Uptime, NbrConnection, MeanConnectionTime, MeanNbrPlayer, + * RecvNetRate, SendNetRate, TotalReceivingSize, TotalSendingSize and an array of structures named PlayerNetInfos. + * Each structure of the array PlayerNetInfos is a Structures\Player object contains the following fields : Login, IPAddress, LastTransferTime, DeltaBetweenTwoLastNetState, PacketLossRate. + * @return Structures\NetworkStats + */ + function getNetworkStats() + { + return Structures\NetworkStats::fromArray($this->execute(ucfirst(__FUNCTION__))); + } + + /** + * Start a server on lan, using the current configuration. + * @param bool $multicall + * @return bool + */ + function startServerLan($multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array(), $multicall); + } + + /** + * Start a server on internet using the 'Login' and 'Password' specified in the struct passed as parameters. + * @param array $ids + * @param bool $multicall + * @return bool + * @throws InvalidArgumentException + */ + function startServerInternet($multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array(), $multicall); + } + + /** + * Returns the current status of the server. + * @return Structures\Status + */ + function getStatus() + { + return Structures\Status::fromArray($this->execute(ucfirst(__FUNCTION__))); + } + + /** + * Quit the application. + * @param bool $multicall + * @return bool + */ + function quitGame($multicall = false) + { + return $this->execute(ucfirst(__FUNCTION__), array(), $multicall); + } + + /** + * Returns the path of the game datas directory. + * @return string + */ + function gameDataDirectory() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Returns the path of the maps directory. + * @return string + */ + function getMapsDirectory() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Returns the path of the skins directory. + * @return string + */ + function getSkinsDirectory() + { + return $this->execute(ucfirst(__FUNCTION__)); + } + + /** + * Returns the login of the given player + * @param mixed $player Structures\Player or string + * @return string + */ + private function getLogin($player) + { + if(is_string($player)) return $player; + if($player instanceof Structures\Player) return $player->login; + return null; + } + + /** + * Returns logins of given players + * @param mixed $player Structures\Player or string or array + * @return string + */ + private function getLogins($players) + { + if(is_array($players)) + { + $logins = array(); + foreach($players as $player) + { + if(($login = $this->getLogin($player))) $logins[] = $login; + else return null; + } + + return implode(',', $logins); + } + return $this->getLogin($players); + } + +} + +/** + * Exception Dedicated to Query Error + */ +class QueryException extends \Exception +{ + +} + +/** + * Exception Dedicated to Connection Error + */ +class ConnectionException extends \Exception +{ + +} + +/** + * Exception Dedicated to Invalid Argument Error on Request Call + */ +class InvalidArgumentException extends \Exception +{ + +} + +?> diff --git a/application/core/Maniaplanet/DedicatedServer/Structures/AbstractStructure.php b/application/core/Maniaplanet/DedicatedServer/Structures/AbstractStructure.php new file mode 100644 index 00000000..c474538c --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Structures/AbstractStructure.php @@ -0,0 +1,56 @@ + $value) + $object->{lcfirst($key)} = $value; + return $object; + } + + static public function fromArrayOfArray($array) + { + if(!is_array($array)) + return $array; + + $result = array(); + foreach($array as $key => $value) + $result[$key] = static::fromArray($value); + return $result; + } + + static public function getPropertyFromArray($array, $property) + { + return array_map(get_called_class().'::extractProperty', $array, array_fill(0, count($array), $property)); + } + + static protected function extractProperty($element, $property) + { + if(!is_a($element, get_called_class()) || !property_exists($element, $property)) + throw new \InvalidArgumentException('property '.$property.' does not exists in class: '.get_called_class()); + + return $element->$property; + } + + function toArray() + { + $out = array(); + foreach(get_object_vars($this) as $key => $value) + $out[ucfirst($key)] = $value; + return $out; + } +} + +?> \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Structures/Bill.php b/application/core/Maniaplanet/DedicatedServer/Structures/Bill.php new file mode 100644 index 00000000..d8ed30f9 --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Structures/Bill.php @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Structures/GameInfos.php b/application/core/Maniaplanet/DedicatedServer/Structures/GameInfos.php new file mode 100644 index 00000000..489790ee --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Structures/GameInfos.php @@ -0,0 +1,47 @@ + diff --git a/application/core/Maniaplanet/DedicatedServer/Structures/LobbyInfo.php b/application/core/Maniaplanet/DedicatedServer/Structures/LobbyInfo.php new file mode 100644 index 00000000..82e2259d --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Structures/LobbyInfo.php @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Structures/Map.php b/application/core/Maniaplanet/DedicatedServer/Structures/Map.php new file mode 100644 index 00000000..49019738 --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Structures/Map.php @@ -0,0 +1,27 @@ +$this->env,'Url'=>$this->url); + } +} \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Structures/Music.php b/application/core/Maniaplanet/DedicatedServer/Structures/Music.php new file mode 100644 index 00000000..bc810e58 --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Structures/Music.php @@ -0,0 +1,14 @@ +playerNetInfos = Player::fromArrayOfArray($object->playerNetInfos); + return $object; + } +} \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Structures/Player.php b/application/core/Maniaplanet/DedicatedServer/Structures/Player.php new file mode 100644 index 00000000..594d9def --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Structures/Player.php @@ -0,0 +1,97 @@ +path); + } + + /** + * @return Player + */ + static public function fromArray($array) + { + $object = parent::fromArray($array); + + $object->skins = Skin::fromArrayOfArray($object->skins); + //Detail flags + $object->forceSpectator = $object->flags % 10; // 0, 1 or 2 + $object->isReferee = (bool) (intval($object->flags / 10) % 10); + $object->isPodiumReady = (bool) (intval($object->flags / 100) % 10); + $object->isUsingStereoscopy = (bool) (intval($object->flags / 1000) % 10); + $object->isManagedByAnOtherServer = (bool) (intval($object->flags / 10000) % 10); + $object->isServer = (bool) (intval($object->flags / 100000) % 10); + $object->hasPlayerSlot = (bool) (intval($object->flags / 1000000) % 10); + $object->isBroadcasting = (bool) (intval($object->flags / 10000000) % 10); + $object->hasJoinedGame = (bool) (intval($object->flags / 100000000) % 10); + //Details spectatorStatus + $object->spectator = (bool) ($object->spectatorStatus % 10); + $object->temporarySpectator = (bool) (intval($object->spectatorStatus / 10) % 10); + $object->pureSpectator = (bool) (intval($object->spectatorStatus / 100) % 10); + $object->autoTarget = (bool) (intval($object->spectatorStatus / 1000) % 10); + $object->currentTargetId = intval($object->spectatorStatus / 10000); + + return $object; + } +} +?> \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Structures/ScriptInfo.php b/application/core/Maniaplanet/DedicatedServer/Structures/ScriptInfo.php new file mode 100644 index 00000000..2d0125e6 --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Structures/ScriptInfo.php @@ -0,0 +1,32 @@ +paramDescs) + { + $object->paramDescs = ScriptSettings::fromArrayOfArray($object->paramDescs); + } + return $object; + } + +} + +?> \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Structures/ScriptSettings.php b/application/core/Maniaplanet/DedicatedServer/Structures/ScriptSettings.php new file mode 100644 index 00000000..a53818a9 --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Structures/ScriptSettings.php @@ -0,0 +1,20 @@ + diff --git a/application/core/Maniaplanet/DedicatedServer/Structures/ServerOptions.php b/application/core/Maniaplanet/DedicatedServer/Structures/ServerOptions.php new file mode 100644 index 00000000..301ce853 --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Structures/ServerOptions.php @@ -0,0 +1,42 @@ + \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Structures/Team.php b/application/core/Maniaplanet/DedicatedServer/Structures/Team.php new file mode 100644 index 00000000..988fddcb --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Structures/Team.php @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Structures/Version.php b/application/core/Maniaplanet/DedicatedServer/Structures/Version.php new file mode 100644 index 00000000..0b40e82e --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Structures/Version.php @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Structures/Vote.php b/application/core/Maniaplanet/DedicatedServer/Structures/Vote.php new file mode 100644 index 00000000..d06925b6 --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Structures/Vote.php @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Structures/VoteRatio.php b/application/core/Maniaplanet/DedicatedServer/Structures/VoteRatio.php new file mode 100644 index 00000000..5e575344 --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Structures/VoteRatio.php @@ -0,0 +1,31 @@ +command = $command; + $this->ratio = $ratio; + } +} +?> \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Base64.php b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Base64.php new file mode 100644 index 00000000..750ac1e7 --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Base64.php @@ -0,0 +1,25 @@ +data = $data; + } + + function getXml() + { + return ''.base64_encode($this->data).''; + } +} + +?> \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Client.php b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Client.php new file mode 100644 index 00000000..4abd28b5 --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Client.php @@ -0,0 +1,472 @@ + $f_v) + { + $repeater = intval(substr($f_v, 1)); + if ($repeater == 0) + { + $repeater = 1; + } + if ($f_v{1} == '*') + { + $repeater = count($ar) - $i; + } + if ($f_v{0} != 'd') + { + $i += $repeater; + continue; + } + $j = $i + $repeater; + for ($a = $i; $a < $j; ++$a) + { + $p = pack('d', $vals[$i]); + $p = strrev($p); + list($vals[$i]) = array_values(unpack('d1d', $p)); + ++$i; + } + } + $a = 0; + foreach ($ar as $ar_k => $ar_v) + { + $ar[$ar_k] = $vals[$a]; + ++$a; + } + return $ar; + } + } + } + } + + function __construct($hostname = 'localhost', $port = 5000, $timeout) + { + $this->socket = false; + $this->reqhandle = 0x80000000; + $this->init($hostname, $port, $timeout); + } + + function __destruct() + { + $this->terminate(); + } + + protected function init($hostname, $port, $timeout) + { + + $this->bigEndianTest(); + + // open connection + $this->socket = @fsockopen($hostname, $port, $errno, $errstr, $timeout); + if (!$this->socket) + { + throw new Exception("transport error - could not open socket (error: $errno, $errstr)", -32300); + } + // handshake + $array_result = unpack('Vsize', fread($this->socket, 4)); + $size = $array_result['size']; + if ($size > 64) + { + throw new Exception('transport error - wrong lowlevel protocol header', -32300); + } + $handshake = fread($this->socket, $size); + if ($handshake == 'GBXRemote 1') + { + $this->protocol = 1; + } + elseif ($handshake == 'GBXRemote 2') + { + $this->protocol = 2; + } + else + { + throw new Exception('transport error - wrong lowlevel protocol version', -32300); + } + } + + function terminate() + { + if ($this->socket) + { + fclose($this->socket); + $this->socket = false; + } + } + + protected function sendRequest(Request $request) + { + $xml = $request->getXml(); + + @stream_set_timeout($this->socket, 20); // timeout 20 s (to write the request) + // send request + $this->reqhandle++; + if ($this->protocol == 1) + { + $bytes = pack('Va*', strlen($xml), $xml); + } + else + { + $bytes = pack('VVa*', strlen($xml), $this->reqhandle, $xml); + } + + $bytes_to_write = strlen($bytes); + + // increase sent counter ... + self::$sent += $bytes_to_write; + + while ($bytes_to_write > 0) + { + $r = fwrite($this->socket, $bytes); + if ($r === false || $r == 0) + { + throw new Exception('Connection interupted'); + } + + $bytes_to_write -= $r; + if ($bytes_to_write == 0) + { + break; + } + + $bytes = substr($bytes, $r); + } + } + + protected function getResult() + { + $contents = ''; + $contents_length = 0; + do + { + $size = 0; + $recvhandle = 0; + @stream_set_timeout($this->socket, 5); // timeout 20 s (to read the reply header) + // Get result + if ($this->protocol == 1) + { + $contents = fread($this->socket, 4); + if (strlen($contents) == 0) + { + throw new Exception('transport error - connection interrupted!', -32700); + } + $array_result = unpack('Vsize', $contents); + $size = $array_result['size']; + $recvhandle = $this->reqhandle; + } + else + { + $contents = fread($this->socket, 8); + if (strlen($contents) == 0) + { + throw new Exception('transport error - connection interrupted!', -32700); + } + $array_result = unpack('Vsize/Vhandle', $contents); + $size = $array_result['size']; + $recvhandle = $array_result['handle']; + // -- amd64 support -- + $bits = sprintf('%b', $recvhandle); + if (strlen($bits) == 64) + { + $recvhandle = bindec(substr($bits, 32)); + } + } + + if ($recvhandle == 0 || $size == 0) + { + throw new Exception('transport error - connection interrupted!', -32700); + } + + if ($size > SIZE_MAX) + { + throw new Exception("transport error - answer too big ($size)", -32700); + } + + self::$received += $size; + + $contents = ''; + $contents_length = 0; + @stream_set_timeout($this->socket, 0, 10000); // timeout 10 ms (for successive reads until end) + while ($contents_length < $size) + { + $contents .= fread($this->socket, $size-$contents_length); + $contents_length = strlen($contents); + } + + if (($recvhandle & 0x80000000) == 0) + { + // this is a callback, not our answer! handle= $recvhandle, xml-rpc= $contents + // just add it to the message list for the user to read + $new_cb_message = new Message($contents); + if ($new_cb_message->parse() && $new_cb_message->messageType != 'fault') + { + array_push($this->cb_message, array($new_cb_message->methodName, $new_cb_message->params)); + } + } + } + while ((int)$recvhandle != (int)$this->reqhandle); + + $this->message = new Message($contents); + if (!$this->message->parse()) + { + // XML error + throw new Exception('parse error. not well formed', -32700); + } + // Is the message a fault? + if ($this->message->messageType == 'fault') + { + throw new Exception($this->message->faultString, $this->message->faultCode); + } + + return $this->message; + } + + + function query() + { + $args = func_get_args(); + $method = array_shift($args); + + if (!$this->socket || $this->protocol == 0) + { + throw new Exception('transport error - Client not initialized', -32300); + } + + $request = new Request($method, $args); + + // Check if request is larger than 512 Kbytes + if ($request->getLength() > 512*1024-8) + { + throw new Exception('transport error - request too large!', -32700); + } + + $this->sendRequest($request); + return $this->getResult(); + } + + // Non-blocking query method: doesn't read the response + function queryIgnoreResult() + { + $args = func_get_args(); + $method = array_shift($args); + + if (!$this->socket || $this->protocol == 0) + { + throw new Exception('transport error - Client not initialized', -32300); + } + + $request = new Request($method, $args); + + // Check if the request is greater than 512 Kbytes to avoid errors + // If the method is system.multicall, make two calls (possibly recursively) + if ($request->getLength() > 512*1024-8) + { + if ($method == 'system.multicall' && isset($args[0])) + { + $count = count($args[0]); + // If count is 1, query cannot be reduced + if ($count < 2) + { + throw new Exception('transport error - request too large!', -32700); + } + $length = floor($count/2); + + $args1 = array_slice($args[0], 0, $length); + $args2 = array_slice($args[0], $length, ($count-$length)); + + $res1 = $this->queryIgnoreResult('system.multicall', $args1); + $res2 = $this->queryIgnoreResult('system.multicall', $args2); + return ($res1 && $res2); + } + // If the method is not a multicall, just stop + else + { + throw new Exception('transport error - request too large!', -32700); + } + } + + $this->sendRequest($request); + } + + function getResponse() + { + // methodResponses can only have one param - return that + return $this->message->params[0]; + } + + function readCallbacks($timeout = 2000) + { + if (!$this->socket || $this->protocol == 0) + throw new Exception('transport error - Client not initialized', -32300); + if ($this->protocol == 1) + return false; + + // flo: moved to end + //$something_received = count($this->cb_message)>0; + $contents = ''; + $contents_length = 0; + + @stream_set_timeout($this->socket, 0, 10000); // timeout 10 ms (to read available data) + // (assignment in arguments is forbidden since php 5.1.1) + $read = array($this->socket); + $write = NULL; + $except = NULL; + $nb = false; + + try + { + $nb = @stream_select($read, $write, $except, 0, $timeout); + } + catch (\Exception $e) + { + if (strpos($e->getMessage(), 'Invalid CRT') !== false) + { + $nb = true; + } + elseif (strpos($e->getMessage(), 'Interrupted system call') !== false) + { + return; + } + else + { + throw $e; + } + } + + // workaround for stream_select bug with amd64 + if ($nb !== false) + { + $nb = count($read); + } + + while ($nb !== false && $nb > 0) + { + $timeout = 0; // we don't want to wait for the full time again, just flush the available data + + $size = 0; + $recvhandle = 0; + // Get result + $contents = fread($this->socket, 8); + if (strlen($contents) == 0) + { + throw new Exception('transport error - connection interrupted!', -32700); + } + $array_result = unpack('Vsize/Vhandle', $contents); + $size = $array_result['size']; + $recvhandle = $array_result['handle']; + + if ($recvhandle == 0 || $size == 0) + { + throw new Exception('transport error - connection interrupted!', -32700); + } + if ($size > SIZE_MAX) + { + throw new Exception("transport error - answer too big ($size)", -32700); + } + + self::$received += $size; + + $contents = ''; + $contents_length = 0; + while ($contents_length < $size) + { + $contents .= fread($this->socket, $size-$contents_length); + $contents_length = strlen($contents); + } + + if (($recvhandle & 0x80000000) == 0) + { + // this is a callback. handle= $recvhandle, xml-rpc= $contents + //echo 'CALLBACK('.$contents_length.')[ '.$contents.' ]' . LF; + $new_cb_message = new Message($contents); + if ($new_cb_message->parse() && $new_cb_message->messageType != 'fault') + { + array_push($this->cb_message, array($new_cb_message->methodName, $new_cb_message->params)); + } + // flo: moved to end ... + // $something_received = true; + } + + // (assignment in arguments is forbidden since php 5.1.1) + $read = array($this->socket); + $write = NULL; + $except = NULL; + + try + { + $nb = @stream_select($read, $write, $except, 0, $timeout); + } + catch (\Exception $e) + { + if (strpos($e->getMessage(), 'Invalid CRT') !== false) + { + $nb = true; + } + else + { + throw $e; + } + } + + // workaround for stream_select bug with amd64 + if ($nb !== false) + { + $nb = count($read); + } + } + return !empty($this->cb_message); + } + + function getCallbackResponses() + { + // (look at the end of basic.php for an example) + $messages = $this->cb_message; + $this->cb_message = array(); + return $messages; + } +} + +?> \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Xmlrpc/ClientMulticall.php b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/ClientMulticall.php new file mode 100644 index 00000000..c18b1ccb --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/ClientMulticall.php @@ -0,0 +1,47 @@ + $methodName, 'params' => $args); + $this->calls[] = $struct; + + return (count($this->calls) - 1); + } + + function multiquery() + { + $result = array(); + if(count($this->calls)) + { + $result = parent::query('system.multicall', $this->calls); + $this->calls = array(); // reset for next calls + } + return $result; + } + + function multiqueryIgnoreResult() + { + if(count($this->calls)) + { + parent::queryIgnoreResult('system.multicall', $this->calls); + $this->calls = array(); // reset for next calls + } + } +} + +?> \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Date.php b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Date.php new file mode 100644 index 00000000..46e1d7ea --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Date.php @@ -0,0 +1,68 @@ +parseTimestamp($time); + } + else + { + $this->parseIso($time); + } + } + + function parseTimestamp($timestamp) + { + $this->year = date('Y', $timestamp); + $this->month = date('m', $timestamp); + $this->day = date('d', $timestamp); + $this->hour = date('H', $timestamp); + $this->minute = date('i', $timestamp); + $this->second = date('s', $timestamp); + } + + function parseIso($iso) + { + $this->year = substr($iso, 0, 4); + $this->month = substr($iso, 4, 2); + $this->day = substr($iso, 6, 2); + $this->hour = substr($iso, 9, 2); + $this->minute = substr($iso, 12, 2); + $this->second = substr($iso, 15, 2); + } + + function getIso() + { + return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second; + } + + function getXml() + { + return ''.$this->getIso().''; + } + + function getTimestamp() + { + return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year); + } +} + +?> \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Exception.php b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Exception.php new file mode 100644 index 00000000..1d00fdf5 --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Exception.php @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Message.php b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Message.php new file mode 100644 index 00000000..22dedb22 --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Message.php @@ -0,0 +1,189 @@ +message = $message; + } + + function parse() + { + + // first remove the XML declaration + $this->message = preg_replace('/<\?xml(.*)?\?'.'>/', '', $this->message); + if (trim($this->message) == '') + { + return false; + } + $this->parser = xml_parser_create(); + // Set XML parser to take the case of tags into account + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false); + // Set XML parser callback functions + xml_set_object($this->parser, $this); + xml_set_element_handler($this->parser, 'tag_open', 'tag_close'); + xml_set_character_data_handler($this->parser, 'cdata'); + if (!xml_parse($this->parser, $this->message)) + { + /* die(sprintf('GbxRemote XML error: %s at line %d', + xml_error_string(xml_get_error_code($this->_parser)), + xml_get_current_line_number($this->_parser))); */ + return false; + } + xml_parser_free($this->parser); + // Grab the error messages, if any + if ($this->messageType == 'fault') + { + $this->faultCode = $this->params[0]['faultCode']; + $this->faultString = $this->params[0]['faultString']; + } + return true; + } + + function tag_open($parser, $tag, $attr) + { + $this->currentTag = $tag; + switch ($tag) + { + case 'methodCall': + case 'methodResponse': + case 'fault': + $this->messageType = $tag; + break; + // Deal with stacks of arrays and structs + case 'data': // data is to all intents and purposes more interesting than array + $this->arrayStructsTypes[] = 'array'; + $this->arrayStructs[] = array(); + break; + case 'struct': + $this->arrayStructsTypes[] = 'struct'; + $this->arrayStructs[] = array(); + break; + } + } + + function cdata($parser, $cdata) + { + $this->currentTagContents .= $cdata; + } + + function tag_close($parser, $tag) + { + $valueFlag = false; + switch ($tag) + { + case 'int': + case 'i4': + $value = (int)trim($this->currentTagContents); + $this->currentTagContents = ''; + $valueFlag = true; + break; + case 'double': + $value = (double)trim($this->currentTagContents); + $this->currentTagContents = ''; + $valueFlag = true; + break; + case 'string': + $value = (string)trim($this->currentTagContents); + $this->currentTagContents = ''; + $valueFlag = true; + break; + case 'dateTime.iso8601': + $value = new Date(trim($this->currentTagContents)); + // $value = $iso->getTimestamp(); + $this->currentTagContents = ''; + $valueFlag = true; + break; + case 'value': + // If no type is indicated, the type is string + if (trim($this->currentTagContents) != '') { + $value = (string)$this->currentTagContents; + $this->currentTagContents = ''; + $valueFlag = true; + } + break; + case 'boolean': + $value = (boolean)trim($this->currentTagContents); + $this->currentTagContents = ''; + $valueFlag = true; + break; + case 'base64': + $value = base64_decode($this->currentTagContents); + $this->currentTagContents = ''; + $valueFlag = true; + break; + // Deal with stacks of arrays and structs + case 'data': + case 'struct': + $value = array_pop($this->arrayStructs); + array_pop($this->arrayStructsTypes); + $valueFlag = true; + break; + case 'member': + array_pop($this->currentStructName); + break; + case 'name': + $this->currentStructName[] = trim($this->currentTagContents); + $this->currentTagContents = ''; + break; + case 'methodName': + $this->methodName = trim($this->currentTagContents); + $this->currentTagContents = ''; + break; + } + + if ($valueFlag) + { + /* + if (!is_array($value) && !is_object($value)) { + $value = trim($value); + } + */ + if (count($this->arrayStructs) > 0) + { + // Add value to struct or array + if ($this->arrayStructsTypes[count($this->arrayStructsTypes)-1] == 'struct') + { + // Add to struct + $this->arrayStructs[count($this->arrayStructs)-1][$this->currentStructName[count($this->currentStructName)-1]] = $value; + } + else + { + // Add to array + $this->arrayStructs[count($this->arrayStructs)-1][] = $value; + } + } + else + { + // Just add as a paramater + $this->params[] = $value; + } + } + } +} + +?> \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Request.php b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Request.php new file mode 100644 index 00000000..eb9d179c --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Request.php @@ -0,0 +1,42 @@ +method = $method; + $this->args = $args; + $this->xml = '' . $this->method . ''; + foreach ($this->args as $arg) + { + $this->xml .= ''; + $v = new Value($arg); + $this->xml .= $v->getXml(); + $this->xml .= '' . LF; + } + $this->xml .= ''; + } + + function getLength() + { + return strlen($this->xml); + } + + function getXml() + { + return $this->xml; + } +} + +?> \ No newline at end of file diff --git a/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Value.php b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Value.php new file mode 100644 index 00000000..e9441f07 --- /dev/null +++ b/application/core/Maniaplanet/DedicatedServer/Xmlrpc/Value.php @@ -0,0 +1,144 @@ +data = $data; + if (!$type) + { + $type = $this->calculateType(); + } + $this->type = $type; + if ($type == 'struct') + { + // Turn all the values in the array into new Value objects + foreach ($this->data as $key => $value) + { + $this->data[$key] = new Value($value); + } + } + if ($type == 'array') + { + for ($i = 0, $j = count($this->data); $i < $j; $i++) + { + $this->data[$i] = new Value($this->data[$i]); + } + } + } + + function calculateType() + { + if ($this->data === true || $this->data === false) + { + return 'boolean'; + } + if (is_integer($this->data)) + { + return 'int'; + } + if (is_double($this->data)) + { + return 'double'; + } + // Deal with IXR object types base64 and date + if (is_object($this->data) && $this->data instanceof Date) + { + return 'date'; + } + if (is_object($this->data) && $this->data instanceof Base64) + { + return 'base64'; + } + // If it is a normal PHP object convert it into a struct + if (is_object($this->data)) + { + $this->data = get_object_vars($this->data); + return 'struct'; + } + if (!is_array($this->data)) + { + return 'string'; + } + // We have an array - is it an array or a struct? + if ($this->isStruct($this->data)) + { + return 'struct'; + } + else + { + return 'array'; + } + } + + function getXml() + { + // Return XML for this value + switch ($this->type) + { + case 'boolean': + return '' . ($this->data ? '1' : '0') . ''; + break; + case 'int': + return '' . $this->data . ''; + break; + case 'double': + return '' . $this->data . ''; + break; + case 'string': + return '' . htmlspecialchars($this->data) . ''; + break; + case 'array': + $return = '' . LF; + foreach ($this->data as $item) + { + $return .= ' ' . $item->getXml() . '' . LF; + } + $return .= ''; + return $return; + break; + case 'struct': + $return = '' . LF; + foreach ($this->data as $name => $value) + { + $return .= ' ' . $name . ''; + $return .= $value->getXml() . '' . LF; + } + $return .= ''; + return $return; + break; + case 'date': + case 'base64': + return $this->data->getXml(); + break; + } + return false; + } + + function isStruct($array) + { + // Nasty function to check if an array is a struct or not + $expected = 0; + foreach ($array as $key => $value) + { + if ((string)$key != (string)$expected) + { + return true; + } + $expected++; + } + return false; + } +} + +?> \ No newline at end of file