Merge remote-tracking branch 'refs/remotes/ManiaControl/master'
This commit is contained in:
		
							
								
								
									
										2
									
								
								.idea/codeStyleSettings.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								.idea/codeStyleSettings.xml
									
									
									
										generated
									
									
									
								
							| @@ -54,6 +54,7 @@ | |||||||
|           <option name="ALIGN_GROUP_FIELD_DECLARATIONS" value="true" /> |           <option name="ALIGN_GROUP_FIELD_DECLARATIONS" value="true" /> | ||||||
|           <option name="SPACE_AFTER_TYPE_CAST" value="true" /> |           <option name="SPACE_AFTER_TYPE_CAST" value="true" /> | ||||||
|           <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> |           <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> | ||||||
|  |           <option name="ARRAY_INITIALIZER_WRAP" value="1" /> | ||||||
|           <option name="IF_BRACE_FORCE" value="3" /> |           <option name="IF_BRACE_FORCE" value="3" /> | ||||||
|           <option name="DOWHILE_BRACE_FORCE" value="3" /> |           <option name="DOWHILE_BRACE_FORCE" value="3" /> | ||||||
|           <option name="WHILE_BRACE_FORCE" value="3" /> |           <option name="WHILE_BRACE_FORCE" value="3" /> | ||||||
| @@ -73,4 +74,3 @@ | |||||||
|     <option name="USE_PER_PROJECT_SETTINGS" value="true" /> |     <option name="USE_PER_PROJECT_SETTINGS" value="true" /> | ||||||
|   </component> |   </component> | ||||||
| </project> | </project> | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								.idea/encodings.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								.idea/encodings.xml
									
									
									
										generated
									
									
									
								
							| @@ -4,4 +4,3 @@ | |||||||
|     <file url="PROJECT" charset="UTF-8" /> |     <file url="PROJECT" charset="UTF-8" /> | ||||||
|   </component> |   </component> | ||||||
| </project> | </project> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -34,11 +34,11 @@ http://www.maniacontrol.com | |||||||
| ## REQUIREMENTS: | ## REQUIREMENTS: | ||||||
| - MySQL Database | - MySQL Database | ||||||
| - PHP 5.4+ | - PHP 5.4+ | ||||||
| - Needed extensions: | - Needed extensions (on ManiaControl startup you will see if you have them activated): | ||||||
| 	- php_mysqli | 	- php_mysqli | ||||||
| 	- php_curl | 	- php_curl | ||||||
| 	- php_xmlrpc (TM only) | 	- php_xmlrpc (TM only, recomended for SM) | ||||||
|  | 	- php_zlib | ||||||
|  |  | ||||||
| ### How to report bugs or request features?: | ### How to report bugs or request features?: | ||||||
| - Write a mail to bugs(at)maniacontrol(dot)com | - Write a mail to bugs(at)maniacontrol(dot)com | ||||||
|   | |||||||
							
								
								
									
										60
									
								
								changelog.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								changelog.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | |||||||
|  | ###v0.163### | ||||||
|  | #Additions | ||||||
|  | - completely reworked the filereader (new version, way more flexible), old methods are still working but deprecated | ||||||
|  | - added pause command and vote command for other gamemodes than elite (especially Chase/Combo) | ||||||
|  | - added Scriptcallbacks SCORESREADY / SCORES | ||||||
|  | - added SSL support as well as http Redirections of the FileReader | ||||||
|  |  | ||||||
|  | # Bug fixes | ||||||
|  | - Banning of not connected Players now possible | ||||||
|  |  | ||||||
|  | ###v0.162### | ||||||
|  | #Additions | ||||||
|  | - added typhinting ladderStat in Player object | ||||||
|  | - added optional AsynchronousFileReader Parameter for loadFile and postFile to set additional Headers | ||||||
|  | - added ServerLogin header for Mania-Exchange downloads | ||||||
|  |  | ||||||
|  | ###v0.161### | ||||||
|  | #Additions | ||||||
|  | - added admin chatcommand //uptime which displays the time since when the server is running | ||||||
|  | - updated playerhitstructure with new properties | ||||||
|  |  | ||||||
|  | #Bug Fixes | ||||||
|  | - fixed some z positions to be in front of overlays (especially in Trackmania) | ||||||
|  | - fixed limit problem on maniaexchange list | ||||||
|  |  | ||||||
|  | ###v0.16### | ||||||
|  | #Additions | ||||||
|  | - added changelog | ||||||
|  | - added CommunicationManager which acts like a communication interface you can connect to and interact with ManiaControl (also thanks to TGYoshi for some help) | ||||||
|  | 	- You can call ManiaControl from a Website or from ManiaControl itself | ||||||
|  | - added "//removerights login" command | ||||||
|  | - added new EchoManager which handles Interactions between different Controllers | ||||||
|  | 	- It is possible to send an Echo command via the Method sendEcho, as message Parameter strings, objects or arrays can get used | ||||||
|  | 	- An EchoListener can be added, callable by closure or implicit use (like on callbacks) | ||||||
|  | 	- The Listener always returns either an Stringer or an Object back as Param (arrays get converted into objects) | ||||||
|  | 	- On sending an Echo Message from another controller you need to provide an string to the dedicated method or an json_encoded array or object | ||||||
|  | 	- 4 Echos are Implemented by ManiaControl (ManiaControl.Restart, ManiaControl.AuthenticationManager.GrandLevel, ManiaControl.AuthenticationManager.RevokeLevel, ManiaControl.PlayerManager.WarnPlayer) | ||||||
|  | - added Method getServerLoginByIndex to Server object | ||||||
|  | - added to PlayerManager's Method PlayerManager the Parameter "withoutBots" (default on true) | ||||||
|  | - added Method getSpectators() in PlayerManager | ||||||
|  | - added Method restartMap(), skipToMapByMxId(), skipToMapByUid() into MapActions | ||||||
|  | - added some missing PHP Docs | ||||||
|  | - added some depency libraries as they are used by the Socket Handler | ||||||
|  | - added additional Callback which gets triggered on ManiaControl Restart | ||||||
|  | - added class name to the BillData object | ||||||
|  | - updated some depency libraries | ||||||
|  |  | ||||||
|  | #Bug Fixes | ||||||
|  | - fixed TriggerDebugNotice Method | ||||||
|  | - Exception fix on kicking Players | ||||||
|  | - updated FaultException List | ||||||
|  |  | ||||||
|  | ###v0.157### | ||||||
|  | - labelline improvements | ||||||
|  | 	- new usage examples: | ||||||
|  | 			$positions = array($posX + 5, $posX + 18, $posX + 70); | ||||||
|  | 			$texts     = array($index, $admin->nickname, $admin->login); | ||||||
|  | 			$this->maniaControl->getManialinkManager()->labelLine($playerFrame, array($positions, $texts)); | ||||||
|  | - improvements on Billmanager, added receiver to the BillData | ||||||
|  | - increased timeout time (fixes crashes on speedball) | ||||||
| @@ -290,7 +290,7 @@ class ActionsMenu implements CallbackListener, ManialinkPageAnswerListener { | |||||||
| 				unset($this->playerMenuItems[$order]); | 				unset($this->playerMenuItems[$order]); | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			if (isset($this->playerMenuItems[$order])) { | 			if (isset($this->adminMenuItems[$order])) { | ||||||
| 				unset($this->adminMenuItems[$order]); | 				unset($this->adminMenuItems[$order]); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -133,9 +133,9 @@ class AdminLists implements ManialinkPageAnswerListener, CallbackListener { | |||||||
| 				$lineQuad->setZ(0.001); | 				$lineQuad->setZ(0.001); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			$array = array($index => $posX + 5, $admin->nickname => $posX + 18, $admin->login => $posX + 70); | 			$positions = array($posX + 5, $posX + 18, $posX + 70); | ||||||
| 			$this->maniaControl->getManialinkManager()->labelLine($playerFrame, $array); | 			$texts     = array($index, $admin->nickname, $admin->login); | ||||||
|  | 			$this->maniaControl->getManialinkManager()->labelLine($playerFrame, array($positions, $texts)); | ||||||
|  |  | ||||||
| 			// Level Quad | 			// Level Quad | ||||||
| 			$rightQuad = new Quad_BgRaceScore2(); | 			$rightQuad = new Quad_BgRaceScore2(); | ||||||
|   | |||||||
| @@ -32,6 +32,8 @@ class AuthCommands implements CommandListener { | |||||||
| 		$this->maniaControl->getCommandManager()->registerCommandListener('addsuperadmin', $this, 'command_AddSuperAdmin', true, 'Add Player to the AdminList as SuperAdmin.'); | 		$this->maniaControl->getCommandManager()->registerCommandListener('addsuperadmin', $this, 'command_AddSuperAdmin', true, 'Add Player to the AdminList as SuperAdmin.'); | ||||||
| 		$this->maniaControl->getCommandManager()->registerCommandListener('addadmin', $this, 'command_AddAdmin', true, 'Add Player to the AdminList as Admin.'); | 		$this->maniaControl->getCommandManager()->registerCommandListener('addadmin', $this, 'command_AddAdmin', true, 'Add Player to the AdminList as Admin.'); | ||||||
| 		$this->maniaControl->getCommandManager()->registerCommandListener('addmod', $this, 'command_AddModerator', true, 'Add Player to the AdminList as Moderator.'); | 		$this->maniaControl->getCommandManager()->registerCommandListener('addmod', $this, 'command_AddModerator', true, 'Add Player to the AdminList as Moderator.'); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommandManager()->registerCommandListener('removerights', $this, 'command_RemoveRights', true, 'Remove Player from the AdminList.'); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -159,4 +161,53 @@ class AuthCommands implements CommandListener { | |||||||
| 		$message = "Usage Example: '//addmod login'"; | 		$message = "Usage Example: '//addmod login'"; | ||||||
| 		return $this->maniaControl->getChat()->sendUsageInfo($message, $player); | 		return $this->maniaControl->getChat()->sendUsageInfo($message, $player); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Handle //removerights command | ||||||
|  | 	 * | ||||||
|  | 	 * @param array  $chatCallback | ||||||
|  | 	 * @param Player $player | ||||||
|  | 	 */ | ||||||
|  | 	public function command_RemoveRights(array $chatCallback, Player $player) { | ||||||
|  | 		if (!AuthenticationManager::checkRight($player, AuthenticationManager::AUTH_LEVEL_ADMIN)) { | ||||||
|  | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		$text         = $chatCallback[1][2]; | ||||||
|  | 		$commandParts = explode(' ', $text); | ||||||
|  | 		if (!array_key_exists(1, $commandParts)) { | ||||||
|  | 			$this->sendRemoveRightsUsageInfo($player); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		$target = $this->maniaControl->getPlayerManager()->getPlayer($commandParts[1]); | ||||||
|  | 		if (!$target) { | ||||||
|  | 			$this->maniaControl->getChat()->sendError("Player '{$commandParts[1]}' not found!", $player); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if ($target->authLevel == AuthenticationManager::AUTH_LEVEL_MASTERADMIN) { | ||||||
|  | 			$this->maniaControl->getChat()->sendError("You can't remove an MasterAdmin from the Adminlists", $player); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		$success = $this->maniaControl->getAuthenticationManager()->grantAuthLevel($target, AuthenticationManager::AUTH_LEVEL_PLAYER); | ||||||
|  | 		if (!$success) { | ||||||
|  | 			$this->maniaControl->getChat()->sendError('Error occurred.', $player); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		$message = $player->getEscapedNickname() . ' removed ' . $target->getEscapedNickname() . ' from the Adminlists!'; | ||||||
|  | 		$this->maniaControl->getChat()->sendSuccess($message); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Send usage example for //removerights command | ||||||
|  | 	 * | ||||||
|  | 	 * @param Player $player | ||||||
|  | 	 * @return bool | ||||||
|  | 	 */ | ||||||
|  | 	private function sendRemoveRightsUsageInfo(Player $player) { | ||||||
|  | 		$message = "Usage Example: '//addadmin login'"; | ||||||
|  | 		return $this->maniaControl->getChat()->sendUsageInfo($message, $player); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,6 +4,10 @@ namespace ManiaControl\Admin; | |||||||
|  |  | ||||||
| use ManiaControl\Callbacks\CallbackListener; | use ManiaControl\Callbacks\CallbackListener; | ||||||
| use ManiaControl\Callbacks\Callbacks; | use ManiaControl\Callbacks\Callbacks; | ||||||
|  | use ManiaControl\Callbacks\EchoListener; | ||||||
|  | use ManiaControl\Communication\CommunicationAnswer; | ||||||
|  | use ManiaControl\Communication\CommunicationListener; | ||||||
|  | use ManiaControl\Communication\CommunicationMethods; | ||||||
| use ManiaControl\Logger; | use ManiaControl\Logger; | ||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| use ManiaControl\Players\Player; | use ManiaControl\Players\Player; | ||||||
| @@ -17,7 +21,7 @@ use ManiaControl\Settings\Setting; | |||||||
|  * @copyright 2014-2015 ManiaControl Team |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  */ |  */ | ||||||
| class AuthenticationManager implements CallbackListener { | class AuthenticationManager implements CallbackListener, EchoListener, CommunicationListener { | ||||||
| 	/* | 	/* | ||||||
| 	 * Constants | 	 * Constants | ||||||
| 	 */ | 	 */ | ||||||
| @@ -33,6 +37,8 @@ class AuthenticationManager implements CallbackListener { | |||||||
| 	const AUTH_NAME_MASTERADMIN  = 'MasterAdmin'; | 	const AUTH_NAME_MASTERADMIN  = 'MasterAdmin'; | ||||||
| 	const CB_AUTH_LEVEL_CHANGED  = 'AuthenticationManager.AuthLevelChanged'; | 	const CB_AUTH_LEVEL_CHANGED  = 'AuthenticationManager.AuthLevelChanged'; | ||||||
|  |  | ||||||
|  | 	const ECHO_GRANT_LEVEL  = 'ManiaControl.AuthenticationManager.GrandLevel'; | ||||||
|  | 	const ECHO_REVOKE_LEVEL = 'ManiaControl.AuthenticationManager.RevokeLevel'; | ||||||
| 	/* | 	/* | ||||||
| 	 * Private properties | 	 * Private properties | ||||||
| 	 */ | 	 */ | ||||||
| @@ -52,6 +58,56 @@ class AuthenticationManager implements CallbackListener { | |||||||
|  |  | ||||||
| 		// Callbacks | 		// Callbacks | ||||||
| 		$this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::ONINIT, $this, 'handleOnInit'); | 		$this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::ONINIT, $this, 'handleOnInit'); | ||||||
|  |  | ||||||
|  | 		// Echo Grant Level Command (Usage: sendEcho json_encode("player" => "loginName", "level" => "AUTH_LEVEL_NUMBER") | ||||||
|  | 		$this->maniaControl->getEchoManager()->registerEchoListener(self::ECHO_GRANT_LEVEL, $this, function ($params) { | ||||||
|  | 			if (property_exists($params, 'level') && property_exists($params, 'player')) { | ||||||
|  | 				$player = $this->maniaControl->getPlayerManager()->getPlayer($params->player); | ||||||
|  | 				if ($player) { | ||||||
|  | 					$this->grantAuthLevel($player, $params->level); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		// Echo Revoke Level Command (Usage: sendEcho json_encode("player" => "loginName") | ||||||
|  | 		$this->maniaControl->getEchoManager()->registerEchoListener(self::ECHO_REVOKE_LEVEL, $this, function ($params) { | ||||||
|  | 			if (property_exists($params, 'player')) { | ||||||
|  | 				$player = $this->maniaControl->getPlayerManager()->getPlayer($params->player); | ||||||
|  | 				if ($player) { | ||||||
|  | 					$this->maniaControl->getAuthenticationManager()->grantAuthLevel($player, self::AUTH_LEVEL_PLAYER); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		//Communication Listenings | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::GRANT_AUTH_LEVEL, $this, function ($data) { | ||||||
|  | 			if (!is_object($data) || !property_exists($data, 'level') || !property_exists($data, 'login')) { | ||||||
|  | 				return new CommunicationAnswer("No valid level or player login provided!", true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$player = $this->maniaControl->getPlayerManager()->getPlayer($data->login); | ||||||
|  | 			if ($player) { | ||||||
|  | 				$success = $this->grantAuthLevel($player, $data->level); | ||||||
|  | 				return new CommunicationAnswer(array("success" => $success)); | ||||||
|  | 			} else { | ||||||
|  | 				return new CommunicationAnswer("Player not found!", true); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::REVOKE_AUTH_LEVEL, $this, function ($data) { | ||||||
|  | 			if (!is_object($data) || !property_exists($data, 'login')) { | ||||||
|  | 				return new CommunicationAnswer("No valid player login provided!", true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$player = $this->maniaControl->getPlayerManager()->getPlayer($data->login); | ||||||
|  | 			if ($player) { | ||||||
|  | 				$success = $this->maniaControl->getAuthenticationManager()->grantAuthLevel($player, self::AUTH_LEVEL_PLAYER); | ||||||
|  | 				return new CommunicationAnswer(array("success" => $success)); | ||||||
|  | 			} else { | ||||||
|  | 				return new CommunicationAnswer("Player not found!", true); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
|   | |||||||
| @@ -21,22 +21,28 @@ class BillData { | |||||||
| 	public $receiverLogin = null; | 	public $receiverLogin = null; | ||||||
| 	public $amount        = 0; | 	public $amount        = 0; | ||||||
| 	public $creationTime  = -1; | 	public $creationTime  = -1; | ||||||
|  | 	public $message       = ""; | ||||||
|  | 	public $class         = ""; | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Construct new Bill Data Model | 	 * Construct new Bill Data Model | ||||||
| 	 * | 	 * | ||||||
|  | 	 * @param string        $class | ||||||
| 	 * @param callable      $function | 	 * @param callable      $function | ||||||
| 	 * @param Player|string $player | 	 * @param Player|string $player | ||||||
| 	 * @param int           $amount | 	 * @param int           $amount | ||||||
| 	 * @param bool          $pay | 	 * @param bool          $pay | ||||||
| 	 * @param string        $receiverLogin | 	 * @param string        $receiverLogin | ||||||
|  | 	 * @param string        $message | ||||||
| 	 */ | 	 */ | ||||||
| 	public function __construct(callable $function, $player, $amount, $pay = false, $receiverLogin = null) { | 	public function __construct($class, callable $function, $player, $amount, $pay = false, $receiverLogin = null, $message = '') { | ||||||
|  | 		$this->class         = $class; | ||||||
| 		$this->function      = $function; | 		$this->function      = $function; | ||||||
| 		$this->player        = $player; | 		$this->player        = $player; | ||||||
| 		$this->amount        = $amount; | 		$this->amount        = $amount; | ||||||
| 		$this->pay           = $pay; | 		$this->pay           = $pay; | ||||||
| 		$this->receiverLogin = $receiverLogin; | 		$this->receiverLogin = $receiverLogin; | ||||||
|  | 		$this->message       = $message; | ||||||
| 		$this->creationTime  = time(); | 		$this->creationTime  = time(); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ use ManiaControl\Callbacks\CallbackListener; | |||||||
| use ManiaControl\Callbacks\CallbackManager; | use ManiaControl\Callbacks\CallbackManager; | ||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| use ManiaControl\Players\Player; | use ManiaControl\Players\Player; | ||||||
|  | use Maniaplanet\DedicatedServer\InvalidArgumentException; | ||||||
| use Maniaplanet\DedicatedServer\Structures\Bill; | use Maniaplanet\DedicatedServer\Structures\Bill; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -57,11 +58,21 @@ class BillManager implements CallbackListener { | |||||||
| 	 * @return bool | 	 * @return bool | ||||||
| 	 */ | 	 */ | ||||||
| 	public function sendBill(callable $function, Player $player, $amount, $message, $receiver = '') { | 	public function sendBill(callable $function, Player $player, $amount, $message, $receiver = '') { | ||||||
| 		$billId                   = $this->maniaControl->getClient()->sendBill($player->login, $amount, $message, $receiver); | 		//Get the Caller Class | ||||||
| 		$this->openBills[$billId] = new BillData($function, $player, $amount); | 		$backTrace = debug_backtrace(); | ||||||
|  | 		$class     = $backTrace[1]['class']; | ||||||
|  |  | ||||||
|  | 		try { | ||||||
|  | 			$billId = $this->maniaControl->getClient()->sendBill($player->login, intval($amount), $message, $receiver); | ||||||
|  | 		} catch (InvalidArgumentException $e) { | ||||||
|  | 			//TODO better error handling, maybe call the user func with ERROR_WHILE_TRANSACTION | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		$this->openBills[$billId] = new BillData($class, $function, $player, $amount, false, $receiver, $message); | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Send planets from the server to a player | 	 * Send planets from the server to a player | ||||||
| 	 * | 	 * | ||||||
| @@ -72,8 +83,17 @@ class BillManager implements CallbackListener { | |||||||
| 	 * @return bool | 	 * @return bool | ||||||
| 	 */ | 	 */ | ||||||
| 	public function sendPlanets(callable $function, $receiverLogin, $amount, $message) { | 	public function sendPlanets(callable $function, $receiverLogin, $amount, $message) { | ||||||
| 		$billId                   = $this->maniaControl->getClient()->pay($receiverLogin, $amount, $message); | 		//Get the Caller Class | ||||||
| 		$this->openBills[$billId] = new BillData($function, $receiverLogin, $amount, true); | 		$backTrace = debug_backtrace(); | ||||||
|  | 		$class     = $backTrace[1]['class']; | ||||||
|  |  | ||||||
|  | 		try { | ||||||
|  | 			$billId = $this->maniaControl->getClient()->pay($receiverLogin, intval($amount), $message); | ||||||
|  | 		} catch (InvalidArgumentException $e) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		$this->openBills[$billId] = new BillData($class, $function, $receiverLogin, $amount, true, $receiverLogin, $message); | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -153,8 +153,6 @@ class CallbackManager { | |||||||
| 		return $this->removeCallbackListener($this->callbackListenings, $listener); | 		return $this->removeCallbackListener($this->callbackListenings, $listener); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	//TODO better name (used only in customvotesPlugin) |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Remove the Callback Listener from the given Listeners Array | 	 * Remove the Callback Listener from the given Listeners Array | ||||||
| 	 * | 	 * | ||||||
| @@ -212,6 +210,9 @@ class CallbackManager { | |||||||
| 		// Manage Timings | 		// Manage Timings | ||||||
| 		$this->maniaControl->getTimerManager()->manageTimings(); | 		$this->maniaControl->getTimerManager()->manageTimings(); | ||||||
|  |  | ||||||
|  | 		// Manage Socket Tickets | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->tick(); | ||||||
|  |  | ||||||
| 		// Server Callbacks | 		// Server Callbacks | ||||||
| 		if (!$this->maniaControl->getClient()) { | 		if (!$this->maniaControl->getClient()) { | ||||||
| 			return; | 			return; | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ interface Callbacks { | |||||||
| 	const ONINIT     = 'Callbacks.OnInit'; | 	const ONINIT     = 'Callbacks.OnInit'; | ||||||
| 	const AFTERINIT  = 'Callbacks.AfterInit'; | 	const AFTERINIT  = 'Callbacks.AfterInit'; | ||||||
| 	const ONSHUTDOWN = 'Callbacks.OnShutdown'; | 	const ONSHUTDOWN = 'Callbacks.OnShutdown'; | ||||||
|  | 	const ONRESTART  = 'Callbacks.OnRestart'; | ||||||
|  |  | ||||||
| 	/** Script Callback: CallbackName, CallbackData */ | 	/** Script Callback: CallbackName, CallbackData */ | ||||||
| 	const SCRIPTCALLBACK = 'Callbacks.ScriptCallback'; | 	const SCRIPTCALLBACK = 'Callbacks.ScriptCallback'; | ||||||
| @@ -49,6 +50,8 @@ interface Callbacks { | |||||||
| 	const ENDTURNSTOP = 'Callbacks.EndTurnStop'; | 	const ENDTURNSTOP = 'Callbacks.EndTurnStop'; | ||||||
| 	/** EndRound Callback: RoundNumber */ | 	/** EndRound Callback: RoundNumber */ | ||||||
| 	const ENDROUND = 'Callbacks.EndRound'; | 	const ENDROUND = 'Callbacks.EndRound'; | ||||||
|  | 	/** EndRound Callback: RoundNumber */ | ||||||
|  | 	const ENDROUNDSTOP = 'Callbacks.EndRoundStop'; | ||||||
| 	/** EndSubmatch Callback: SubmatchNumber */ | 	/** EndSubmatch Callback: SubmatchNumber */ | ||||||
| 	const ENDSUBMATCH = 'Callbacks.EndSubmatch'; | 	const ENDSUBMATCH = 'Callbacks.EndSubmatch'; | ||||||
| 	/** EndMap Callback: Map */ | 	/** EndMap Callback: Map */ | ||||||
| @@ -67,6 +70,12 @@ interface Callbacks { | |||||||
| 	/** EndWarmup Callback */ | 	/** EndWarmup Callback */ | ||||||
| 	const ENDWARMUP = 'Callbacks.EndWarmUp'; | 	const ENDWARMUP = 'Callbacks.EndWarmUp'; | ||||||
|  |  | ||||||
|  | 	/** Scores Callback (returned after LibXmlRpc_PlayerRanking): Scores */ | ||||||
|  | 	const SCORESREADY = 'Callbacks.ScoresReady'; | ||||||
|  |  | ||||||
|  | 	/** Scores Callback (returned after LibXmlRpc_PlayerRanking in SM, or LibXmlRpc_TeamsScores in Trackmania): Scores */ | ||||||
|  | 	const SCORES = 'Callbacks.Scores'; | ||||||
|  |  | ||||||
| 	/** PlayerRanking Callback, returned after LibXmlRpc_PlayerRanking | 	/** PlayerRanking Callback, returned after LibXmlRpc_PlayerRanking | ||||||
| 	 * try to avoid to use this, just use the Get function of the RankingsManager instead | 	 * try to avoid to use this, just use the Get function of the RankingsManager instead | ||||||
| 	 * param1 Player $player | 	 * param1 Player $player | ||||||
| @@ -80,8 +89,6 @@ interface Callbacks { | |||||||
| 	 */ | 	 */ | ||||||
| 	/** RankingsUpdated Callback: SortedRankings */ | 	/** RankingsUpdated Callback: SortedRankings */ | ||||||
| 	const RANKINGSUPDATED = 'Callbacks.RankingsUpdated'; | 	const RANKINGSUPDATED = 'Callbacks.RankingsUpdated'; | ||||||
| 	/** Scores Callback (returned after LibXmlRpc_PlayerRanking): Scores */ |  | ||||||
| 	const SCORES = 'Callbacks.Scores'; |  | ||||||
|  |  | ||||||
| 	/** Returns the AFKStatus of an Player, returned after  param1 Scores */ //returned after TODO | 	/** Returns the AFKStatus of an Player, returned after  param1 Scores */ //returned after TODO | ||||||
| 	const AFKSTATUS = 'Callbacks.AfkStatus'; | 	const AFKSTATUS = 'Callbacks.AfkStatus'; | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								core/Callbacks/EchoListener.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								core/Callbacks/EchoListener.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | <?php | ||||||
|  | namespace ManiaControl\Callbacks; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Interface for EchoListener | ||||||
|  |  * | ||||||
|  |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  |  */ | ||||||
|  | interface EchoListener { | ||||||
|  | } | ||||||
							
								
								
									
										150
									
								
								core/Callbacks/EchoManager.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								core/Callbacks/EchoManager.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,150 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace ManiaControl\Callbacks; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | use ManiaControl\ManiaControl; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Class for managing Echo Callbacks | ||||||
|  |  * | ||||||
|  |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  |  */ | ||||||
|  | class EchoManager implements CallbackListener, EchoListener { | ||||||
|  | 	/* | ||||||
|  | 	 * Private properties | ||||||
|  | 	 */ | ||||||
|  | 	/** @var ManiaControl $maniaControl */ | ||||||
|  | 	private $maniaControl = null; | ||||||
|  | 	/** @var Listening[] $echoListenings */ | ||||||
|  | 	private $echoListenings = array(); | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Create a new Echo Handler Instance | ||||||
|  | 	 * | ||||||
|  | 	 * @param ManiaControl $maniaControl | ||||||
|  | 	 */ | ||||||
|  | 	public function __construct(ManiaControl $maniaControl) { | ||||||
|  | 		$this->maniaControl = $maniaControl; | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCallbackManager()->registerCallbackListener(CallbackManager::CB_MP_ECHO, $this, 'handleEchos'); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Sends an Echo Message | ||||||
|  | 	 * | ||||||
|  | 	 * @param string $name | ||||||
|  | 	 * @param mixed  $data (can be array, object or string) | ||||||
|  | 	 * @return bool | ||||||
|  | 	 * @throws \Maniaplanet\DedicatedServer\InvalidArgumentException | ||||||
|  | 	 */ | ||||||
|  | 	public function sendEcho($name, $data) { | ||||||
|  | 		if (is_string($data)) { | ||||||
|  | 			$success = $this->maniaControl->getClient()->dedicatedEcho($data, $name); | ||||||
|  | 		} else { | ||||||
|  | 			$success = $this->maniaControl->getClient()->dedicatedEcho(json_encode($data), $name); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return $success; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Register a new Echo Listener | ||||||
|  | 	 * | ||||||
|  | 	 * @param string       $callbackName | ||||||
|  | 	 * @param EchoListener $listener | ||||||
|  | 	 * @param string       $method | ||||||
|  | 	 * @return bool | ||||||
|  | 	 */ | ||||||
|  | 	public function registerEchoListener($echoName, EchoListener $listener, $method) { | ||||||
|  | 		if (!Listening::checkValidCallback($listener, $method)) { | ||||||
|  | 			$listenerClass = get_class($listener); | ||||||
|  | 			trigger_error("Given Listener '{$listenerClass}' can't handle Callback '{$echoName}': No callable Method '{$method}'!"); | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (!array_key_exists($echoName, $this->echoListenings)) { | ||||||
|  | 			$this->echoListenings[$echoName] = array(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		$listening = new Listening($listener, $method); | ||||||
|  | 		array_push($this->echoListenings[$echoName], $listening); | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Unregister a Echo Listener | ||||||
|  | 	 * | ||||||
|  | 	 * @param EchoListener $listener | ||||||
|  | 	 * @return bool | ||||||
|  | 	 */ | ||||||
|  | 	public function unregisterEchoListener(EchoListener $listener) { | ||||||
|  | 		return $this->removeEchoListener($this->echoListenings, $listener); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Remove the Echo Listener from the given Listeners Array | ||||||
|  | 	 * | ||||||
|  | 	 * @param Listening[]  $listeningsArray | ||||||
|  | 	 * @param EchoListener $listener | ||||||
|  | 	 * @return bool | ||||||
|  | 	 */ | ||||||
|  | 	private function removeEchoListener(array &$listeningsArray, EchoListener $listener) { | ||||||
|  | 		$removed = false; | ||||||
|  | 		foreach ($listeningsArray as &$listenings) { | ||||||
|  | 			foreach ($listenings as $key => &$listening) { | ||||||
|  | 				if ($listening->listener === $listener) { | ||||||
|  | 					unset($listenings[$key]); | ||||||
|  | 					$removed = true; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return $removed; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Trigger a specific Callback | ||||||
|  | 	 * | ||||||
|  | 	 * @param mixed $callback | ||||||
|  | 	 */ | ||||||
|  | 	public function triggerEchoCallback($callbackName) { | ||||||
|  | 		if (!array_key_exists($callbackName, $this->echoListenings)) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		$params = func_get_args(); | ||||||
|  | 		$params = array_slice($params, 1, null, true); | ||||||
|  |  | ||||||
|  | 		//var_dump($params); | ||||||
|  | 		foreach ($this->echoListenings[$callbackName] as $listening) { | ||||||
|  | 			/** @var Listening $listening */ | ||||||
|  | 			$listening->triggerCallbackWithParams($params); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Handle the given Callback | ||||||
|  | 	 * | ||||||
|  | 	 * @param array $callback | ||||||
|  | 	 */ | ||||||
|  | 	public function handleEchos($param) { | ||||||
|  | 		$name = $param[1][0]; | ||||||
|  | 		if (is_object($decode = json_decode($param[1][1]))) { | ||||||
|  | 			$message = $decode; | ||||||
|  | 		} else { | ||||||
|  | 			$message = $param[1][1]; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		switch ($name) { | ||||||
|  | 			case 'ManiaControl.Restart': | ||||||
|  | 				$this->maniaControl->restart($message); | ||||||
|  | 				break; | ||||||
|  | 			default: | ||||||
|  | 				$this->triggerEchoCallback($name, $message); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -82,6 +82,9 @@ class LibXmlRpcCallbacks implements CallbackListener { | |||||||
| 			case 'LibXmlRpc_EndRound': | 			case 'LibXmlRpc_EndRound': | ||||||
| 				$this->maniaControl->getCallbackManager()->triggerCallback(Callbacks::ENDROUND, $data[0]); | 				$this->maniaControl->getCallbackManager()->triggerCallback(Callbacks::ENDROUND, $data[0]); | ||||||
| 				break; | 				break; | ||||||
|  | 			case 'LibXmlRpc_EndRoundStop': | ||||||
|  | 				$this->maniaControl->getCallbackManager()->triggerCallback(Callbacks::ENDROUNDSTOP, $data[0]); | ||||||
|  | 				break; | ||||||
| 			case 'LibXmlRpc_EndSubmatch': | 			case 'LibXmlRpc_EndSubmatch': | ||||||
| 				$this->maniaControl->getCallbackManager()->triggerCallback(Callbacks::ENDSUBMATCH, $data[0]); | 				$this->maniaControl->getCallbackManager()->triggerCallback(Callbacks::ENDSUBMATCH, $data[0]); | ||||||
| 				break; | 				break; | ||||||
| @@ -146,6 +149,12 @@ class LibXmlRpcCallbacks implements CallbackListener { | |||||||
| 				$player = $this->maniaControl->getPlayerManager()->getPlayer($data[0]); | 				$player = $this->maniaControl->getPlayerManager()->getPlayer($data[0]); | ||||||
| 				$this->maniaControl->getCallbackManager()->triggerCallback(Callbacks::ONPLAYERREQUESTRESPAWN, $player); | 				$this->maniaControl->getCallbackManager()->triggerCallback(Callbacks::ONPLAYERREQUESTRESPAWN, $player); | ||||||
| 				break; | 				break; | ||||||
|  | 			case 'LibXmlRpc_Scores': | ||||||
|  | 				$this->maniaControl->getCallbackManager()->triggerCallback(Callbacks::SCORES, $data); | ||||||
|  | 				break; | ||||||
|  | 			case 'LibXmlRpc_ScoresReady': | ||||||
|  | 				$this->maniaControl->getCallbackManager()->triggerCallback(Callbacks::SCORESREADY, $data); | ||||||
|  | 				break; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -57,9 +57,10 @@ class Listening { | |||||||
| 	 * Trigger the Listener's Method with the given Array of Params | 	 * Trigger the Listener's Method with the given Array of Params | ||||||
| 	 * | 	 * | ||||||
| 	 * @param array $params | 	 * @param array $params | ||||||
|  | 	 * @return mixed | ||||||
| 	 */ | 	 */ | ||||||
| 	public function triggerCallbackWithParams(array $params) { | 	public function triggerCallbackWithParams(array $params) { | ||||||
| 		call_user_func_array($this->getUserFunction(), $params); | 		return call_user_func_array($this->getUserFunction(), $params); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
|   | |||||||
| @@ -52,9 +52,6 @@ class ShootManiaCallbacks implements CallbackListener { | |||||||
| 			case 'LibXmlRpc_Rankings': | 			case 'LibXmlRpc_Rankings': | ||||||
| 				$this->maniaControl->getServer()->getRankingManager()->updateRankings($data[0]); | 				$this->maniaControl->getServer()->getRankingManager()->updateRankings($data[0]); | ||||||
| 				break; | 				break; | ||||||
| 			case 'LibXmlRpc_Scores': |  | ||||||
| 				$this->maniaControl->getCallbackManager()->triggerCallback(Callbacks::SCORES, $data); |  | ||||||
| 				break; |  | ||||||
| 			case 'LibAFK_IsAFK': | 			case 'LibAFK_IsAFK': | ||||||
| 				$this->triggerAfkStatus($data[0]); | 				$this->triggerAfkStatus($data[0]); | ||||||
| 				break; | 				break; | ||||||
|   | |||||||
| @@ -4,7 +4,13 @@ namespace ManiaControl\Callbacks\Structures; | |||||||
|  |  | ||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| use ManiaControl\Players\Player; | use ManiaControl\Players\Player; | ||||||
|  | /** | ||||||
|  |  * Structure Class for the ArmorEmpty Callback | ||||||
|  |  * | ||||||
|  |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  |  */ | ||||||
| class ArmorEmptyStructure { | class ArmorEmptyStructure { | ||||||
| 	/* | 	/* | ||||||
| 	 * Private properties | 	 * Private properties | ||||||
|   | |||||||
| @@ -5,6 +5,13 @@ namespace ManiaControl\Callbacks\Structures; | |||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| use ManiaControl\Players\Player; | use ManiaControl\Players\Player; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Structure Class for the Capture Callback | ||||||
|  |  * | ||||||
|  |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  |  */ | ||||||
| class CaptureStructure { | class CaptureStructure { | ||||||
| 	/* | 	/* | ||||||
| 	 * Private properties | 	 * Private properties | ||||||
|   | |||||||
| @@ -5,6 +5,13 @@ namespace ManiaControl\Callbacks\Structures; | |||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| use ManiaControl\Players\Player; | use ManiaControl\Players\Player; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Structure Class for the EliteBeginTurn Callback | ||||||
|  |  * | ||||||
|  |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  |  */ | ||||||
| class EliteBeginTurnStructure { | class EliteBeginTurnStructure { | ||||||
| 	/* | 	/* | ||||||
| 	 * Private properties | 	 * Private properties | ||||||
|   | |||||||
| @@ -5,6 +5,13 @@ namespace ManiaControl\Callbacks\Structures; | |||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| use ManiaControl\Players\Player; | use ManiaControl\Players\Player; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Structure Class for the NearMiss Callback | ||||||
|  |  * | ||||||
|  |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  |  */ | ||||||
| class NearMissStructure { | class NearMissStructure { | ||||||
| 	/* | 	/* | ||||||
| 	 * Private properties | 	 * Private properties | ||||||
|   | |||||||
| @@ -1,16 +1,17 @@ | |||||||
| <?php | <?php | ||||||
| /** |  | ||||||
|  * Player Hit Structure |  | ||||||
|  * |  | ||||||
|  * @author    ManiaControl Team <mail@maniacontrol.com> |  | ||||||
|  * @copyright 2014-2015 ManiaControl Team |  | ||||||
|  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 |  | ||||||
|  */ |  | ||||||
| namespace ManiaControl\Callbacks\Structures; | namespace ManiaControl\Callbacks\Structures; | ||||||
|  |  | ||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| use ManiaControl\Players\Player; | use ManiaControl\Players\Player; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Structure Class for the Player Hit Callback | ||||||
|  |  * | ||||||
|  |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  |  */ | ||||||
| class PlayerHitStructure { | class PlayerHitStructure { | ||||||
| 	/* | 	/* | ||||||
| 	 * Private properties | 	 * Private properties | ||||||
| @@ -20,7 +21,11 @@ class PlayerHitStructure { | |||||||
| 	private $damage; | 	private $damage; | ||||||
| 	private $shooterPoints; | 	private $shooterPoints; | ||||||
| 	private $weapon; | 	private $weapon; | ||||||
| 	private $hitDistance = 0; | 	private $hitDistance; | ||||||
|  | 	private $shooterPosition     = 0; | ||||||
|  | 	private $victimPosition      = 0; | ||||||
|  | 	private $shooterAimDirection = 0; | ||||||
|  | 	private $victimAimDirection  = 0; | ||||||
|  |  | ||||||
| 	/** @var ManiaControl $maniaControl */ | 	/** @var ManiaControl $maniaControl */ | ||||||
| 	private $maniaControl; | 	private $maniaControl; | ||||||
| @@ -38,10 +43,23 @@ class PlayerHitStructure { | |||||||
| 		$this->damage        = $data[2]; | 		$this->damage        = $data[2]; | ||||||
| 		$this->weapon        = $data[3]; | 		$this->weapon        = $data[3]; | ||||||
| 		$this->shooterPoints = $data[4]; | 		$this->shooterPoints = $data[4]; | ||||||
| 		 |  | ||||||
| 		//TODO remove key check in some months (hitDistance got implemented 2014-10-16) |  | ||||||
| 		if (array_key_exists(5, $data)) { |  | ||||||
| 		$this->hitDistance   = $data[5]; | 		$this->hitDistance   = $data[5]; | ||||||
|  |  | ||||||
|  | 		//TODO remove key check in some months (got implemented 2015-05-03) | ||||||
|  | 		if (array_key_exists(6, $data)) { | ||||||
|  | 			$this->shooterPosition = $data[6]; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (array_key_exists(7, $data)) { | ||||||
|  | 			$this->victimPosition = $data[7]; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (array_key_exists(8, $data)) { | ||||||
|  | 			$this->shooterAimDirection = $data[8]; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (array_key_exists(9, $data)) { | ||||||
|  | 			$this->victimAimDirection = $data[9]; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										107
									
								
								core/Chat.php
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								core/Chat.php
									
									
									
									
									
								
							| @@ -3,6 +3,11 @@ | |||||||
| namespace ManiaControl; | namespace ManiaControl; | ||||||
|  |  | ||||||
| use ManiaControl\Admin\AuthenticationManager; | use ManiaControl\Admin\AuthenticationManager; | ||||||
|  | use ManiaControl\Callbacks\CallbackListener; | ||||||
|  | use ManiaControl\Callbacks\CallbackManager; | ||||||
|  | use ManiaControl\Communication\CommunicationAnswer; | ||||||
|  | use ManiaControl\Communication\CommunicationListener; | ||||||
|  | use ManiaControl\Communication\CommunicationMethods; | ||||||
| use ManiaControl\Players\Player; | use ManiaControl\Players\Player; | ||||||
| use Maniaplanet\DedicatedServer\Xmlrpc\UnknownPlayerException; | use Maniaplanet\DedicatedServer\Xmlrpc\UnknownPlayerException; | ||||||
|  |  | ||||||
| @@ -13,7 +18,7 @@ use Maniaplanet\DedicatedServer\Xmlrpc\UnknownPlayerException; | |||||||
|  * @copyright 2014-2015 ManiaControl Team |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  */ |  */ | ||||||
| class Chat { | class Chat implements CallbackListener, CommunicationListener { | ||||||
| 	/* | 	/* | ||||||
| 	 * Constants | 	 * Constants | ||||||
| 	 */ | 	 */ | ||||||
| @@ -22,12 +27,13 @@ class Chat { | |||||||
| 	const SETTING_FORMAT_SUCCESS     = 'Success Format'; | 	const SETTING_FORMAT_SUCCESS     = 'Success Format'; | ||||||
| 	const SETTING_FORMAT_ERROR       = 'Error Format'; | 	const SETTING_FORMAT_ERROR       = 'Error Format'; | ||||||
| 	const SETTING_FORMAT_USAGEINFO   = 'UsageInfo Format'; | 	const SETTING_FORMAT_USAGEINFO   = 'UsageInfo Format'; | ||||||
|  | 	const CHAT_BUFFER_SIZE           = 200; | ||||||
| 	/* | 	/* | ||||||
| 	 * Private properties | 	 * Private properties | ||||||
| 	 */ | 	 */ | ||||||
| 	/** @var ManiaControl $maniaControl */ | 	/** @var ManiaControl $maniaControl */ | ||||||
| 	private $maniaControl = null; | 	private $maniaControl = null; | ||||||
|  | 	private $chatBuffer   = array(); | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Construct chat utility | 	 * Construct chat utility | ||||||
| @@ -43,6 +49,15 @@ class Chat { | |||||||
| 		$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_FORMAT_SUCCESS, '$0f0'); | 		$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_FORMAT_SUCCESS, '$0f0'); | ||||||
| 		$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_FORMAT_ERROR, '$f30'); | 		$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_FORMAT_ERROR, '$f30'); | ||||||
| 		$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_FORMAT_USAGEINFO, '$f80'); | 		$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_FORMAT_USAGEINFO, '$f80'); | ||||||
|  |  | ||||||
|  | 		//Callbacks | ||||||
|  | 		$this->maniaControl->getCallbackManager()->registerCallbackListener(CallbackManager::CB_MP_PLAYERCHAT, $this, 'onPlayerChat'); | ||||||
|  |  | ||||||
|  | 		//Socket Listenings | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::SEND_CHAT_MESSAGE, $this, "communcationSendChat"); | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::GET_SERVER_CHAT, $this, function ($data) { | ||||||
|  | 			return new CommunicationAnswer($this->chatBuffer); | ||||||
|  | 		}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -226,4 +241,92 @@ class Chat { | |||||||
| 		$format = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_FORMAT_USAGEINFO); | 		$format = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_FORMAT_USAGEINFO); | ||||||
| 		return $this->sendChat($format . $message, $login, $prefix); | 		return $this->sendChat($format . $message, $login, $prefix); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Handles SendChat Communication Request | ||||||
|  | 	 * | ||||||
|  | 	 * @param $data | ||||||
|  | 	 * @return array | ||||||
|  | 	 */ | ||||||
|  | 	public function communcationSendChat($data) { | ||||||
|  | 		if (!is_object($data) || !property_exists($data, "message")) { | ||||||
|  | 			return new CommunicationAnswer("You have to provide a valid message", true); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		$prefix = true; | ||||||
|  | 		if (property_exists($data, "prefix")) { | ||||||
|  | 			$prefix = $data->prefix; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		$login = null; | ||||||
|  | 		if (property_exists($data, "login")) { | ||||||
|  | 			$login = $data->login; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		$adminLevel = 0; | ||||||
|  | 		if (property_exists($data, "adminLevel")) { | ||||||
|  | 			$adminLevel = $data->adminLevel; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		$type = "default"; | ||||||
|  | 		if (property_exists($data, "type")) { | ||||||
|  | 			$type = $data->type; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		switch ($type) { | ||||||
|  | 			case "information": | ||||||
|  | 				if ($adminLevel) { | ||||||
|  | 					$this->sendInformationToAdmins($data->message, $adminLevel, $prefix); | ||||||
|  | 				} else { | ||||||
|  | 					$this->sendInformation($data->message, $login, $prefix); | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 			case "success": | ||||||
|  | 				if ($adminLevel) { | ||||||
|  | 					$this->sendInformationToAdmins($data->message, $adminLevel, $prefix); | ||||||
|  | 				} else { | ||||||
|  | 					$this->sendSuccess($data->message, $login, $prefix); | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 			case "error": | ||||||
|  | 				if ($adminLevel) { | ||||||
|  | 					$this->sendErrorToAdmins($data->message, $adminLevel, $prefix); | ||||||
|  | 				} else { | ||||||
|  | 					$this->sendError($data->message, $login, $prefix); | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 			case "usage": | ||||||
|  | 				$this->sendUsageInfo($data->message, $login, $prefix); | ||||||
|  | 				break; | ||||||
|  | 			default: | ||||||
|  | 				if ($adminLevel) { | ||||||
|  | 					$this->sendMessageToAdmins($data->message, $adminLevel, $prefix); | ||||||
|  | 				} else { | ||||||
|  | 					$this->sendChat($data->message, $login, $prefix); | ||||||
|  | 				} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return new CommunicationAnswer(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Stores the ChatMessage in the Buffer | ||||||
|  | 	 * | ||||||
|  | 	 * @param $data | ||||||
|  | 	 */ | ||||||
|  | 	public function onPlayerChat($data) { | ||||||
|  | 		$login  = $data[1][1]; | ||||||
|  | 		$player = $this->maniaControl->getPlayerManager()->getPlayer($login); | ||||||
|  |  | ||||||
|  | 		$nickname = ""; | ||||||
|  | 		if ($player) { | ||||||
|  | 			$nickname = $player->nickname; | ||||||
|  | 		} | ||||||
|  | 		array_push($this->chatBuffer, array("user" => $login, "nickname" => $nickname, "message" => $data[1][2])); | ||||||
|  | 		if (count($this->chatBuffer) > self::CHAT_BUFFER_SIZE) { | ||||||
|  | 			array_shift($this->chatBuffer); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -19,7 +19,6 @@ use ManiaControl\Players\Player; | |||||||
|  * @copyright 2014-2015 ManiaControl Team |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| class HelpManager implements CommandListener, CallbackListener { | class HelpManager implements CommandListener, CallbackListener { | ||||||
| 	/* | 	/* | ||||||
| 	 * Private properties | 	 * Private properties | ||||||
| @@ -62,7 +61,7 @@ class HelpManager implements CommandListener, CallbackListener { | |||||||
| 		$message = $this->parseHelpList($this->adminCommands); | 		$message = $this->parseHelpList($this->adminCommands); | ||||||
|  |  | ||||||
| 		// Show message when it's not empty | 		// Show message when it's not empty | ||||||
|         if($message != NULL){ | 		if ($message != null) { | ||||||
| 			$message = 'Supported Admin Commands: ' . $message; | 			$message = 'Supported Admin Commands: ' . $message; | ||||||
| 			$this->maniaControl->getChat()->sendChat($message, $player); | 			$this->maniaControl->getChat()->sendChat($message, $player); | ||||||
| 		} | 		} | ||||||
| @@ -79,7 +78,7 @@ class HelpManager implements CommandListener, CallbackListener { | |||||||
| 		$message = $this->parseHelpList($this->playerCommands); | 		$message = $this->parseHelpList($this->playerCommands); | ||||||
|  |  | ||||||
| 		// Show message when it's not empty | 		// Show message when it's not empty | ||||||
|         if($message != NULL){ | 		if ($message != null) { | ||||||
| 			$message = 'Supported Player Commands: ' . $message; | 			$message = 'Supported Player Commands: ' . $message; | ||||||
| 			$this->maniaControl->getChat()->sendChat($message, $player); | 			$this->maniaControl->getChat()->sendChat($message, $player); | ||||||
| 		} | 		} | ||||||
| @@ -97,6 +96,7 @@ class HelpManager implements CommandListener, CallbackListener { | |||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Parse list with commands from array | 	 * Parse list with commands from array | ||||||
|  | 	 * | ||||||
| 	 * @param array  $commands | 	 * @param array  $commands | ||||||
| 	 * @param bool   $isHelpAll | 	 * @param bool   $isHelpAll | ||||||
| 	 * @param Player $player | 	 * @param Player $player | ||||||
| @@ -130,15 +130,12 @@ class HelpManager implements CommandListener, CallbackListener { | |||||||
| 				$message .= $command['Name'] . ','; | 				$message .= $command['Name'] . ','; | ||||||
| 			} | 			} | ||||||
| 			$message = substr($message, 0, -1); | 			$message = substr($message, 0, -1); | ||||||
|  |  | ||||||
| 			return $message; |  | ||||||
| 		} else { | 		} else { | ||||||
| 			if($player != NULL){ | 			if ($player != null) { | ||||||
| 				$this->showHelpAllList($showCommands, $player); | 				$this->showHelpAllList($showCommands, $player); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|          | 		return $message; | ||||||
|         return; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
|   | |||||||
							
								
								
									
										107
									
								
								core/Communication/Communication.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								core/Communication/Communication.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace ManiaControl\Communication; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Class for Communicating with other ManiaControls | ||||||
|  |  * to call @see ManiaControl\Communication\CommunicationManager\createCommunication | ||||||
|  |  * | ||||||
|  |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  |  */ | ||||||
|  | class Communication { | ||||||
|  | 	private $socket; | ||||||
|  | 	private $ip; | ||||||
|  | 	private $port; | ||||||
|  | 	private $encryptionPassword; | ||||||
|  |  | ||||||
|  | 	private $buffer       = ""; | ||||||
|  | 	private $messageQueue = array(); | ||||||
|  |  | ||||||
|  | 	public function __construct($ip, $port, $encryptionPassword) { | ||||||
|  | 		$this->ip                 = $ip; | ||||||
|  | 		$this->port               = $port; | ||||||
|  | 		$this->encryptionPassword = $encryptionPassword; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** Create an Connection */ | ||||||
|  | 	public function createConnection() { | ||||||
|  | 		$errno        = null; | ||||||
|  | 		$errstr       = null; | ||||||
|  | 		$this->socket = @fsockopen($this->ip, $this->port, $errno, $errstr, 2); | ||||||
|  |  | ||||||
|  | 		//socket_set_nonblock($this->socket); | ||||||
|  | 		stream_set_blocking($this->socket, 0); | ||||||
|  |  | ||||||
|  | 		if ($errno != 0 || !$this->socket) { | ||||||
|  | 			var_dump($errstr); | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Call an Method Asynchronously | ||||||
|  | 	 * | ||||||
|  | 	 * @param callable $function | ||||||
|  | 	 * @param          $method | ||||||
|  | 	 * @param string   $data | ||||||
|  | 	 */ | ||||||
|  | 	public function call(callable $function, $method, $data = "") { | ||||||
|  | 		if (!$this->socket) { | ||||||
|  | 			call_user_func($function, true, "You need to create an Communication before using it"); | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		$data = json_encode(array("method" => $method, "data" => $data)); | ||||||
|  |  | ||||||
|  | 		$data = openssl_encrypt($data, CommunicationManager::ENCRYPTION_METHOD, $this->encryptionPassword, OPENSSL_RAW_DATA, CommunicationManager::ENCRYPTION_IV); | ||||||
|  |  | ||||||
|  | 		array_push($this->messageQueue, $function); | ||||||
|  |  | ||||||
|  | 		// Write Request on Socket | ||||||
|  | 		fwrite($this->socket, strlen($data) . "\n" . $data); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Process data on every Tick | ||||||
|  | 	 */ | ||||||
|  | 	public function tick() { | ||||||
|  | 		//Check if the connection is enabled | ||||||
|  | 		if (!$this->socket) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		$data = fgets($this->socket, 1024); // reads as much as possible OR nothing at all | ||||||
|  | 		if (strlen($data) > 0) { // got new data | ||||||
|  | 			$this->buffer .= $data; // append new data to buffer | ||||||
|  | 			// handle the data the exact same way | ||||||
|  | 			$arr = explode("\n", $this->buffer, 2); | ||||||
|  | 			while (count($arr) == 2 && strlen($arr[1]) >= (int) $arr[0]) { | ||||||
|  | 				// received full message | ||||||
|  | 				$len          = (int) $arr[0]; | ||||||
|  | 				$msg          = substr($arr[1], 0, $len); // clip msg | ||||||
|  | 				$this->buffer = substr($this->buffer, strlen((string) $len) + 1 /* newline */ + $len); // clip buffer | ||||||
|  |  | ||||||
|  | 				// Decode Message | ||||||
|  | 				$data = openssl_decrypt($msg, CommunicationManager::ENCRYPTION_METHOD, $this->encryptionPassword, OPENSSL_RAW_DATA, CommunicationManager::ENCRYPTION_IV); | ||||||
|  | 				$data = json_decode($data); | ||||||
|  |  | ||||||
|  | 				// Received something! | ||||||
|  | 				//Call Function with Data | ||||||
|  | 				call_user_func(array_shift($this->messageQueue), $data->error, $data->data); | ||||||
|  |  | ||||||
|  | 				// next msg | ||||||
|  | 				$arr = explode("\n", $this->buffer, 2); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** Closes the connection, don't call yourself, let it do the Communication Manager */ | ||||||
|  | 	public function closeConnection() { | ||||||
|  | 		if ($this->socket) { | ||||||
|  | 			fclose($this->socket); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								core/Communication/CommunicationAnswer.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								core/Communication/CommunicationAnswer.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace ManiaControl\Communication; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Class for Answer of Communication Request | ||||||
|  |  * | ||||||
|  |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  |  */ | ||||||
|  | class CommunicationAnswer { | ||||||
|  | 	/** Properties are Public for serialization */ | ||||||
|  | 	public $error; | ||||||
|  | 	public $data; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param string $data | ||||||
|  | 	 * @param bool   $error | ||||||
|  | 	 */ | ||||||
|  | 	public function __construct($data = "", $error = false) { | ||||||
|  | 		$this->data  = $data; | ||||||
|  | 		$this->error = $error; | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								core/Communication/CommunicationListener.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								core/Communication/CommunicationListener.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace ManiaControl\Communication; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Interface for SocketListener | ||||||
|  |  * | ||||||
|  |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  |  */ | ||||||
|  | interface CommunicationListener { | ||||||
|  | } | ||||||
							
								
								
									
										311
									
								
								core/Communication/CommunicationManager.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										311
									
								
								core/Communication/CommunicationManager.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,311 @@ | |||||||
|  | <?php | ||||||
|  | namespace ManiaControl\Communication; | ||||||
|  |  | ||||||
|  | use ManiaControl\Callbacks\CallbackListener; | ||||||
|  | use ManiaControl\Callbacks\Callbacks; | ||||||
|  | use ManiaControl\Callbacks\Listening; | ||||||
|  | use ManiaControl\Logger; | ||||||
|  | use ManiaControl\ManiaControl; | ||||||
|  | use ManiaControl\Settings\Setting; | ||||||
|  | use ManiaControl\Settings\SettingManager; | ||||||
|  | use React\EventLoop\Factory; | ||||||
|  | use React\EventLoop\LoopInterface; | ||||||
|  | use React\Socket\Connection; | ||||||
|  | use React\Socket\ConnectionException; | ||||||
|  | use React\Socket\Server; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Class for managing Socket Callbacks | ||||||
|  |  * | ||||||
|  |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  |  */ | ||||||
|  | class CommunicationManager implements CallbackListener { | ||||||
|  | 	/** Constants */ | ||||||
|  | 	const SETTING_SOCKET_ENABLED  = "Activate Socket"; | ||||||
|  | 	const SETTING_SOCKET_PASSWORD = "Password for the Socket Connection"; | ||||||
|  | 	const SETTING_SOCKET_PORT     = "Socket Port for Server "; | ||||||
|  |  | ||||||
|  | 	const ENCRYPTION_IV     = "kZ2Kt0CzKUjN2MJX"; | ||||||
|  | 	const ENCRYPTION_METHOD = "aes-192-cbc"; | ||||||
|  |  | ||||||
|  | 	/** @var ManiaControl $maniaControl */ | ||||||
|  | 	private $maniaControl = null; | ||||||
|  |  | ||||||
|  | 	/** @var LoopInterface $loop */ | ||||||
|  | 	private $loop = null; | ||||||
|  |  | ||||||
|  | 	/** @var Listening[] $communicationListenings */ | ||||||
|  | 	private $communicationListenings = array(); | ||||||
|  |  | ||||||
|  | 	/** @var Server $socket */ | ||||||
|  | 	private $socket = null; | ||||||
|  | 	/** @var Communication[] $communcations */ | ||||||
|  | 	private $communications = array(); | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Create a new Communication Handler Instance | ||||||
|  | 	 * | ||||||
|  | 	 * @param ManiaControl $maniaControl | ||||||
|  | 	 */ | ||||||
|  | 	public function __construct(ManiaControl $maniaControl) { | ||||||
|  | 		$this->maniaControl = $maniaControl; | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCallbackManager()->registerCallbackListener(SettingManager::CB_SETTING_CHANGED, $this, 'updateSettings'); | ||||||
|  | 		$this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::AFTERINIT, $this, 'initCommunicationManager'); | ||||||
|  | 		$this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::ONRESTART, $this, 'onShutDown'); | ||||||
|  | 		$this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::ONSHUTDOWN, $this, 'onShutDown'); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Creates a Communication to another ManiaControl | ||||||
|  | 	 * | ||||||
|  | 	 * @param $ip | ||||||
|  | 	 * @param $port | ||||||
|  | 	 * @return \ManiaControl\Communication\Communication | ||||||
|  | 	 */ | ||||||
|  | 	public function createCommunication($ip, $port, $encryptionKey) { | ||||||
|  | 		$communication = new Communication($ip, $port, $encryptionKey); | ||||||
|  | 		$communication->createConnection(); | ||||||
|  |  | ||||||
|  | 		$this->communications[] = $communication; | ||||||
|  | 		return $communication; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Closes a opened Communication | ||||||
|  | 	 * Does not necessarily need be called, all connections get destroyed on ManiaControl Shutdown | ||||||
|  | 	 * | ||||||
|  | 	 * @param Communication $communication | ||||||
|  | 	 * @return bool | ||||||
|  | 	 */ | ||||||
|  | 	public function closeCommunication($communication) { | ||||||
|  | 		$key = array_search($communication, $this->communications); | ||||||
|  | 		if (isset($this->communications[$key])) { | ||||||
|  | 			$this->communications[$key]->closeConnection(); | ||||||
|  | 			unset($this->communications[$key]); | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** Close all Sockets on maniaControl Shutdown */ | ||||||
|  | 	public function onShutDown() { | ||||||
|  | 		if ($this->socket && $this->socket->master) { | ||||||
|  | 			//Stop the Socket Listening | ||||||
|  | 			$this->socket->shutdown(); | ||||||
|  | 			$this->socket = null; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		foreach ($this->communications as $communication) { | ||||||
|  | 			$this->closeCommunication($communication); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Register a new Communication Listener | ||||||
|  | 	 * | ||||||
|  | 	 * @param string                $callbackName | ||||||
|  | 	 * @param CommunicationListener $listener | ||||||
|  | 	 * @param string                $method | ||||||
|  | 	 * @return bool | ||||||
|  | 	 */ | ||||||
|  | 	public function registerCommunicationListener($echoName, CommunicationListener $listener, $method) { | ||||||
|  | 		if (!Listening::checkValidCallback($listener, $method)) { | ||||||
|  | 			$listenerClass = get_class($listener); | ||||||
|  | 			trigger_error("Given Listener '{$listenerClass}' can't handle Callback '{$echoName}': No callable Method '{$method}'!"); | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (!array_key_exists($echoName, $this->communicationListenings)) { | ||||||
|  | 			$this->communicationListenings[$echoName] = new Listening($listener, $method); | ||||||
|  | 		} else { | ||||||
|  | 			//TODO say which is already listening and other stuff | ||||||
|  | 			trigger_error("Only one Listener can listen on a specific Communication Message"); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Trigger a specific Callback | ||||||
|  | 	 * | ||||||
|  | 	 * @param mixed $callback | ||||||
|  | 	 */ | ||||||
|  | 	public function triggerCommuncationCallback($callbackName) { | ||||||
|  | 		if (!array_key_exists($callbackName, $this->communicationListenings)) { | ||||||
|  | 			return null; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		$params = func_get_args(); | ||||||
|  | 		$params = array_slice($params, 1, null, true); | ||||||
|  |  | ||||||
|  | 		$listening = $this->communicationListenings[$callbackName]; | ||||||
|  | 		/** @var Listening $listening */ | ||||||
|  | 		return $listening->triggerCallbackWithParams($params); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Unregister a Communication Listener | ||||||
|  | 	 * | ||||||
|  | 	 * @param CommunicationListener $listener | ||||||
|  | 	 * @return bool | ||||||
|  | 	 */ | ||||||
|  | 	public function unregisterCommunicationListener(CommunicationListener $listener) { | ||||||
|  | 		return $this->removeCommunicationListener($this->communicationListenings, $listener); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Remove the Communication Listener from the given Listeners Array | ||||||
|  | 	 * | ||||||
|  | 	 * @param Listening[]           $listeningsArray | ||||||
|  | 	 * @param CommunicationListener $listener | ||||||
|  | 	 * @return bool | ||||||
|  | 	 */ | ||||||
|  | 	private function removeCommunicationListener(array &$listeningsArray, CommunicationListener $listener) { | ||||||
|  | 		$removed = false; | ||||||
|  | 		foreach ($listeningsArray as &$listening) { | ||||||
|  | 			if ($listening->listener === $listener) { | ||||||
|  | 				unset($listening); | ||||||
|  | 				$removed = true; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return $removed; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Inits the Communication Manager after ManiaControl Startup | ||||||
|  | 	 */ | ||||||
|  | 	public function initCommunicationManager() { | ||||||
|  | 		$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_SOCKET_ENABLED, false); | ||||||
|  | 		$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_SOCKET_PASSWORD, ""); | ||||||
|  |  | ||||||
|  | 		$servers = $this->maniaControl->getServer()->getAllServers(); | ||||||
|  | 		foreach ($servers as $server) { | ||||||
|  | 			$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_SOCKET_PORT . $server->login, 31500 + $server->index); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		$this->createListeningSocket(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Update Setting | ||||||
|  | 	 * | ||||||
|  | 	 * @param Setting $setting | ||||||
|  | 	 */ | ||||||
|  | 	public function updateSettings(Setting $setting) { | ||||||
|  | 		if (!$setting->belongsToClass($this)) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		$socketEnabled = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SOCKET_ENABLED); | ||||||
|  |  | ||||||
|  | 		if ($socketEnabled && !$this->socket) { | ||||||
|  | 			$this->createListeningSocket(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (!$socketEnabled) { | ||||||
|  | 			$this->socket = null; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Creates The Socket | ||||||
|  | 	 */ | ||||||
|  | 	private function createListeningSocket() { | ||||||
|  | 		$socketEnabled = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SOCKET_ENABLED); | ||||||
|  | 		if ($socketEnabled) { | ||||||
|  |  | ||||||
|  | 			Logger::log("[CommunicationManager] Trying to create Socket"); | ||||||
|  |  | ||||||
|  | 			// Check for MySQLi | ||||||
|  | 			$message = '[CommunicationManager] Checking for installed openssl ... '; | ||||||
|  | 			if (!extension_loaded('openssl')) { | ||||||
|  | 				Logger::log($message . 'NOT FOUND!'); | ||||||
|  | 				Logger::log(" -- You don't have openssl installed! Check: http://www.php.net/manual/en/openssl.installation.php"); | ||||||
|  | 				return; | ||||||
|  | 			} else { | ||||||
|  | 				Logger::log($message . 'FOUND!'); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$serverLogin = $this->maniaControl->getServer()->login; | ||||||
|  | 			$socketPort  = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SOCKET_PORT . $serverLogin); | ||||||
|  | 			$password    = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SOCKET_PASSWORD); | ||||||
|  |  | ||||||
|  | 			try { | ||||||
|  | 				$this->loop   = Factory::create(); | ||||||
|  | 				$this->socket = new Server($this->loop); | ||||||
|  |  | ||||||
|  | 				$this->socket->on('error', function ($e) { | ||||||
|  | 					Logger::log("[CommunicationManager] Socket Error" . $e); | ||||||
|  | 				}); | ||||||
|  |  | ||||||
|  | 				$this->socket->on('connection', function (Connection $connection) use ($password) { | ||||||
|  | 					$buffer = ''; | ||||||
|  | 					$connection->on('data', function ($data) use (&$buffer, &$connection, $password) { | ||||||
|  | 						$buffer .= $data; | ||||||
|  | 						$arr = explode("\n", $buffer, 2); | ||||||
|  | 						while (count($arr) == 2 && strlen($arr[1]) >= (int) $arr[0]) { | ||||||
|  | 							// received full message | ||||||
|  | 							$len    = (int) $arr[0]; | ||||||
|  | 							$msg    = substr($arr[1], 0, $len); // clip msg | ||||||
|  | 							$buffer = substr($buffer, strlen((string) $len) + 1 /* newline */ + $len); // clip buffer | ||||||
|  |  | ||||||
|  | 							// Decode Message | ||||||
|  | 							$data = openssl_decrypt($msg, self::ENCRYPTION_METHOD, $password, OPENSSL_RAW_DATA, self::ENCRYPTION_IV); | ||||||
|  | 							$data = json_decode($data); | ||||||
|  |  | ||||||
|  | 							if ($data == null) { | ||||||
|  | 								$data = array("error" => true, "data" => "Data is not provided as an valid AES-196-encrypted encrypted JSON"); | ||||||
|  | 							} else if (!property_exists($data, "method") || !property_exists($data, "data")) { | ||||||
|  | 								$data = array("error" => true, "data" => "Invalid Message"); | ||||||
|  | 							} else { | ||||||
|  | 								$answer = $this->triggerCommuncationCallback($data->method, $data->data); | ||||||
|  | 								//Prepare Response | ||||||
|  | 								if (!$answer) { | ||||||
|  | 									$data = new CommunicationAnswer("No listener or response on the given Message", true); | ||||||
|  | 								} else { | ||||||
|  | 									$data = $answer; | ||||||
|  | 								} | ||||||
|  | 							} | ||||||
|  |  | ||||||
|  | 							//Encode, Encrypt and Send Response | ||||||
|  | 							$data = json_encode($data); | ||||||
|  |  | ||||||
|  | 							$data = openssl_encrypt($data, self::ENCRYPTION_METHOD, $password, OPENSSL_RAW_DATA, self::ENCRYPTION_IV); | ||||||
|  | 							$connection->write(strlen($data) . "\n" . $data); | ||||||
|  |  | ||||||
|  | 							// next msg | ||||||
|  | 							$arr = explode("\n", $buffer, 2); | ||||||
|  | 						} | ||||||
|  | 					}); | ||||||
|  | 				}); | ||||||
|  | 				//TODO check if port is closed | ||||||
|  | 				$this->socket->listen($socketPort, $this->maniaControl->getServer()->ip); | ||||||
|  |  | ||||||
|  | 				Logger::log("[CommunicationManager] Socket " . $this->maniaControl->getServer()->ip . ":" . $this->socket->getPort() . " Successfully created!"); | ||||||
|  | 			} catch (ConnectionException $e) { | ||||||
|  | 				Logger::log("[CommunicationManager] Exception: " . $e->getMessage()); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Processes Data on every ManiaControl Tick, don't call this Method | ||||||
|  | 	 */ | ||||||
|  | 	public function tick() { | ||||||
|  | 		if ($this->loop) { | ||||||
|  | 			$this->loop->tick(); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		foreach ($this->communications as $communication) { | ||||||
|  | 			$communication->tick(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										173
									
								
								core/Communication/CommunicationMethods.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								core/Communication/CommunicationMethods.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,173 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace ManiaControl\Communication; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Communication Methods Interface | ||||||
|  |  * | ||||||
|  |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  |  */ | ||||||
|  | interface CommunicationMethods { | ||||||
|  | 	/** Restarts Mania Control | ||||||
|  | 	 *   Optional Params | ||||||
|  | 	 *      - message | ||||||
|  | 	 */ | ||||||
|  | 	const RESTART_MANIA_CONTROL = "ManiaControl.Restart"; | ||||||
|  |  | ||||||
|  | 	/** Grands an Authentication Level on a Player | ||||||
|  | 	 *   Required Parameters | ||||||
|  | 	 *      - login (login of the player) | ||||||
|  | 	 *      - level (integer, 0-3 possible, @see AuthenticationManager) | ||||||
|  | 	 */ | ||||||
|  | 	const GRANT_AUTH_LEVEL = "AuthenticationManager.GrandLevel"; | ||||||
|  |  | ||||||
|  | 	/** Revokes an Authentication Level on a Player | ||||||
|  | 	 *   Required Parameters | ||||||
|  | 	 *      - login (login of the player) | ||||||
|  | 	 */ | ||||||
|  | 	const REVOKE_AUTH_LEVEL = "AuthenticationManager.RevokeLevel"; | ||||||
|  |  | ||||||
|  | 	/** Provides the Server Options | ||||||
|  | 	 *  no Parameters | ||||||
|  | 	 */ | ||||||
|  | 	const GET_SERVER_OPTIONS = "ServerOptions.GetServerOptions"; | ||||||
|  |  | ||||||
|  | 	/** Set Server Options | ||||||
|  | 	 *   Required Parameter | ||||||
|  | 	 *    - scriptSettings (array(optionName1 => value1, optionName2 => value2...)) | ||||||
|  | 	 */ | ||||||
|  | 	const SET_SERVER_OPTIONS = "ServerOptions.SetServerOptions"; | ||||||
|  |  | ||||||
|  | 	/** Provides the ModeScriptSettings | ||||||
|  | 	 *  no Parameters | ||||||
|  | 	 */ | ||||||
|  | 	const GET_SCRIPT_SETTINGS = "ScriptSettings.GetScriptSettings"; | ||||||
|  |  | ||||||
|  | 	/** Set ModeScriptSettings | ||||||
|  | 	 *   Required Parameter | ||||||
|  | 	 *    - scriptSettings (array(settingName1 => value1, settingName2 => value2...)) | ||||||
|  | 	 */ | ||||||
|  | 	const SET_SCRIPT_SETTINGS = "ScriptSettings.SetScriptSettings"; | ||||||
|  |  | ||||||
|  | 	/** Restarts the Current Map | ||||||
|  | 	 *  no Parameters | ||||||
|  | 	 */ | ||||||
|  | 	const RESTART_MAP = "MapActions.RestartMap"; | ||||||
|  |  | ||||||
|  | 	/** Skips the Current Map | ||||||
|  | 	 *  no Parameters | ||||||
|  | 	 */ | ||||||
|  | 	const SKIP_MAP = "MapActions.SkipMap"; | ||||||
|  |  | ||||||
|  | 	/** Skips to a Specific Map by MxId or MapUid | ||||||
|  | 	 *  Required Parameters | ||||||
|  | 	 *   - mxId (integer) | ||||||
|  | 	 *   OR | ||||||
|  | 	 *   - mapUid (string) | ||||||
|  | 	 */ | ||||||
|  | 	const SKIP_TO_MAP = "MapActions.SkipToMap"; | ||||||
|  |  | ||||||
|  | 	/** Adds a Map from Mania Exchange to the Server | ||||||
|  | 	 *  Required Parameters | ||||||
|  | 	 *  - mxId (integer) | ||||||
|  | 	 * (no success returning yet because of asynchronously of adding) | ||||||
|  | 	 */ | ||||||
|  | 	const ADD_MAP = "MapManager.AddMap"; | ||||||
|  |  | ||||||
|  | 	/** Removes a Map from the Server | ||||||
|  | 	 *  Required Parameters | ||||||
|  | 	 *  - mapUid (string) | ||||||
|  | 	 *  Optional Parameters | ||||||
|  | 	 *  - displayMessage (default true) | ||||||
|  | 	 *  - eraseMapFile   (default false) | ||||||
|  | 	 */ | ||||||
|  | 	const REMOVE_MAP = "MapManager.RemoveMap"; | ||||||
|  |  | ||||||
|  | 	/** Updates a Map over Mania Exchange | ||||||
|  | 	 *  Required Parameters | ||||||
|  | 	 *  - mapUid | ||||||
|  | 	 * (no success returning yet because of asynchronously of adding) | ||||||
|  | 	 */ | ||||||
|  | 	const UPDATE_MAP = "MapManager.UpdateMap"; | ||||||
|  |  | ||||||
|  | 	/** Gets the current Map | ||||||
|  | 	 *  Required Parameters | ||||||
|  | 	 *   - mxId (integer) | ||||||
|  | 	 *   OR | ||||||
|  | 	 *   - mapUid (string) | ||||||
|  | 	 */ | ||||||
|  | 	const GET_CURRENT_MAP = "MapManager.GetCurrentMap"; | ||||||
|  |  | ||||||
|  | 	/** Gets the specific Map | ||||||
|  | 	 *  no Parameters | ||||||
|  | 	 */ | ||||||
|  | 	const GET_MAP = "MapManager.GetMap"; | ||||||
|  |  | ||||||
|  | 	/** Gets the current Map List | ||||||
|  | 	 *  no Parameters | ||||||
|  | 	 */ | ||||||
|  | 	const GET_MAP_LIST = "MapManager.GetMapList"; | ||||||
|  |  | ||||||
|  | 	/** Gets Mania Control PlayerList | ||||||
|  | 	 *  no Parameters | ||||||
|  | 	 */ | ||||||
|  | 	const GET_PLAYER_LIST = "PlayerManager.GetPlayerList"; | ||||||
|  |  | ||||||
|  | 	/** Warns a Player | ||||||
|  | 	 *  Required Params | ||||||
|  | 	 *  - login | ||||||
|  | 	 */ | ||||||
|  | 	const WARN_PLAYER = "PlayerActions.WarnPlayer"; | ||||||
|  |  | ||||||
|  | 	/** Mutes a Player | ||||||
|  | 	 *  Required Params | ||||||
|  | 	 *  - login | ||||||
|  | 	 */ | ||||||
|  | 	const MUTE_PLAYER = "PlayerActions.MutePlayer"; | ||||||
|  |  | ||||||
|  | 	/** UnMutes a Player | ||||||
|  | 	 *  Required Params | ||||||
|  | 	 *  - login | ||||||
|  | 	 */ | ||||||
|  | 	const UNMUTE_PLAYER = "PlayerActions.UnMutePlayer"; | ||||||
|  |  | ||||||
|  | 	/** UnMutes a Player | ||||||
|  | 	 *  Required Params | ||||||
|  | 	 *  - login | ||||||
|  | 	 *  Optional Params | ||||||
|  | 	 *  - message | ||||||
|  | 	 */ | ||||||
|  | 	const KICK_PLAYER = "PlayerActions.KickPlayer"; | ||||||
|  |  | ||||||
|  | 	/** Forces a player to Spectator | ||||||
|  | 	 *  Required Params | ||||||
|  | 	 *  - login | ||||||
|  | 	 */ | ||||||
|  | 	const FORCE_PLAYER_TO_SPEC = "PlayerActions.ForcePlayerToSpec"; | ||||||
|  |  | ||||||
|  | 	/** Forces a player to Spectator | ||||||
|  | 	 *  Required Params | ||||||
|  | 	 *  - login | ||||||
|  | 	 *  Optional Params | ||||||
|  | 	 *  - teamId (integer, id of the team the player should get forced into it) | ||||||
|  | 	 */ | ||||||
|  | 	const FORCE_PLAYER_TO_PLAY = "PlayerActions.ForcePlayerToPlay"; | ||||||
|  |  | ||||||
|  | 	/** Returns the last 200 lines of the chat (inclusive player logins and nicknames) | ||||||
|  | 	 * No Params | ||||||
|  | 	 */ | ||||||
|  | 	const GET_SERVER_CHAT = "Chat.GetServerChat"; | ||||||
|  |  | ||||||
|  | 	/** Sends a ChatMessage to the Server | ||||||
|  | 	 *  Required Params: | ||||||
|  | 	 *  - message | ||||||
|  | 	 *  Optional Params | ||||||
|  | 	 *  - prefix        (use custom prefix or false for no prefix) | ||||||
|  | 	 *  - login         (login of a receiver if the message don't get sent to all) | ||||||
|  | 	 *  - adminLevel    (minimum Admin Level if the Message should get sent to an Admin) | ||||||
|  | 	 *  - type          (type of the message (information, error, success or usage) | ||||||
|  | 	 */ | ||||||
|  | 	const SEND_CHAT_MESSAGE = "Chat.SendChatMessage"; | ||||||
|  | } | ||||||
							
								
								
									
										53
									
								
								core/Communication/usage_documentation.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								core/Communication/usage_documentation.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | The CommuncationListening of the Communcation Manager can be enabled in the ingame Settings. | ||||||
|  |  | ||||||
|  | There the following settings are existing: | ||||||
|  | -- Enable Socket Listening (Let the CommunicationManager listen for incoming calls) | ||||||
|  | -- Passsword (Password which get used to encrypt and decrypt the messages for the openssl connection) | ||||||
|  | -- Listening port for every server (this is the port the CommunicationManager listens at) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | For the description of the available implemented communcation Methods check the CommunicationMethods interface. | ||||||
|  |  | ||||||
|  | If you need methods which are not implemented, or additional Parameters, feel free to contact us. | ||||||
|  |  | ||||||
|  | Sample ManiaControl Implementation (for ManiaControl to ManiaControl connections) | ||||||
|  |  | ||||||
|  | ##php code begin | ||||||
|  | 	$communication = $this->maniaControl->getCommunicationManager()->createCommunication(IP/Domain, PORT, 'YOUR_PASSWORD'); | ||||||
|  | 	$communication->call(function($data){ | ||||||
|  | 		var_dump($data); | ||||||
|  | 	}, CommunicationMethods::GET_SERVER_CHAT); | ||||||
|  | ##php code end | ||||||
|  |  | ||||||
|  | Sample Web Implementation (to call ManiaControl from a website) | ||||||
|  | ##php code begin | ||||||
|  | 	$errno = null; | ||||||
|  | 	$errstr = null; | ||||||
|  | 	$socket = fsockopen("xx.xxx.xx.xx", xxxxx, $errno, $errstr, 2); | ||||||
|  | 	echo "ok?" . $errno . " - " . $errstr . "\n"; | ||||||
|  |  | ||||||
|  | 	$data = array("method" => "getServerChat", "data" => ""); | ||||||
|  |  | ||||||
|  | 	// Encode and Encrypt the Data | ||||||
|  | 	$data = json_encode(array("method" => "getServerChat", "data" => "")); | ||||||
|  | 	$data = openssl_encrypt($data, 'aes-192-cbc', 'YOUR_PASSWORD', OPENSSL_RAW_DATA, 'kZ2Kt0CzKUjN2MJX'); | ||||||
|  |  | ||||||
|  | 	// Write the Data on the Socket | ||||||
|  | 	fwrite($socket, strlen($data) . "\n" . $data); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	// Read Answer Data | ||||||
|  | 	$len = (int)fgets($socket); | ||||||
|  | 	echo $len; | ||||||
|  | 	$buff = ''; | ||||||
|  | 	while (!feof($socket) && strlen($buff) < $len) { | ||||||
|  | 		$buff .= fgets($socket, $len - strlen($buff) + 1); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Decrypt and Decode the Response Data | ||||||
|  | 	$data = openssl_decrypt($buff, 'aes-192-cbc', 'YOUR_PASSWORD', OPENSSL_RAW_DATA, 'kZ2Kt0CzKUjN2MJX'); | ||||||
|  | 	echo json_decode($data); | ||||||
|  |  | ||||||
|  | 	//Close the Socket | ||||||
|  | 	fclose($socket); | ||||||
|  | ##php code end | ||||||
| @@ -199,11 +199,11 @@ class Configurator implements CallbackListener, CommandListener, ManialinkPageAn | |||||||
|  |  | ||||||
| 		$frame = new Frame(); | 		$frame = new Frame(); | ||||||
| 		$manialink->add($frame); | 		$manialink->add($frame); | ||||||
| 		$frame->setPosition($menuPosX, $menuPosY, 10); | 		$frame->setPosition($menuPosX, $menuPosY, 34); | ||||||
|  |  | ||||||
| 		$backgroundQuad = new Quad(); | 		$backgroundQuad = new Quad(); | ||||||
| 		$frame->add($backgroundQuad); | 		$frame->add($backgroundQuad); | ||||||
| 		$backgroundQuad->setZ(-10)->setSize($menuWidth, $menuHeight)->setStyles($quadStyle, $quadSubstyle); | 		$backgroundQuad->setZ(-2)->setSize($menuWidth, $menuHeight)->setStyles($quadStyle, $quadSubstyle); | ||||||
|  |  | ||||||
| 		$menuItemsFrame = new Frame(); | 		$menuItemsFrame = new Frame(); | ||||||
| 		$frame->add($menuItemsFrame); | 		$frame->add($menuItemsFrame); | ||||||
| @@ -211,7 +211,7 @@ class Configurator implements CallbackListener, CommandListener, ManialinkPageAn | |||||||
|  |  | ||||||
| 		$itemsBackgroundQuad = new Quad(); | 		$itemsBackgroundQuad = new Quad(); | ||||||
| 		$menuItemsFrame->add($itemsBackgroundQuad); | 		$menuItemsFrame->add($itemsBackgroundQuad); | ||||||
| 		$backgroundQuad->setZ(-9); | 		$backgroundQuad->setZ(-1); | ||||||
| 		$itemsBackgroundQuad->setSize($menuListWidth, $menuHeight)->setStyles($quadStyle, $quadSubstyle); | 		$itemsBackgroundQuad->setSize($menuListWidth, $menuHeight)->setStyles($quadStyle, $quadSubstyle); | ||||||
|  |  | ||||||
| 		$menusFrame = new Frame(); | 		$menusFrame = new Frame(); | ||||||
|   | |||||||
| @@ -14,6 +14,9 @@ use FML\Script\Script; | |||||||
| use ManiaControl\Admin\AuthenticationManager; | use ManiaControl\Admin\AuthenticationManager; | ||||||
| use ManiaControl\Callbacks\CallbackListener; | use ManiaControl\Callbacks\CallbackListener; | ||||||
| use ManiaControl\Callbacks\Callbacks; | use ManiaControl\Callbacks\Callbacks; | ||||||
|  | use ManiaControl\Communication\CommunicationAnswer; | ||||||
|  | use ManiaControl\Communication\CommunicationListener; | ||||||
|  | use ManiaControl\Communication\CommunicationMethods; | ||||||
| use ManiaControl\Logger; | use ManiaControl\Logger; | ||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| use ManiaControl\Players\Player; | use ManiaControl\Players\Player; | ||||||
| @@ -26,7 +29,7 @@ use Maniaplanet\DedicatedServer\Xmlrpc\GameModeException; | |||||||
|  * @copyright 2014-2015 ManiaControl Team |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  */ |  */ | ||||||
| class ScriptSettings implements ConfiguratorMenu, CallbackListener { | class ScriptSettings implements ConfiguratorMenu, CallbackListener, CommunicationListener { | ||||||
| 	/* | 	/* | ||||||
| 	 * Constants | 	 * Constants | ||||||
| 	 */ | 	 */ | ||||||
| @@ -61,6 +64,10 @@ class ScriptSettings implements ConfiguratorMenu, CallbackListener { | |||||||
|  |  | ||||||
| 		// Permissions | 		// Permissions | ||||||
| 		$this->maniaControl->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_CHANGE_SCRIPT_SETTINGS, AuthenticationManager::AUTH_LEVEL_ADMIN); | 		$this->maniaControl->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_CHANGE_SCRIPT_SETTINGS, AuthenticationManager::AUTH_LEVEL_ADMIN); | ||||||
|  |  | ||||||
|  | 		//TODO remove to somewhere cleaner | ||||||
|  | 		//Communication Listenings | ||||||
|  | 		$this->initalizeCommunicationListenings(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -149,8 +156,7 @@ class ScriptSettings implements ConfiguratorMenu, CallbackListener { | |||||||
| 	 * Handle Begin Map Callback | 	 * Handle Begin Map Callback | ||||||
| 	 */ | 	 */ | ||||||
| 	public function onBeginMap() { | 	public function onBeginMap() { | ||||||
| 		if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_LOAD_DEFAULT_SETTINGS_MAP_BEGIN) | 		if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_LOAD_DEFAULT_SETTINGS_MAP_BEGIN)) { | ||||||
| 		) { |  | ||||||
| 			$this->loadSettingsFromDatabase(); | 			$this->loadSettingsFromDatabase(); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -282,8 +288,7 @@ class ScriptSettings implements ConfiguratorMenu, CallbackListener { | |||||||
| 	 * @see \ManiaControl\Configurators\ConfiguratorMenu::saveConfigData() | 	 * @see \ManiaControl\Configurators\ConfiguratorMenu::saveConfigData() | ||||||
| 	 */ | 	 */ | ||||||
| 	public function saveConfigData(array $configData, Player $player) { | 	public function saveConfigData(array $configData, Player $player) { | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CHANGE_SCRIPT_SETTINGS) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CHANGE_SCRIPT_SETTINGS)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -327,6 +332,7 @@ class ScriptSettings implements ConfiguratorMenu, CallbackListener { | |||||||
| 		$this->maniaControl->getConfigurator()->showMenu($player, $this); | 		$this->maniaControl->getConfigurator()->showMenu($player, $this); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Apply the Array of new Script Settings | 	 * Apply the Array of new Script Settings | ||||||
| 	 * | 	 * | ||||||
| @@ -408,4 +414,61 @@ class ScriptSettings implements ConfiguratorMenu, CallbackListener { | |||||||
| 		} | 		} | ||||||
| 		return (string) $value; | 		return (string) $value; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Initializes the communication Listenings | ||||||
|  | 	 */ | ||||||
|  | 	private function initalizeCommunicationListenings() { | ||||||
|  | 		//Communication Listenings | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::GET_SCRIPT_SETTINGS, $this, function ($data) { | ||||||
|  | 			try { | ||||||
|  | 				$scriptSettings = $this->maniaControl->getClient()->getModeScriptSettings(); | ||||||
|  | 			} catch (GameModeException $e) { | ||||||
|  | 				return new CommunicationAnswer($e->getMessage(), true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			return new CommunicationAnswer($scriptSettings); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::SET_SCRIPT_SETTINGS, $this, function ($data) { | ||||||
|  | 			if (!is_object($data) || !property_exists($data, "scriptSettings")) { | ||||||
|  | 				return new CommunicationAnswer("No valid ScriptSettings provided!", true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			try { | ||||||
|  | 				$scriptSettings = $this->maniaControl->getClient()->getModeScriptSettings(); | ||||||
|  | 			} catch (GameModeException $e) { | ||||||
|  | 				return new CommunicationAnswer($e->getMessage(), true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$newSettings = array(); | ||||||
|  | 			foreach ($data->scriptSettings as $name => $value) { | ||||||
|  | 				if (!isset($scriptSettings[$name])) { | ||||||
|  | 					var_dump('no setting ' . $name); | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if ($value == $scriptSettings[$name]) { | ||||||
|  | 					// Not changed | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				$newSettings[$name] = $value; | ||||||
|  | 				settype($newSettings[$name], gettype($scriptSettings[$name])); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			//No new Settings | ||||||
|  | 			if (empty($newSettings)) { | ||||||
|  | 				return new CommunicationAnswer(array("success" => true)); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			//Trigger Scriptsettings Changed Callback | ||||||
|  | 			$this->maniaControl->getCallbackManager()->triggerCallback(self::CB_SCRIPTSETTINGS_CHANGED); | ||||||
|  |  | ||||||
|  | 			//Set the Settings | ||||||
|  | 			$success = $this->maniaControl->getClient()->setModeScriptSettings($newSettings); | ||||||
|  |  | ||||||
|  | 			return new CommunicationAnswer(array("success" => $success)); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										207
									
								
								core/Files/AsyncHttpRequest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								core/Files/AsyncHttpRequest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,207 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace ManiaControl\Files; | ||||||
|  |  | ||||||
|  | use cURL\Event; | ||||||
|  | use cURL\Request; | ||||||
|  | use ManiaControl\ManiaControl; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Asynchronous Http Request Class | ||||||
|  |  * | ||||||
|  |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  |  */ | ||||||
|  | class AsyncHttpRequest { | ||||||
|  | 	/* | ||||||
|  | 	 * Constants | ||||||
|  | 	 */ | ||||||
|  | 	const CONTENT_TYPE_JSON = 'application/json'; | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 	 * Private properties | ||||||
|  | 	 */ | ||||||
|  | 	/** @var  ManiaControl $maniaControl */ | ||||||
|  | 	private $maniaControl; | ||||||
|  |  | ||||||
|  | 	private $url; | ||||||
|  | 	private $function; | ||||||
|  | 	private $content; | ||||||
|  | 	private $compression = false; | ||||||
|  | 	private $contentType = 'text/xml; charset=UTF-8;'; | ||||||
|  | 	private $headers     = array(); | ||||||
|  |  | ||||||
|  | 	public function __construct($maniaControl, $url) { | ||||||
|  | 		$this->maniaControl = $maniaControl; | ||||||
|  | 		$this->url          = $url; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Create a new cURL Request for the given URL | ||||||
|  | 	 * | ||||||
|  | 	 * @param string $url | ||||||
|  | 	 * @return Request | ||||||
|  | 	 */ | ||||||
|  | 	private function newRequest($url) { | ||||||
|  | 		$request = new Request($url); | ||||||
|  | 		$request->getOptions()->set(CURLOPT_TIMEOUT, 60)->set(CURLOPT_HEADER, false)// don't display response header | ||||||
|  | 		        ->set(CURLOPT_CRLF, true)// linux line feed | ||||||
|  | 		        ->set(CURLOPT_ENCODING, '')// accept encoding | ||||||
|  | 		        ->set(CURLOPT_USERAGENT, 'ManiaControl v' . ManiaControl::VERSION)// user-agent | ||||||
|  | 		        ->set(CURLOPT_RETURNTRANSFER, true)// | ||||||
|  | 		        ->set(CURLOPT_FOLLOWLOCATION, true)// support redirect | ||||||
|  | 		        ->set(CURLOPT_SSL_VERIFYPEER, false); | ||||||
|  | 		return $request; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Carry out a GetData Request | ||||||
|  | 	 * | ||||||
|  | 	 * @param int $keepAlive | ||||||
|  | 	 */ | ||||||
|  | 	public function getData($keepAlive = 0) { | ||||||
|  | 		array_push($this->headers, 'Content-Type: ' . $this->contentType); | ||||||
|  | 		if ($keepAlive) { | ||||||
|  | 			array_push($this->headers, 'Keep-Alive: ' . $keepAlive); | ||||||
|  | 			array_push($this->headers, 'Connection: Keep-Alive'); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		$request = $this->newRequest($this->url); | ||||||
|  | 		$request->getOptions()->set(CURLOPT_AUTOREFERER, true)// accept link reference | ||||||
|  | 		        ->set(CURLOPT_HTTPHEADER, $this->headers); // headers | ||||||
|  |  | ||||||
|  | 		$this->processRequest($request); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Carry out a PostData Request | ||||||
|  | 	 */ | ||||||
|  | 	public function postData() { | ||||||
|  | 		array_push($this->headers, 'Content-Type: ' . $this->contentType); | ||||||
|  | 		array_push($this->headers, 'Keep-Alive: timeout=600, max=2000'); | ||||||
|  | 		array_push($this->headers, 'Connection: Keep-Alive'); | ||||||
|  |  | ||||||
|  | 		$content = str_replace(array("\r", "\n"), '', $this->content); | ||||||
|  | 		if ($this->compression) { | ||||||
|  | 			$content = zlib_encode($content, 31); | ||||||
|  | 			array_push($this->headers, 'Content-Encoding: gzip'); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		$request = $this->newRequest($this->url); | ||||||
|  | 		$request->getOptions()->set(CURLOPT_POST, true)// post method | ||||||
|  | 		        ->set(CURLOPT_POSTFIELDS, $content)// post content field | ||||||
|  | 		        ->set(CURLOPT_HTTPHEADER, $this->headers) // headers | ||||||
|  | 		; | ||||||
|  |  | ||||||
|  | 		$this->processRequest($request); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Processes the Request | ||||||
|  | 	 * | ||||||
|  | 	 * @param Request $request | ||||||
|  | 	 */ | ||||||
|  | 	private function processRequest(Request $request) { | ||||||
|  | 		$request->addListener('complete', function (Event $event) { | ||||||
|  | 			$error   = null; | ||||||
|  | 			$content = null; | ||||||
|  | 			if ($event->response->hasError()) { | ||||||
|  | 				$error = $event->response->getError()->getMessage(); | ||||||
|  | 			} else { | ||||||
|  | 				$content = $event->response->getContent(); | ||||||
|  | 			} | ||||||
|  | 			call_user_func($this->function, $content, $error); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$fileReader = $this->maniaControl->getFileReader(); | ||||||
|  | 		$fileReader->addRequest($request); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param $url | ||||||
|  | 	 * @return $this | ||||||
|  | 	 */ | ||||||
|  | 	public function setURL($url) { | ||||||
|  | 		$this->url = $url; | ||||||
|  | 		return $this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param callable $function | ||||||
|  | 	 * @return $this | ||||||
|  | 	 */ | ||||||
|  | 	public function setCallable($function) { | ||||||
|  | 		$this->function = $function; | ||||||
|  | 		return $this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return mixed | ||||||
|  | 	 */ | ||||||
|  | 	public function getContent() { | ||||||
|  | 		return $this->content; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param mixed $content | ||||||
|  | 	 * @return $this | ||||||
|  | 	 */ | ||||||
|  | 	public function setContent($content) { | ||||||
|  | 		$this->content = $content; | ||||||
|  | 		return $this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return boolean | ||||||
|  | 	 */ | ||||||
|  | 	public function getCompression() { | ||||||
|  | 		return $this->compression; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param boolean $compression | ||||||
|  | 	 * @return $this | ||||||
|  | 	 */ | ||||||
|  | 	public function setCompression($compression) { | ||||||
|  | 		$this->compression = $compression; | ||||||
|  | 		return $this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return array | ||||||
|  | 	 */ | ||||||
|  | 	public function getHeaders() { | ||||||
|  | 		return $this->headers; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param array $headers | ||||||
|  | 	 * @return $this | ||||||
|  | 	 */ | ||||||
|  | 	public function setHeaders($headers) { | ||||||
|  | 		if(is_array($headers)){ | ||||||
|  | 			$this->headers = $headers; | ||||||
|  | 		} | ||||||
|  | 		return $this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return string | ||||||
|  | 	 */ | ||||||
|  | 	public function getContentType() { | ||||||
|  | 		return $this->contentType; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param string $contentType | ||||||
|  | 	 * @return $this | ||||||
|  | 	 */ | ||||||
|  | 	public function setContentType($contentType) { | ||||||
|  | 		$this->contentType = $contentType; | ||||||
|  | 		return $this; | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -2,7 +2,6 @@ | |||||||
|  |  | ||||||
| namespace ManiaControl\Files; | namespace ManiaControl\Files; | ||||||
|  |  | ||||||
| use cURL\Event; |  | ||||||
| use cURL\Request; | use cURL\Request; | ||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
|  |  | ||||||
| @@ -66,93 +65,15 @@ class AsynchronousFileReader { | |||||||
| 	 * @param callable $function | 	 * @param callable $function | ||||||
| 	 * @param string   $contentType | 	 * @param string   $contentType | ||||||
| 	 * @param int      $keepAlive | 	 * @param int      $keepAlive | ||||||
|  | 	 * @param array    $headers Additional Headers | ||||||
|  | 	 * @deprecated @see ManiaControl\Files\AsyncHttpRequest | ||||||
| 	 */ | 	 */ | ||||||
| 	public function loadFile($url, callable $function, $contentType = 'UTF-8', $keepAlive = 0) { | 	public function loadFile($url, callable $function, $contentType = 'UTF-8', $keepAlive = 0, $headers = array()) { | ||||||
| 		$headers = array(); | 		$httpRequest = new AsyncHttpRequest($this->maniaControl, $url); | ||||||
| 		array_push($headers, 'Content-Type: ' . $contentType); | 		$httpRequest->setCallable($function)->setContentType($contentType)->setHeaders($headers); | ||||||
| 		if ($keepAlive) { | 		$httpRequest->getData($keepAlive); | ||||||
| 			array_push($headers, 'Keep-Alive: ' . $keepAlive); |  | ||||||
| 			array_push($headers, 'Connection: Keep-Alive'); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		$request = $this->newRequest($url); |  | ||||||
| 		$request->getOptions()->set(CURLOPT_AUTOREFERER, true) // accept link reference |  | ||||||
| 		        ->set(CURLOPT_HTTPHEADER, $headers); // headers |  | ||||||
|  |  | ||||||
| 		$request->addListener('complete', function (Event $event) use (&$function) { |  | ||||||
| 			$error   = null; |  | ||||||
| 			$content = null; |  | ||||||
| 			if ($event->response->hasError()) { |  | ||||||
| 				$error = $event->response->getError()->getMessage(); |  | ||||||
| 			} else { |  | ||||||
| 				$content = $event->response->getContent(); |  | ||||||
| 			} |  | ||||||
| 			call_user_func($function, $content, $error); |  | ||||||
| 		}); |  | ||||||
|  |  | ||||||
| 		$this->addRequest($request); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Create a new cURL Request for the given URL |  | ||||||
| 	 * |  | ||||||
| 	 * @param string $url |  | ||||||
| 	 * @return Request |  | ||||||
| 	 */ |  | ||||||
| 	protected function newRequest($url) { |  | ||||||
| 		$request = new Request($url); |  | ||||||
| 		$request->getOptions()->set(CURLOPT_TIMEOUT, 60)->set(CURLOPT_HEADER, false) // don't display response header |  | ||||||
| 		        ->set(CURLOPT_CRLF, true) // linux line feed |  | ||||||
| 		        ->set(CURLOPT_ENCODING, '') // accept encoding |  | ||||||
| 		        ->set(CURLOPT_USERAGENT, 'ManiaControl v' . ManiaControl::VERSION) // user-agent |  | ||||||
| 		        ->set(CURLOPT_RETURNTRANSFER, true); // return instead of output content |  | ||||||
| 		return $request; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	//TODO remove, they are just for testing dedimania |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Add a Request to the queue |  | ||||||
| 	 * |  | ||||||
| 	 * @param Request $request |  | ||||||
| 	 */ |  | ||||||
| 	protected function addRequest(Request $request) { |  | ||||||
| 		array_push($this->requests, $request); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	public function postDataTest(Request $request, $url, callable $function, $content, $compression = false, $contentType = 'text/xml; charset=UTF-8;') { |  | ||||||
|  |  | ||||||
| 		$headers = array(); |  | ||||||
| 		array_push($headers, 'Content-Type: ' . $contentType); |  | ||||||
| 		array_push($headers, 'Keep-Alive: timeout=600, max=2000'); |  | ||||||
| 		array_push($headers, 'Connection: Keep-Alive'); |  | ||||||
|  |  | ||||||
| 		$content = str_replace(array("\r", "\n"), '', $content); |  | ||||||
| 		if ($compression) { |  | ||||||
| 			$content = zlib_encode($content, 31); |  | ||||||
| 			array_push($headers, 'Content-Encoding: gzip'); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		$request->getOptions()->set(CURLOPT_POST, true) // post method |  | ||||||
| 		        ->set(CURLOPT_POSTFIELDS, $content) // post content field |  | ||||||
| 		        ->set(CURLOPT_HTTPHEADER, $headers) // headers |  | ||||||
| 		; |  | ||||||
| 		$request->addListener('complete', function (Event $event) use (&$function) { |  | ||||||
| 			$error   = null; |  | ||||||
| 			$content = null; |  | ||||||
| 			if ($event->response->hasError()) { |  | ||||||
| 				$error = $event->response->getError()->getMessage(); |  | ||||||
| 			} else { |  | ||||||
| 				$content = $event->response->getContent(); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			call_user_func($function, $content, $error); |  | ||||||
| 		}); |  | ||||||
|  |  | ||||||
| 		$this->addRequest($request); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Send Data via POST Method | 	 * Send Data via POST Method | ||||||
| 	 * | 	 * | ||||||
| @@ -161,36 +82,21 @@ class AsynchronousFileReader { | |||||||
| 	 * @param string   $content | 	 * @param string   $content | ||||||
| 	 * @param bool     $compression | 	 * @param bool     $compression | ||||||
| 	 * @param string   $contentType | 	 * @param string   $contentType | ||||||
|  | 	 * @param array    $headers Additional Headers | ||||||
|  | 	 * @deprecated @see ManiaControl\Files\AsyncHttpRequest | ||||||
| 	 */ | 	 */ | ||||||
| 	public function postData($url, callable $function, $content, $compression = false, $contentType = 'text/xml; charset=UTF-8;') { | 	public function postData($url, callable $function, $content, $compression = false, $contentType = 'text/xml; charset=UTF-8;', $headers = array()) { | ||||||
|  | 		$httpRequest = new AsyncHttpRequest($this->maniaControl, $url); | ||||||
| 		$headers = array(); | 		$httpRequest->setCallable($function)->setContent($content)->setCompression($compression)->setContentType($contentType)->setHeaders($headers); | ||||||
| 		array_push($headers, 'Content-Type: ' . $contentType); | 		$httpRequest->postData(); | ||||||
| 		array_push($headers, 'Keep-Alive: timeout=600, max=2000'); |  | ||||||
| 		array_push($headers, 'Connection: Keep-Alive'); |  | ||||||
|  |  | ||||||
| 		$content = str_replace(array("\r", "\n"), '', $content); |  | ||||||
| 		if ($compression) { |  | ||||||
| 			$content = zlib_encode($content, 31); |  | ||||||
| 			array_push($headers, 'Content-Encoding: gzip'); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		$request = $this->newRequest($url); | 	/** | ||||||
| 		$request->getOptions()->set(CURLOPT_POST, true) // post method | 	 * Add a Request to the queue, DO NOT CALL MANUALLY! | ||||||
| 		        ->set(CURLOPT_POSTFIELDS, $content) // post content field | 	 * | ||||||
| 		        ->set(CURLOPT_HTTPHEADER, $headers) // headers | 	 * @param Request $request | ||||||
| 		; | 	 */ | ||||||
| 		$request->addListener('complete', function (Event $event) use (&$function) { | 	public function addRequest(Request $request) { | ||||||
| 			$error   = null; | 		array_push($this->requests, $request); | ||||||
| 			$content = null; |  | ||||||
| 			if ($event->response->hasError()) { |  | ||||||
| 				$error = $event->response->getError()->getMessage(); |  | ||||||
| 			} else { |  | ||||||
| 				$content = $event->response->getContent(); |  | ||||||
| 			} |  | ||||||
| 			call_user_func($function, $content, $error); |  | ||||||
| 		}); |  | ||||||
|  |  | ||||||
| 		$this->addRequest($request); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -8,10 +8,15 @@ use ManiaControl\Bills\BillManager; | |||||||
| use ManiaControl\Callbacks\CallbackListener; | use ManiaControl\Callbacks\CallbackListener; | ||||||
| use ManiaControl\Callbacks\CallbackManager; | use ManiaControl\Callbacks\CallbackManager; | ||||||
| use ManiaControl\Callbacks\Callbacks; | use ManiaControl\Callbacks\Callbacks; | ||||||
|  | use ManiaControl\Callbacks\EchoManager; | ||||||
| use ManiaControl\Callbacks\TimerListener; | use ManiaControl\Callbacks\TimerListener; | ||||||
| use ManiaControl\Callbacks\TimerManager; | use ManiaControl\Callbacks\TimerManager; | ||||||
| use ManiaControl\Commands\CommandListener; | use ManiaControl\Commands\CommandListener; | ||||||
| use ManiaControl\Commands\CommandManager; | use ManiaControl\Commands\CommandManager; | ||||||
|  | use ManiaControl\Communication\CommunicationAnswer; | ||||||
|  | use ManiaControl\Communication\CommunicationListener; | ||||||
|  | use ManiaControl\Communication\CommunicationManager; | ||||||
|  | use ManiaControl\Communication\CommunicationMethods; | ||||||
| use ManiaControl\Configurator\Configurator; | use ManiaControl\Configurator\Configurator; | ||||||
| use ManiaControl\Database\Database; | use ManiaControl\Database\Database; | ||||||
| use ManiaControl\Files\AsynchronousFileReader; | use ManiaControl\Files\AsynchronousFileReader; | ||||||
| @@ -38,11 +43,11 @@ use Maniaplanet\DedicatedServer\Xmlrpc\TransportException; | |||||||
|  * @copyright 2014-2015 ManiaControl Team |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  */ |  */ | ||||||
| class ManiaControl implements CallbackListener, CommandListener, TimerListener { | class ManiaControl implements CallbackListener, CommandListener, TimerListener, CommunicationListener { | ||||||
| 	/* | 	/* | ||||||
| 	 * Constants | 	 * Constants | ||||||
| 	 */ | 	 */ | ||||||
| 	const VERSION                     = '0.155'; | 	const VERSION                     = '0.163'; | ||||||
| 	const API_VERSION                 = '2013-04-16'; | 	const API_VERSION                 = '2013-04-16'; | ||||||
| 	const MIN_DEDIVERSION             = '2014-04-02_18_00'; | 	const MIN_DEDIVERSION             = '2014-04-02_18_00'; | ||||||
| 	const SCRIPT_TIMEOUT              = 10; | 	const SCRIPT_TIMEOUT              = 10; | ||||||
| @@ -164,6 +169,10 @@ class ManiaControl implements CallbackListener, CommandListener, TimerListener { | |||||||
| 	 */ | 	 */ | ||||||
| 	private $requestQuitMessage = null; | 	private $requestQuitMessage = null; | ||||||
|  |  | ||||||
|  | 	/** @var EchoManager $echoManager */ | ||||||
|  | 	private $echoManager          = null; | ||||||
|  | 	private $communicationManager = null; | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Construct a new ManiaControl instance | 	 * Construct a new ManiaControl instance | ||||||
| 	 */ | 	 */ | ||||||
| @@ -176,6 +185,8 @@ class ManiaControl implements CallbackListener, CommandListener, TimerListener { | |||||||
|  |  | ||||||
| 		// Load ManiaControl Modules | 		// Load ManiaControl Modules | ||||||
| 		$this->callbackManager       = new CallbackManager($this); | 		$this->callbackManager       = new CallbackManager($this); | ||||||
|  | 		$this->echoManager           = new EchoManager($this); | ||||||
|  | 		$this->communicationManager  = new CommunicationManager($this); | ||||||
| 		$this->timerManager          = new TimerManager($this); | 		$this->timerManager          = new TimerManager($this); | ||||||
| 		$this->database              = new Database($this); | 		$this->database              = new Database($this); | ||||||
| 		$this->fileReader            = new AsynchronousFileReader($this); | 		$this->fileReader            = new AsynchronousFileReader($this); | ||||||
| @@ -194,6 +205,7 @@ class ManiaControl implements CallbackListener, CommandListener, TimerListener { | |||||||
| 		$this->pluginManager         = new PluginManager($this); | 		$this->pluginManager         = new PluginManager($this); | ||||||
| 		$this->updateManager         = new UpdateManager($this); | 		$this->updateManager         = new UpdateManager($this); | ||||||
|  |  | ||||||
|  |  | ||||||
| 		$this->getErrorHandler()->init(); | 		$this->getErrorHandler()->init(); | ||||||
|  |  | ||||||
| 		// Permissions | 		// Permissions | ||||||
| @@ -207,6 +219,18 @@ class ManiaControl implements CallbackListener, CommandListener, TimerListener { | |||||||
|  |  | ||||||
| 		// Check connection every 30 seconds | 		// Check connection every 30 seconds | ||||||
| 		$this->getTimerManager()->registerTimerListening($this, 'checkConnection', 1000 * 30); | 		$this->getTimerManager()->registerTimerListening($this, 'checkConnection', 1000 * 30); | ||||||
|  |  | ||||||
|  | 		// Communication Methods | ||||||
|  | 		$this->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::RESTART_MANIA_CONTROL, $this, function ($data) { | ||||||
|  | 			//Delay Shutdown to send answer first | ||||||
|  | 			$this->getTimerManager()->registerOneTimeListening($this, function () use ($data) { | ||||||
|  | 				if (is_object($data) && property_exists($data, "message")) { | ||||||
|  | 					$this->restart($data->message); | ||||||
|  | 				} | ||||||
|  | 				$this->restart(); | ||||||
|  | 			}, 3000); | ||||||
|  | 			return new CommunicationAnswer(); | ||||||
|  | 		}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -278,6 +302,24 @@ class ManiaControl implements CallbackListener, CommandListener, TimerListener { | |||||||
| 		return $this->callbackManager; | 		return $this->callbackManager; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Return the echo manager | ||||||
|  | 	 * | ||||||
|  | 	 * @return EchoManager | ||||||
|  | 	 */ | ||||||
|  | 	public function getEchoManager() { | ||||||
|  | 		return $this->echoManager; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Return the socket manager | ||||||
|  | 	 * | ||||||
|  | 	 * @return CommunicationManager | ||||||
|  | 	 */ | ||||||
|  | 	public function getCommunicationManager() { | ||||||
|  | 		return $this->communicationManager; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Return the chat | 	 * Return the chat | ||||||
| 	 * | 	 * | ||||||
| @@ -465,6 +507,9 @@ class ManiaControl implements CallbackListener, CommandListener, TimerListener { | |||||||
| 	 * @param string $message | 	 * @param string $message | ||||||
| 	 */ | 	 */ | ||||||
| 	public function restart($message = null) { | 	public function restart($message = null) { | ||||||
|  | 		// Trigger callback on Restart | ||||||
|  | 		$this->getCallbackManager()->triggerCallback(Callbacks::ONRESTART); | ||||||
|  |  | ||||||
| 		// Announce restart | 		// Announce restart | ||||||
| 		try { | 		try { | ||||||
| 			$this->getChat()->sendInformation('Restarting ManiaControl...'); | 			$this->getChat()->sendInformation('Restarting ManiaControl...'); | ||||||
|   | |||||||
| @@ -130,14 +130,18 @@ class ManiaExchangeList implements CallbackListener, ManialinkPageAnswerListener | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// search for matching maps | 		//Search the Maps | ||||||
| 		$this->maniaControl->getMapManager()->getMXManager()->fetchMapsAsync(function (array $maps) use (&$player) { | 		$mxSearch = new ManiaExchangeMapSearch($this->maniaControl); | ||||||
|  | 		$mxSearch->setAuthorName($author); | ||||||
|  | 		$mxSearch->setEnvironments($environment); | ||||||
|  | 		$mxSearch->setMapName($searchString); | ||||||
|  | 		$mxSearch->fetchMapsAsync(function (array $maps) use (&$player) { | ||||||
| 			if (!$maps) { | 			if (!$maps) { | ||||||
| 				$this->maniaControl->getChat()->sendError('No maps found, or MX is down!', $player->login); | 				$this->maniaControl->getChat()->sendError('No maps found, or MX is down!', $player->login); | ||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| 			$this->showManiaExchangeList($maps, $player); | 			$this->showManiaExchangeList($maps, $player); | ||||||
| 		}, $searchString, $author, $environment); | 		}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ use ManiaControl\Maps\MapManager; | |||||||
| use Maniaplanet\DedicatedServer\Xmlrpc\GameModeException; | use Maniaplanet\DedicatedServer\Xmlrpc\GameModeException; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Mania Exchange Info Searcher Class |  * Mania Exchange Manager Class | ||||||
|  * |  * | ||||||
|  * @author    ManiaControl Team <mail@maniacontrol.com> |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  * @copyright 2014-2015 ManiaControl Team |  * @copyright 2014-2015 ManiaControl Team | ||||||
| @@ -18,8 +18,9 @@ use Maniaplanet\DedicatedServer\Xmlrpc\GameModeException; | |||||||
| class ManiaExchangeManager { | class ManiaExchangeManager { | ||||||
| 	/* | 	/* | ||||||
| 	 * Constants | 	 * Constants | ||||||
|  | 	 * @deprecated SEARCH Constants | ||||||
| 	 */ | 	 */ | ||||||
| 	//Search others | 	//Search orders (prior parameter) http://api.mania-exchange.com/documents/enums#orderings | ||||||
| 	const SEARCH_ORDER_NONE               = -1; | 	const SEARCH_ORDER_NONE               = -1; | ||||||
| 	const SEARCH_ORDER_TRACK_NAME         = 0; | 	const SEARCH_ORDER_TRACK_NAME         = 0; | ||||||
| 	const SEARCH_ORDER_AUTHOR             = 1; | 	const SEARCH_ORDER_AUTHOR             = 1; | ||||||
| @@ -269,9 +270,9 @@ class ManiaExchangeManager { | |||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @deprecated | 	 * @deprecated | ||||||
| 	 * @see \ManiaControl\ManiaExchange\ManiaExchangeManager::fetchMapsAsync() | 	 * @see \ManiaControl\ManiaExchange\ManiaExchangeMapSearch | ||||||
| 	 */ | 	 */ | ||||||
| 	public function getMapsAsync(callable $function, $name = '', $author = '', $env = '', $maxMapsReturned = 100, $searchOrder = self::SEARCH_ORDER_UPDATED_NEWEST) { | 	public function getMapsAsync(callable $function, $name = '', $author = '', $env = '', $maxMapsReturned = 100, $searchOrder = ManiaExchangeMapSearch::SEARCH_ORDER_UPDATED_NEWEST) { | ||||||
| 		$this->fetchMapsAsync($function, $name, $author, $env, $maxMapsReturned, $searchOrder); | 		$this->fetchMapsAsync($function, $name, $author, $env, $maxMapsReturned, $searchOrder); | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
| @@ -285,73 +286,22 @@ class ManiaExchangeManager { | |||||||
| 	 * @param string   $env | 	 * @param string   $env | ||||||
| 	 * @param int      $maxMapsReturned | 	 * @param int      $maxMapsReturned | ||||||
| 	 * @param int      $searchOrder | 	 * @param int      $searchOrder | ||||||
|  | 	 * | ||||||
|  | 	 * @deprecated | ||||||
|  | 	 * @see \ManiaControl\ManiaExchange\ManiaExchangeMapSearch | ||||||
| 	 */ | 	 */ | ||||||
| 	public function fetchMapsAsync(callable $function, $name = '', $author = '', $env = '', $maxMapsReturned = 100, $searchOrder = self::SEARCH_ORDER_UPDATED_NEWEST) { | 	public function fetchMapsAsync(callable $function, $name = '', $author = '', $env = '', $maxMapsReturned = 100, $sortOrder = ManiaExchangeMapSearch::SEARCH_ORDER_UPDATED_NEWEST) { | ||||||
| 		// TODO: remove $env because it's not really used? | 		$mapSearch = new ManiaExchangeMapSearch($this->maniaControl); | ||||||
|  | 		$mapSearch->setMapName($name); | ||||||
|  | 		$mapSearch->setAuthorName($author); | ||||||
|  | 		$mapSearch->setMapLimit($maxMapsReturned); | ||||||
|  | 		$mapSearch->setPrioritySortOrder($sortOrder); | ||||||
|  |  | ||||||
| 		// Get Title Id | 		if($env){ | ||||||
| 		$titleId     = $this->maniaControl->getServer()->titleId; | 			$mapSearch->setEnvironments($env); | ||||||
| 		$titlePrefix = $this->maniaControl->getMapManager()->getCurrentMap()->getGame(); |  | ||||||
|  |  | ||||||
| 		// compile search URL |  | ||||||
| 		$url = 'http://' . $titlePrefix . '.mania-exchange.com/tracksearch2/search?api=on'; |  | ||||||
|  |  | ||||||
| 		$game      = explode('@', $titleId); |  | ||||||
| 		$envNumber = $this->getEnvironment($game[0]); |  | ||||||
| 		if ($env || $envNumber > -1) { |  | ||||||
| 			$url .= '&environments=' . $envNumber; |  | ||||||
| 		} |  | ||||||
| 		if ($name) { |  | ||||||
| 			$url .= '&trackname=' . str_replace(" ", "%20", $name); |  | ||||||
| 		} |  | ||||||
| 		if ($author) { |  | ||||||
| 			$url .= '&author=' . $author; |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		$url .= '&priord=' . $searchOrder; | 		$mapSearch->fetchMapsAsync($function); | ||||||
| 		$url .= '&limit=' . $maxMapsReturned; |  | ||||||
|  |  | ||||||
| 		if ($titlePrefix !== "tm") { |  | ||||||
| 			$url .= '&minexebuild=' . self::MIN_EXE_BUILD; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Get MapTypes |  | ||||||
| 		try { |  | ||||||
| 			$scriptInfos = $this->maniaControl->getClient()->getModeScriptInfo(); |  | ||||||
| 			$mapTypes    = $scriptInfos->compatibleMapTypes; |  | ||||||
| 			$url .= '&mtype=' . $mapTypes; |  | ||||||
| 		} catch (GameModeException $e) { |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		$this->maniaControl->getFileReader()->loadFile($url, function ($mapInfo, $error) use (&$function, $titlePrefix) { |  | ||||||
| 			if ($error) { |  | ||||||
| 				trigger_error($error); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			$mxMapList = json_decode($mapInfo); |  | ||||||
|  |  | ||||||
| 			if (!isset($mxMapList->results)) { |  | ||||||
| 				trigger_error('Cannot decode searched JSON data'); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			$mxMapList = $mxMapList->results; |  | ||||||
|  |  | ||||||
| 			if ($mxMapList === null) { |  | ||||||
| 				trigger_error('Cannot decode searched JSON data'); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			$maps = array(); |  | ||||||
| 			foreach ($mxMapList as $map) { |  | ||||||
| 				if (!empty($map)) { |  | ||||||
| 					array_push($maps, new MXMapInfo($titlePrefix, $map)); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			call_user_func($function, $maps); |  | ||||||
| 		}, AsynchronousFileReader::CONTENT_TYPE_JSON); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
|   | |||||||
							
								
								
									
										437
									
								
								core/ManiaExchange/ManiaExchangeMapSearch.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										437
									
								
								core/ManiaExchange/ManiaExchangeMapSearch.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,437 @@ | |||||||
|  | <?php | ||||||
|  | namespace ManiaControl\ManiaExchange; | ||||||
|  |  | ||||||
|  | use ManiaControl\Files\AsynchronousFileReader; | ||||||
|  | use ManiaControl\ManiaControl; | ||||||
|  | use Maniaplanet\DedicatedServer\Xmlrpc\GameModeException; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Mania Exchange Map Searching Class | ||||||
|  |  * | ||||||
|  |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  |  */ | ||||||
|  | class ManiaExchangeMapSearch { | ||||||
|  | 	//Search orders (prior parameter) http://api.mania-exchange.com/documents/enums#orderings | ||||||
|  | 	const SEARCH_ORDER_NONE               = -1; | ||||||
|  | 	const SEARCH_ORDER_TRACK_NAME         = 0; | ||||||
|  | 	const SEARCH_ORDER_AUTHOR             = 1; | ||||||
|  | 	const SEARCH_ORDER_UPLOADED_NEWEST    = 2; | ||||||
|  | 	const SEARCH_ORDER_UPLOADED_OLDEST    = 3; | ||||||
|  | 	const SEARCH_ORDER_UPDATED_NEWEST     = 4; | ||||||
|  | 	const SEARCH_ORDER_UPDATED_OLDEST     = 5; | ||||||
|  | 	const SEARCH_ORDER_ACTIVITY_LATEST    = 6; | ||||||
|  | 	const SEARCH_ORDER_ACTIVITY_OLDEST    = 7; | ||||||
|  | 	const SEARCH_ORDER_AWARDS_MOST        = 8; | ||||||
|  | 	const SEARCH_ORDER_AWARDS_LEAST       = 9; | ||||||
|  | 	const SEARCH_ORDER_COMMENTS_MOST      = 10; | ||||||
|  | 	const SEARCH_ORDER_COMMENTS_LEAST     = 11; | ||||||
|  | 	const SEARCH_ORDER_DIFFICULTY_EASIEST = 12; | ||||||
|  | 	const SEARCH_ORDER_DIFFICULTY_HARDEST = 13; | ||||||
|  | 	const SEARCH_ORDER_LENGTH_SHORTEST    = 14; | ||||||
|  | 	const SEARCH_ORDER_LENGTH_LONGEST     = 15; | ||||||
|  | 	const SEARCH_ORDER_TRACK_VALUE_LTH    = 24; | ||||||
|  | 	const SEARCH_ORDER_TRACK_VALUE_HTL    = 25; | ||||||
|  | 	const SEARCH_ORDER_ONLINE_RATING_LTH  = 26; | ||||||
|  | 	const SEARCH_ORDER_ONLINE_RATING_HTL  = 27; | ||||||
|  |  | ||||||
|  | 	//Special Search Orders (mode parameter): http://api.mania-exchange.com/documents/enums#modes | ||||||
|  | 	const SEARCH_ORDER_SPECIAL_DEFAULT                  = 0; | ||||||
|  | 	const SEARCH_ORDER_SPECIAL_USER_TRACKS              = 1; | ||||||
|  | 	const SEARCH_ORDER_SPECIAL_LATEST_TRACKS            = 2; | ||||||
|  | 	const SEARCH_ORDER_SPECIAL_RECENTLY_AWARDED         = 3; | ||||||
|  | 	const SEARCH_ORDER_SPECIAL_BEST_OF_WEEK_AWARDS      = 4; | ||||||
|  | 	const SEARCH_ORDER_SPECIAL_BEST_OF_MONTH_AWARDS     = 5; | ||||||
|  | 	const SEARCH_ORDER_SPECIAL_MX_SUPPORTER_TRACKS      = 10; | ||||||
|  | 	const SEARCH_ORDER_SPECIAL_DUO_ACCOUNT_TRACKS       = 11; | ||||||
|  | 	const SEARCH_ORDER_SPECIAL_MOST_COMPETITIVE_WEEK    = 19; | ||||||
|  | 	const SEARCH_ORDER_SPECIAL_MOST_COMPETITIVE_MONTH   = 20; | ||||||
|  | 	const SEARCH_ORDER_SPECIAL_BEST_ONLINE_RATING_WEEK  = 21; | ||||||
|  | 	const SEARCH_ORDER_SPECIAL_BEST_ONLINE_RATING_MONTH = 22; | ||||||
|  |  | ||||||
|  | 	//Private Properties | ||||||
|  | 	private $url         = ""; | ||||||
|  | 	private $titlePrefix = ""; | ||||||
|  |  | ||||||
|  | 	private $mode              = null; | ||||||
|  | 	private $mapName           = null; | ||||||
|  | 	private $authorName        = null; | ||||||
|  | 	private $mod               = null; | ||||||
|  | 	private $authorId          = null; | ||||||
|  | 	private $maniaScriptType   = null; | ||||||
|  | 	private $titlePack         = null; | ||||||
|  | 	private $replayType        = null; | ||||||
|  | 	private $style             = null; | ||||||
|  | 	private $length            = null; | ||||||
|  | 	private $lengthOperator    = null; | ||||||
|  | 	private $priorityOrder     = null; | ||||||
|  | 	private $secondaryOrder    = null; | ||||||
|  | 	private $environments      = null; | ||||||
|  | 	private $vehicles          = null; | ||||||
|  | 	private $page              = null; | ||||||
|  | 	private $mapLimit          = null; | ||||||
|  | 	private $unreleased        = null; | ||||||
|  | 	private $mapGroup          = null; | ||||||
|  | 	private $commentsMinLength = null; | ||||||
|  | 	private $customScreenshot  = null; | ||||||
|  | 	private $minExeBuild       = null; | ||||||
|  | 	private $envMix            = null; | ||||||
|  | 	private $ghostBlocks       = null; | ||||||
|  | 	private $embeddedObjects   = null; | ||||||
|  |  | ||||||
|  | 	/** @var ManiaControl $maniaControl */ | ||||||
|  | 	private $maniaControl = null; | ||||||
|  |  | ||||||
|  | 	//TODO use class by mxlist | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Construct map manager | ||||||
|  | 	 * | ||||||
|  | 	 * @param \ManiaControl\ManiaControl $maniaControl | ||||||
|  | 	 */ | ||||||
|  | 	public function __construct(ManiaControl $maniaControl) { | ||||||
|  | 		$this->maniaControl = $maniaControl; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		$titleId           = $this->maniaControl->getServer()->titleId; | ||||||
|  | 		$this->titlePrefix = $this->maniaControl->getMapManager()->getCurrentMap()->getGame(); | ||||||
|  |  | ||||||
|  | 		$this->url = 'https://' . $this->titlePrefix . '.mania-exchange.com/tracksearch2/search?api=on'; | ||||||
|  |  | ||||||
|  | 		//Set some defaults: | ||||||
|  | 		$this->mapLimit      = 100; | ||||||
|  | 		$this->priorityOrder = self::SEARCH_ORDER_UPDATED_NEWEST; | ||||||
|  |  | ||||||
|  | 		//Set Min Exe Build Default for games which are not Trackmania | ||||||
|  | 		if ($this->titlePrefix !== "tm") { | ||||||
|  | 			$this->minExeBuild = ManiaExchangeManager::MIN_EXE_BUILD; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		//Set MapTypes | ||||||
|  | 		try { | ||||||
|  | 			$scriptInfos           = $this->maniaControl->getClient()->getModeScriptInfo(); | ||||||
|  | 			$mapTypes              = $scriptInfos->compatibleMapTypes; | ||||||
|  | 			$this->maniaScriptType = $mapTypes; | ||||||
|  | 		} catch (GameModeException $e) { | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		//Set Environments on Trackmania | ||||||
|  | 		$game      = explode('@', $titleId); | ||||||
|  | 		$envNumber = $this->getEnvironment($game[0]); //TODO enviroment as constant | ||||||
|  | 		if ($envNumber > -1) { | ||||||
|  | 			$this->environments = $envNumber; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Fetch a MapList Asynchronously | ||||||
|  | 	 * | ||||||
|  | 	 * @param callable $function | ||||||
|  | 	 */ | ||||||
|  | 	public function fetchMapsAsync(callable $function) { | ||||||
|  | 		// compile search URL | ||||||
|  | 		$parameters = ""; | ||||||
|  |  | ||||||
|  | 		if ($this->mode) { | ||||||
|  | 			$parameters .= "&mode=" . $this->mode; | ||||||
|  | 		} | ||||||
|  | 		if ($this->mapName) { | ||||||
|  | 			$parameters .= "&trackname=" . urlencode($this->mapName); | ||||||
|  | 		} | ||||||
|  | 		if ($this->authorName) { | ||||||
|  | 			$parameters .= "&author=" . urlencode($this->authorName); | ||||||
|  | 		} | ||||||
|  | 		if ($this->mod) { | ||||||
|  | 			$parameters .= "&mod=" . urlencode($this->mod); | ||||||
|  | 		} | ||||||
|  | 		if ($this->authorId) { | ||||||
|  | 			$parameters .= "&authorid= " . $this->authorId; | ||||||
|  | 		} | ||||||
|  | 		if ($this->maniaScriptType) { | ||||||
|  | 			$parameters .= "&mtype=" . urlencode($this->maniaScriptType); | ||||||
|  | 		} | ||||||
|  | 		if ($this->titlePack) { | ||||||
|  | 			$parameters .= "&tpack=" . urlencode($this->titlePack); | ||||||
|  | 		} | ||||||
|  | 		if ($this->replayType) { | ||||||
|  | 			$parameters .= "&rytpe=" . $this->replayType; | ||||||
|  | 		} | ||||||
|  | 		if ($this->style) { | ||||||
|  | 			$parameters .= "&style=" . $this->style; | ||||||
|  | 		} | ||||||
|  | 		if ($this->length) { | ||||||
|  | 			$parameters .= "&length=" . $this->length; | ||||||
|  | 		} | ||||||
|  | 		if ($this->lengthOperator) { | ||||||
|  | 			$parameters .= "&lengthop=" . $this->lengthOperator; | ||||||
|  | 		} | ||||||
|  | 		if ($this->priorityOrder) { | ||||||
|  | 			$parameters .= "&priord=" . $this->priorityOrder; | ||||||
|  | 		} | ||||||
|  | 		if ($this->secondaryOrder) { | ||||||
|  | 			$parameters .= "&secord=" . $this->secondaryOrder; | ||||||
|  | 		} | ||||||
|  | 		if ($this->environments) { | ||||||
|  | 			$parameters .= "&environemtns=" . $this->environments; | ||||||
|  | 		} | ||||||
|  | 		if ($this->vehicles) { | ||||||
|  | 			$parameters .= "&vehicles=" . $this->vehicles; | ||||||
|  | 		} | ||||||
|  | 		if ($this->page) { | ||||||
|  | 			$parameters .= "&page=" . $this->page; | ||||||
|  | 		} | ||||||
|  | 		if ($this->mapLimit) { | ||||||
|  | 			$parameters .= "&limit=" . $this->mapLimit; | ||||||
|  | 		} | ||||||
|  | 		if (isset($this->unreleased)) { | ||||||
|  | 			$parameters .= "&unreleased=" . (int) $this->unreleased; | ||||||
|  | 		} | ||||||
|  | 		if ($this->mapGroup) { | ||||||
|  | 			$parameters .= "&mapgroup=" . $this->mapGroup; | ||||||
|  | 		} | ||||||
|  | 		if ($this->commentsMinLength) { | ||||||
|  | 			$parameters .= "&commentsminlength=" . $this->commentsMinLength; | ||||||
|  | 		} | ||||||
|  | 		if (isset($this->customScreenshot)) { | ||||||
|  | 			$parameters .= "&customscreenshot=" . $this->customScreenshot; | ||||||
|  | 		} | ||||||
|  | 		if ($this->minExeBuild) { | ||||||
|  | 			$parameters .= "&minexebuild=" . urlencode($this->minExeBuild); | ||||||
|  | 		} | ||||||
|  | 		if (isset($this->envMix)) { | ||||||
|  | 			$parameters .= "&envmix=" . (int) $this->envMix; | ||||||
|  | 		} | ||||||
|  | 		if (isset($this->ghostBlocks)) { | ||||||
|  | 			$parameters .= "&ghostblocks=" . (int) $this->ghostBlocks; | ||||||
|  | 		} | ||||||
|  | 		if (isset($this->embeddedObjects)) { | ||||||
|  | 			$parameters .= "&embeddedobjects=" . (int) $this->embeddedObjects; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getFileReader()->loadFile($this->url . $parameters, function ($mapInfo, $error) use (&$function) { | ||||||
|  | 			if ($error) { | ||||||
|  | 				trigger_error($error); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$mxMapList = json_decode($mapInfo); | ||||||
|  |  | ||||||
|  | 			if (!isset($mxMapList->results)) { | ||||||
|  | 				trigger_error('Cannot decode searched JSON data'); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$mxMapList = $mxMapList->results; | ||||||
|  | 			 | ||||||
|  | 			if ($mxMapList === null) { | ||||||
|  | 				trigger_error('Cannot decode searched JSON data'); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$maps = array(); | ||||||
|  | 			foreach ($mxMapList as $map) { | ||||||
|  | 				if (!empty($map)) { | ||||||
|  | 					array_push($maps, new MXMapInfo($this->titlePrefix, $map)); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			call_user_func($function, $maps); | ||||||
|  | 		}, AsynchronousFileReader::CONTENT_TYPE_JSON); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Get the Current Environment by String | ||||||
|  | 	 * | ||||||
|  | 	 * @param string $env | ||||||
|  | 	 * @return int | ||||||
|  | 	 */ | ||||||
|  | 	private function getEnvironment($env) { | ||||||
|  | 		switch ($env) { | ||||||
|  | 			case 'TMCanyon': | ||||||
|  | 				return 1; | ||||||
|  | 			case 'TMStadium': | ||||||
|  | 				return 2; | ||||||
|  | 			case 'TMValley': | ||||||
|  | 				return 3; | ||||||
|  | 			default: | ||||||
|  | 				return -1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param int $mode | ||||||
|  | 	 */ | ||||||
|  | 	public function setMode($mode) { | ||||||
|  | 		$this->mode = $mode; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param string $mapName | ||||||
|  | 	 */ | ||||||
|  | 	public function setMapName($mapName) { | ||||||
|  | 		$this->mapName = $mapName; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param string $authorName | ||||||
|  | 	 */ | ||||||
|  | 	public function setAuthorName($authorName) { | ||||||
|  | 		$this->authorName = $authorName; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param int $authorId | ||||||
|  | 	 */ | ||||||
|  | 	public function setAuthorId($authorId) { | ||||||
|  | 		$this->authorId = $authorId; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param string $maniaScriptType | ||||||
|  | 	 */ | ||||||
|  | 	public function setManiaScriptType($maniaScriptType) { | ||||||
|  | 		$this->maniaScriptType = $maniaScriptType; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param string $mod | ||||||
|  | 	 */ | ||||||
|  | 	public function setMod($mod) { | ||||||
|  | 		$this->mod = $mod; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param string $titlePack | ||||||
|  | 	 */ | ||||||
|  | 	public function setTitlePack($titlePack) { | ||||||
|  | 		$this->titlePack = $titlePack; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param int $replayType | ||||||
|  | 	 */ | ||||||
|  | 	public function setReplayType($replayType) { | ||||||
|  | 		$this->replayType = $replayType; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param int $length | ||||||
|  | 	 */ | ||||||
|  | 	public function setLength($length) { | ||||||
|  | 		$this->length = $length; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param int $style | ||||||
|  | 	 */ | ||||||
|  | 	public function setStyle($style) { | ||||||
|  | 		$this->style = $style; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param int $lengthOperator | ||||||
|  | 	 */ | ||||||
|  | 	public function setLengthOperator($lengthOperator) { | ||||||
|  | 		$this->lengthOperator = $lengthOperator; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param int $secondaryOrder | ||||||
|  | 	 */ | ||||||
|  | 	public function setSecondarySortOrder($secondaryOrder) { | ||||||
|  | 		$this->secondaryOrder = $secondaryOrder; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param int $priorityOrder | ||||||
|  | 	 */ | ||||||
|  | 	public function setPrioritySortOrder($priorityOrder) { | ||||||
|  | 		$this->priorityOrder = $priorityOrder; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param string $environments | ||||||
|  | 	 */ | ||||||
|  | 	public function setEnvironments($environments) { | ||||||
|  | 		$this->environments = $environments; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param int $page | ||||||
|  | 	 */ | ||||||
|  | 	public function setPage($page) { | ||||||
|  | 		$this->page = $page; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param string $vehicles | ||||||
|  | 	 */ | ||||||
|  | 	public function setVehicles($vehicles) { | ||||||
|  | 		$this->vehicles = $vehicles; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param bool $unreleased | ||||||
|  | 	 */ | ||||||
|  | 	public function setUnreleased($unreleased) { | ||||||
|  | 		$this->unreleased = $unreleased; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param int $mapGroup | ||||||
|  | 	 */ | ||||||
|  | 	public function setMapGroup($mapGroup) { | ||||||
|  | 		$this->mapGroup = $mapGroup; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param int $commentsMinLength | ||||||
|  | 	 */ | ||||||
|  | 	public function setCommentsMinLength($commentsMinLength) { | ||||||
|  | 		$this->commentsMinLength = $commentsMinLength; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param bool $customScreenshot | ||||||
|  | 	 */ | ||||||
|  | 	public function setCustomScreenshot($customScreenshot) { | ||||||
|  | 		$this->customScreenshot = $customScreenshot; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param bool $envMix | ||||||
|  | 	 */ | ||||||
|  | 	public function setEnvMix($envMix) { | ||||||
|  | 		$this->envMix = $envMix; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param string $minExeBuild | ||||||
|  | 	 */ | ||||||
|  | 	public function setMinExeBuild($minExeBuild) { | ||||||
|  | 		$this->minExeBuild = $minExeBuild; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param bool $ghostBlocks | ||||||
|  | 	 */ | ||||||
|  | 	public function setGhostBlocks($ghostBlocks) { | ||||||
|  | 		$this->ghostBlocks = $ghostBlocks; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param bool $embeddedObjects | ||||||
|  | 	 */ | ||||||
|  | 	public function setEmbeddedObjects($embeddedObjects) { | ||||||
|  | 		$this->embeddedObjects = $embeddedObjects; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param null $mapLimit | ||||||
|  | 	 */ | ||||||
|  | 	public function setMapLimit($mapLimit) { | ||||||
|  | 		$this->mapLimit = $mapLimit; | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -10,7 +10,7 @@ use ManiaControl\Players\Player; | |||||||
| use ManiaControl\Players\PlayerManager; | use ManiaControl\Players\PlayerManager; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Class managing the Custom UI in TrackMania |  * Class managing the Custom UI in ManiaPlanet | ||||||
|  * |  * | ||||||
|  * @author    ManiaControl Team <mail@maniacontrol.com> |  * @author    ManiaControl Team <mail@maniacontrol.com> | ||||||
|  * @copyright 2014-2015 ManiaControl Team |  * @copyright 2014-2015 ManiaControl Team | ||||||
|   | |||||||
| @@ -349,8 +349,11 @@ class ManialinkManager implements ManialinkPageAnswerListener, CallbackListener | |||||||
| 		return $success; | 		return $success; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Adds a line of labels | 	 * Adds a line of labels | ||||||
|  | 	 * LabelLine should be an array with the following structure: array(array(positions), array(texts)) | ||||||
|  | 	 * or array($text1 => $pos1, $text2 => $pos2 ...) | ||||||
| 	 * | 	 * | ||||||
| 	 * @param Frame $frame | 	 * @param Frame $frame | ||||||
| 	 * @param array $labelStrings | 	 * @param array $labelStrings | ||||||
| @@ -366,6 +369,33 @@ class ManialinkManager implements ManialinkPageAnswerListener, CallbackListener | |||||||
| 		$profile   = (isset($properties['profile']) ? $properties['profile'] : false); | 		$profile   = (isset($properties['profile']) ? $properties['profile'] : false); | ||||||
|  |  | ||||||
| 		$labels = array(); | 		$labels = array(); | ||||||
|  |  | ||||||
|  | 		//If you call LabelLine with array(array(positions), array(texts)) | ||||||
|  | 		if (count($labelStrings) == 2 && array_key_exists(0, $labelStrings) && array_key_exists(1, $labelStrings) && array_key_exists(0, $labelStrings[0]) && array_key_exists(0, $labelStrings[1])) { | ||||||
|  | 			$positions = $labelStrings[0]; | ||||||
|  | 			$texts     = $labelStrings[1]; | ||||||
|  |  | ||||||
|  | 			if (count($positions) != count($texts)) { | ||||||
|  | 				trigger_error("LabelLine Position length is not equal to Text Length", E_USER_ERROR); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			foreach ($positions as $key => $x) { | ||||||
|  | 				$label = new Label_Text(); | ||||||
|  | 				$frame->add($label); | ||||||
|  | 				$label->setHAlign($hAlign); | ||||||
|  | 				$label->setX($x); | ||||||
|  | 				$label->setStyle($style); | ||||||
|  | 				$label->setTextSize($textSize); | ||||||
|  | 				$label->setText($texts[$key]); | ||||||
|  | 				$label->setTextColor($textColor); | ||||||
|  |  | ||||||
|  | 				if ($profile) { | ||||||
|  | 					$label->addPlayerProfileFeature($profile); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				array_push($labels, $label); | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
| 			foreach ($labelStrings as $text => $x) { | 			foreach ($labelStrings as $text => $x) { | ||||||
| 				$label = new Label_Text(); | 				$label = new Label_Text(); | ||||||
| 				$frame->add($label); | 				$frame->add($label); | ||||||
| @@ -382,6 +412,7 @@ class ManialinkManager implements ManialinkPageAnswerListener, CallbackListener | |||||||
|  |  | ||||||
| 				array_push($labels, $label); | 				array_push($labels, $label); | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		return $labels; | 		return $labels; | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -161,6 +161,13 @@ class StyleManager { | |||||||
| 		$frame = new Frame(); | 		$frame = new Frame(); | ||||||
| 		$frame->setSize($width, $height)->setZ(45); //TODO place before scoreboards | 		$frame->setSize($width, $height)->setZ(45); //TODO place before scoreboards | ||||||
|  |  | ||||||
|  | 		//TODO remove: (just temporary fix for tm bug) | ||||||
|  | 		if ($this->maniaControl->getMapManager()->getCurrentMap()->getGame() === 'tm' | ||||||
|  | 		) { | ||||||
|  | 			$frame->setSize($width, $height)->setZ(32); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  |  | ||||||
| 		// Background Quad | 		// Background Quad | ||||||
| 		$backgroundQuad = new Quad(); | 		$backgroundQuad = new Quad(); | ||||||
| 		$frame->add($backgroundQuad); | 		$frame->add($backgroundQuad); | ||||||
|   | |||||||
| @@ -2,6 +2,9 @@ | |||||||
|  |  | ||||||
| namespace ManiaControl\Maps; | namespace ManiaControl\Maps; | ||||||
|  |  | ||||||
|  | use ManiaControl\Communication\CommunicationAnswer; | ||||||
|  | use ManiaControl\Communication\CommunicationListener; | ||||||
|  | use ManiaControl\Communication\CommunicationMethods; | ||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| use Maniaplanet\DedicatedServer\Xmlrpc\ChangeInProgressException; | use Maniaplanet\DedicatedServer\Xmlrpc\ChangeInProgressException; | ||||||
|  |  | ||||||
| @@ -12,7 +15,7 @@ use Maniaplanet\DedicatedServer\Xmlrpc\ChangeInProgressException; | |||||||
|  * @copyright 2014-2015 ManiaControl Team |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  */ |  */ | ||||||
| class MapActions { | class MapActions implements CommunicationListener { | ||||||
| 	/* | 	/* | ||||||
| 	 * Private properties | 	 * Private properties | ||||||
| 	 */ | 	 */ | ||||||
| @@ -26,12 +29,79 @@ class MapActions { | |||||||
| 	 */ | 	 */ | ||||||
| 	public function __construct(ManiaControl $maniaControl) { | 	public function __construct(ManiaControl $maniaControl) { | ||||||
| 		$this->maniaControl = $maniaControl; | 		$this->maniaControl = $maniaControl; | ||||||
|  |  | ||||||
|  | 		//Communication Listenings | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::SKIP_MAP, $this, function ($data) { | ||||||
|  | 			$success = $this->skipMap(); | ||||||
|  | 			return new CommunicationAnswer(array("success" => $success)); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::RESTART_MAP, $this, function ($data) { | ||||||
|  | 			$success = $this->restartMap(); | ||||||
|  | 			return new CommunicationAnswer(array("success" => $success)); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::SKIP_TO_MAP, $this, function ($data) { | ||||||
|  | 			if (!is_object($data)) { | ||||||
|  | 				return new CommunicationAnswer("Error in provided Data", true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (property_exists($data, "mxId")) { | ||||||
|  | 				$success = $this->skipToMapByMxId($data->mxId); | ||||||
|  | 			} else if (property_exists($data, "mapUid")) { | ||||||
|  | 				$success = $this->skipToMapByUid($data->mapUid); | ||||||
|  | 			} else { | ||||||
|  | 				return new CommunicationAnswer("No mxId or mapUid provided.", true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			return new CommunicationAnswer(array("success" => $success)); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Skips to a Map by its given UID | ||||||
|  | 	 * | ||||||
|  | 	 * @param String $uid | ||||||
|  | 	 * @return bool | ||||||
|  | 	 */ | ||||||
|  | 	public function skipToMapByUid($uid) { | ||||||
|  | 		//TODO message | ||||||
|  | 		//Check if Map exists | ||||||
|  | 		$map = $this->maniaControl->getMapManager()->getMapByUid($uid); | ||||||
|  | 		if (!$map) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		try { | ||||||
|  | 			$this->maniaControl->getClient()->jumpToMapIdent($uid); | ||||||
|  | 		} catch (ChangeInProgressException $e) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Skips to a Map by its given MxId | ||||||
|  | 	 * | ||||||
|  | 	 * @param int $mxId | ||||||
|  | 	 * @return bool | ||||||
|  | 	 */ | ||||||
|  | 	public function skipToMapByMxId($mxId) { | ||||||
|  | 		$map = $this->maniaControl->getMapManager()->getMapByMxId($mxId); | ||||||
|  | 		if (!$map) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		return $this->skipToMapByUid($map->uid); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Skip the current Map | 	 * Skip the current Map | ||||||
|  | 	 * | ||||||
|  | 	 * @return bool | ||||||
| 	 */ | 	 */ | ||||||
| 	public function skipMap() { | 	public function skipMap() { | ||||||
|  | 		//TODO message | ||||||
|  |  | ||||||
| 		// Force an EndMap on the MapQueue to set the next Map | 		// Force an EndMap on the MapQueue to set the next Map | ||||||
| 		$this->maniaControl->getMapManager()->getMapQueue()->endMap(null); | 		$this->maniaControl->getMapManager()->getMapQueue()->endMap(null); | ||||||
|  |  | ||||||
| @@ -42,6 +112,27 @@ class MapActions { | |||||||
| 		try { | 		try { | ||||||
| 			$this->maniaControl->getClient()->nextMap(); | 			$this->maniaControl->getClient()->nextMap(); | ||||||
| 		} catch (ChangeInProgressException $e) { | 		} catch (ChangeInProgressException $e) { | ||||||
| 		} | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Restarts the Current Map | ||||||
|  | 	 * | ||||||
|  | 	 * @return bool | ||||||
|  | 	 */ | ||||||
|  | 	public function restartMap() { | ||||||
|  | 		//TODO message | ||||||
|  |  | ||||||
|  | 		//Restarts the Current Map | ||||||
|  | 		try { | ||||||
|  | 			$this->maniaControl->getClient()->restartMap(); | ||||||
|  | 		} catch (ChangeInProgressException $e) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -437,7 +437,17 @@ class MapCommands implements CommandListener, ManialinkPageAnswerListener, Callb | |||||||
| 	private function showMapListKarma($best, Player $player) { | 	private function showMapListKarma($best, Player $player) { | ||||||
| 		/** @var \MCTeam\KarmaPlugin $karmaPlugin */ | 		/** @var \MCTeam\KarmaPlugin $karmaPlugin */ | ||||||
| 		$karmaPlugin    = $this->maniaControl->getPluginManager()->getPlugin(MapList::DEFAULT_KARMA_PLUGIN); | 		$karmaPlugin    = $this->maniaControl->getPluginManager()->getPlugin(MapList::DEFAULT_KARMA_PLUGIN); | ||||||
|  | 		$displayMxKarma = $this->maniaControl->getSettingManager()->getSettingValue($karmaPlugin, $karmaPlugin::SETTING_WIDGET_DISPLAY_MX); | ||||||
|  |  | ||||||
| 		if ($karmaPlugin) { | 		if ($karmaPlugin) { | ||||||
|  | 			//Sort by Mx Karma in Maplist | ||||||
|  | 			if ($displayMxKarma) { //TODO | ||||||
|  |  | ||||||
|  | 				//Sort by Local Karma in Maplist | ||||||
|  | 			} else { | ||||||
|  |  | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			$maps    = $this->maniaControl->getMapManager()->getMaps(); | 			$maps    = $this->maniaControl->getMapManager()->getMaps(); | ||||||
| 			$mapList = array(); | 			$mapList = array(); | ||||||
| 			foreach ($maps as $map) { | 			foreach ($maps as $map) { | ||||||
|   | |||||||
| @@ -441,9 +441,20 @@ class MapList implements ManialinkPageAnswerListener, CallbackListener { | |||||||
|  |  | ||||||
| 			// Display Karma bar | 			// Display Karma bar | ||||||
| 			if ($karmaPlugin) { | 			if ($karmaPlugin) { | ||||||
|  | 				$displayMxKarma = $this->maniaControl->getSettingManager()->getSettingValue($karmaPlugin, $karmaPlugin::SETTING_WIDGET_DISPLAY_MX); | ||||||
|  |  | ||||||
|  | 				//Display Mx Karma | ||||||
|  | 				if ($displayMxKarma && $map->mx) { | ||||||
|  | 					$karma = $map->mx->ratingVoteAverage / 100; | ||||||
|  | 					$votes = array("count" => $map->mx->ratingVoteCount); | ||||||
|  |  | ||||||
|  | 					//Display Local Karma | ||||||
|  | 				} else { | ||||||
| 					$karma = $karmaPlugin->getMapKarma($map); | 					$karma = $karmaPlugin->getMapKarma($map); | ||||||
| 					$votes = $karmaPlugin->getMapVotes($map); | 					$votes = $karmaPlugin->getMapVotes($map); | ||||||
| 				if (is_numeric($karma)) { | 				} | ||||||
|  |  | ||||||
|  | 				if (is_numeric($karma) && $votes['count'] > 0) { | ||||||
| 					if ($this->maniaControl->getSettingManager()->getSettingValue($karmaPlugin, $karmaPlugin::SETTING_NEWKARMA) | 					if ($this->maniaControl->getSettingManager()->getSettingValue($karmaPlugin, $karmaPlugin::SETTING_NEWKARMA) | ||||||
| 					) { | 					) { | ||||||
| 						$karmaText = '  ' . round($karma * 100.) . '% (' . $votes['count'] . ')'; | 						$karmaText = '  ' . round($karma * 100.) . '% (' . $votes['count'] . ')'; | ||||||
|   | |||||||
| @@ -6,6 +6,9 @@ use ManiaControl\Admin\AuthenticationManager; | |||||||
| use ManiaControl\Callbacks\CallbackListener; | use ManiaControl\Callbacks\CallbackListener; | ||||||
| use ManiaControl\Callbacks\CallbackManager; | use ManiaControl\Callbacks\CallbackManager; | ||||||
| use ManiaControl\Callbacks\Callbacks; | use ManiaControl\Callbacks\Callbacks; | ||||||
|  | use ManiaControl\Communication\CommunicationAnswer; | ||||||
|  | use ManiaControl\Communication\CommunicationListener; | ||||||
|  | use ManiaControl\Communication\CommunicationMethods; | ||||||
| use ManiaControl\Files\FileUtil; | use ManiaControl\Files\FileUtil; | ||||||
| use ManiaControl\Logger; | use ManiaControl\Logger; | ||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| @@ -30,7 +33,7 @@ use Maniaplanet\DedicatedServer\Xmlrpc\UnavailableFeatureException; | |||||||
|  * @copyright 2014-2015 ManiaControl Team |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  */ |  */ | ||||||
| class MapManager implements CallbackListener { | class MapManager implements CallbackListener, CommunicationListener { | ||||||
| 	/* | 	/* | ||||||
| 	 * Constants | 	 * Constants | ||||||
| 	 */ | 	 */ | ||||||
| @@ -135,34 +138,9 @@ class MapManager implements CallbackListener { | |||||||
| 		$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_AUTOSAVE_MAPLIST, true); | 		$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_AUTOSAVE_MAPLIST, true); | ||||||
| 		$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MAPLIST_FILE, "MatchSettings/tracklist.txt"); | 		$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_MAPLIST_FILE, "MatchSettings/tracklist.txt"); | ||||||
| 		$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_WRITE_OWN_MAPLIST_FILE, false); | 		$this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_WRITE_OWN_MAPLIST_FILE, false); | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** | 		//Initlaize Communication Listenings | ||||||
| 	 * Initialize necessary database tables | 		$this->initalizeCommunicationListenings(); | ||||||
| 	 * |  | ||||||
| 	 * @return bool |  | ||||||
| 	 */ |  | ||||||
| 	private function initTables() { |  | ||||||
| 		$mysqli = $this->maniaControl->getDatabase()->getMysqli(); |  | ||||||
| 		$query  = "CREATE TABLE IF NOT EXISTS `" . self::TABLE_MAPS . "` ( |  | ||||||
| 				`index` int(11) NOT NULL AUTO_INCREMENT, |  | ||||||
| 				`mxid` int(11), |  | ||||||
| 				`uid` varchar(50) NOT NULL, |  | ||||||
| 				`name` varchar(150) NOT NULL, |  | ||||||
| 				`authorLogin` varchar(100) NOT NULL, |  | ||||||
| 				`fileName` varchar(100) NOT NULL, |  | ||||||
| 				`environment` varchar(50) NOT NULL, |  | ||||||
| 				`mapType` varchar(50) NOT NULL, |  | ||||||
| 				`changed` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |  | ||||||
| 				PRIMARY KEY (`index`), |  | ||||||
| 				UNIQUE KEY `uid` (`uid`) |  | ||||||
| 				) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Map Data' AUTO_INCREMENT=1;"; |  | ||||||
| 		$result = $mysqli->query($query); |  | ||||||
| 		if ($mysqli->error) { |  | ||||||
| 			trigger_error($mysqli->error, E_USER_ERROR); |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 		return $result; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -213,14 +191,16 @@ class MapManager implements CallbackListener { | |||||||
| 	/** | 	/** | ||||||
| 	 * Update a Map from Mania Exchange | 	 * Update a Map from Mania Exchange | ||||||
| 	 * | 	 * | ||||||
| 	 * @param Player $admin | 	 * @param Player|null $admin | ||||||
| 	 * @param string      $uid | 	 * @param string      $uid | ||||||
| 	 */ | 	 */ | ||||||
| 	public function updateMap(Player $admin, $uid) { | 	public function updateMap($admin, $uid) { | ||||||
| 		$this->updateMapTimestamp($uid); | 		$this->updateMapTimestamp($uid); | ||||||
|  |  | ||||||
| 		if (!isset($uid) || !isset($this->maps[$uid])) { | 		if (!isset($uid) || !isset($this->maps[$uid])) { | ||||||
|  | 			if ($admin) { | ||||||
| 				$this->maniaControl->getChat()->sendError("Error updating Map: Unknown UID '{$uid}'!", $admin); | 				$this->maniaControl->getChat()->sendError("Error updating Map: Unknown UID '{$uid}'!", $admin); | ||||||
|  | 			} | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -229,7 +209,11 @@ class MapManager implements CallbackListener { | |||||||
|  |  | ||||||
| 		$mxId = $map->mx->id; | 		$mxId = $map->mx->id; | ||||||
| 		$this->removeMap($admin, $uid, true, false); | 		$this->removeMap($admin, $uid, true, false); | ||||||
|  | 		if ($admin) { | ||||||
| 			$this->addMapFromMx($mxId, $admin->login, true); | 			$this->addMapFromMx($mxId, $admin->login, true); | ||||||
|  | 		} else { | ||||||
|  | 			$this->addMapFromMx($mxId, null, true); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -263,15 +247,18 @@ class MapManager implements CallbackListener { | |||||||
| 	/** | 	/** | ||||||
| 	 * Remove a Map | 	 * Remove a Map | ||||||
| 	 * | 	 * | ||||||
| 	 * @param Player $admin | 	 * @param Player|null $admin | ||||||
| 	 * @param string      $uid | 	 * @param string      $uid | ||||||
| 	 * @param bool        $eraseFile | 	 * @param bool        $eraseFile | ||||||
| 	 * @param bool        $message | 	 * @param bool        $message | ||||||
|  | 	 * @return bool | ||||||
| 	 */ | 	 */ | ||||||
| 	public function removeMap(Player $admin, $uid, $eraseFile = false, $message = true) { | 	public function removeMap($admin, $uid, $eraseFile = false, $message = true) { | ||||||
| 		if (!isset($this->maps[$uid])) { | 		if (!isset($this->maps[$uid])) { | ||||||
|  | 			if ($admin) { | ||||||
| 				$this->maniaControl->getChat()->sendError('Map does not exist!', $admin); | 				$this->maniaControl->getChat()->sendError('Map does not exist!', $admin); | ||||||
| 			return; | 			} | ||||||
|  | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		/** @var Map $map */ | 		/** @var Map $map */ | ||||||
| @@ -296,15 +283,18 @@ class MapManager implements CallbackListener { | |||||||
| 		if ($eraseFile) { | 		if ($eraseFile) { | ||||||
| 			// Check if ManiaControl can even write to the maps dir | 			// Check if ManiaControl can even write to the maps dir | ||||||
| 			$mapDir = $this->maniaControl->getClient()->getMapsDirectory(); | 			$mapDir = $this->maniaControl->getClient()->getMapsDirectory(); | ||||||
| 			if ($this->maniaControl->getServer()->checkAccess($mapDir) | 			if ($this->maniaControl->getServer()->checkAccess($mapDir)) { | ||||||
| 			) { |  | ||||||
| 				// Delete map file | 				// Delete map file | ||||||
| 				if (!@unlink($mapDir . $map->fileName)) { | 				if (!@unlink($mapDir . $map->fileName)) { | ||||||
|  | 					if ($admin) { | ||||||
| 						$this->maniaControl->getChat()->sendError("Couldn't erase the map file.", $admin); | 						$this->maniaControl->getChat()->sendError("Couldn't erase the map file.", $admin); | ||||||
|  | 					} | ||||||
| 					$eraseFile = false; | 					$eraseFile = false; | ||||||
| 				} | 				} | ||||||
| 			} else { | 			} else { | ||||||
|  | 				if ($admin) { | ||||||
| 					$this->maniaControl->getChat()->sendError("Couldn't erase the map file (no access).", $admin); | 					$this->maniaControl->getChat()->sendError("Couldn't erase the map file (no access).", $admin); | ||||||
|  | 				} | ||||||
| 				$eraseFile = false; | 				$eraseFile = false; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -312,10 +302,16 @@ class MapManager implements CallbackListener { | |||||||
| 		// Show Message | 		// Show Message | ||||||
| 		if ($message) { | 		if ($message) { | ||||||
| 			$action = ($eraseFile ? 'erased' : 'removed'); | 			$action = ($eraseFile ? 'erased' : 'removed'); | ||||||
|  | 			if ($admin) { | ||||||
| 				$message = $admin->getEscapedNickname() . ' ' . $action . ' ' . $map->getEscapedName() . '!'; | 				$message = $admin->getEscapedNickname() . ' ' . $action . ' ' . $map->getEscapedName() . '!'; | ||||||
|  | 			} else { | ||||||
|  | 				$message = $map->getEscapedName() . ' got ' . $action . '!'; | ||||||
|  | 			} | ||||||
| 			$this->maniaControl->getChat()->sendSuccess($message); | 			$this->maniaControl->getChat()->sendSuccess($message); | ||||||
| 			Logger::logInfo($message, true); | 			Logger::logInfo($message, true); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -342,6 +338,7 @@ class MapManager implements CallbackListener { | |||||||
| 	 * @param int    $mapId | 	 * @param int    $mapId | ||||||
| 	 * @param string $login | 	 * @param string $login | ||||||
| 	 * @param bool   $update | 	 * @param bool   $update | ||||||
|  | 	 * @param bool   $displayMessage | ||||||
| 	 */ | 	 */ | ||||||
| 	public function addMapFromMx($mapId, $login, $update = false) { | 	public function addMapFromMx($mapId, $login, $update = false) { | ||||||
| 		if (is_numeric($mapId)) { | 		if (is_numeric($mapId)) { | ||||||
| @@ -350,8 +347,10 @@ class MapManager implements CallbackListener { | |||||||
| 				&$login, &$update | 				&$login, &$update | ||||||
| 			) { | 			) { | ||||||
| 				if (!$mapInfo || !isset($mapInfo->uploaded)) { | 				if (!$mapInfo || !isset($mapInfo->uploaded)) { | ||||||
|  | 					if ($login) { | ||||||
| 						// Invalid id | 						// Invalid id | ||||||
| 						$this->maniaControl->getChat()->sendError('Invalid MX-Id!', $login); | 						$this->maniaControl->getChat()->sendError('Invalid MX-Id!', $login); | ||||||
|  | 					} | ||||||
| 					return; | 					return; | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| @@ -360,14 +359,17 @@ class MapManager implements CallbackListener { | |||||||
| 					&$login, &$mapInfo, &$update | 					&$login, &$mapInfo, &$update | ||||||
| 				) { | 				) { | ||||||
| 					if (!$file || $error) { | 					if (!$file || $error) { | ||||||
|  | 						if ($login) { | ||||||
| 							// Download error | 							// Download error | ||||||
| 							$this->maniaControl->getChat()->sendError("Download failed: '{$error}'!", $login); | 							$this->maniaControl->getChat()->sendError("Download failed: '{$error}'!", $login); | ||||||
|  | 						} | ||||||
| 						return; | 						return; | ||||||
| 					} | 					} | ||||||
| 					$this->processMapFile($file, $mapInfo, $login, $update); | 					$this->processMapFile($file, $mapInfo, $login, $update); | ||||||
| 				}); | 				}, 'UTF-8', 0, array("X-ManiaPlanet-ServerLogin: " . $this->maniaControl->getServer()->login)); | ||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
|  | 		return; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -459,8 +461,9 @@ class MapManager implements CallbackListener { | |||||||
| 		} | 		} | ||||||
| 		$map->lastUpdate = time(); | 		$map->lastUpdate = time(); | ||||||
|  |  | ||||||
|  | 		//TODO messages for communication | ||||||
|  | 		if ($login) { | ||||||
| 			$player = $this->maniaControl->getPlayerManager()->getPlayer($login); | 			$player = $this->maniaControl->getPlayerManager()->getPlayer($login); | ||||||
|  |  | ||||||
| 			if (!$update) { | 			if (!$update) { | ||||||
| 				// Message | 				// Message | ||||||
| 				$message = $player->getEscapedNickname() . ' added $<' . $mapInfo->name . '$>!'; | 				$message = $player->getEscapedNickname() . ' added $<' . $mapInfo->name . '$>!'; | ||||||
| @@ -474,6 +477,7 @@ class MapManager implements CallbackListener { | |||||||
| 				Logger::logInfo($message, true); | 				Logger::logInfo($message, true); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Get Map by UID | 	 * Get Map by UID | ||||||
| @@ -522,10 +526,8 @@ class MapManager implements CallbackListener { | |||||||
| 		$this->maniaControl->getCallbackManager()->triggerCallback(self::CB_MAPS_UPDATED); | 		$this->maniaControl->getCallbackManager()->triggerCallback(self::CB_MAPS_UPDATED); | ||||||
|  |  | ||||||
| 		// Write MapList | 		// Write MapList | ||||||
| 		if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_AUTOSAVE_MAPLIST) | 		if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_AUTOSAVE_MAPLIST)) { | ||||||
| 		) { | 			if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_WRITE_OWN_MAPLIST_FILE)) { | ||||||
| 			if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_WRITE_OWN_MAPLIST_FILE) |  | ||||||
| 			) { |  | ||||||
| 				$serverLogin           = $this->maniaControl->getServer()->login; | 				$serverLogin           = $this->maniaControl->getServer()->login; | ||||||
| 				$matchSettingsFileName = "MatchSettings/{$serverLogin}.txt"; | 				$matchSettingsFileName = "MatchSettings/{$serverLogin}.txt"; | ||||||
| 			} else { | 			} else { | ||||||
| @@ -884,4 +886,102 @@ class MapManager implements CallbackListener { | |||||||
| 	public function getMapsCount() { | 	public function getMapsCount() { | ||||||
| 		return count($this->maps); | 		return count($this->maps); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Initializes the Communication Listenings | ||||||
|  | 	 */ | ||||||
|  | 	private function initalizeCommunicationListenings() { | ||||||
|  | 		// Communication Listenings | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::GET_CURRENT_MAP, $this, function ($data) { | ||||||
|  | 			return new CommunicationAnswer($this->getCurrentMap()); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::GET_MAP_LIST, $this, function ($data) { | ||||||
|  | 			return new CommunicationAnswer($this->getMaps()); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::GET_MAP, $this, function ($data) { | ||||||
|  | 			if (!is_object($data)) { | ||||||
|  | 				return new CommunicationAnswer("Error in provided Data", true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (property_exists($data, "mxId")) { | ||||||
|  | 				return new CommunicationAnswer($this->getMapByMxId($data->mxId)); | ||||||
|  | 			} else if (property_exists($data, "mapUid")) { | ||||||
|  | 				return new CommunicationAnswer($this->getMapByUid($data->mapUid)); | ||||||
|  | 			} else { | ||||||
|  | 				return new CommunicationAnswer("No mxId or mapUid provided.", true); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::ADD_MAP, $this, function ($data) { | ||||||
|  | 			if (!is_object($data) || !property_exists($data, "mxId")) { | ||||||
|  | 				return new CommunicationAnswer("No valid mxId provided.", true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$this->addMapFromMx($data->mxId, null); | ||||||
|  |  | ||||||
|  | 			return new CommunicationAnswer(); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::REMOVE_MAP, $this, function ($data) { | ||||||
|  | 			if (!is_object($data) || !property_exists($data, "mapUid")) { | ||||||
|  | 				return new CommunicationAnswer("No valid mapUid provided.", true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (!$this->getMapByUid($data->mapUid)) { | ||||||
|  | 				return new CommunicationAnswer("Map not found.", true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$erase = false; | ||||||
|  | 			if (property_exists($data, "eraseMapFile")) { | ||||||
|  | 				$erase = $data->eraseMapFile; | ||||||
|  | 			} | ||||||
|  | 			$showMessage = true; | ||||||
|  | 			if (property_exists($data, "showChatMessage")) { | ||||||
|  | 				$showMessage = $data->showChatMessage; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$success = $this->removeMap(null, $data->mapUid, $erase, $showMessage); | ||||||
|  | 			return new CommunicationAnswer(array("success" => $success)); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::UPDATE_MAP, $this, function ($data) { | ||||||
|  | 			if (!is_object($data) || !property_exists($data, "mapUid")) { | ||||||
|  | 				return new CommunicationAnswer("No valid mapUid provided.", true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$this->updateMap(null, $data->mapUid); | ||||||
|  | 			return new CommunicationAnswer(); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Initialize necessary database tables | ||||||
|  | 	 * | ||||||
|  | 	 * @return bool | ||||||
|  | 	 */ | ||||||
|  | 	private function initTables() { | ||||||
|  | 		$mysqli = $this->maniaControl->getDatabase()->getMysqli(); | ||||||
|  | 		$query  = "CREATE TABLE IF NOT EXISTS `" . self::TABLE_MAPS . "` ( | ||||||
|  | 				`index` int(11) NOT NULL AUTO_INCREMENT, | ||||||
|  | 				`mxid` int(11), | ||||||
|  | 				`uid` varchar(50) NOT NULL, | ||||||
|  | 				`name` varchar(150) NOT NULL, | ||||||
|  | 				`authorLogin` varchar(100) NOT NULL, | ||||||
|  | 				`fileName` varchar(100) NOT NULL, | ||||||
|  | 				`environment` varchar(50) NOT NULL, | ||||||
|  | 				`mapType` varchar(50) NOT NULL, | ||||||
|  | 				`changed` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||||
|  | 				PRIMARY KEY (`index`), | ||||||
|  | 				UNIQUE KEY `uid` (`uid`) | ||||||
|  | 				) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Map Data' AUTO_INCREMENT=1;"; | ||||||
|  | 		$result = $mysqli->query($query); | ||||||
|  | 		if ($mysqli->error) { | ||||||
|  | 			trigger_error($mysqli->error, E_USER_ERROR); | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		return $result; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -108,8 +108,7 @@ class MapQueue implements CallbackListener, CommandListener { | |||||||
| 	 * @param Player $admin |null | 	 * @param Player $admin |null | ||||||
| 	 */ | 	 */ | ||||||
| 	public function clearMapQueue(Player $admin = null) { | 	public function clearMapQueue(Player $admin = null) { | ||||||
| 		if ($admin && !$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_CLEAR_MAPQUEUE) | 		if ($admin && !$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_CLEAR_MAPQUEUE)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -223,8 +222,8 @@ class MapQueue implements CallbackListener, CommandListener { | |||||||
| 			if (array_key_exists($map->uid, $this->queuedMaps)) { | 			if (array_key_exists($map->uid, $this->queuedMaps)) { | ||||||
| 				unset($this->queuedMaps[$map->uid]); | 				unset($this->queuedMaps[$map->uid]); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			array_unshift($this->queuedMaps, array($player, $map, true)); | 			array_unshift($this->queuedMaps, array($player, $map, true)); | ||||||
|  | 			$this->maniaControl->callbackManager->triggerCallback(self::CB_MAPQUEUE_CHANGED, array('add', $map)); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -308,8 +307,7 @@ class MapQueue implements CallbackListener, CommandListener { | |||||||
| 		// Check if map is in the buffer | 		// Check if map is in the buffer | ||||||
| 		if (in_array($uid, $this->buffer)) { | 		if (in_array($uid, $this->buffer)) { | ||||||
| 			$this->maniaControl->getChat()->sendError('That map has recently been played!', $login); | 			$this->maniaControl->getChat()->sendError('That map has recently been played!', $login); | ||||||
| 			if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CLEAR_MAPQUEUE) | 			if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CLEAR_MAPQUEUE)) { | ||||||
| 			) { |  | ||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -329,10 +327,10 @@ class MapQueue implements CallbackListener, CommandListener { | |||||||
| 	/** | 	/** | ||||||
| 	 * Remove a Map from the Map queue | 	 * Remove a Map from the Map queue | ||||||
| 	 * | 	 * | ||||||
| 	 * @param Player $player | 	 * @param Player|null $player | ||||||
| 	 * @param string      $uid | 	 * @param string      $uid | ||||||
| 	 */ | 	 */ | ||||||
| 	public function removeFromMapQueue(Player $player, $uid) { | 	public function removeFromMapQueue($player, $uid) { | ||||||
| 		if (!isset($this->queuedMaps[$uid])) { | 		if (!isset($this->queuedMaps[$uid])) { | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -340,7 +338,9 @@ class MapQueue implements CallbackListener, CommandListener { | |||||||
| 		$map = $this->queuedMaps[$uid][1]; | 		$map = $this->queuedMaps[$uid][1]; | ||||||
| 		unset($this->queuedMaps[$uid]); | 		unset($this->queuedMaps[$uid]); | ||||||
|  |  | ||||||
|  | 		if ($player) { | ||||||
| 			$this->maniaControl->getChat()->sendInformation('$fa0$<$fff' . $map->name . '$> is removed from the Map-Queue by $<$fff' . $player->nickname . '$>.'); | 			$this->maniaControl->getChat()->sendInformation('$fa0$<$fff' . $map->name . '$> is removed from the Map-Queue by $<$fff' . $player->nickname . '$>.'); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		// Trigger callback | 		// Trigger callback | ||||||
| 		$this->maniaControl->getCallbackManager()->triggerCallback(self::CB_MAPQUEUE_CHANGED, array('remove', $map)); | 		$this->maniaControl->getCallbackManager()->triggerCallback(self::CB_MAPQUEUE_CHANGED, array('remove', $map)); | ||||||
| @@ -359,8 +359,7 @@ class MapQueue implements CallbackListener, CommandListener { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		$this->nextMap = null; | 		$this->nextMap = null; | ||||||
| 		if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SKIP_MAP_ON_LEAVE) | 		if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_SKIP_MAP_ON_LEAVE)) { | ||||||
| 		) { |  | ||||||
| 			// Skip Map if requester has left | 			// Skip Map if requester has left | ||||||
| 			foreach ($this->queuedMaps as $queuedMap) { | 			foreach ($this->queuedMaps as $queuedMap) { | ||||||
| 				$player = $queuedMap[0]; | 				$player = $queuedMap[0]; | ||||||
| @@ -423,8 +422,7 @@ class MapQueue implements CallbackListener, CommandListener { | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (count($this->buffer) >= $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_BUFFERSIZE) | 		if (count($this->buffer) >= $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_BUFFERSIZE)) { | ||||||
| 		) { |  | ||||||
| 			array_shift($this->buffer); | 			array_shift($this->buffer); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ namespace ManiaControl\Players; | |||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| use ManiaControl\Utils\ClassUtil; | use ManiaControl\Utils\ClassUtil; | ||||||
| use ManiaControl\Utils\Formatter; | use ManiaControl\Utils\Formatter; | ||||||
|  | use Maniaplanet\DedicatedServer\Structures\LadderStats; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Player Model Class |  * Player Model Class | ||||||
| @@ -32,6 +33,7 @@ class Player { | |||||||
| 	public $isOfficial  = null; | 	public $isOfficial  = null; | ||||||
| 	public $ladderScore = -1.; | 	public $ladderScore = -1.; | ||||||
| 	public $ladderRank  = -1; | 	public $ladderRank  = -1; | ||||||
|  | 	/** @var LadderStats $ladderStats */ | ||||||
| 	public $ladderStats              = null; | 	public $ladderStats              = null; | ||||||
| 	public $joinTime                 = -1; | 	public $joinTime                 = -1; | ||||||
| 	public $ipAddress                = null; | 	public $ipAddress                = null; | ||||||
|   | |||||||
| @@ -8,6 +8,10 @@ use FML\Controls\Quad; | |||||||
| use FML\Controls\Quads\Quad_Icons64x64_1; | use FML\Controls\Quads\Quad_Icons64x64_1; | ||||||
| use FML\ManiaLink; | use FML\ManiaLink; | ||||||
| use ManiaControl\Admin\AuthenticationManager; | use ManiaControl\Admin\AuthenticationManager; | ||||||
|  | use ManiaControl\Callbacks\EchoListener; | ||||||
|  | use ManiaControl\Communication\CommunicationAnswer; | ||||||
|  | use ManiaControl\Communication\CommunicationListener; | ||||||
|  | use ManiaControl\Communication\CommunicationMethods; | ||||||
| use ManiaControl\Logger; | use ManiaControl\Logger; | ||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| use ManiaControl\Manialinks\ManialinkManager; | use ManiaControl\Manialinks\ManialinkManager; | ||||||
| @@ -26,7 +30,7 @@ use Maniaplanet\DedicatedServer\Xmlrpc\UnknownPlayerException; | |||||||
|  * @copyright 2014-2015 ManiaControl Team |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  */ |  */ | ||||||
| class PlayerActions { | class PlayerActions implements EchoListener, CommunicationListener { | ||||||
| 	/* | 	/* | ||||||
| 	 * Constants | 	 * Constants | ||||||
| 	 */ | 	 */ | ||||||
| @@ -36,6 +40,7 @@ class PlayerActions { | |||||||
| 	const SPECTATOR_SPECTATOR           = 1; | 	const SPECTATOR_SPECTATOR           = 1; | ||||||
| 	const SPECTATOR_PLAYER              = 2; | 	const SPECTATOR_PLAYER              = 2; | ||||||
| 	const SPECTATOR_BUT_KEEP_SELECTABLE = 3; | 	const SPECTATOR_BUT_KEEP_SELECTABLE = 3; | ||||||
|  | 	const ECHO_WARN_PLAYER              = 'ManiaControl.PlayerManager.WarnPlayer'; | ||||||
|  |  | ||||||
| 	/* | 	/* | ||||||
| 	 * Permission Setting Constants | 	 * Permission Setting Constants | ||||||
| @@ -48,6 +53,7 @@ class PlayerActions { | |||||||
| 	const SETTING_PERMISSION_KICK_PLAYER       = 'Kick Player'; | 	const SETTING_PERMISSION_KICK_PLAYER       = 'Kick Player'; | ||||||
| 	const SETTING_PERMISSION_BAN_PLAYER        = 'Ban Player'; | 	const SETTING_PERMISSION_BAN_PLAYER        = 'Ban Player'; | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/* | 	/* | ||||||
| 	 * Private properties | 	 * Private properties | ||||||
| 	 */ | 	 */ | ||||||
| @@ -70,6 +76,75 @@ class PlayerActions { | |||||||
| 		$this->maniaControl->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_FORCE_PLAYER_PLAY, AuthenticationManager::AUTH_LEVEL_MODERATOR); | 		$this->maniaControl->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_FORCE_PLAYER_PLAY, AuthenticationManager::AUTH_LEVEL_MODERATOR); | ||||||
| 		$this->maniaControl->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_FORCE_PLAYER_TEAM, AuthenticationManager::AUTH_LEVEL_MODERATOR); | 		$this->maniaControl->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_FORCE_PLAYER_TEAM, AuthenticationManager::AUTH_LEVEL_MODERATOR); | ||||||
| 		$this->maniaControl->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_FORCE_PLAYER_SPEC, AuthenticationManager::AUTH_LEVEL_MODERATOR); | 		$this->maniaControl->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_FORCE_PLAYER_SPEC, AuthenticationManager::AUTH_LEVEL_MODERATOR); | ||||||
|  |  | ||||||
|  | 		// Echo Warn Command (Usage: sendEcho json_encode("player" => "loginName") | ||||||
|  | 		$this->maniaControl->getEchoManager()->registerEchoListener(self::ECHO_WARN_PLAYER, $this, function ($params) { | ||||||
|  | 			$this->warnPlayer(null, $params->player, false); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		//Communication Manager Methods | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::WARN_PLAYER, $this, function ($data) { | ||||||
|  | 			if (!is_object($data) || !property_exists($data, "login")) { | ||||||
|  | 				return new CommunicationAnswer("You have to provide a valid player Login", true); | ||||||
|  | 			} | ||||||
|  | 			$success = $this->warnPlayer(null, $data->login, false); | ||||||
|  | 			return new CommunicationAnswer(array("success" => $success)); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::MUTE_PLAYER, $this, function ($data) { | ||||||
|  | 			if (!is_object($data) || !property_exists($data, "login")) { | ||||||
|  | 				return new CommunicationAnswer("You have to provide a valid player Login", true); | ||||||
|  | 			} | ||||||
|  | 			$success = $this->mutePlayer(null, $data->login, false); | ||||||
|  | 			return new CommunicationAnswer(array("success" => $success)); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::UNMUTE_PLAYER, $this, function ($data) { | ||||||
|  | 			if (!is_object($data) || !property_exists($data, "login")) { | ||||||
|  | 				return new CommunicationAnswer("You have to provide a valid player Login", true); | ||||||
|  | 			} | ||||||
|  | 			$success = $this->unMutePlayer(null, $data->login, false); | ||||||
|  | 			return new CommunicationAnswer(array("success" => $success)); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::KICK_PLAYER, $this, function ($data) { | ||||||
|  | 			if (!is_object($data) || !property_exists($data, "login")) { | ||||||
|  | 				return new CommunicationAnswer("You have to provide a valid player Login", true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$message = ""; | ||||||
|  | 			if (property_exists($data, "message")) { | ||||||
|  | 				$message = $data->message; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$success = $this->kickPlayer(null, $data->login, $message, false); | ||||||
|  |  | ||||||
|  | 			return new CommunicationAnswer(array("success" => $success)); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::FORCE_PLAYER_TO_SPEC, $this, function ($data) { | ||||||
|  | 			if (!is_object($data) || !property_exists($data, "login")) { | ||||||
|  | 				return new CommunicationAnswer("You have to provide a valid player Login", true); | ||||||
|  | 			} | ||||||
|  | 			//TODO allow parameters like spectator state | ||||||
|  | 			$success = $this->forcePlayerToSpectator(null, $data->login, self::SPECTATOR_BUT_KEEP_SELECTABLE, true, false); | ||||||
|  | 			return new CommunicationAnswer(array("success" => $success)); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::FORCE_PLAYER_TO_PLAY, $this, function ($data) { | ||||||
|  | 			if (!is_object($data) || !property_exists($data, "login")) { | ||||||
|  | 				return new CommunicationAnswer("You have to provide a valid player Login", true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			//TODO allow parameters like spectator state | ||||||
|  | 			if (property_exists($data, "teamId")) { | ||||||
|  | 				$success = $this->forcePlayerToTeam(null, $data->login, $data->teamId, false); | ||||||
|  | 			} else { | ||||||
|  | 				$success = $this->forcePlayerToPlay(null, $data->login, true, true, false); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			return new CommunicationAnswer(array("success" => $success)); | ||||||
|  | 		}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -78,54 +153,78 @@ class PlayerActions { | |||||||
| 	 * @param string $adminLogin | 	 * @param string $adminLogin | ||||||
| 	 * @param string $targetLogin | 	 * @param string $targetLogin | ||||||
| 	 * @param int    $teamId | 	 * @param int    $teamId | ||||||
|  | 	 * @param bool   $calledByAdmin | ||||||
|  | 	 * @return bool | ||||||
| 	 */ | 	 */ | ||||||
| 	public function forcePlayerToTeam($adminLogin, $targetLogin, $teamId) { | 	public function forcePlayerToTeam($adminLogin, $targetLogin, $teamId, $calledByAdmin = true) { | ||||||
|  | 		if ($calledByAdmin) { | ||||||
| 			$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | 			$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_FORCE_PLAYER_TEAM) | 			if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_FORCE_PLAYER_TEAM)) { | ||||||
| 		) { |  | ||||||
| 				$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | 				$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | ||||||
| 			return; | 				return false; | ||||||
|  | 			} | ||||||
|  | 			if (!$admin) { | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | ||||||
| 		if (!$target || !$admin) { | 		if (!$target) { | ||||||
| 			return; | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if ($target->isSpectator) { | 		if ($target->isSpectator) { | ||||||
| 			try { | 			try { | ||||||
| 				if (!$this->forcePlayerToPlay($adminLogin, $targetLogin, true, false)) { | 				if (!$this->forcePlayerToPlay($adminLogin, $targetLogin, true, false, $calledByAdmin)) { | ||||||
| 					return; | 					return false; | ||||||
| 				} | 				} | ||||||
| 			} catch (FaultException $exception) { | 			} catch (FaultException $exception) { | ||||||
|  | 				if ($calledByAdmin) { | ||||||
| 					$this->maniaControl->getChat()->sendException($exception, $admin); | 					$this->maniaControl->getChat()->sendException($exception, $admin); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		try { | 		try { | ||||||
| 			$this->maniaControl->getClient()->forcePlayerTeam($target->login, $teamId); | 			$this->maniaControl->getClient()->forcePlayerTeam($target->login, $teamId); | ||||||
| 		} catch (ServerOptionsException $exception) { | 		} catch (ServerOptionsException $exception) { | ||||||
| 			$this->forcePlayerToPlay($adminLogin, $targetLogin); | 			$this->forcePlayerToPlay($adminLogin, $targetLogin); | ||||||
| 			return; | 			return false; | ||||||
| 		} catch (UnknownPlayerException $exception) { | 		} catch (UnknownPlayerException $exception) { | ||||||
|  | 			if ($calledByAdmin) { | ||||||
| 				$this->maniaControl->getChat()->sendException($exception, $admin); | 				$this->maniaControl->getChat()->sendException($exception, $admin); | ||||||
| 			return; | 			} | ||||||
|  | 			return false; | ||||||
| 		} catch (GameModeException $exception) { | 		} catch (GameModeException $exception) { | ||||||
|  | 			if ($calledByAdmin) { | ||||||
| 				$this->maniaControl->getChat()->sendException($exception, $admin); | 				$this->maniaControl->getChat()->sendException($exception, $admin); | ||||||
| 			return; | 			} | ||||||
|  | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		$chatMessage = false; | 		$chatMessage = false; | ||||||
|  |  | ||||||
|  | 		if ($calledByAdmin) { | ||||||
| 			$title = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($admin->authLevel); | 			$title = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($admin->authLevel); | ||||||
| 			if ($teamId === self::TEAM_BLUE) { | 			if ($teamId === self::TEAM_BLUE) { | ||||||
| 				$chatMessage = $title . ' ' . $admin->getEscapedNickname() . ' forced ' . $target->getEscapedNickname() . ' into the Blue-Team!'; | 				$chatMessage = $title . ' ' . $admin->getEscapedNickname() . ' forced ' . $target->getEscapedNickname() . ' into the Blue-Team!'; | ||||||
| 			} else if ($teamId === self::TEAM_RED) { | 			} else if ($teamId === self::TEAM_RED) { | ||||||
| 				$chatMessage = $title . ' ' . $admin->getEscapedNickname() . ' forced ' . $target->getEscapedNickname() . ' into the Red-Team!'; | 				$chatMessage = $title . ' ' . $admin->getEscapedNickname() . ' forced ' . $target->getEscapedNickname() . ' into the Red-Team!'; | ||||||
| 			} | 			} | ||||||
|  | 		} else { | ||||||
|  | 			if ($teamId === self::TEAM_BLUE) { | ||||||
|  | 				$chatMessage = $target->getEscapedNickname() . ' got forced into the Blue-Team!'; | ||||||
|  | 			} else if ($teamId === self::TEAM_RED) { | ||||||
|  | 				$chatMessage = $target->getEscapedNickname() . ' got forced into the Red-Team!'; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		if (!$chatMessage) { | 		if (!$chatMessage) { | ||||||
| 			return; | 			return false; | ||||||
| 		} | 		} | ||||||
| 		$this->maniaControl->getChat()->sendInformation($chatMessage); | 		$this->maniaControl->getChat()->sendInformation($chatMessage); | ||||||
| 		Logger::logInfo($chatMessage, true); | 		Logger::logInfo($chatMessage, true); | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -135,15 +234,18 @@ class PlayerActions { | |||||||
| 	 * @param string $targetLogin | 	 * @param string $targetLogin | ||||||
| 	 * @param bool   $userIsAbleToSelect | 	 * @param bool   $userIsAbleToSelect | ||||||
| 	 * @param bool   $displayAnnouncement | 	 * @param bool   $displayAnnouncement | ||||||
|  | 	 * @param bool   $calledByAdmin | ||||||
| 	 * @return bool | 	 * @return bool | ||||||
| 	 */ | 	 */ | ||||||
| 	public function forcePlayerToPlay($adminLogin, $targetLogin, $userIsAbleToSelect = true, $displayAnnouncement = true) { | 	public function forcePlayerToPlay($adminLogin, $targetLogin, $userIsAbleToSelect = true, $displayAnnouncement = true, $calledByAdmin = true) { | ||||||
|  | 		if ($calledByAdmin) { | ||||||
| 			$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | 			$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_FORCE_PLAYER_PLAY) | 			if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_FORCE_PLAYER_PLAY)) { | ||||||
| 		) { |  | ||||||
| 				$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | 				$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | ||||||
| 				return false; | 				return false; | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | ||||||
| 		if (!$target) { | 		if (!$target) { | ||||||
| 			return false; | 			return false; | ||||||
| @@ -152,7 +254,9 @@ class PlayerActions { | |||||||
| 		try { | 		try { | ||||||
| 			$this->maniaControl->getClient()->forceSpectator($target->login, self::SPECTATOR_PLAYER); | 			$this->maniaControl->getClient()->forceSpectator($target->login, self::SPECTATOR_PLAYER); | ||||||
| 		} catch (ServerOptionsException $exception) { | 		} catch (ServerOptionsException $exception) { | ||||||
|  | 			if ($calledByAdmin) { | ||||||
| 				$this->maniaControl->getChat()->sendException($exception, $admin); | 				$this->maniaControl->getChat()->sendException($exception, $admin); | ||||||
|  | 			} | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -160,14 +264,22 @@ class PlayerActions { | |||||||
| 			try { | 			try { | ||||||
| 				$this->maniaControl->getClient()->forceSpectator($target->login, self::SPECTATOR_USER_SELECTABLE); | 				$this->maniaControl->getClient()->forceSpectator($target->login, self::SPECTATOR_USER_SELECTABLE); | ||||||
| 			} catch (ServerOptionsException $exception) { | 			} catch (ServerOptionsException $exception) { | ||||||
|  | 				if ($calledByAdmin) { | ||||||
| 					$this->maniaControl->getChat()->sendException($exception, $admin); | 					$this->maniaControl->getChat()->sendException($exception, $admin); | ||||||
|  | 				} | ||||||
| 				return false; | 				return false; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Announce force | 		// Announce force | ||||||
| 		if ($displayAnnouncement) { | 		if ($displayAnnouncement) { | ||||||
|  | 			if ($calledByAdmin) { | ||||||
| 				$chatMessage = $admin->getEscapedNickname() . ' forced ' . $target->getEscapedNickname() . ' to Play!'; | 				$chatMessage = $admin->getEscapedNickname() . ' forced ' . $target->getEscapedNickname() . ' to Play!'; | ||||||
|  | 			} else { | ||||||
|  | 				$chatMessage = $target->getEscapedNickname() . ' got forced to Play!'; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  |  | ||||||
| 			$this->maniaControl->getChat()->sendInformation($chatMessage); | 			$this->maniaControl->getChat()->sendInformation($chatMessage); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -181,29 +293,43 @@ class PlayerActions { | |||||||
| 	 * @param string $targetLogin | 	 * @param string $targetLogin | ||||||
| 	 * @param int    $spectatorState | 	 * @param int    $spectatorState | ||||||
| 	 * @param bool   $releaseSlot | 	 * @param bool   $releaseSlot | ||||||
|  | 	 * @param bool   $calledByAdmin | ||||||
|  | 	 * @return bool | ||||||
| 	 */ | 	 */ | ||||||
| 	public function forcePlayerToSpectator($adminLogin, $targetLogin, $spectatorState = self::SPECTATOR_BUT_KEEP_SELECTABLE, $releaseSlot = true) { | 	public function forcePlayerToSpectator($adminLogin, $targetLogin, $spectatorState = self::SPECTATOR_BUT_KEEP_SELECTABLE, $releaseSlot = true, $calledByAdmin = true) { | ||||||
|  | 		if ($calledByAdmin) { | ||||||
| 			$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | 			$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_FORCE_PLAYER_SPEC) | 			if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_FORCE_PLAYER_SPEC)) { | ||||||
| 		) { |  | ||||||
| 				$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | 				$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | ||||||
| 			return; | 				return false; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | 			if (!$admin) { | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | ||||||
|  |  | ||||||
| 		if (!$admin || !$target || $target->isSpectator) { | 		if (!$target || $target->isSpectator) { | ||||||
| 			return; | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		try { | 		try { | ||||||
| 			$this->maniaControl->getClient()->forceSpectator($target->login, $spectatorState); | 			$this->maniaControl->getClient()->forceSpectator($target->login, $spectatorState); | ||||||
| 		} catch (ServerOptionsException $exception) { | 		} catch (ServerOptionsException $exception) { | ||||||
|  | 			if ($calledByAdmin) { | ||||||
| 				$this->maniaControl->getChat()->sendException($exception, $admin->login); | 				$this->maniaControl->getChat()->sendException($exception, $admin->login); | ||||||
| 			return; | 			} | ||||||
|  | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		if ($calledByAdmin) { | ||||||
| 			$title       = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($admin->authLevel); | 			$title       = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($admin->authLevel); | ||||||
| 			$chatMessage = $title . ' ' . $admin->getEscapedNickname() . ' forced ' . $target->getEscapedNickname() . ' to Spectator!'; | 			$chatMessage = $title . ' ' . $admin->getEscapedNickname() . ' forced ' . $target->getEscapedNickname() . ' to Spectator!'; | ||||||
|  | 		} else { | ||||||
|  | 			$chatMessage = $target->getEscapedNickname() . ' got forced to Spectator!'; | ||||||
|  | 		} | ||||||
| 		$this->maniaControl->getChat()->sendInformation($chatMessage); | 		$this->maniaControl->getChat()->sendInformation($chatMessage); | ||||||
| 		Logger::logInfo($chatMessage, true); | 		Logger::logInfo($chatMessage, true); | ||||||
|  |  | ||||||
| @@ -215,39 +341,50 @@ class PlayerActions { | |||||||
| 			} catch (UnknownPlayerException $e) { | 			} catch (UnknownPlayerException $e) { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * UnMute a Player | 	 * UnMute a Player | ||||||
| 	 * | 	 * | ||||||
| 	 * @param string $adminLogin | 	 * @param      $adminLogin | ||||||
| 	 * @param string $targetLogin | 	 * @param      $targetLogin | ||||||
|  | 	 * @param bool $calledByAdmin | ||||||
|  | 	 * @return bool | ||||||
| 	 */ | 	 */ | ||||||
| 	public function unMutePlayer($adminLogin, $targetLogin) { | 	public function unMutePlayer($adminLogin, $targetLogin, $calledByAdmin = true) { | ||||||
|  | 		if ($calledByAdmin) { | ||||||
| 			$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | 			$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_MUTE_PLAYER) | 			if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_MUTE_PLAYER)) { | ||||||
| 		) { |  | ||||||
| 				$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | 				$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | ||||||
| 			return; | 				return false; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | ||||||
|  |  | ||||||
| 		if (!$target) { | 		if (!$target) { | ||||||
| 			return; | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		try { | 		try { | ||||||
| 			$this->maniaControl->getClient()->unIgnore($targetLogin); | 			$this->maniaControl->getClient()->unIgnore($targetLogin); | ||||||
| 		} catch (NotInListException $e) { | 		} catch (NotInListException $e) { | ||||||
| 			$this->maniaControl->getChat()->sendError('Player is not ignored!', $adminLogin); | 			$this->maniaControl->getChat()->sendError('Player is not ignored!', $adminLogin); | ||||||
| 			return; | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		if ($calledByAdmin) { | ||||||
| 			$title       = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($admin->authLevel); | 			$title       = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($admin->authLevel); | ||||||
| 			$chatMessage = $title . ' ' . $admin->getEscapedNickname() . ' un-muted ' . $target->getEscapedNickname() . '!'; | 			$chatMessage = $title . ' ' . $admin->getEscapedNickname() . ' un-muted ' . $target->getEscapedNickname() . '!'; | ||||||
|  | 		} else { | ||||||
|  | 			$chatMessage = $target->getEscapedNickname() . ' got un-muted!'; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		$this->maniaControl->getChat()->sendInformation($chatMessage); | 		$this->maniaControl->getChat()->sendInformation($chatMessage); | ||||||
| 		Logger::logInfo($chatMessage, true); | 		Logger::logInfo($chatMessage, true); | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -255,32 +392,42 @@ class PlayerActions { | |||||||
| 	 * | 	 * | ||||||
| 	 * @param string $adminLogin | 	 * @param string $adminLogin | ||||||
| 	 * @param string $targetLogin | 	 * @param string $targetLogin | ||||||
|  | 	 * @param bool   $calledByAdmin | ||||||
|  | 	 * @return bool | ||||||
| 	 */ | 	 */ | ||||||
| 	public function mutePlayer($adminLogin, $targetLogin) { | 	public function mutePlayer($adminLogin, $targetLogin, $calledByAdmin = true) { | ||||||
|  | 		if ($calledByAdmin) { | ||||||
| 			$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | 			$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_MUTE_PLAYER) | 			if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_MUTE_PLAYER)) { | ||||||
| 		) { |  | ||||||
| 				$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | 				$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | ||||||
| 			return; | 				return false; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | ||||||
|  |  | ||||||
| 		if (!$target) { | 		if (!$target) { | ||||||
| 			return; | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		try { | 		try { | ||||||
| 			$this->maniaControl->getClient()->ignore($targetLogin); | 			$this->maniaControl->getClient()->ignore($targetLogin); | ||||||
| 		} catch (AlreadyInListException $e) { | 		} catch (AlreadyInListException $e) { | ||||||
| 			$this->maniaControl->getChat()->sendError("Player already ignored!", $adminLogin); | 			$this->maniaControl->getChat()->sendError("Player already ignored!", $adminLogin); | ||||||
| 			return; | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		// Announce warning | ||||||
|  | 		if ($calledByAdmin) { | ||||||
| 			$title       = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($admin->authLevel); | 			$title       = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($admin->authLevel); | ||||||
| 			$chatMessage = $title . ' ' . $admin->getEscapedNickname() . ' muted ' . $target->getEscapedNickname() . '!'; | 			$chatMessage = $title . ' ' . $admin->getEscapedNickname() . ' muted ' . $target->getEscapedNickname() . '!'; | ||||||
|  | 		} else { | ||||||
|  | 			$chatMessage = $target->getEscapedNickname() . ' got muted!'; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		$this->maniaControl->getChat()->sendInformation($chatMessage); | 		$this->maniaControl->getChat()->sendInformation($chatMessage); | ||||||
| 		Logger::logInfo($chatMessage, true); | 		Logger::logInfo($chatMessage, true); | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -288,19 +435,22 @@ class PlayerActions { | |||||||
| 	 * | 	 * | ||||||
| 	 * @param string $adminLogin | 	 * @param string $adminLogin | ||||||
| 	 * @param string $targetLogin | 	 * @param string $targetLogin | ||||||
|  | 	 * @param bool   $calledByAdmin | ||||||
|  | 	 * @return bool | ||||||
| 	 */ | 	 */ | ||||||
| 	public function warnPlayer($adminLogin, $targetLogin) { | 	public function warnPlayer($adminLogin, $targetLogin, $calledByAdmin = true) { | ||||||
|  | 		if ($calledByAdmin) { | ||||||
| 			$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | 			$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_WARN_PLAYER) | 			if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_WARN_PLAYER)) { | ||||||
| 		) { |  | ||||||
| 				$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | 				$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | ||||||
| 			return; | 				return false; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | ||||||
|  |  | ||||||
| 		if (!$target) { | 		if (!$target) { | ||||||
| 			return; | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Display warning message | 		// Display warning message | ||||||
| @@ -360,49 +510,78 @@ class PlayerActions { | |||||||
| 		$this->maniaControl->getManialinkManager()->displayWidget($maniaLink, $target); | 		$this->maniaControl->getManialinkManager()->displayWidget($maniaLink, $target); | ||||||
|  |  | ||||||
| 		// Announce warning | 		// Announce warning | ||||||
|  | 		if ($calledByAdmin) { | ||||||
| 			$title       = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($admin->authLevel); | 			$title       = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($admin->authLevel); | ||||||
| 			$chatMessage = $title . ' ' . $admin->getEscapedNickname() . ' warned ' . $target->getEscapedNickname() . '!'; | 			$chatMessage = $title . ' ' . $admin->getEscapedNickname() . ' warned ' . $target->getEscapedNickname() . '!'; | ||||||
|  | 		} else { | ||||||
|  | 			$chatMessage = $target->getEscapedNickname() . ' got an administrative warning!'; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		$this->maniaControl->getChat()->sendInformation($chatMessage); | 		$this->maniaControl->getChat()->sendInformation($chatMessage); | ||||||
| 		Logger::log($chatMessage, true); | 		Logger::log($chatMessage, true); | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Kick a Player | 	 * Kick a Player | ||||||
| 	 * | 	 * | ||||||
| 	 * @param string $adminLogin | 	 * @param        $adminLogin | ||||||
| 	 * @param string $targetLogin | 	 * @param        $targetLogin | ||||||
| 	 * @param string $message | 	 * @param string $message | ||||||
|  | 	 * @param bool   $calledByAdmin | ||||||
|  | 	 * @return bool | ||||||
| 	 */ | 	 */ | ||||||
| 	public function kickPlayer($adminLogin, $targetLogin, $message = '') { | 	public function kickPlayer($adminLogin, $targetLogin, $message = '', $calledByAdmin = true) { | ||||||
|  | 		if ($calledByAdmin) { | ||||||
| 			$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | 			$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_KICK_PLAYER) | 			if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_KICK_PLAYER)) { | ||||||
| 		) { |  | ||||||
| 				$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | 				$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | ||||||
| 			return; | 				return false; | ||||||
| 			} | 			} | ||||||
| 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); |  | ||||||
| 		if (!$target) { |  | ||||||
| 			return; |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		try { | 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | ||||||
| 			if ($target->isFakePlayer()) { | 		if (!$target) { | ||||||
| 				$this->maniaControl->getClient()->disconnectFakePlayer($target->login); | 			return false; | ||||||
| 			} else { |  | ||||||
| 				$this->maniaControl->getClient()->kick($target->login, $message); |  | ||||||
| 		} | 		} | ||||||
| 		} catch (UnknownPlayerException $e) { |  | ||||||
|  | 		if ($target->isFakePlayer()) { | ||||||
|  | 			try { | ||||||
|  | 				$this->maniaControl->getClient()->disconnectFakePlayer($target->login); | ||||||
|  | 			} catch (PlayerStateException $e) { | ||||||
|  | 				if ($calledByAdmin) { | ||||||
| 					$this->maniaControl->getChat()->sendException($e, $admin); | 					$this->maniaControl->getChat()->sendException($e, $admin); | ||||||
| 			return; | 				} | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			try { | ||||||
|  | 				$this->maniaControl->getClient()->kick($target->login, $message); | ||||||
|  | 			} catch (UnknownPlayerException $e) { | ||||||
|  | 				if ($calledByAdmin) { | ||||||
|  | 					$this->maniaControl->getChat()->sendException($e, $admin); | ||||||
|  | 				} | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Announce kick | 		// Announce kick | ||||||
|  | 		if ($calledByAdmin) { | ||||||
| 			$title       = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($admin->authLevel); | 			$title       = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($admin->authLevel); | ||||||
| 			$chatMessage = $title . ' ' . $admin->getEscapedNickname() . ' kicked ' . $target->getEscapedNickname() . '!'; | 			$chatMessage = $title . ' ' . $admin->getEscapedNickname() . ' kicked ' . $target->getEscapedNickname() . '!'; | ||||||
|  | 		} else { | ||||||
|  | 			$chatMessage = $target->getEscapedNickname() . ' got kicked!'; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		$this->maniaControl->getChat()->sendInformation($chatMessage); | 		$this->maniaControl->getChat()->sendInformation($chatMessage); | ||||||
| 		Logger::logInfo($chatMessage, true); | 		Logger::logInfo($chatMessage, true); | ||||||
|  |  | ||||||
|  | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Ban a Player | 	 * Ban a Player | ||||||
| 	 * | 	 * | ||||||
| @@ -412,17 +591,18 @@ class PlayerActions { | |||||||
| 	 */ | 	 */ | ||||||
| 	public function banPlayer($adminLogin, $targetLogin, $message = '') { | 	public function banPlayer($adminLogin, $targetLogin, $message = '') { | ||||||
| 		$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | 		$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_BAN_PLAYER) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_BAN_PLAYER)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | 		$target = $this->maniaControl->getPlayerManager()->getPlayer($targetLogin); | ||||||
| 		if (!$target) { | 		if (!$target) { | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if ($target->isFakePlayer()) { | 		//Todo Validate (Problem: Not connected player isFakePlayer) | ||||||
|  | 		if ($target->isOfficial && $target->isFakePlayer()) { | ||||||
| 			$this->maniaControl->getChat()->sendError('It is not possible to Ban a bot', $admin); | 			$this->maniaControl->getChat()->sendError('It is not possible to Ban a bot', $admin); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -450,8 +630,7 @@ class PlayerActions { | |||||||
| 	 */ | 	 */ | ||||||
| 	public function unBanPlayer($adminLogin, $targetLogin) { | 	public function unBanPlayer($adminLogin, $targetLogin) { | ||||||
| 		$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | 		$admin = $this->maniaControl->getPlayerManager()->getPlayer($adminLogin); | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_BAN_PLAYER) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($admin, self::SETTING_PERMISSION_BAN_PLAYER)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($admin); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -485,14 +664,12 @@ class PlayerActions { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		$authLevelName = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($authLevel); | 		$authLevelName = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($authLevel); | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkRight($admin, $authLevel + 1) | 		if (!$this->maniaControl->getAuthenticationManager()->checkRight($admin, $authLevel + 1)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getChat()->sendError("You don't have the permission to add a {$authLevelName}!", $admin); | 			$this->maniaControl->getChat()->sendError("You don't have the permission to add a {$authLevelName}!", $admin); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if ($this->maniaControl->getAuthenticationManager()->checkRight($target, $authLevel) | 		if ($this->maniaControl->getAuthenticationManager()->checkRight($target, $authLevel)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getChat()->sendError("This Player is already {$authLevelName}!", $admin); | 			$this->maniaControl->getChat()->sendError("This Player is already {$authLevelName}!", $admin); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -523,15 +700,13 @@ class PlayerActions { | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkRight($admin, $target->authLevel + 1) | 		if (!$this->maniaControl->getAuthenticationManager()->checkRight($admin, $target->authLevel + 1)) { | ||||||
| 		) { |  | ||||||
| 			$title = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($target->authLevel); | 			$title = $this->maniaControl->getAuthenticationManager()->getAuthLevelName($target->authLevel); | ||||||
| 			$this->maniaControl->getChat()->sendError("You can't revoke the Rights of a {$title}!", $admin); | 			$this->maniaControl->getChat()->sendError("You can't revoke the Rights of a {$title}!", $admin); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if ($this->maniaControl->getAuthenticationManager()->checkRight($target, AuthenticationManager::AUTH_LEVEL_MASTERADMIN) | 		if ($this->maniaControl->getAuthenticationManager()->checkRight($target, AuthenticationManager::AUTH_LEVEL_MASTERADMIN)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getChat()->sendError("MasterAdmins can't be removed!", $admin); | 			$this->maniaControl->getChat()->sendError("MasterAdmins can't be removed!", $admin); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -163,9 +163,9 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer | |||||||
| 		$headFrame = new Frame(); | 		$headFrame = new Frame(); | ||||||
| 		$frame->add($headFrame); | 		$frame->add($headFrame); | ||||||
| 		$headFrame->setY($posY - 5); | 		$headFrame->setY($posY - 5); | ||||||
|  |  | ||||||
| 		$labelLineArray = array('Id' => $posX + 5, 'Nickname' => $posX + 18, 'Login' => $posX + 70, 'Location' => $posX + 101); | 		$labelLineArray = array('Id' => $posX + 5, 'Nickname' => $posX + 18, 'Login' => $posX + 70, 'Location' => $posX + 101); | ||||||
| 		if ($this->maniaControl->getAuthenticationManager()->checkRight($player, AuthenticationManager::AUTH_LEVEL_MODERATOR) | 		if ($this->maniaControl->getAuthenticationManager()->checkRight($player, AuthenticationManager::AUTH_LEVEL_MODERATOR)) { | ||||||
| 		) { |  | ||||||
| 			$labelLineArray['Actions'] = $posX + 135; | 			$labelLineArray['Actions'] = $posX + 135; | ||||||
| 		} | 		} | ||||||
| 		$this->maniaControl->getManialinkManager()->labelLine($headFrame, $labelLineArray); | 		$this->maniaControl->getManialinkManager()->labelLine($headFrame, $labelLineArray); | ||||||
| @@ -195,8 +195,9 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer | |||||||
| 				$lineQuad->setZ(0.001); | 				$lineQuad->setZ(0.001); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			$array = array($index => $posX + 5, $listPlayer->nickname => $posX + 18, $listPlayer->login => $posX + 70, $path => $posX + 101); | 			$positions = array($posX + 5, $posX + 18, $posX + 70, $posX + 101); | ||||||
| 			$this->maniaControl->getManialinkManager()->labelLine($playerFrame, $array); | 			$texts     = array($index, $listPlayer->nickname, $listPlayer->login, $path); | ||||||
|  | 			$this->maniaControl->getManialinkManager()->labelLine($playerFrame, array($positions, $texts)); | ||||||
|  |  | ||||||
| 			$playerFrame->setY($posY); | 			$playerFrame->setY($posY); | ||||||
|  |  | ||||||
| @@ -304,8 +305,7 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer | |||||||
| 			$description = 'View Player Profile of $<' . $listPlayer->nickname . '$>'; | 			$description = 'View Player Profile of $<' . $listPlayer->nickname . '$>'; | ||||||
| 			$playerQuad->addTooltipLabelFeature($descriptionLabel, $description); | 			$playerQuad->addTooltipLabelFeature($descriptionLabel, $description); | ||||||
|  |  | ||||||
| 			if ($this->maniaControl->getAuthenticationManager()->checkRight($player, AuthenticationManager::AUTH_LEVEL_MODERATOR) | 			if ($this->maniaControl->getAuthenticationManager()->checkRight($player, AuthenticationManager::AUTH_LEVEL_MODERATOR)) { | ||||||
| 			) { |  | ||||||
| 				// Further Player actions Quad | 				// Further Player actions Quad | ||||||
| 				$playerQuad = new Quad_Icons64x64_1(); | 				$playerQuad = new Quad_Icons64x64_1(); | ||||||
| 				$playerFrame->add($playerQuad); | 				$playerFrame->add($playerQuad); | ||||||
| @@ -320,10 +320,8 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer | |||||||
| 				$playerQuad->addTooltipLabelFeature($descriptionLabel, $description); | 				$playerQuad->addTooltipLabelFeature($descriptionLabel, $description); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if ($this->maniaControl->getServer()->isTeamMode() | 			if ($this->maniaControl->getServer()->isTeamMode()) { | ||||||
| 			) { | 				if ($this->maniaControl->getAuthenticationManager()->checkPermission($player, PlayerActions::SETTING_PERMISSION_FORCE_PLAYER_TEAM)) { | ||||||
| 				if ($this->maniaControl->getAuthenticationManager()->checkPermission($player, PlayerActions::SETTING_PERMISSION_FORCE_PLAYER_TEAM) |  | ||||||
| 				) { |  | ||||||
| 					// Force to Red-Team Quad | 					// Force to Red-Team Quad | ||||||
| 					$redQuad = new Quad_Emblems(); | 					$redQuad = new Quad_Emblems(); | ||||||
| 					$playerFrame->add($redQuad); | 					$playerFrame->add($redQuad); | ||||||
| @@ -350,8 +348,7 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer | |||||||
| 					$description = 'Force $<' . $listPlayer->nickname . '$> to Blue Team!'; | 					$description = 'Force $<' . $listPlayer->nickname . '$> to Blue Team!'; | ||||||
| 					$blueQuad->addTooltipLabelFeature($descriptionLabel, $description); | 					$blueQuad->addTooltipLabelFeature($descriptionLabel, $description); | ||||||
|  |  | ||||||
| 				} else if ($this->maniaControl->getPluginManager()->isPluginActive(self::DEFAULT_CUSTOM_VOTE_PLUGIN) | 				} else if ($this->maniaControl->getPluginManager()->isPluginActive(self::DEFAULT_CUSTOM_VOTE_PLUGIN)) { | ||||||
| 				) { |  | ||||||
| 					// Kick Player Vote | 					// Kick Player Vote | ||||||
| 					$kickQuad = new Quad_UIConstruction_Buttons(); | 					$kickQuad = new Quad_UIConstruction_Buttons(); | ||||||
| 					$playerFrame->add($kickQuad); | 					$playerFrame->add($kickQuad); | ||||||
| @@ -365,8 +362,7 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer | |||||||
| 					$kickQuad->addTooltipLabelFeature($descriptionLabel, $description); | 					$kickQuad->addTooltipLabelFeature($descriptionLabel, $description); | ||||||
| 				} | 				} | ||||||
| 			} else { | 			} else { | ||||||
| 				if ($this->maniaControl->getAuthenticationManager()->checkPermission($player, PlayerActions::SETTING_PERMISSION_FORCE_PLAYER_PLAY) | 				if ($this->maniaControl->getAuthenticationManager()->checkPermission($player, PlayerActions::SETTING_PERMISSION_FORCE_PLAYER_PLAY)) { | ||||||
| 				) { |  | ||||||
| 					// Force to Play | 					// Force to Play | ||||||
| 					$playQuad = new Quad_Emblems(); | 					$playQuad = new Quad_Emblems(); | ||||||
| 					$playerFrame->add($playQuad); | 					$playerFrame->add($playQuad); | ||||||
| @@ -381,8 +377,7 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if ($this->maniaControl->getAuthenticationManager()->checkPermission($player, PlayerActions::SETTING_PERMISSION_FORCE_PLAYER_SPEC) | 			if ($this->maniaControl->getAuthenticationManager()->checkPermission($player, PlayerActions::SETTING_PERMISSION_FORCE_PLAYER_SPEC)) { | ||||||
| 			) { |  | ||||||
| 				// Force to Spectator Quad | 				// Force to Spectator Quad | ||||||
| 				$spectatorQuad = new Quad_BgRaceScore2(); | 				$spectatorQuad = new Quad_BgRaceScore2(); | ||||||
| 				$playerFrame->add($spectatorQuad); | 				$playerFrame->add($spectatorQuad); | ||||||
| @@ -395,8 +390,7 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer | |||||||
| 				// Force to Spectator Description Label | 				// Force to Spectator Description Label | ||||||
| 				$description = 'Force $<' . $listPlayer->nickname . '$> to Spectator!'; | 				$description = 'Force $<' . $listPlayer->nickname . '$> to Spectator!'; | ||||||
| 				$spectatorQuad->addTooltipLabelFeature($descriptionLabel, $description); | 				$spectatorQuad->addTooltipLabelFeature($descriptionLabel, $description); | ||||||
| 			} else if ($this->maniaControl->getPluginManager()->isPluginActive(self::DEFAULT_CUSTOM_VOTE_PLUGIN) | 			} else if ($this->maniaControl->getPluginManager()->isPluginActive(self::DEFAULT_CUSTOM_VOTE_PLUGIN)) { | ||||||
| 			) { |  | ||||||
| 				// Force to Spectator Quad | 				// Force to Spectator Quad | ||||||
| 				$spectatorQuad = new Quad_BgRaceScore2(); | 				$spectatorQuad = new Quad_BgRaceScore2(); | ||||||
| 				$playerFrame->add($spectatorQuad); | 				$playerFrame->add($spectatorQuad); | ||||||
| @@ -451,7 +445,7 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer | |||||||
| 		// mainframe | 		// mainframe | ||||||
| 		$frame = new Frame(); | 		$frame = new Frame(); | ||||||
| 		$frame->setSize($width, $height); | 		$frame->setSize($width, $height); | ||||||
| 		$frame->setPosition($posX + $width / 2, 0); | 		$frame->setPosition($posX + $width / 2, 0, 31); | ||||||
|  |  | ||||||
| 		// Add Close Quad (X) | 		// Add Close Quad (X) | ||||||
| 		$closeQuad = new Quad_Icons64x64_1(); | 		$closeQuad = new Quad_Icons64x64_1(); | ||||||
| @@ -467,14 +461,14 @@ class PlayerList implements ManialinkPageAnswerListener, CallbackListener, Timer | |||||||
| 		$backgroundQuad->setSize($width, $height); | 		$backgroundQuad->setSize($width, $height); | ||||||
| 		$backgroundQuad->setImage('https://dl.dropboxusercontent.com/u/105352981/Stuff/CAM%20SM%20BORDER%20PNG.png'); //TODO just a test | 		$backgroundQuad->setImage('https://dl.dropboxusercontent.com/u/105352981/Stuff/CAM%20SM%20BORDER%20PNG.png'); //TODO just a test | ||||||
| 		//$backgroundQuad->setStyles($quadStyle, $quadSubstyle); | 		//$backgroundQuad->setStyles($quadStyle, $quadSubstyle); | ||||||
| 		$backgroundQuad->setZ(0.2); | 		$backgroundQuad->setZ(-0.3); | ||||||
|  |  | ||||||
| 		// Background Quad | 		// Background Quad | ||||||
| 		$backgroundQuad = new Quad(); | 		$backgroundQuad = new Quad(); | ||||||
| 		$frame->add($backgroundQuad); | 		$frame->add($backgroundQuad); | ||||||
| 		$backgroundQuad->setSize($width - 2, $height - 2); | 		$backgroundQuad->setSize($width - 2, $height - 2); | ||||||
| 		$backgroundQuad->setStyles($quadStyle, $quadSubstyle); | 		$backgroundQuad->setStyles($quadStyle, $quadSubstyle); | ||||||
| 		$backgroundQuad->setZ(0.1); | 		$backgroundQuad->setZ(-0.4); | ||||||
|  |  | ||||||
| 		// Show headline | 		// Show headline | ||||||
| 		$label = new Label_Text(); | 		$label = new Label_Text(); | ||||||
|   | |||||||
| @@ -7,6 +7,9 @@ use ManiaControl\Callbacks\CallbackListener; | |||||||
| use ManiaControl\Callbacks\CallbackManager; | use ManiaControl\Callbacks\CallbackManager; | ||||||
| use ManiaControl\Callbacks\Callbacks; | use ManiaControl\Callbacks\Callbacks; | ||||||
| use ManiaControl\Callbacks\TimerListener; | use ManiaControl\Callbacks\TimerListener; | ||||||
|  | use ManiaControl\Communication\CommunicationAnswer; | ||||||
|  | use ManiaControl\Communication\CommunicationListener; | ||||||
|  | use ManiaControl\Communication\CommunicationMethods; | ||||||
| use ManiaControl\Logger; | use ManiaControl\Logger; | ||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| use ManiaControl\Statistics\StatisticManager; | use ManiaControl\Statistics\StatisticManager; | ||||||
| @@ -20,7 +23,7 @@ use Maniaplanet\DedicatedServer\Xmlrpc\UnknownPlayerException; | |||||||
|  * @copyright 2014-2015 ManiaControl Team |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  */ |  */ | ||||||
| class PlayerManager implements CallbackListener, TimerListener { | class PlayerManager implements CallbackListener, TimerListener, CommunicationListener { | ||||||
| 	/* | 	/* | ||||||
| 	 * Constants | 	 * Constants | ||||||
| 	 */ | 	 */ | ||||||
| @@ -105,6 +108,12 @@ class PlayerManager implements CallbackListener, TimerListener { | |||||||
| 		// Player stats | 		// Player stats | ||||||
| 		$this->maniaControl->getStatisticManager()->defineStatMetaData(self::STAT_JOIN_COUNT); | 		$this->maniaControl->getStatisticManager()->defineStatMetaData(self::STAT_JOIN_COUNT); | ||||||
| 		$this->maniaControl->getStatisticManager()->defineStatMetaData(self::STAT_SERVERTIME, StatisticManager::STAT_TYPE_TIME); | 		$this->maniaControl->getStatisticManager()->defineStatMetaData(self::STAT_SERVERTIME, StatisticManager::STAT_TYPE_TIME); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		// Communication Listenings | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::GET_PLAYER_LIST, $this, function ($data) { | ||||||
|  | 			return new CommunicationAnswer($this->players); | ||||||
|  | 		}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -184,6 +193,7 @@ class PlayerManager implements CallbackListener, TimerListener { | |||||||
| 		return $this->adminLists; | 		return $this->adminLists; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Handle OnInit callback | 	 * Handle OnInit callback | ||||||
| 	 */ | 	 */ | ||||||
| @@ -374,15 +384,24 @@ class PlayerManager implements CallbackListener, TimerListener { | |||||||
| 	 * Get the count of all Players | 	 * Get the count of all Players | ||||||
| 	 * | 	 * | ||||||
| 	 * @param bool $withoutSpectators | 	 * @param bool $withoutSpectators | ||||||
|  | 	 * @param bool $withoutBots | ||||||
| 	 * @return int | 	 * @return int | ||||||
| 	 */ | 	 */ | ||||||
| 	public function getPlayerCount($withoutSpectators = true) { | 	public function getPlayerCount($withoutSpectators = true, $withoutBots = true) { | ||||||
| 		if (!$withoutSpectators) { |  | ||||||
| 			return count($this->players); |  | ||||||
| 		} |  | ||||||
| 		$count = 0; | 		$count = 0; | ||||||
| 		foreach ($this->players as $player) { | 		foreach ($this->players as $player) { | ||||||
| 			if (!$player->isSpectator) { | 			$valid = true; | ||||||
|  | 			if ($withoutSpectators) { | ||||||
|  | 				if ($player->isSpectator) { | ||||||
|  | 					$valid = false; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if ($withoutBots) { | ||||||
|  | 				if ($player->isFakePlayer()) { | ||||||
|  | 					$valid = false; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if ($valid) { | ||||||
| 				$count++; | 				$count++; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -516,6 +535,22 @@ class PlayerManager implements CallbackListener, TimerListener { | |||||||
| 		return $this->players; | 		return $this->players; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Get a List of Spectators | ||||||
|  | 	 * | ||||||
|  | 	 * @return Player[] | ||||||
|  | 	 */ | ||||||
|  | 	public function getSpectators() { | ||||||
|  | 		$spectators = array(); | ||||||
|  | 		foreach ($this->players as $player) { | ||||||
|  | 			if ($player->isSpectator) { | ||||||
|  | 				$spectators[] = $player; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return $spectators; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Get the count of all spectators | 	 * Get the count of all spectators | ||||||
| 	 * | 	 * | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| namespace ManiaControl\Plugins; | namespace ManiaControl\Plugins; | ||||||
|  |  | ||||||
| use ManiaControl\Callbacks\CallbackListener; | use ManiaControl\Callbacks\CallbackListener; | ||||||
|  | use ManiaControl\Callbacks\EchoListener; | ||||||
| use ManiaControl\Callbacks\TimerListener; | use ManiaControl\Callbacks\TimerListener; | ||||||
| use ManiaControl\Commands\CommandListener; | use ManiaControl\Commands\CommandListener; | ||||||
| use ManiaControl\Files\FileUtil; | use ManiaControl\Files\FileUtil; | ||||||
| @@ -141,6 +142,9 @@ class PluginManager { | |||||||
|  |  | ||||||
| 		$plugin->unload(); | 		$plugin->unload(); | ||||||
|  |  | ||||||
|  | 		if ($plugin instanceof EchoListener) { | ||||||
|  | 			$this->maniaControl->getEchoManager()->unregisterEchoListener($plugin); | ||||||
|  | 		} | ||||||
| 		if ($plugin instanceof CallbackListener) { | 		if ($plugin instanceof CallbackListener) { | ||||||
| 			$this->maniaControl->getCallbackManager()->unregisterCallbackListener($plugin); | 			$this->maniaControl->getCallbackManager()->unregisterCallbackListener($plugin); | ||||||
| 			$this->maniaControl->getCallbackManager()->unregisterScriptCallbackListener($plugin); | 			$this->maniaControl->getCallbackManager()->unregisterScriptCallbackListener($plugin); | ||||||
|   | |||||||
| @@ -40,6 +40,7 @@ class Commands implements CallbackListener, CommandListener, ManialinkPageAnswer | |||||||
| 	const SETTING_PERMISSION_CHANGE_SERVERSETTINGS = 'Change ServerSettings'; | 	const SETTING_PERMISSION_CHANGE_SERVERSETTINGS = 'Change ServerSettings'; | ||||||
| 	const COMMAND_EXTEND_WARMUP                    = 'WarmUp_Extend'; | 	const COMMAND_EXTEND_WARMUP                    = 'WarmUp_Extend'; | ||||||
| 	const COMMAND_FORCE_WARMUP                     = 'Command_ForceWarmUp'; | 	const COMMAND_FORCE_WARMUP                     = 'Command_ForceWarmUp'; | ||||||
|  | 	const COMMAND_SET_PAUSE                        = 'Command_SetPause'; | ||||||
|  |  | ||||||
| 	/* | 	/* | ||||||
| 	 * Private properties | 	 * Private properties | ||||||
| @@ -113,7 +114,7 @@ class Commands implements CallbackListener, CommandListener, ManialinkPageAnswer | |||||||
| 		try { | 		try { | ||||||
| 			$scriptInfos = $this->maniaControl->getClient()->getModeScriptInfo(); | 			$scriptInfos = $this->maniaControl->getClient()->getModeScriptInfo(); | ||||||
| 			foreach ($scriptInfos->commandDescs as $param) { | 			foreach ($scriptInfos->commandDescs as $param) { | ||||||
| 				if ($param->name === self::COMMAND_FORCE_WARMUP) { | 				if ($param->name === self::COMMAND_FORCE_WARMUP || $param->name === self::COMMAND_SET_PAUSE) { | ||||||
| 					$pauseExists = true; | 					$pauseExists = true; | ||||||
| 					break; | 					break; | ||||||
| 				} | 				} | ||||||
| @@ -163,14 +164,12 @@ class Commands implements CallbackListener, CommandListener, ManialinkPageAnswer | |||||||
| 	 * @param Player $player | 	 * @param Player $player | ||||||
| 	 */ | 	 */ | ||||||
| 	public function commandCancelVote(array $chatCallback, Player $player) { | 	public function commandCancelVote(array $chatCallback, Player $player) { | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CANCEL_VOTE) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CANCEL_VOTE)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if ($this->maniaControl->getClient()->cancelVote() | 		if ($this->maniaControl->getClient()->cancelVote()) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getChat()->sendInformation($player->getEscapedNickname() . ' cancelled the Vote!'); | 			$this->maniaControl->getChat()->sendInformation($player->getEscapedNickname() . ' cancelled the Vote!'); | ||||||
| 		} else { | 		} else { | ||||||
| 			$this->maniaControl->getChat()->sendInformation("There's no vote running currently!", $player); | 			$this->maniaControl->getChat()->sendInformation("There's no vote running currently!", $player); | ||||||
| @@ -187,8 +186,7 @@ class Commands implements CallbackListener, CommandListener, ManialinkPageAnswer | |||||||
| 	 * @param Player $player | 	 * @param Player $player | ||||||
| 	 */ | 	 */ | ||||||
| 	public function commandExtendWarmup(array $callback, Player $player) { | 	public function commandExtendWarmup(array $callback, Player $player) { | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_HANDLE_WARMUP) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_HANDLE_WARMUP)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -207,8 +205,7 @@ class Commands implements CallbackListener, CommandListener, ManialinkPageAnswer | |||||||
| 	 * @param Player $player | 	 * @param Player $player | ||||||
| 	 */ | 	 */ | ||||||
| 	public function commandEndWarmup(array $callback, Player $player) { | 	public function commandEndWarmup(array $callback, Player $player) { | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_HANDLE_WARMUP) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_HANDLE_WARMUP)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -227,16 +224,27 @@ class Commands implements CallbackListener, CommandListener, ManialinkPageAnswer | |||||||
| 	 * @param Player $player | 	 * @param Player $player | ||||||
| 	 */ | 	 */ | ||||||
| 	public function setPause(array $callback, Player $player) { | 	public function setPause(array $callback, Player $player) { | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_SET_PAUSE) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_SET_PAUSE)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		//Normal Gamemodes | ||||||
| 		try { | 		try { | ||||||
| 			$this->maniaControl->getClient()->sendModeScriptCommands(array('Command_ForceWarmUp' => true)); | 			$this->maniaControl->getClient()->sendModeScriptCommands(array('Command_ForceWarmUp' => true)); | ||||||
| 			$this->maniaControl->getChat()->sendInformation($player->getEscapedNickname() . ' paused the Game!'); | 			$this->maniaControl->getChat()->sendInformation($player->getEscapedNickname() . ' paused the Game!'); | ||||||
| 		} catch (GameModeException $e) { | 		} catch (GameModeException $e) { | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		try { | ||||||
|  | 			//Chase and Combo? | ||||||
|  | 			$this->maniaControl->getClient()->sendModeScriptCommands(array('Command_SetPause' => true)); | ||||||
|  | 			$this->maniaControl->getChat()->sendInformation($player->getEscapedNickname() . ' paused the Game!'); | ||||||
|  |  | ||||||
|  | 			//Especially for chase, force end of the round to reach a draw | ||||||
|  | 			$this->maniaControl->getClient()->sendModeScriptCommands(array('Command_ForceEndRound' => true)); | ||||||
|  | 		} catch (GameModeException $ex) { | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -246,8 +254,7 @@ class Commands implements CallbackListener, CommandListener, ManialinkPageAnswer | |||||||
| 		// TODO: move empty & delayed shutdown code into server class | 		// TODO: move empty & delayed shutdown code into server class | ||||||
| 		// Empty shutdown | 		// Empty shutdown | ||||||
| 		if ($this->serverShutdownEmpty) { | 		if ($this->serverShutdownEmpty) { | ||||||
| 			if ($this->maniaControl->getPlayerManager()->getPlayerCount(false) <= 0 | 			if ($this->maniaControl->getPlayerManager()->getPlayerCount(false) <= 0) { | ||||||
| 			) { |  | ||||||
| 				$this->shutdownServer('empty'); | 				$this->shutdownServer('empty'); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -277,8 +284,7 @@ class Commands implements CallbackListener, CommandListener, ManialinkPageAnswer | |||||||
| 	 * @param Player $player | 	 * @param Player $player | ||||||
| 	 */ | 	 */ | ||||||
| 	public function commandSystemInfo(array $chat, Player $player) { | 	public function commandSystemInfo(array $chat, Player $player) { | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_SHOW_SYSTEMINFO) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_SHOW_SYSTEMINFO)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -294,8 +300,7 @@ class Commands implements CallbackListener, CommandListener, ManialinkPageAnswer | |||||||
| 	 * @param Player $player | 	 * @param Player $player | ||||||
| 	 */ | 	 */ | ||||||
| 	public function commandShutdownServer(array $chat, Player $player) { | 	public function commandShutdownServer(array $chat, Player $player) { | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_SHUTDOWN_SERVER) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_SHUTDOWN_SERVER)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -334,8 +339,7 @@ class Commands implements CallbackListener, CommandListener, ManialinkPageAnswer | |||||||
| 	 * @param Player $player | 	 * @param Player $player | ||||||
| 	 */ | 	 */ | ||||||
| 	public function commandSetServerName(array $chat, Player $player) { | 	public function commandSetServerName(array $chat, Player $player) { | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CHANGE_SERVERSETTINGS) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CHANGE_SERVERSETTINGS)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -356,8 +360,7 @@ class Commands implements CallbackListener, CommandListener, ManialinkPageAnswer | |||||||
| 	 * @param Player $player | 	 * @param Player $player | ||||||
| 	 */ | 	 */ | ||||||
| 	public function commandSetPwd(array $chatCallback, Player $player) { | 	public function commandSetPwd(array $chatCallback, Player $player) { | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CHANGE_SERVERSETTINGS) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CHANGE_SERVERSETTINGS)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -379,8 +382,7 @@ class Commands implements CallbackListener, CommandListener, ManialinkPageAnswer | |||||||
| 	 * @param Player $player | 	 * @param Player $player | ||||||
| 	 */ | 	 */ | ||||||
| 	public function commandSetSpecPwd(array $chatCallback, Player $player) { | 	public function commandSetSpecPwd(array $chatCallback, Player $player) { | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CHANGE_SERVERSETTINGS) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CHANGE_SERVERSETTINGS)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -402,8 +404,7 @@ class Commands implements CallbackListener, CommandListener, ManialinkPageAnswer | |||||||
| 	 * @param Player $player | 	 * @param Player $player | ||||||
| 	 */ | 	 */ | ||||||
| 	public function commandSetMaxPlayers(array $chatCallback, Player $player) { | 	public function commandSetMaxPlayers(array $chatCallback, Player $player) { | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CHANGE_SERVERSETTINGS) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CHANGE_SERVERSETTINGS)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -433,8 +434,7 @@ class Commands implements CallbackListener, CommandListener, ManialinkPageAnswer | |||||||
| 	 * @param Player $player | 	 * @param Player $player | ||||||
| 	 */ | 	 */ | ||||||
| 	public function commandSetMaxSpectators(array $chatCallback, Player $player) { | 	public function commandSetMaxSpectators(array $chatCallback, Player $player) { | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CHANGE_SERVERSETTINGS) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CHANGE_SERVERSETTINGS)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ namespace ManiaControl\Server; | |||||||
|  |  | ||||||
| use ManiaControl\Logger; | use ManiaControl\Logger; | ||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
|  | use Maniaplanet\DedicatedServer\Xmlrpc\GameModeException; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Manager for Game Mode Script related Stuff |  * Manager for Game Mode Script related Stuff | ||||||
| @@ -39,7 +40,12 @@ class ScriptManager { | |||||||
| 		if (!$this->isScriptMode()) { | 		if (!$this->isScriptMode()) { | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		try { | ||||||
| 			$scriptSettings = $this->maniaControl->getClient()->getModeScriptSettings(); | 			$scriptSettings = $this->maniaControl->getClient()->getModeScriptSettings(); | ||||||
|  | 		} catch (GameModeException $e) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		if (!array_key_exists('S_UseScriptCallbacks', $scriptSettings)) { | 		if (!array_key_exists('S_UseScriptCallbacks', $scriptSettings)) { | ||||||
| 			return false; | 			return false; | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ namespace ManiaControl\Server; | |||||||
|  |  | ||||||
| use ManiaControl\Callbacks\CallbackListener; | use ManiaControl\Callbacks\CallbackListener; | ||||||
| use ManiaControl\Callbacks\Callbacks; | use ManiaControl\Callbacks\Callbacks; | ||||||
|  | use ManiaControl\Commands\CommandListener; | ||||||
| use ManiaControl\Logger; | use ManiaControl\Logger; | ||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| use ManiaControl\Players\Player; | use ManiaControl\Players\Player; | ||||||
| @@ -17,7 +18,7 @@ use Maniaplanet\DedicatedServer\Xmlrpc\Exception; | |||||||
|  * @copyright 2014-2015 ManiaControl Team |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  */ |  */ | ||||||
| class Server implements CallbackListener { | class Server implements CallbackListener, CommandListener { | ||||||
| 	/* | 	/* | ||||||
| 	 * Constants | 	 * Constants | ||||||
| 	 */ | 	 */ | ||||||
| @@ -85,6 +86,30 @@ class Server implements CallbackListener { | |||||||
|  |  | ||||||
| 		// Callbacks | 		// Callbacks | ||||||
| 		$this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::ONINIT, $this, 'onInit'); | 		$this->maniaControl->getCallbackManager()->registerCallbackListener(Callbacks::ONINIT, $this, 'onInit'); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommandManager()->registerCommandListener("uptime", $this, "chatUpTime", true, "Show how long the server is running."); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Displays how long the Server is running already in the Chat | ||||||
|  | 	 * | ||||||
|  | 	 * @param array                        $chatCallback | ||||||
|  | 	 * @param \ManiaControl\Players\Player $player | ||||||
|  | 	 */ | ||||||
|  | 	public function chatUpTime(array $chatCallback, Player $player) { | ||||||
|  | 		$networkStats = $this->maniaControl->getClient()->getNetworkStats(); | ||||||
|  |  | ||||||
|  | 		$minutestotal = $networkStats->uptime / 60; | ||||||
|  | 		$hourstotal   = $minutestotal / 60; | ||||||
|  | 		$days         = intval($hourstotal / 24); | ||||||
|  | 		$hours        = intval($hourstotal - 24 * $days); | ||||||
|  | 		$minutes      = intval($minutestotal - 24 * 60 * $days - $hours * 60); | ||||||
|  |  | ||||||
|  | 		$days > 1 ? $dayString = 'days' : $dayString = 'day'; | ||||||
|  | 		$hours > 1 ? $hourString = 'hours' : $hourString = 'hour'; | ||||||
|  | 		$minutes > 1 ? $minuteString = 'minutes' : $minuteString = 'minute'; | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getChat()->sendChat('Server is running since $<$fff' . $days . '$> ' . $dayString . ', $<$fff' . $hours . '$> ' . $hourString . ' and $<$fff' . $minutes . '$> ' . $minuteString, $player); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -226,6 +251,30 @@ class Server implements CallbackListener { | |||||||
| 		return $servers; | 		return $servers; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** Get Server Login by Index | ||||||
|  | 	 * | ||||||
|  | 	 * @param int $index | ||||||
|  | 	 * @return string | ||||||
|  | 	 */ | ||||||
|  | 	public function getServerLoginByIndex($index) { | ||||||
|  | 		$mysqli = $this->maniaControl->getDatabase()->getMysqli(); | ||||||
|  | 		$query  = "SELECT * FROM `" . self::TABLE_SERVERS . "` WHERE `index`=" . $index . ";"; | ||||||
|  | 		$result = $mysqli->query($query); | ||||||
|  |  | ||||||
|  | 		if (!$result) { | ||||||
|  | 			trigger_error($mysqli->error); | ||||||
|  | 			return ""; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if ($result->num_rows != 1) { | ||||||
|  | 			return ""; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		$row = $result->fetch_object(); | ||||||
|  |  | ||||||
|  | 		return $row->login; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Handle OnInit Callback | 	 * Handle OnInit Callback | ||||||
| 	 */ | 	 */ | ||||||
|   | |||||||
| @@ -14,6 +14,9 @@ use ManiaControl\Admin\AuthenticationManager; | |||||||
| use ManiaControl\Callbacks\CallbackListener; | use ManiaControl\Callbacks\CallbackListener; | ||||||
| use ManiaControl\Callbacks\Callbacks; | use ManiaControl\Callbacks\Callbacks; | ||||||
| use ManiaControl\Callbacks\TimerListener; | use ManiaControl\Callbacks\TimerListener; | ||||||
|  | use ManiaControl\Communication\CommunicationAnswer; | ||||||
|  | use ManiaControl\Communication\CommunicationListener; | ||||||
|  | use ManiaControl\Communication\CommunicationMethods; | ||||||
| use ManiaControl\Configurator\ConfiguratorMenu; | use ManiaControl\Configurator\ConfiguratorMenu; | ||||||
| use ManiaControl\Logger; | use ManiaControl\Logger; | ||||||
| use ManiaControl\ManiaControl; | use ManiaControl\ManiaControl; | ||||||
| @@ -28,7 +31,7 @@ use Maniaplanet\DedicatedServer\Xmlrpc\ServerOptionsException; | |||||||
|  * @copyright 2014-2015 ManiaControl Team |  * @copyright 2014-2015 ManiaControl Team | ||||||
|  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 |  * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3 | ||||||
|  */ |  */ | ||||||
| class ServerOptionsMenu implements CallbackListener, ConfiguratorMenu, TimerListener { | class ServerOptionsMenu implements CallbackListener, ConfiguratorMenu, TimerListener, CommunicationListener { | ||||||
| 	/* | 	/* | ||||||
| 	 * Constants | 	 * Constants | ||||||
| 	 */ | 	 */ | ||||||
| @@ -64,6 +67,10 @@ class ServerOptionsMenu implements CallbackListener, ConfiguratorMenu, TimerList | |||||||
|  |  | ||||||
| 		// Permissions | 		// Permissions | ||||||
| 		$this->maniaControl->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_CHANGE_SERVER_OPTIONS, AuthenticationManager::AUTH_LEVEL_SUPERADMIN); | 		$this->maniaControl->getAuthenticationManager()->definePermissionLevel(self::SETTING_PERMISSION_CHANGE_SERVER_OPTIONS, AuthenticationManager::AUTH_LEVEL_SUPERADMIN); | ||||||
|  |  | ||||||
|  | 		//TODO remove to somewhere cleaner | ||||||
|  | 		//Communication Listenings | ||||||
|  | 		$this->initalizeCommunicationListenings(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -322,8 +329,7 @@ class ServerOptionsMenu implements CallbackListener, ConfiguratorMenu, TimerList | |||||||
| 	 * @see \ManiaControl\Configurators\ConfiguratorMenu::saveConfigData() | 	 * @see \ManiaControl\Configurators\ConfiguratorMenu::saveConfigData() | ||||||
| 	 */ | 	 */ | ||||||
| 	public function saveConfigData(array $configData, Player $player) { | 	public function saveConfigData(array $configData, Player $player) { | ||||||
| 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CHANGE_SERVER_OPTIONS) | 		if (!$this->maniaControl->getAuthenticationManager()->checkPermission($player, self::SETTING_PERMISSION_CHANGE_SERVER_OPTIONS)) { | ||||||
| 		) { |  | ||||||
| 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | 			$this->maniaControl->getAuthenticationManager()->sendNotAllowed($player); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @@ -376,4 +382,43 @@ class ServerOptionsMenu implements CallbackListener, ConfiguratorMenu, TimerList | |||||||
|  |  | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Initializes the communication Listenings | ||||||
|  | 	 */ | ||||||
|  | 	private function initalizeCommunicationListenings() { | ||||||
|  | 		//Communication Listenings | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::GET_SERVER_OPTIONS, $this, function ($data) { | ||||||
|  | 			return new CommunicationAnswer($this->maniaControl->getClient()->getServerOptions()); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$this->maniaControl->getCommunicationManager()->registerCommunicationListener(CommunicationMethods::SET_SERVER_OPTIONS, $this, function ($data) { | ||||||
|  | 			if (!is_object($data) || !property_exists($data, "serverOptions")) { | ||||||
|  | 				return new CommunicationAnswer("No valid ServerOptions provided!", true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$oldServerOptions = $this->maniaControl->getClient()->getServerOptions(); | ||||||
|  | 			$newServerOptions = new ServerOptions(); | ||||||
|  |  | ||||||
|  | 			foreach ($data->serverOptions as $name => $value) { | ||||||
|  | 				$optionName                    = $name; | ||||||
|  | 				$newServerOptions->$optionName = $value; | ||||||
|  | 				settype($newServerOptions->$optionName, gettype($oldServerOptions->$optionName)); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			$this->fillUpMandatoryOptions($newServerOptions, $oldServerOptions); | ||||||
|  |  | ||||||
|  | 			try { | ||||||
|  | 				$success = $this->maniaControl->getClient()->setServerOptions($newServerOptions); | ||||||
|  | 			} catch (ServerOptionsException $exception) { | ||||||
|  | 				return new CommunicationAnswer($exception->getMessage(), true); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			//Trigger Server Options Changed Callback | ||||||
|  | 			$this->maniaControl->getCallbackManager()->triggerCallback(self::CB_SERVER_OPTIONS_CHANGED, array(self::CB_SERVER_OPTIONS_CHANGED)); | ||||||
|  |  | ||||||
|  | 			return new CommunicationAnswer(array("success" => $success)); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -77,6 +77,16 @@ class SystemUtil { | |||||||
| 			Logger::log($message . 'FOUND!'); | 			Logger::log($message . 'FOUND!'); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		// Check for Zlib | ||||||
|  | 		$message = 'Checking for installed Zlib ... '; | ||||||
|  | 		if (!extension_loaded('zlib')) { | ||||||
|  | 			Logger::log($message . 'NOT FOUND!'); | ||||||
|  | 			Logger::log(" -- You don't have Zlib installed! Check: http://php.net/manual/de/zlib.setup.php"); | ||||||
|  | 			$success = false; | ||||||
|  | 		} else { | ||||||
|  | 			Logger::log($message . 'FOUND!'); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		if (!$success) { | 		if (!$success) { | ||||||
| 			// Missing requirements | 			// Missing requirements | ||||||
| 			self::quit(); | 			self::quit(); | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								libs/Evenement/EventEmitter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								libs/Evenement/EventEmitter.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * This file is part of Evenement. | ||||||
|  |  * | ||||||
|  |  * (c) Igor Wiedler <igor@wiedler.ch> | ||||||
|  |  * | ||||||
|  |  * For the full copyright and license information, please view the LICENSE | ||||||
|  |  * file that was distributed with this source code. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | namespace Evenement; | ||||||
|  |  | ||||||
|  | class EventEmitter implements EventEmitterInterface | ||||||
|  | { | ||||||
|  |     use EventEmitterTrait; | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								libs/Evenement/EventEmitterInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								libs/Evenement/EventEmitterInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * This file is part of Evenement. | ||||||
|  |  * | ||||||
|  |  * (c) Igor Wiedler <igor@wiedler.ch> | ||||||
|  |  * | ||||||
|  |  * For the full copyright and license information, please view the LICENSE | ||||||
|  |  * file that was distributed with this source code. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | namespace Evenement; | ||||||
|  |  | ||||||
|  | interface EventEmitterInterface | ||||||
|  | { | ||||||
|  |     public function on($event, callable $listener); | ||||||
|  |     public function once($event, callable $listener); | ||||||
|  |     public function removeListener($event, callable $listener); | ||||||
|  |     public function removeAllListeners($event = null); | ||||||
|  |     public function listeners($event); | ||||||
|  |     public function emit($event, array $arguments = []); | ||||||
|  | } | ||||||
							
								
								
									
										68
									
								
								libs/Evenement/EventEmitterTrait.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								libs/Evenement/EventEmitterTrait.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * This file is part of Evenement. | ||||||
|  |  * | ||||||
|  |  * (c) Igor Wiedler <igor@wiedler.ch> | ||||||
|  |  * | ||||||
|  |  * For the full copyright and license information, please view the LICENSE | ||||||
|  |  * file that was distributed with this source code. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | namespace Evenement; | ||||||
|  |  | ||||||
|  | trait EventEmitterTrait | ||||||
|  | { | ||||||
|  |     protected $listeners = []; | ||||||
|  |  | ||||||
|  |     public function on($event, callable $listener) | ||||||
|  |     { | ||||||
|  |         if (!isset($this->listeners[$event])) { | ||||||
|  |             $this->listeners[$event] = []; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->listeners[$event][] = $listener; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function once($event, callable $listener) | ||||||
|  |     { | ||||||
|  |         $onceListener = function () use (&$onceListener, $event, $listener) { | ||||||
|  |             $this->removeListener($event, $onceListener); | ||||||
|  |  | ||||||
|  |             call_user_func_array($listener, func_get_args()); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         $this->on($event, $onceListener); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function removeListener($event, callable $listener) | ||||||
|  |     { | ||||||
|  |         if (isset($this->listeners[$event])) { | ||||||
|  |             $index = array_search($listener, $this->listeners[$event], true); | ||||||
|  |             if (false !== $index) { | ||||||
|  |                 unset($this->listeners[$event][$index]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function removeAllListeners($event = null) | ||||||
|  |     { | ||||||
|  |         if ($event !== null) { | ||||||
|  |             unset($this->listeners[$event]); | ||||||
|  |         } else { | ||||||
|  |             $this->listeners = []; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function listeners($event) | ||||||
|  |     { | ||||||
|  |         return isset($this->listeners[$event]) ? $this->listeners[$event] : []; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function emit($event, array $arguments = []) | ||||||
|  |     { | ||||||
|  |         foreach ($this->listeners($event) as $listener) { | ||||||
|  |             call_user_func_array($listener, $arguments); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -4250,9 +4250,9 @@ class Connection | |||||||
| 		if(is_string($filename)) | 		if(is_string($filename)) | ||||||
| 		{ | 		{ | ||||||
| 			$filename = $this->stripBom($filename); | 			$filename = $this->stripBom($filename); | ||||||
| 			if(mb_check_encoding($filename, 'ascii')) | 			if(preg_match('/[^\x09\x0A\x0D\x20-\x7E]/', $filename)) | ||||||
| 				return $filename; |  | ||||||
| 				return "\xEF\xBB\xBF".$filename; | 				return "\xEF\xBB\xBF".$filename; | ||||||
|  | 			return $filename; | ||||||
| 		} | 		} | ||||||
| 		return array_map(array($this, 'secureUtf8'), $filename); | 		return array_map(array($this, 'secureUtf8'), $filename); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -7,12 +7,9 @@ | |||||||
|  |  | ||||||
| namespace Maniaplanet\DedicatedServer\Xmlrpc; | namespace Maniaplanet\DedicatedServer\Xmlrpc; | ||||||
|  |  | ||||||
| class FaultException extends Exception | class FaultException extends Exception { | ||||||
| { | 	static function create($faultString, $faultCode) { | ||||||
| 	static function create($faultString, $faultCode) | 		switch ($faultString) { | ||||||
| 	{ |  | ||||||
| 		switch($faultString) |  | ||||||
| 		{ |  | ||||||
| 			case 'Password incorrect.': | 			case 'Password incorrect.': | ||||||
| 			case 'Permission denied.': | 			case 'Permission denied.': | ||||||
| 				return new AuthenticationException($faultString, $faultCode); | 				return new AuthenticationException($faultString, $faultCode); | ||||||
| @@ -34,6 +31,7 @@ class FaultException extends Exception | |||||||
| 				return new LockedFeatureException($faultString, $faultCode); | 				return new LockedFeatureException($faultString, $faultCode); | ||||||
| 			case 'Login or Uid unknown.': | 			case 'Login or Uid unknown.': | ||||||
| 			case 'Login unknown.': | 			case 'Login unknown.': | ||||||
|  | 			case 'Payer login unknown.': | ||||||
| 				return new UnknownPlayerException($faultString, $faultCode); | 				return new UnknownPlayerException($faultString, $faultCode); | ||||||
| 			case 'The player is not a spectator': | 			case 'The player is not a spectator': | ||||||
| 			case 'The player is not a spectator.': | 			case 'The player is not a spectator.': | ||||||
| @@ -72,6 +70,7 @@ class FaultException extends Exception | |||||||
| 			case 'You cannot change the max spectators count: AllowSpectatorRelays is activated.': | 			case 'You cannot change the max spectators count: AllowSpectatorRelays is activated.': | ||||||
| 			case 'There are too many players': | 			case 'There are too many players': | ||||||
| 			case 'There are too many spectators': | 			case 'There are too many spectators': | ||||||
|  | 			case 'Unknown hideserver value': | ||||||
| 				return new ServerOptionsException($faultString, $faultCode); | 				return new ServerOptionsException($faultString, $faultCode); | ||||||
| 			case 'New mode unknown.': | 			case 'New mode unknown.': | ||||||
| 			case 'You need to stop the server to change to/from script mode.': | 			case 'You need to stop the server to change to/from script mode.': | ||||||
| @@ -79,6 +78,7 @@ class FaultException extends Exception | |||||||
| 			case 'Not in Team mode.': | 			case 'Not in Team mode.': | ||||||
| 			case 'Not in Rounds or Laps mode.': | 			case 'Not in Rounds or Laps mode.': | ||||||
| 			case 'The scores must be decreasing.': | 			case 'The scores must be decreasing.': | ||||||
|  | 			case 'No current script.': | ||||||
| 				return new GameModeException($faultString, $faultCode); | 				return new GameModeException($faultString, $faultCode); | ||||||
| 			case 'Unable to write the black list file.': | 			case 'Unable to write the black list file.': | ||||||
| 			case 'Unable to write the guest list file.': | 			case 'Unable to write the guest list file.': | ||||||
| @@ -90,26 +90,55 @@ class FaultException extends Exception | |||||||
| 			case 'Invalid url.': | 			case 'Invalid url.': | ||||||
| 				return new FileException($faultString, $faultCode); | 				return new FileException($faultString, $faultCode); | ||||||
| 		} | 		} | ||||||
| 		if(preg_match('~^Unknown setting \'.*\'\.$~iu', $faultString)) | 		if (preg_match('~^Unknown setting \'.*\'\.$~iu', $faultString)) { | ||||||
| 			return new GameModeException($faultString, $faultCode); | 			return new GameModeException($faultString, $faultCode); | ||||||
| 		if(preg_match('~^Couldn\'t load \'.*\'\.$~iu', $faultString)) | 		} | ||||||
|  | 		if (preg_match('~^Couldn\'t load \'.*\'\.$~iu', $faultString)) { | ||||||
| 			return new FileException($faultString, $faultCode); | 			return new FileException($faultString, $faultCode); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		return new self($faultString, $faultCode); | 		return new self($faultString, $faultCode); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| class AuthenticationException extends FaultException {} | class AuthenticationException extends FaultException { | ||||||
| class UnavailableFeatureException extends FaultException {} | } | ||||||
| class LockedFeatureException extends FaultException {} |  | ||||||
| class UnknownPlayerException extends FaultException {} | class UnavailableFeatureException extends FaultException { | ||||||
| class PlayerStateException extends FaultException {} | } | ||||||
| class AlreadyInListException extends FaultException {} |  | ||||||
| class NotInListException extends FaultException {} | class LockedFeatureException extends FaultException { | ||||||
| class IndexOutOfBoundException extends FaultException {} | } | ||||||
| class NextMapException extends FaultException{} |  | ||||||
| class ChangeInProgressException extends FaultException {} | class UnknownPlayerException extends FaultException { | ||||||
| class InvalidMapException extends FaultException{} | } | ||||||
| class GameModeException extends FaultException {} |  | ||||||
| class ServerOptionsException extends FaultException {} | class PlayerStateException extends FaultException { | ||||||
| class FileException extends FaultException {} | } | ||||||
|  |  | ||||||
|  | class AlreadyInListException extends FaultException { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class NotInListException extends FaultException { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class IndexOutOfBoundException extends FaultException { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class NextMapException extends FaultException { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class ChangeInProgressException extends FaultException { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class InvalidMapException extends FaultException { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class GameModeException extends FaultException { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class ServerOptionsException extends FaultException { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class FileException extends FaultException { | ||||||
|  | } | ||||||
|   | |||||||
| @@ -16,8 +16,8 @@ class GbxRemote | |||||||
| 	public static $sent; | 	public static $sent; | ||||||
|  |  | ||||||
| 	private $socket; | 	private $socket; | ||||||
| 	private $readTimeout = array('sec' => 5, 'usec' => 0); | 	private $readTimeout = array('sec' => 30, 'usec' => 0); | ||||||
| 	private $writeTimeout = array('sec' => 5, 'usec' => 0); | 	private $writeTimeout = array('sec' => 30, 'usec' => 0); | ||||||
| 	private $requestHandle; | 	private $requestHandle; | ||||||
| 	private $callbacksBuffer = array(); | 	private $callbacksBuffer = array(); | ||||||
| 	private $multicallBuffer = array(); | 	private $multicallBuffer = array(); | ||||||
|   | |||||||
							
								
								
									
										327
									
								
								libs/React/EventLoop/ExtEventLoop.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								libs/React/EventLoop/ExtEventLoop.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,327 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\EventLoop; | ||||||
|  |  | ||||||
|  | use Event; | ||||||
|  | use EventBase; | ||||||
|  | use EventConfig as EventBaseConfig; | ||||||
|  | use React\EventLoop\Tick\FutureTickQueue; | ||||||
|  | use React\EventLoop\Tick\NextTickQueue; | ||||||
|  | use React\EventLoop\Timer\Timer; | ||||||
|  | use React\EventLoop\Timer\TimerInterface; | ||||||
|  | use SplObjectStorage; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * An ext-event based React. | ||||||
|  |  */ | ||||||
|  | class ExtEventLoop implements LoopInterface | ||||||
|  | { | ||||||
|  |     private $eventBase; | ||||||
|  |     private $nextTickQueue; | ||||||
|  |     private $futureTickQueue; | ||||||
|  |     private $timerCallback; | ||||||
|  |     private $timerEvents; | ||||||
|  |     private $streamCallback; | ||||||
|  |     private $streamEvents = []; | ||||||
|  |     private $streamFlags = []; | ||||||
|  |     private $readListeners = []; | ||||||
|  |     private $writeListeners = []; | ||||||
|  |     private $running; | ||||||
|  |  | ||||||
|  |     public function __construct(EventBaseConfig $config = null) | ||||||
|  |     { | ||||||
|  |         $this->eventBase = new EventBase($config); | ||||||
|  |         $this->nextTickQueue = new NextTickQueue($this); | ||||||
|  |         $this->futureTickQueue = new FutureTickQueue($this); | ||||||
|  |         $this->timerEvents = new SplObjectStorage(); | ||||||
|  |  | ||||||
|  |         $this->createTimerCallback(); | ||||||
|  |         $this->createStreamCallback(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addReadStream($stream, callable $listener) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (!isset($this->readListeners[$key])) { | ||||||
|  |             $this->readListeners[$key] = $listener; | ||||||
|  |             $this->subscribeStreamEvent($stream, Event::READ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addWriteStream($stream, callable $listener) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (!isset($this->writeListeners[$key])) { | ||||||
|  |             $this->writeListeners[$key] = $listener; | ||||||
|  |             $this->subscribeStreamEvent($stream, Event::WRITE); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function removeReadStream($stream) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (isset($this->readListeners[$key])) { | ||||||
|  |             unset($this->readListeners[$key]); | ||||||
|  |             $this->unsubscribeStreamEvent($stream, Event::READ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function removeWriteStream($stream) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (isset($this->writeListeners[$key])) { | ||||||
|  |             unset($this->writeListeners[$key]); | ||||||
|  |             $this->unsubscribeStreamEvent($stream, Event::WRITE); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function removeStream($stream) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (isset($this->streamEvents[$key])) { | ||||||
|  |             $this->streamEvents[$key]->free(); | ||||||
|  |  | ||||||
|  |             unset( | ||||||
|  |                 $this->streamFlags[$key], | ||||||
|  |                 $this->streamEvents[$key], | ||||||
|  |                 $this->readListeners[$key], | ||||||
|  |                 $this->writeListeners[$key] | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addTimer($interval, callable $callback) | ||||||
|  |     { | ||||||
|  |         $timer = new Timer($this, $interval, $callback, false); | ||||||
|  |  | ||||||
|  |         $this->scheduleTimer($timer); | ||||||
|  |  | ||||||
|  |         return $timer; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addPeriodicTimer($interval, callable $callback) | ||||||
|  |     { | ||||||
|  |         $timer = new Timer($this, $interval, $callback, true); | ||||||
|  |  | ||||||
|  |         $this->scheduleTimer($timer); | ||||||
|  |  | ||||||
|  |         return $timer; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function cancelTimer(TimerInterface $timer) | ||||||
|  |     { | ||||||
|  |         if ($this->isTimerActive($timer)) { | ||||||
|  |             $this->timerEvents[$timer]->free(); | ||||||
|  |             $this->timerEvents->detach($timer); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function isTimerActive(TimerInterface $timer) | ||||||
|  |     { | ||||||
|  |         return $this->timerEvents->contains($timer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function nextTick(callable $listener) | ||||||
|  |     { | ||||||
|  |         $this->nextTickQueue->add($listener); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function futureTick(callable $listener) | ||||||
|  |     { | ||||||
|  |         $this->futureTickQueue->add($listener); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function tick() | ||||||
|  |     { | ||||||
|  |         $this->nextTickQueue->tick(); | ||||||
|  |  | ||||||
|  |         $this->futureTickQueue->tick(); | ||||||
|  |  | ||||||
|  |         // @-suppression: https://github.com/reactphp/react/pull/234#discussion-diff-7759616R226 | ||||||
|  |         @$this->eventBase->loop(EventBase::LOOP_ONCE | EventBase::LOOP_NONBLOCK); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function run() | ||||||
|  |     { | ||||||
|  |         $this->running = true; | ||||||
|  |  | ||||||
|  |         while ($this->running) { | ||||||
|  |             $this->nextTickQueue->tick(); | ||||||
|  |  | ||||||
|  |             $this->futureTickQueue->tick(); | ||||||
|  |  | ||||||
|  |             $flags = EventBase::LOOP_ONCE; | ||||||
|  |             if (!$this->running || !$this->nextTickQueue->isEmpty() || !$this->futureTickQueue->isEmpty()) { | ||||||
|  |                 $flags |= EventBase::LOOP_NONBLOCK; | ||||||
|  |             } elseif (!$this->streamEvents && !$this->timerEvents->count()) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // @-suppression: https://github.com/reactphp/react/pull/234#discussion-diff-7759616R226 | ||||||
|  |             @$this->eventBase->loop($flags); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function stop() | ||||||
|  |     { | ||||||
|  |         $this->running = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Schedule a timer for execution. | ||||||
|  |      * | ||||||
|  |      * @param TimerInterface $timer | ||||||
|  |      */ | ||||||
|  |     private function scheduleTimer(TimerInterface $timer) | ||||||
|  |     { | ||||||
|  |         $flags = Event::TIMEOUT; | ||||||
|  |  | ||||||
|  |         if ($timer->isPeriodic()) { | ||||||
|  |             $flags |= Event::PERSIST; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $event = new Event($this->eventBase, -1, $flags, $this->timerCallback, $timer); | ||||||
|  |         $this->timerEvents[$timer] = $event; | ||||||
|  |  | ||||||
|  |         $event->add($timer->getInterval()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a new ext-event Event object, or update the existing one. | ||||||
|  |      * | ||||||
|  |      * @param resource $stream | ||||||
|  |      * @param integer  $flag   Event::READ or Event::WRITE | ||||||
|  |      */ | ||||||
|  |     private function subscribeStreamEvent($stream, $flag) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (isset($this->streamEvents[$key])) { | ||||||
|  |             $event = $this->streamEvents[$key]; | ||||||
|  |             $flags = ($this->streamFlags[$key] |= $flag); | ||||||
|  |  | ||||||
|  |             $event->del(); | ||||||
|  |             $event->set($this->eventBase, $stream, Event::PERSIST | $flags, $this->streamCallback); | ||||||
|  |         } else { | ||||||
|  |             $event = new Event($this->eventBase, $stream, Event::PERSIST | $flag, $this->streamCallback); | ||||||
|  |  | ||||||
|  |             $this->streamEvents[$key] = $event; | ||||||
|  |             $this->streamFlags[$key] = $flag; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $event->add(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Update the ext-event Event object for this stream to stop listening to | ||||||
|  |      * the given event type, or remove it entirely if it's no longer needed. | ||||||
|  |      * | ||||||
|  |      * @param resource $stream | ||||||
|  |      * @param integer  $flag   Event::READ or Event::WRITE | ||||||
|  |      */ | ||||||
|  |     private function unsubscribeStreamEvent($stream, $flag) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         $flags = $this->streamFlags[$key] &= ~$flag; | ||||||
|  |  | ||||||
|  |         if (0 === $flags) { | ||||||
|  |             $this->removeStream($stream); | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $event = $this->streamEvents[$key]; | ||||||
|  |  | ||||||
|  |         $event->del(); | ||||||
|  |         $event->set($this->eventBase, $stream, Event::PERSIST | $flags, $this->streamCallback); | ||||||
|  |         $event->add(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a callback used as the target of timer events. | ||||||
|  |      * | ||||||
|  |      * A reference is kept to the callback for the lifetime of the loop | ||||||
|  |      * to prevent "Cannot destroy active lambda function" fatal error from | ||||||
|  |      * the event extension. | ||||||
|  |      */ | ||||||
|  |     private function createTimerCallback() | ||||||
|  |     { | ||||||
|  |         $this->timerCallback = function ($_, $_, $timer) { | ||||||
|  |             call_user_func($timer->getCallback(), $timer); | ||||||
|  |  | ||||||
|  |             if (!$timer->isPeriodic() && $this->isTimerActive($timer)) { | ||||||
|  |                 $this->cancelTimer($timer); | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a callback used as the target of stream events. | ||||||
|  |      * | ||||||
|  |      * A reference is kept to the callback for the lifetime of the loop | ||||||
|  |      * to prevent "Cannot destroy active lambda function" fatal error from | ||||||
|  |      * the event extension. | ||||||
|  |      */ | ||||||
|  |     private function createStreamCallback() | ||||||
|  |     { | ||||||
|  |         $this->streamCallback = function ($stream, $flags) { | ||||||
|  |             $key = (int) $stream; | ||||||
|  |  | ||||||
|  |             if (Event::READ === (Event::READ & $flags) && isset($this->readListeners[$key])) { | ||||||
|  |                 call_user_func($this->readListeners[$key], $stream, $this); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (Event::WRITE === (Event::WRITE & $flags) && isset($this->writeListeners[$key])) { | ||||||
|  |                 call_user_func($this->writeListeners[$key], $stream, $this); | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								libs/React/EventLoop/Factory.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								libs/React/EventLoop/Factory.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\EventLoop; | ||||||
|  |  | ||||||
|  | class Factory | ||||||
|  | { | ||||||
|  |     public static function create() | ||||||
|  |     { | ||||||
|  |         // @codeCoverageIgnoreStart | ||||||
|  |         if (function_exists('event_base_new')) { | ||||||
|  |             return new LibEventLoop(); | ||||||
|  |         } elseif (class_exists('libev\EventLoop', false)) { | ||||||
|  |             return new LibEvLoop; | ||||||
|  |         } elseif (class_exists('EventBase', false)) { | ||||||
|  |             return new ExtEventLoop; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return new StreamSelectLoop(); | ||||||
|  |         // @codeCoverageIgnoreEnd | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										218
									
								
								libs/React/EventLoop/LibEvLoop.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								libs/React/EventLoop/LibEvLoop.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,218 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\EventLoop; | ||||||
|  |  | ||||||
|  | use libev\EventLoop; | ||||||
|  | use libev\IOEvent; | ||||||
|  | use libev\TimerEvent; | ||||||
|  | use React\EventLoop\Tick\FutureTickQueue; | ||||||
|  | use React\EventLoop\Tick\NextTickQueue; | ||||||
|  | use React\EventLoop\Timer\Timer; | ||||||
|  | use React\EventLoop\Timer\TimerInterface; | ||||||
|  | use SplObjectStorage; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @see https://github.com/m4rw3r/php-libev | ||||||
|  |  * @see https://gist.github.com/1688204 | ||||||
|  |  */ | ||||||
|  | class LibEvLoop implements LoopInterface | ||||||
|  | { | ||||||
|  |     private $loop; | ||||||
|  |     private $nextTickQueue; | ||||||
|  |     private $futureTickQueue; | ||||||
|  |     private $timerEvents; | ||||||
|  |     private $readEvents = []; | ||||||
|  |     private $writeEvents = []; | ||||||
|  |     private $running; | ||||||
|  |  | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         $this->loop = new EventLoop(); | ||||||
|  |         $this->nextTickQueue = new NextTickQueue($this); | ||||||
|  |         $this->futureTickQueue = new FutureTickQueue($this); | ||||||
|  |         $this->timerEvents = new SplObjectStorage(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addReadStream($stream, callable $listener) | ||||||
|  |     { | ||||||
|  |         $callback = function () use ($stream, $listener) { | ||||||
|  |             call_user_func($listener, $stream, $this); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         $event = new IOEvent($callback, $stream, IOEvent::READ); | ||||||
|  |         $this->loop->add($event); | ||||||
|  |  | ||||||
|  |         $this->readEvents[(int) $stream] = $event; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addWriteStream($stream, callable $listener) | ||||||
|  |     { | ||||||
|  |         $callback = function () use ($stream, $listener) { | ||||||
|  |             call_user_func($listener, $stream, $this); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         $event = new IOEvent($callback, $stream, IOEvent::WRITE); | ||||||
|  |         $this->loop->add($event); | ||||||
|  |  | ||||||
|  |         $this->writeEvents[(int) $stream] = $event; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function removeReadStream($stream) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (isset($this->readEvents[$key])) { | ||||||
|  |             $this->readEvents[$key]->stop(); | ||||||
|  |             unset($this->readEvents[$key]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function removeWriteStream($stream) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (isset($this->writeEvents[$key])) { | ||||||
|  |             $this->writeEvents[$key]->stop(); | ||||||
|  |             unset($this->writeEvents[$key]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function removeStream($stream) | ||||||
|  |     { | ||||||
|  |         $this->removeReadStream($stream); | ||||||
|  |         $this->removeWriteStream($stream); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addTimer($interval, callable $callback) | ||||||
|  |     { | ||||||
|  |         $timer = new Timer($this, $interval, $callback, false); | ||||||
|  |  | ||||||
|  |         $callback = function () use ($timer) { | ||||||
|  |             call_user_func($timer->getCallback(), $timer); | ||||||
|  |  | ||||||
|  |             if ($this->isTimerActive($timer)) { | ||||||
|  |                 $this->cancelTimer($timer); | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         $event = new TimerEvent($callback, $timer->getInterval()); | ||||||
|  |         $this->timerEvents->attach($timer, $event); | ||||||
|  |         $this->loop->add($event); | ||||||
|  |  | ||||||
|  |         return $timer; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addPeriodicTimer($interval, callable $callback) | ||||||
|  |     { | ||||||
|  |         $timer = new Timer($this, $interval, $callback, true); | ||||||
|  |  | ||||||
|  |         $callback = function () use ($timer) { | ||||||
|  |             call_user_func($timer->getCallback(), $timer); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         $event = new TimerEvent($callback, $interval, $interval); | ||||||
|  |         $this->timerEvents->attach($timer, $event); | ||||||
|  |         $this->loop->add($event); | ||||||
|  |  | ||||||
|  |         return $timer; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function cancelTimer(TimerInterface $timer) | ||||||
|  |     { | ||||||
|  |         if (isset($this->timerEvents[$timer])) { | ||||||
|  |             $this->loop->remove($this->timerEvents[$timer]); | ||||||
|  |             $this->timerEvents->detach($timer); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function isTimerActive(TimerInterface $timer) | ||||||
|  |     { | ||||||
|  |         return $this->timerEvents->contains($timer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function nextTick(callable $listener) | ||||||
|  |     { | ||||||
|  |         $this->nextTickQueue->add($listener); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function futureTick(callable $listener) | ||||||
|  |     { | ||||||
|  |         $this->futureTickQueue->add($listener); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function tick() | ||||||
|  |     { | ||||||
|  |         $this->nextTickQueue->tick(); | ||||||
|  |  | ||||||
|  |         $this->futureTickQueue->tick(); | ||||||
|  |  | ||||||
|  |         $this->loop->run(EventLoop::RUN_ONCE | EventLoop::RUN_NOWAIT); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function run() | ||||||
|  |     { | ||||||
|  |         $this->running = true; | ||||||
|  |  | ||||||
|  |         while ($this->running) { | ||||||
|  |             $this->nextTickQueue->tick(); | ||||||
|  |  | ||||||
|  |             $this->futureTickQueue->tick(); | ||||||
|  |  | ||||||
|  |             $flags = EventLoop::RUN_ONCE; | ||||||
|  |             if (!$this->running || !$this->nextTickQueue->isEmpty() || !$this->futureTickQueue->isEmpty()) { | ||||||
|  |                 $flags |= EventLoop::RUN_NOWAIT; | ||||||
|  |             } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count()) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $this->loop->run($flags); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function stop() | ||||||
|  |     { | ||||||
|  |         $this->running = false; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										343
									
								
								libs/React/EventLoop/LibEventLoop.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										343
									
								
								libs/React/EventLoop/LibEventLoop.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,343 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\EventLoop; | ||||||
|  |  | ||||||
|  | use Event; | ||||||
|  | use EventBase; | ||||||
|  | use React\EventLoop\Tick\FutureTickQueue; | ||||||
|  | use React\EventLoop\Tick\NextTickQueue; | ||||||
|  | use React\EventLoop\Timer\Timer; | ||||||
|  | use React\EventLoop\Timer\TimerInterface; | ||||||
|  | use SplObjectStorage; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * An ext-libevent based React. | ||||||
|  |  */ | ||||||
|  | class LibEventLoop implements LoopInterface | ||||||
|  | { | ||||||
|  |     const MICROSECONDS_PER_SECOND = 1000000; | ||||||
|  |  | ||||||
|  |     private $eventBase; | ||||||
|  |     private $nextTickQueue; | ||||||
|  |     private $futureTickQueue; | ||||||
|  |     private $timerCallback; | ||||||
|  |     private $timerEvents; | ||||||
|  |     private $streamCallback; | ||||||
|  |     private $streamEvents = []; | ||||||
|  |     private $streamFlags = []; | ||||||
|  |     private $readListeners = []; | ||||||
|  |     private $writeListeners = []; | ||||||
|  |     private $running; | ||||||
|  |  | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         $this->eventBase = event_base_new(); | ||||||
|  |         $this->nextTickQueue = new NextTickQueue($this); | ||||||
|  |         $this->futureTickQueue = new FutureTickQueue($this); | ||||||
|  |         $this->timerEvents = new SplObjectStorage(); | ||||||
|  |  | ||||||
|  |         $this->createTimerCallback(); | ||||||
|  |         $this->createStreamCallback(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addReadStream($stream, callable $listener) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (!isset($this->readListeners[$key])) { | ||||||
|  |             $this->readListeners[$key] = $listener; | ||||||
|  |             $this->subscribeStreamEvent($stream, EV_READ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addWriteStream($stream, callable $listener) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (!isset($this->writeListeners[$key])) { | ||||||
|  |             $this->writeListeners[$key] = $listener; | ||||||
|  |             $this->subscribeStreamEvent($stream, EV_WRITE); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function removeReadStream($stream) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (isset($this->readListeners[$key])) { | ||||||
|  |             unset($this->readListeners[$key]); | ||||||
|  |             $this->unsubscribeStreamEvent($stream, EV_READ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function removeWriteStream($stream) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (isset($this->writeListeners[$key])) { | ||||||
|  |             unset($this->writeListeners[$key]); | ||||||
|  |             $this->unsubscribeStreamEvent($stream, EV_WRITE); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function removeStream($stream) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (isset($this->streamEvents[$key])) { | ||||||
|  |             $event = $this->streamEvents[$key]; | ||||||
|  |  | ||||||
|  |             event_del($event); | ||||||
|  |             event_free($event); | ||||||
|  |  | ||||||
|  |             unset( | ||||||
|  |                 $this->streamFlags[$key], | ||||||
|  |                 $this->streamEvents[$key], | ||||||
|  |                 $this->readListeners[$key], | ||||||
|  |                 $this->writeListeners[$key] | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addTimer($interval, callable $callback) | ||||||
|  |     { | ||||||
|  |         $timer = new Timer($this, $interval, $callback, false); | ||||||
|  |  | ||||||
|  |         $this->scheduleTimer($timer); | ||||||
|  |  | ||||||
|  |         return $timer; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addPeriodicTimer($interval, callable $callback) | ||||||
|  |     { | ||||||
|  |         $timer = new Timer($this, $interval, $callback, true); | ||||||
|  |  | ||||||
|  |         $this->scheduleTimer($timer); | ||||||
|  |  | ||||||
|  |         return $timer; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function cancelTimer(TimerInterface $timer) | ||||||
|  |     { | ||||||
|  |         if ($this->isTimerActive($timer)) { | ||||||
|  |             $event = $this->timerEvents[$timer]; | ||||||
|  |  | ||||||
|  |             event_del($event); | ||||||
|  |             event_free($event); | ||||||
|  |  | ||||||
|  |             $this->timerEvents->detach($timer); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function isTimerActive(TimerInterface $timer) | ||||||
|  |     { | ||||||
|  |         return $this->timerEvents->contains($timer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function nextTick(callable $listener) | ||||||
|  |     { | ||||||
|  |         $this->nextTickQueue->add($listener); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function futureTick(callable $listener) | ||||||
|  |     { | ||||||
|  |         $this->futureTickQueue->add($listener); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function tick() | ||||||
|  |     { | ||||||
|  |         $this->nextTickQueue->tick(); | ||||||
|  |  | ||||||
|  |         $this->futureTickQueue->tick(); | ||||||
|  |  | ||||||
|  |         event_base_loop($this->eventBase, EVLOOP_ONCE | EVLOOP_NONBLOCK); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function run() | ||||||
|  |     { | ||||||
|  |         $this->running = true; | ||||||
|  |  | ||||||
|  |         while ($this->running) { | ||||||
|  |             $this->nextTickQueue->tick(); | ||||||
|  |  | ||||||
|  |             $this->futureTickQueue->tick(); | ||||||
|  |  | ||||||
|  |             $flags = EVLOOP_ONCE; | ||||||
|  |             if (!$this->running || !$this->nextTickQueue->isEmpty() || !$this->futureTickQueue->isEmpty()) { | ||||||
|  |                 $flags |= EVLOOP_NONBLOCK; | ||||||
|  |             } elseif (!$this->streamEvents && !$this->timerEvents->count()) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             event_base_loop($this->eventBase, $flags); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function stop() | ||||||
|  |     { | ||||||
|  |         $this->running = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Schedule a timer for execution. | ||||||
|  |      * | ||||||
|  |      * @param TimerInterface $timer | ||||||
|  |      */ | ||||||
|  |     private function scheduleTimer(TimerInterface $timer) | ||||||
|  |     { | ||||||
|  |         $this->timerEvents[$timer] = $event = event_timer_new(); | ||||||
|  |  | ||||||
|  |         event_timer_set($event, $this->timerCallback, $timer); | ||||||
|  |         event_base_set($event, $this->eventBase); | ||||||
|  |         event_add($event, $timer->getInterval() * self::MICROSECONDS_PER_SECOND); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a new ext-libevent event resource, or update the existing one. | ||||||
|  |      * | ||||||
|  |      * @param resource $stream | ||||||
|  |      * @param integer  $flag   EV_READ or EV_WRITE | ||||||
|  |      */ | ||||||
|  |     private function subscribeStreamEvent($stream, $flag) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (isset($this->streamEvents[$key])) { | ||||||
|  |             $event = $this->streamEvents[$key]; | ||||||
|  |             $flags = $this->streamFlags[$key] |= $flag; | ||||||
|  |  | ||||||
|  |             event_del($event); | ||||||
|  |             event_set($event, $stream, EV_PERSIST | $flags, $this->streamCallback); | ||||||
|  |         } else { | ||||||
|  |             $event = event_new(); | ||||||
|  |  | ||||||
|  |             event_set($event, $stream, EV_PERSIST | $flag, $this->streamCallback); | ||||||
|  |             event_base_set($event, $this->eventBase); | ||||||
|  |  | ||||||
|  |             $this->streamEvents[$key] = $event; | ||||||
|  |             $this->streamFlags[$key] = $flag; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         event_add($event); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Update the ext-libevent event resource for this stream to stop listening to | ||||||
|  |      * the given event type, or remove it entirely if it's no longer needed. | ||||||
|  |      * | ||||||
|  |      * @param resource $stream | ||||||
|  |      * @param integer  $flag   EV_READ or EV_WRITE | ||||||
|  |      */ | ||||||
|  |     private function unsubscribeStreamEvent($stream, $flag) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         $flags = $this->streamFlags[$key] &= ~$flag; | ||||||
|  |  | ||||||
|  |         if (0 === $flags) { | ||||||
|  |             $this->removeStream($stream); | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $event = $this->streamEvents[$key]; | ||||||
|  |  | ||||||
|  |         event_del($event); | ||||||
|  |         event_set($event, $stream, EV_PERSIST | $flags, $this->streamCallback); | ||||||
|  |         event_add($event); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a callback used as the target of timer events. | ||||||
|  |      * | ||||||
|  |      * A reference is kept to the callback for the lifetime of the loop | ||||||
|  |      * to prevent "Cannot destroy active lambda function" fatal error from | ||||||
|  |      * the event extension. | ||||||
|  |      */ | ||||||
|  |     private function createTimerCallback() | ||||||
|  |     { | ||||||
|  |         $this->timerCallback = function ($_, $_, $timer) { | ||||||
|  |             call_user_func($timer->getCallback(), $timer); | ||||||
|  |  | ||||||
|  |             // Timer already cancelled ... | ||||||
|  |             if (!$this->isTimerActive($timer)) { | ||||||
|  |                 return; | ||||||
|  |  | ||||||
|  |             // Reschedule periodic timers ... | ||||||
|  |             } elseif ($timer->isPeriodic()) { | ||||||
|  |                 event_add( | ||||||
|  |                     $this->timerEvents[$timer], | ||||||
|  |                     $timer->getInterval() * self::MICROSECONDS_PER_SECOND | ||||||
|  |                 ); | ||||||
|  |  | ||||||
|  |             // Clean-up one shot timers ... | ||||||
|  |             } else { | ||||||
|  |                 $this->cancelTimer($timer); | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a callback used as the target of stream events. | ||||||
|  |      * | ||||||
|  |      * A reference is kept to the callback for the lifetime of the loop | ||||||
|  |      * to prevent "Cannot destroy active lambda function" fatal error from | ||||||
|  |      * the event extension. | ||||||
|  |      */ | ||||||
|  |     private function createStreamCallback() | ||||||
|  |     { | ||||||
|  |         $this->streamCallback = function ($stream, $flags) { | ||||||
|  |             $key = (int) $stream; | ||||||
|  |  | ||||||
|  |             if (EV_READ === (EV_READ & $flags) && isset($this->readListeners[$key])) { | ||||||
|  |                 call_user_func($this->readListeners[$key], $stream, $this); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (EV_WRITE === (EV_WRITE & $flags) && isset($this->writeListeners[$key])) { | ||||||
|  |                 call_user_func($this->writeListeners[$key], $stream, $this); | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										121
									
								
								libs/React/EventLoop/LoopInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								libs/React/EventLoop/LoopInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\EventLoop; | ||||||
|  |  | ||||||
|  | use React\EventLoop\Timer\TimerInterface; | ||||||
|  |  | ||||||
|  | interface LoopInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Register a listener to be notified when a stream is ready to read. | ||||||
|  |      * | ||||||
|  |      * @param resource $stream   The PHP stream resource to check. | ||||||
|  |      * @param callable $listener Invoked when the stream is ready. | ||||||
|  |      */ | ||||||
|  |     public function addReadStream($stream, callable $listener); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Register a listener to be notified when a stream is ready to write. | ||||||
|  |      * | ||||||
|  |      * @param resource $stream   The PHP stream resource to check. | ||||||
|  |      * @param callable $listener Invoked when the stream is ready. | ||||||
|  |      */ | ||||||
|  |     public function addWriteStream($stream, callable $listener); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Remove the read event listener for the given stream. | ||||||
|  |      * | ||||||
|  |      * @param resource $stream The PHP stream resource. | ||||||
|  |      */ | ||||||
|  |     public function removeReadStream($stream); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Remove the write event listener for the given stream. | ||||||
|  |      * | ||||||
|  |      * @param resource $stream The PHP stream resource. | ||||||
|  |      */ | ||||||
|  |     public function removeWriteStream($stream); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Remove all listeners for the given stream. | ||||||
|  |      * | ||||||
|  |      * @param resource $stream The PHP stream resource. | ||||||
|  |      */ | ||||||
|  |     public function removeStream($stream); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Enqueue a callback to be invoked once after the given interval. | ||||||
|  |      * | ||||||
|  |      * The execution order of timers scheduled to execute at the same time is | ||||||
|  |      * not guaranteed. | ||||||
|  |      * | ||||||
|  |      * @param int|float $interval The number of seconds to wait before execution. | ||||||
|  |      * @param callable  $callback The callback to invoke. | ||||||
|  |      * | ||||||
|  |      * @return TimerInterface | ||||||
|  |      */ | ||||||
|  |     public function addTimer($interval, callable $callback); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Enqueue a callback to be invoked repeatedly after the given interval. | ||||||
|  |      * | ||||||
|  |      * The execution order of timers scheduled to execute at the same time is | ||||||
|  |      * not guaranteed. | ||||||
|  |      * | ||||||
|  |      * @param int|float $interval The number of seconds to wait before execution. | ||||||
|  |      * @param callable  $callback The callback to invoke. | ||||||
|  |      * | ||||||
|  |      * @return TimerInterface | ||||||
|  |      */ | ||||||
|  |     public function addPeriodicTimer($interval, callable $callback); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Cancel a pending timer. | ||||||
|  |      * | ||||||
|  |      * @param TimerInterface $timer The timer to cancel. | ||||||
|  |      */ | ||||||
|  |     public function cancelTimer(TimerInterface $timer); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Check if a given timer is active. | ||||||
|  |      * | ||||||
|  |      * @param TimerInterface $timer The timer to check. | ||||||
|  |      * | ||||||
|  |      * @return boolean True if the timer is still enqueued for execution. | ||||||
|  |      */ | ||||||
|  |     public function isTimerActive(TimerInterface $timer); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Schedule a callback to be invoked on the next tick of the event loop. | ||||||
|  |      * | ||||||
|  |      * Callbacks are guaranteed to be executed in the order they are enqueued, | ||||||
|  |      * before any timer or stream events. | ||||||
|  |      * | ||||||
|  |      * @param callable $listener The callback to invoke. | ||||||
|  |      */ | ||||||
|  |     public function nextTick(callable $listener); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Schedule a callback to be invoked on a future tick of the event loop. | ||||||
|  |      * | ||||||
|  |      * Callbacks are guaranteed to be executed in the order they are enqueued. | ||||||
|  |      * | ||||||
|  |      * @param callable $listener The callback to invoke. | ||||||
|  |      */ | ||||||
|  |     public function futureTick(callable $listener); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Perform a single iteration of the event loop. | ||||||
|  |      */ | ||||||
|  |     public function tick(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Run the event loop until there are no more tasks to perform. | ||||||
|  |      */ | ||||||
|  |     public function run(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Instruct a running event loop to stop. | ||||||
|  |      */ | ||||||
|  |     public function stop(); | ||||||
|  | } | ||||||
							
								
								
									
										262
									
								
								libs/React/EventLoop/StreamSelectLoop.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								libs/React/EventLoop/StreamSelectLoop.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,262 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\EventLoop; | ||||||
|  |  | ||||||
|  | use React\EventLoop\Tick\FutureTickQueue; | ||||||
|  | use React\EventLoop\Tick\NextTickQueue; | ||||||
|  | use React\EventLoop\Timer\Timer; | ||||||
|  | use React\EventLoop\Timer\TimerInterface; | ||||||
|  | use React\EventLoop\Timer\Timers; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A stream_select() based React. | ||||||
|  |  */ | ||||||
|  | class StreamSelectLoop implements LoopInterface | ||||||
|  | { | ||||||
|  |     const MICROSECONDS_PER_SECOND = 1000000; | ||||||
|  |  | ||||||
|  |     private $nextTickQueue; | ||||||
|  |     private $futureTickQueue; | ||||||
|  |     private $timers; | ||||||
|  |     private $readStreams = []; | ||||||
|  |     private $readListeners = []; | ||||||
|  |     private $writeStreams = []; | ||||||
|  |     private $writeListeners = []; | ||||||
|  |     private $running; | ||||||
|  |  | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         $this->nextTickQueue = new NextTickQueue($this); | ||||||
|  |         $this->futureTickQueue = new FutureTickQueue($this); | ||||||
|  |         $this->timers = new Timers(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addReadStream($stream, callable $listener) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (!isset($this->readStreams[$key])) { | ||||||
|  |             $this->readStreams[$key] = $stream; | ||||||
|  |             $this->readListeners[$key] = $listener; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addWriteStream($stream, callable $listener) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         if (!isset($this->writeStreams[$key])) { | ||||||
|  |             $this->writeStreams[$key] = $stream; | ||||||
|  |             $this->writeListeners[$key] = $listener; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function removeReadStream($stream) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         unset( | ||||||
|  |             $this->readStreams[$key], | ||||||
|  |             $this->readListeners[$key] | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function removeWriteStream($stream) | ||||||
|  |     { | ||||||
|  |         $key = (int) $stream; | ||||||
|  |  | ||||||
|  |         unset( | ||||||
|  |             $this->writeStreams[$key], | ||||||
|  |             $this->writeListeners[$key] | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function removeStream($stream) | ||||||
|  |     { | ||||||
|  |         $this->removeReadStream($stream); | ||||||
|  |         $this->removeWriteStream($stream); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addTimer($interval, callable $callback) | ||||||
|  |     { | ||||||
|  |         $timer = new Timer($this, $interval, $callback, false); | ||||||
|  |  | ||||||
|  |         $this->timers->add($timer); | ||||||
|  |  | ||||||
|  |         return $timer; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function addPeriodicTimer($interval, callable $callback) | ||||||
|  |     { | ||||||
|  |         $timer = new Timer($this, $interval, $callback, true); | ||||||
|  |  | ||||||
|  |         $this->timers->add($timer); | ||||||
|  |  | ||||||
|  |         return $timer; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function cancelTimer(TimerInterface $timer) | ||||||
|  |     { | ||||||
|  |         $this->timers->cancel($timer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function isTimerActive(TimerInterface $timer) | ||||||
|  |     { | ||||||
|  |         return $this->timers->contains($timer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function nextTick(callable $listener) | ||||||
|  |     { | ||||||
|  |         $this->nextTickQueue->add($listener); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function futureTick(callable $listener) | ||||||
|  |     { | ||||||
|  |         $this->futureTickQueue->add($listener); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function tick() | ||||||
|  |     { | ||||||
|  |         $this->nextTickQueue->tick(); | ||||||
|  |  | ||||||
|  |         $this->futureTickQueue->tick(); | ||||||
|  |  | ||||||
|  |         $this->timers->tick(); | ||||||
|  |  | ||||||
|  |         $this->waitForStreamActivity(0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function run() | ||||||
|  |     { | ||||||
|  |         $this->running = true; | ||||||
|  |  | ||||||
|  |         while ($this->running) { | ||||||
|  |             $this->nextTickQueue->tick(); | ||||||
|  |  | ||||||
|  |             $this->futureTickQueue->tick(); | ||||||
|  |  | ||||||
|  |             $this->timers->tick(); | ||||||
|  |  | ||||||
|  |             // Next-tick or future-tick queues have pending callbacks ... | ||||||
|  |             if (!$this->running || !$this->nextTickQueue->isEmpty() || !$this->futureTickQueue->isEmpty()) { | ||||||
|  |                 $timeout = 0; | ||||||
|  |  | ||||||
|  |             // There is a pending timer, only block until it is due ... | ||||||
|  |             } elseif ($scheduledAt = $this->timers->getFirst()) { | ||||||
|  |                 $timeout = $scheduledAt - $this->timers->getTime(); | ||||||
|  |                 if ($timeout < 0) { | ||||||
|  |                     $timeout = 0; | ||||||
|  |                 } else { | ||||||
|  |                     $timeout *= self::MICROSECONDS_PER_SECOND; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |             // The only possible event is stream activity, so wait forever ... | ||||||
|  |             } elseif ($this->readStreams || $this->writeStreams) { | ||||||
|  |                 $timeout = null; | ||||||
|  |  | ||||||
|  |             // There's nothing left to do ... | ||||||
|  |             } else { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $this->waitForStreamActivity($timeout); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function stop() | ||||||
|  |     { | ||||||
|  |         $this->running = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Wait/check for stream activity, or until the next timer is due. | ||||||
|  |      */ | ||||||
|  |     private function waitForStreamActivity($timeout) | ||||||
|  |     { | ||||||
|  |         $read  = $this->readStreams; | ||||||
|  |         $write = $this->writeStreams; | ||||||
|  |  | ||||||
|  |         $this->streamSelect($read, $write, $timeout); | ||||||
|  |  | ||||||
|  |         foreach ($read as $stream) { | ||||||
|  |             $key = (int) $stream; | ||||||
|  |  | ||||||
|  |             if (isset($this->readListeners[$key])) { | ||||||
|  |                 call_user_func($this->readListeners[$key], $stream, $this); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         foreach ($write as $stream) { | ||||||
|  |             $key = (int) $stream; | ||||||
|  |  | ||||||
|  |             if (isset($this->writeListeners[$key])) { | ||||||
|  |                 call_user_func($this->writeListeners[$key], $stream, $this); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Emulate a stream_select() implementation that does not break when passed | ||||||
|  |      * empty stream arrays. | ||||||
|  |      * | ||||||
|  |      * @param array        &$read   An array of read streams to select upon. | ||||||
|  |      * @param array        &$write  An array of write streams to select upon. | ||||||
|  |      * @param integer|null $timeout Activity timeout in microseconds, or null to wait forever. | ||||||
|  |      * | ||||||
|  |      * @return integer The total number of streams that are ready for read/write. | ||||||
|  |      */ | ||||||
|  |     protected function streamSelect(array &$read, array &$write, $timeout) | ||||||
|  |     { | ||||||
|  |         if ($read || $write) { | ||||||
|  |             $except = null; | ||||||
|  |  | ||||||
|  |             return stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         usleep($timeout); | ||||||
|  |  | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										59
									
								
								libs/React/EventLoop/Tick/FutureTickQueue.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								libs/React/EventLoop/Tick/FutureTickQueue.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\EventLoop\Tick; | ||||||
|  |  | ||||||
|  | use React\EventLoop\LoopInterface; | ||||||
|  | use SplQueue; | ||||||
|  |  | ||||||
|  | class FutureTickQueue | ||||||
|  | { | ||||||
|  |     private $eventLoop; | ||||||
|  |     private $queue; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param LoopInterface $eventLoop The event loop passed as the first parameter to callbacks. | ||||||
|  |      */ | ||||||
|  |     public function __construct(LoopInterface $eventLoop) | ||||||
|  |     { | ||||||
|  |         $this->eventLoop = $eventLoop; | ||||||
|  |         $this->queue = new SplQueue(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Add a callback to be invoked on a future tick of the event loop. | ||||||
|  |      * | ||||||
|  |      * Callbacks are guaranteed to be executed in the order they are enqueued. | ||||||
|  |      * | ||||||
|  |      * @param callable $listener The callback to invoke. | ||||||
|  |      */ | ||||||
|  |     public function add(callable $listener) | ||||||
|  |     { | ||||||
|  |         $this->queue->enqueue($listener); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Flush the callback queue. | ||||||
|  |      */ | ||||||
|  |     public function tick() | ||||||
|  |     { | ||||||
|  |         // Only invoke as many callbacks as were on the queue when tick() was called. | ||||||
|  |         $count = $this->queue->count(); | ||||||
|  |  | ||||||
|  |         while ($count--) { | ||||||
|  |             call_user_func( | ||||||
|  |                 $this->queue->dequeue(), | ||||||
|  |                 $this->eventLoop | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Check if the next tick queue is empty. | ||||||
|  |      * | ||||||
|  |      * @return boolean | ||||||
|  |      */ | ||||||
|  |     public function isEmpty() | ||||||
|  |     { | ||||||
|  |         return $this->queue->isEmpty(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										57
									
								
								libs/React/EventLoop/Tick/NextTickQueue.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								libs/React/EventLoop/Tick/NextTickQueue.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\EventLoop\Tick; | ||||||
|  |  | ||||||
|  | use React\EventLoop\LoopInterface; | ||||||
|  | use SplQueue; | ||||||
|  |  | ||||||
|  | class NextTickQueue | ||||||
|  | { | ||||||
|  |     private $eventLoop; | ||||||
|  |     private $queue; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param LoopInterface $eventLoop The event loop passed as the first parameter to callbacks. | ||||||
|  |      */ | ||||||
|  |     public function __construct(LoopInterface $eventLoop) | ||||||
|  |     { | ||||||
|  |         $this->eventLoop = $eventLoop; | ||||||
|  |         $this->queue = new SplQueue(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Add a callback to be invoked on the next tick of the event loop. | ||||||
|  |      * | ||||||
|  |      * Callbacks are guaranteed to be executed in the order they are enqueued, | ||||||
|  |      * before any timer or stream events. | ||||||
|  |      * | ||||||
|  |      * @param callable $listener The callback to invoke. | ||||||
|  |      */ | ||||||
|  |     public function add(callable $listener) | ||||||
|  |     { | ||||||
|  |         $this->queue->enqueue($listener); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Flush the callback queue. | ||||||
|  |      */ | ||||||
|  |     public function tick() | ||||||
|  |     { | ||||||
|  |         while (!$this->queue->isEmpty()) { | ||||||
|  |             call_user_func( | ||||||
|  |                 $this->queue->dequeue(), | ||||||
|  |                 $this->eventLoop | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Check if the next tick queue is empty. | ||||||
|  |      * | ||||||
|  |      * @return boolean | ||||||
|  |      */ | ||||||
|  |     public function isEmpty() | ||||||
|  |     { | ||||||
|  |         return $this->queue->isEmpty(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										102
									
								
								libs/React/EventLoop/Timer/Timer.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								libs/React/EventLoop/Timer/Timer.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\EventLoop\Timer; | ||||||
|  |  | ||||||
|  | use React\EventLoop\LoopInterface; | ||||||
|  |  | ||||||
|  | class Timer implements TimerInterface | ||||||
|  | { | ||||||
|  |     const MIN_INTERVAL = 0.000001; | ||||||
|  |  | ||||||
|  |     protected $loop; | ||||||
|  |     protected $interval; | ||||||
|  |     protected $callback; | ||||||
|  |     protected $periodic; | ||||||
|  |     protected $data; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Constructor initializes the fields of the Timer | ||||||
|  |      * | ||||||
|  |      * @param LoopInterface $loop     The loop with which this timer is associated | ||||||
|  |      * @param float         $interval The interval after which this timer will execute, in seconds | ||||||
|  |      * @param callable      $callback The callback that will be executed when this timer elapses | ||||||
|  |      * @param bool          $periodic Whether the time is periodic | ||||||
|  |      * @param mixed         $data     Arbitrary data associated with timer | ||||||
|  |      */ | ||||||
|  |     public function __construct(LoopInterface $loop, $interval, callable $callback, $periodic = false, $data = null) | ||||||
|  |     { | ||||||
|  |         if ($interval < self::MIN_INTERVAL) { | ||||||
|  |             $interval = self::MIN_INTERVAL; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->loop = $loop; | ||||||
|  |         $this->interval = (float) $interval; | ||||||
|  |         $this->callback = $callback; | ||||||
|  |         $this->periodic = (bool) $periodic; | ||||||
|  |         $this->data = null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function getLoop() | ||||||
|  |     { | ||||||
|  |         return $this->loop; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function getInterval() | ||||||
|  |     { | ||||||
|  |         return $this->interval; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function getCallback() | ||||||
|  |     { | ||||||
|  |         return $this->callback; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function setData($data) | ||||||
|  |     { | ||||||
|  |         $this->data = $data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function getData() | ||||||
|  |     { | ||||||
|  |         return $this->data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function isPeriodic() | ||||||
|  |     { | ||||||
|  |         return $this->periodic; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function isActive() | ||||||
|  |     { | ||||||
|  |         return $this->loop->isTimerActive($this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * {@inheritdoc} | ||||||
|  |      */ | ||||||
|  |     public function cancel() | ||||||
|  |     { | ||||||
|  |         $this->loop->cancelTimer($this); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										62
									
								
								libs/React/EventLoop/Timer/TimerInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								libs/React/EventLoop/Timer/TimerInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\EventLoop\Timer; | ||||||
|  |  | ||||||
|  | use React\EventLoop\LoopInterface; | ||||||
|  |  | ||||||
|  | interface TimerInterface | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Get the loop with which this timer is associated | ||||||
|  |      * | ||||||
|  |      * @return LoopInterface | ||||||
|  |      */ | ||||||
|  |     public function getLoop(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get the interval after which this timer will execute, in seconds | ||||||
|  |      * | ||||||
|  |      * @return float | ||||||
|  |      */ | ||||||
|  |     public function getInterval(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get the callback that will be executed when this timer elapses | ||||||
|  |      * | ||||||
|  |      * @return callable | ||||||
|  |      */ | ||||||
|  |     public function getCallback(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set arbitrary data associated with timer | ||||||
|  |      * | ||||||
|  |      * @param mixed $data | ||||||
|  |      */ | ||||||
|  |     public function setData($data); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get arbitrary data associated with timer | ||||||
|  |      * | ||||||
|  |      * @return mixed | ||||||
|  |      */ | ||||||
|  |     public function getData(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Determine whether the time is periodic | ||||||
|  |      * | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     public function isPeriodic(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Determine whether the time is active | ||||||
|  |      * | ||||||
|  |      * @return bool | ||||||
|  |      */ | ||||||
|  |     public function isActive(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Cancel this timer | ||||||
|  |      */ | ||||||
|  |     public function cancel(); | ||||||
|  | } | ||||||
							
								
								
									
										100
									
								
								libs/React/EventLoop/Timer/Timers.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								libs/React/EventLoop/Timer/Timers.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\EventLoop\Timer; | ||||||
|  |  | ||||||
|  | use SplObjectStorage; | ||||||
|  | use SplPriorityQueue; | ||||||
|  |  | ||||||
|  | class Timers | ||||||
|  | { | ||||||
|  |     private $time; | ||||||
|  |     private $timers; | ||||||
|  |     private $scheduler; | ||||||
|  |  | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         $this->timers = new SplObjectStorage(); | ||||||
|  |         $this->scheduler = new SplPriorityQueue(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function updateTime() | ||||||
|  |     { | ||||||
|  |         return $this->time = microtime(true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getTime() | ||||||
|  |     { | ||||||
|  |         return $this->time ?: $this->updateTime(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function add(TimerInterface $timer) | ||||||
|  |     { | ||||||
|  |         $interval = $timer->getInterval(); | ||||||
|  |         $scheduledAt = $interval + $this->getTime(); | ||||||
|  |  | ||||||
|  |         $this->timers->attach($timer, $scheduledAt); | ||||||
|  |         $this->scheduler->insert($timer, -$scheduledAt); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function contains(TimerInterface $timer) | ||||||
|  |     { | ||||||
|  |         return $this->timers->contains($timer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function cancel(TimerInterface $timer) | ||||||
|  |     { | ||||||
|  |         $this->timers->detach($timer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getFirst() | ||||||
|  |     { | ||||||
|  |         while ($this->scheduler->count()) { | ||||||
|  |             $timer = $this->scheduler->top(); | ||||||
|  |  | ||||||
|  |             if ($this->timers->contains($timer)) { | ||||||
|  |                 return $this->timers[$timer]; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $this->scheduler->extract(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function isEmpty() | ||||||
|  |     { | ||||||
|  |         return count($this->timers) === 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function tick() | ||||||
|  |     { | ||||||
|  |         $time = $this->updateTime(); | ||||||
|  |         $timers = $this->timers; | ||||||
|  |         $scheduler = $this->scheduler; | ||||||
|  |  | ||||||
|  |         while (!$scheduler->isEmpty()) { | ||||||
|  |             $timer = $scheduler->top(); | ||||||
|  |  | ||||||
|  |             if (!isset($timers[$timer])) { | ||||||
|  |                 $scheduler->extract(); | ||||||
|  |                 $timers->detach($timer); | ||||||
|  |  | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if ($timers[$timer] >= $time) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $scheduler->extract(); | ||||||
|  |             call_user_func($timer->getCallback(), $timer); | ||||||
|  |  | ||||||
|  |             if ($timer->isPeriodic() && isset($timers[$timer])) { | ||||||
|  |                 $timers[$timer] = $scheduledAt = $timer->getInterval() + $time; | ||||||
|  |                 $scheduler->insert($timer, -$scheduledAt); | ||||||
|  |             } else { | ||||||
|  |                 $timers->detach($timer); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								libs/React/Socket/Connection.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								libs/React/Socket/Connection.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Socket; | ||||||
|  |  | ||||||
|  | use React\Stream\Stream; | ||||||
|  |  | ||||||
|  | class Connection extends Stream implements ConnectionInterface | ||||||
|  | { | ||||||
|  |     public function handleData($stream) | ||||||
|  |     { | ||||||
|  |         // Socket is raw, not using fread as it's interceptable by filters | ||||||
|  |         // See issues #192, #209, and #240 | ||||||
|  |         $data = stream_socket_recvfrom($stream, $this->bufferSize); | ||||||
|  |         if ('' !== $data && false !== $data) { | ||||||
|  |             $this->emit('data', array($data, $this)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ('' === $data || false === $data || !is_resource($stream) || feof($stream)) { | ||||||
|  |             $this->end(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function handleClose() | ||||||
|  |     { | ||||||
|  |         if (is_resource($this->stream)) { | ||||||
|  |             // http://chat.stackoverflow.com/transcript/message/7727858#7727858 | ||||||
|  |             stream_socket_shutdown($this->stream, STREAM_SHUT_RDWR); | ||||||
|  |             stream_set_blocking($this->stream, false); | ||||||
|  |             fclose($this->stream); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getRemoteAddress() | ||||||
|  |     { | ||||||
|  |         return $this->parseAddress(stream_socket_get_name($this->stream, true)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function parseAddress($address) | ||||||
|  |     { | ||||||
|  |         return trim(substr($address, 0, strrpos($address, ':')), '[]'); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								libs/React/Socket/ConnectionException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								libs/React/Socket/ConnectionException.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Socket; | ||||||
|  |  | ||||||
|  | class ConnectionException extends \ErrorException | ||||||
|  | { | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								libs/React/Socket/ConnectionInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								libs/React/Socket/ConnectionInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Socket; | ||||||
|  |  | ||||||
|  | use Evenement\EventEmitterInterface; | ||||||
|  | use React\Stream\ReadableStreamInterface; | ||||||
|  | use React\Stream\WritableStreamInterface; | ||||||
|  |  | ||||||
|  | interface ConnectionInterface extends ReadableStreamInterface, WritableStreamInterface | ||||||
|  | { | ||||||
|  |     public function getRemoteAddress(); | ||||||
|  | } | ||||||
							
								
								
									
										71
									
								
								libs/React/Socket/Server.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								libs/React/Socket/Server.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Socket; | ||||||
|  |  | ||||||
|  | use Evenement\EventEmitter; | ||||||
|  | use React\EventLoop\LoopInterface; | ||||||
|  |  | ||||||
|  | /** @event connection */ | ||||||
|  | class Server extends EventEmitter implements ServerInterface | ||||||
|  | { | ||||||
|  |     public $master; | ||||||
|  |     private $loop; | ||||||
|  |  | ||||||
|  |     public function __construct(LoopInterface $loop) | ||||||
|  |     { | ||||||
|  |         $this->loop = $loop; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function listen($port, $host = '127.0.0.1') | ||||||
|  |     { | ||||||
|  |         if (strpos($host, ':') !== false) { | ||||||
|  |             // enclose IPv6 addresses in square brackets before appending port | ||||||
|  |             $host = '[' . $host . ']'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->master = @stream_socket_server("tcp://$host:$port", $errno, $errstr); | ||||||
|  |         if (false === $this->master) { | ||||||
|  |             $message = "Could not bind to tcp://$host:$port: $errstr"; | ||||||
|  |             throw new ConnectionException($message, $errno); | ||||||
|  |         } | ||||||
|  |         stream_set_blocking($this->master, 0); | ||||||
|  |  | ||||||
|  |         $this->loop->addReadStream($this->master, function ($master) { | ||||||
|  |             $newSocket = stream_socket_accept($master); | ||||||
|  |             if (false === $newSocket) { | ||||||
|  |                 $this->emit('error', array(new \RuntimeException('Error accepting new connection'))); | ||||||
|  |  | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             $this->handleConnection($newSocket); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function handleConnection($socket) | ||||||
|  |     { | ||||||
|  |         stream_set_blocking($socket, 0); | ||||||
|  |  | ||||||
|  |         $client = $this->createConnection($socket); | ||||||
|  |  | ||||||
|  |         $this->emit('connection', array($client)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getPort() | ||||||
|  |     { | ||||||
|  |         $name = stream_socket_get_name($this->master, false); | ||||||
|  |  | ||||||
|  |         return (int) substr(strrchr($name, ':'), 1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function shutdown() | ||||||
|  |     { | ||||||
|  |         $this->loop->removeStream($this->master); | ||||||
|  |         fclose($this->master); | ||||||
|  |         $this->removeAllListeners(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function createConnection($socket) | ||||||
|  |     { | ||||||
|  |         return new Connection($socket, $this->loop); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								libs/React/Socket/ServerInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								libs/React/Socket/ServerInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Socket; | ||||||
|  |  | ||||||
|  | use Evenement\EventEmitterInterface; | ||||||
|  |  | ||||||
|  | /** @event connection */ | ||||||
|  | interface ServerInterface extends EventEmitterInterface | ||||||
|  | { | ||||||
|  |     public function listen($port, $host = '127.0.0.1'); | ||||||
|  |     public function getPort(); | ||||||
|  |     public function shutdown(); | ||||||
|  | } | ||||||
							
								
								
									
										135
									
								
								libs/React/Stream/Buffer.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								libs/React/Stream/Buffer.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Stream; | ||||||
|  |  | ||||||
|  | use Evenement\EventEmitter; | ||||||
|  | use React\EventLoop\LoopInterface; | ||||||
|  |  | ||||||
|  | /** @event full-drain */ | ||||||
|  | class Buffer extends EventEmitter implements WritableStreamInterface | ||||||
|  | { | ||||||
|  |     public $stream; | ||||||
|  |     public $listening = false; | ||||||
|  |     public $softLimit = 2048; | ||||||
|  |     private $writable = true; | ||||||
|  |     private $loop; | ||||||
|  |     private $data = ''; | ||||||
|  |     private $lastError = array( | ||||||
|  |         'number'  => 0, | ||||||
|  |         'message' => '', | ||||||
|  |         'file'    => '', | ||||||
|  |         'line'    => 0, | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     public function __construct($stream, LoopInterface $loop) | ||||||
|  |     { | ||||||
|  |         $this->stream = $stream; | ||||||
|  |         $this->loop = $loop; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function isWritable() | ||||||
|  |     { | ||||||
|  |         return $this->writable; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function write($data) | ||||||
|  |     { | ||||||
|  |         if (!$this->writable) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->data .= $data; | ||||||
|  |  | ||||||
|  |         if (!$this->listening) { | ||||||
|  |             $this->listening = true; | ||||||
|  |  | ||||||
|  |             $this->loop->addWriteStream($this->stream, array($this, 'handleWrite')); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $belowSoftLimit = strlen($this->data) < $this->softLimit; | ||||||
|  |  | ||||||
|  |         return $belowSoftLimit; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function end($data = null) | ||||||
|  |     { | ||||||
|  |         if (null !== $data) { | ||||||
|  |             $this->write($data); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->writable = false; | ||||||
|  |  | ||||||
|  |         if ($this->listening) { | ||||||
|  |             $this->on('full-drain', array($this, 'close')); | ||||||
|  |         } else { | ||||||
|  |             $this->close(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function close() | ||||||
|  |     { | ||||||
|  |         $this->writable = false; | ||||||
|  |         $this->listening = false; | ||||||
|  |         $this->data = ''; | ||||||
|  |  | ||||||
|  |         $this->emit('close', [$this]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function handleWrite() | ||||||
|  |     { | ||||||
|  |         if (!is_resource($this->stream)) { | ||||||
|  |             $this->emit('error', array(new \RuntimeException('Tried to write to invalid stream.'), $this)); | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         set_error_handler(array($this, 'errorHandler')); | ||||||
|  |  | ||||||
|  |         $sent = fwrite($this->stream, $this->data); | ||||||
|  |  | ||||||
|  |         restore_error_handler(); | ||||||
|  |  | ||||||
|  |         if (false === $sent) { | ||||||
|  |             $this->emit('error', array( | ||||||
|  |                 new \ErrorException( | ||||||
|  |                     $this->lastError['message'], | ||||||
|  |                     0, | ||||||
|  |                     $this->lastError['number'], | ||||||
|  |                     $this->lastError['file'], | ||||||
|  |                     $this->lastError['line'] | ||||||
|  |                 ), | ||||||
|  |                 $this | ||||||
|  |             )); | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (0 === $sent && feof($this->stream)) { | ||||||
|  |             $this->emit('error', array(new \RuntimeException('Tried to write to closed stream.'), $this)); | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $len = strlen($this->data); | ||||||
|  |         if ($len >= $this->softLimit && $len - $sent < $this->softLimit) { | ||||||
|  |             $this->emit('drain', [$this]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->data = (string) substr($this->data, $sent); | ||||||
|  |  | ||||||
|  |         if (0 === strlen($this->data)) { | ||||||
|  |             $this->loop->removeWriteStream($this->stream); | ||||||
|  |             $this->listening = false; | ||||||
|  |  | ||||||
|  |             $this->emit('full-drain', [$this]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function errorHandler($errno, $errstr, $errfile, $errline) | ||||||
|  |     { | ||||||
|  |         $this->lastError['number']  = $errno; | ||||||
|  |         $this->lastError['message'] = $errstr; | ||||||
|  |         $this->lastError['file']    = $errfile; | ||||||
|  |         $this->lastError['line']    = $errline; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										59
									
								
								libs/React/Stream/BufferedSink.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								libs/React/Stream/BufferedSink.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Stream; | ||||||
|  |  | ||||||
|  | use React\Promise\Deferred; | ||||||
|  | use React\Promise\PromisorInterface; | ||||||
|  |  | ||||||
|  | class BufferedSink extends WritableStream implements PromisorInterface | ||||||
|  | { | ||||||
|  |     private $buffer = ''; | ||||||
|  |     private $deferred; | ||||||
|  |  | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         $this->deferred = new Deferred(); | ||||||
|  |  | ||||||
|  |         $this->on('pipe', array($this, 'handlePipeEvent')); | ||||||
|  |         $this->on('error', array($this, 'handleErrorEvent')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function handlePipeEvent($source) | ||||||
|  |     { | ||||||
|  |         Util::forwardEvents($source, $this, array('error')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function handleErrorEvent($e) | ||||||
|  |     { | ||||||
|  |         $this->deferred->reject($e); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function write($data) | ||||||
|  |     { | ||||||
|  |         $this->buffer .= $data; | ||||||
|  |         $this->deferred->progress($data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function close() | ||||||
|  |     { | ||||||
|  |         if ($this->closed) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         parent::close(); | ||||||
|  |         $this->deferred->resolve($this->buffer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function promise() | ||||||
|  |     { | ||||||
|  |         return $this->deferred->promise(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static function createPromise(ReadableStreamInterface $stream) | ||||||
|  |     { | ||||||
|  |         $sink = new static(); | ||||||
|  |         $stream->pipe($sink); | ||||||
|  |  | ||||||
|  |         return $sink->promise(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										84
									
								
								libs/React/Stream/CompositeStream.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								libs/React/Stream/CompositeStream.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Stream; | ||||||
|  |  | ||||||
|  | use Evenement\EventEmitter; | ||||||
|  |  | ||||||
|  | class CompositeStream extends EventEmitter implements DuplexStreamInterface | ||||||
|  | { | ||||||
|  |     protected $readable; | ||||||
|  |     protected $writable; | ||||||
|  |     protected $pipeSource; | ||||||
|  |  | ||||||
|  |     public function __construct(ReadableStreamInterface $readable, WritableStreamInterface $writable) | ||||||
|  |     { | ||||||
|  |         $this->readable = $readable; | ||||||
|  |         $this->writable = $writable; | ||||||
|  |  | ||||||
|  |         Util::forwardEvents($this->readable, $this, array('data', 'end', 'error', 'close')); | ||||||
|  |         Util::forwardEvents($this->writable, $this, array('drain', 'error', 'close', 'pipe')); | ||||||
|  |  | ||||||
|  |         $this->readable->on('close', array($this, 'close')); | ||||||
|  |         $this->writable->on('close', array($this, 'close')); | ||||||
|  |  | ||||||
|  |         $this->on('pipe', array($this, 'handlePipeEvent')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function handlePipeEvent($source) | ||||||
|  |     { | ||||||
|  |         $this->pipeSource = $source; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function isReadable() | ||||||
|  |     { | ||||||
|  |         return $this->readable->isReadable(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function pause() | ||||||
|  |     { | ||||||
|  |         if ($this->pipeSource) { | ||||||
|  |             $this->pipeSource->pause(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->readable->pause(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function resume() | ||||||
|  |     { | ||||||
|  |         if ($this->pipeSource) { | ||||||
|  |             $this->pipeSource->resume(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->readable->resume(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function pipe(WritableStreamInterface $dest, array $options = array()) | ||||||
|  |     { | ||||||
|  |         Util::pipe($this, $dest, $options); | ||||||
|  |  | ||||||
|  |         return $dest; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function isWritable() | ||||||
|  |     { | ||||||
|  |         return $this->writable->isWritable(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function write($data) | ||||||
|  |     { | ||||||
|  |         return $this->writable->write($data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function end($data = null) | ||||||
|  |     { | ||||||
|  |         $this->writable->end($data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function close() | ||||||
|  |     { | ||||||
|  |         $this->pipeSource = null; | ||||||
|  |  | ||||||
|  |         $this->readable->close(); | ||||||
|  |         $this->writable->close(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								libs/React/Stream/DuplexStreamInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								libs/React/Stream/DuplexStreamInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Stream; | ||||||
|  |  | ||||||
|  | interface DuplexStreamInterface extends ReadableStreamInterface, WritableStreamInterface | ||||||
|  | { | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								libs/React/Stream/ReadableStream.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								libs/React/Stream/ReadableStream.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Stream; | ||||||
|  |  | ||||||
|  | use Evenement\EventEmitter; | ||||||
|  |  | ||||||
|  | class ReadableStream extends EventEmitter implements ReadableStreamInterface | ||||||
|  | { | ||||||
|  |     protected $closed = false; | ||||||
|  |  | ||||||
|  |     public function isReadable() | ||||||
|  |     { | ||||||
|  |         return !$this->closed; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function pause() | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function resume() | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function pipe(WritableStreamInterface $dest, array $options = array()) | ||||||
|  |     { | ||||||
|  |         Util::pipe($this, $dest, $options); | ||||||
|  |  | ||||||
|  |         return $dest; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function close() | ||||||
|  |     { | ||||||
|  |         if ($this->closed) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->closed = true; | ||||||
|  |         $this->emit('end', array($this)); | ||||||
|  |         $this->emit('close', array($this)); | ||||||
|  |         $this->removeAllListeners(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								libs/React/Stream/ReadableStreamInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								libs/React/Stream/ReadableStreamInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Stream; | ||||||
|  |  | ||||||
|  | use Evenement\EventEmitterInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @event data | ||||||
|  |  * @event end | ||||||
|  |  * @event error | ||||||
|  |  * @event close | ||||||
|  |  */ | ||||||
|  | interface ReadableStreamInterface extends EventEmitterInterface | ||||||
|  | { | ||||||
|  |     public function isReadable(); | ||||||
|  |     public function pause(); | ||||||
|  |     public function resume(); | ||||||
|  |     public function pipe(WritableStreamInterface $dest, array $options = array()); | ||||||
|  |     public function close(); | ||||||
|  | } | ||||||
							
								
								
									
										141
									
								
								libs/React/Stream/Stream.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								libs/React/Stream/Stream.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Stream; | ||||||
|  |  | ||||||
|  | use Evenement\EventEmitter; | ||||||
|  | use React\EventLoop\LoopInterface; | ||||||
|  | use InvalidArgumentException; | ||||||
|  |  | ||||||
|  | class Stream extends EventEmitter implements DuplexStreamInterface | ||||||
|  | { | ||||||
|  |     public $bufferSize = 4096; | ||||||
|  |     public $stream; | ||||||
|  |     protected $readable = true; | ||||||
|  |     protected $writable = true; | ||||||
|  |     protected $closing = false; | ||||||
|  |     protected $loop; | ||||||
|  |     protected $buffer; | ||||||
|  |  | ||||||
|  |     public function __construct($stream, LoopInterface $loop) | ||||||
|  |     { | ||||||
|  |         $this->stream = $stream; | ||||||
|  |         if (!is_resource($this->stream) || get_resource_type($this->stream) !== "stream") { | ||||||
|  |              throw new InvalidArgumentException('First parameter must be a valid stream resource'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         stream_set_blocking($this->stream, 0); | ||||||
|  |  | ||||||
|  |         $this->loop = $loop; | ||||||
|  |         $this->buffer = new Buffer($this->stream, $this->loop); | ||||||
|  |  | ||||||
|  |         $this->buffer->on('error', function ($error) { | ||||||
|  |             $this->emit('error', array($error, $this)); | ||||||
|  |             $this->close(); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         $this->buffer->on('drain', function () { | ||||||
|  |             $this->emit('drain', array($this)); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         $this->resume(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function isReadable() | ||||||
|  |     { | ||||||
|  |         return $this->readable; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function isWritable() | ||||||
|  |     { | ||||||
|  |         return $this->writable; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function pause() | ||||||
|  |     { | ||||||
|  |         $this->loop->removeReadStream($this->stream); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function resume() | ||||||
|  |     { | ||||||
|  |         if ($this->readable) { | ||||||
|  |             $this->loop->addReadStream($this->stream, array($this, 'handleData')); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function write($data) | ||||||
|  |     { | ||||||
|  |         if (!$this->writable) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->buffer->write($data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function close() | ||||||
|  |     { | ||||||
|  |         if (!$this->writable && !$this->closing) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->closing = false; | ||||||
|  |  | ||||||
|  |         $this->readable = false; | ||||||
|  |         $this->writable = false; | ||||||
|  |  | ||||||
|  |         $this->emit('end', array($this)); | ||||||
|  |         $this->emit('close', array($this)); | ||||||
|  |         $this->loop->removeStream($this->stream); | ||||||
|  |         $this->buffer->removeAllListeners(); | ||||||
|  |         $this->removeAllListeners(); | ||||||
|  |  | ||||||
|  |         $this->handleClose(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function end($data = null) | ||||||
|  |     { | ||||||
|  |         if (!$this->writable) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->closing = true; | ||||||
|  |  | ||||||
|  |         $this->readable = false; | ||||||
|  |         $this->writable = false; | ||||||
|  |  | ||||||
|  |         $this->buffer->on('close', function () { | ||||||
|  |             $this->close(); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         $this->buffer->end($data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function pipe(WritableStreamInterface $dest, array $options = array()) | ||||||
|  |     { | ||||||
|  |         Util::pipe($this, $dest, $options); | ||||||
|  |  | ||||||
|  |         return $dest; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function handleData($stream) | ||||||
|  |     { | ||||||
|  |         $data = fread($stream, $this->bufferSize); | ||||||
|  |  | ||||||
|  |         $this->emit('data', array($data, $this)); | ||||||
|  |  | ||||||
|  |         if (!is_resource($stream) || feof($stream)) { | ||||||
|  |             $this->end(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function handleClose() | ||||||
|  |     { | ||||||
|  |         if (is_resource($this->stream)) { | ||||||
|  |             fclose($this->stream); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getBuffer() | ||||||
|  |     { | ||||||
|  |         return $this->buffer; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										33
									
								
								libs/React/Stream/ThroughStream.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								libs/React/Stream/ThroughStream.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Stream; | ||||||
|  |  | ||||||
|  | class ThroughStream extends CompositeStream | ||||||
|  | { | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         $readable = new ReadableStream(); | ||||||
|  |         $writable = new WritableStream(); | ||||||
|  |  | ||||||
|  |         parent::__construct($readable, $writable); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function filter($data) | ||||||
|  |     { | ||||||
|  |         return $data; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function write($data) | ||||||
|  |     { | ||||||
|  |         $this->readable->emit('data', array($this->filter($data), $this)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function end($data = null) | ||||||
|  |     { | ||||||
|  |         if (null !== $data) { | ||||||
|  |             $this->readable->emit('data', array($this->filter($data), $this)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->writable->end($data); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								libs/React/Stream/Util.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								libs/React/Stream/Util.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Stream; | ||||||
|  |  | ||||||
|  | // TODO: move to a trait | ||||||
|  |  | ||||||
|  | class Util | ||||||
|  | { | ||||||
|  |     public static function pipe(ReadableStreamInterface $source, WritableStreamInterface $dest, array $options = array()) | ||||||
|  |     { | ||||||
|  |         // TODO: use stream_copy_to_stream | ||||||
|  |         // it is 4x faster than this | ||||||
|  |         // but can lose data under load with no way to recover it | ||||||
|  |  | ||||||
|  |         $dest->emit('pipe', array($source)); | ||||||
|  |  | ||||||
|  |         $source->on('data', function ($data) use ($source, $dest) { | ||||||
|  |             $feedMore = $dest->write($data); | ||||||
|  |  | ||||||
|  |             if (false === $feedMore) { | ||||||
|  |                 $source->pause(); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         $dest->on('drain', function () use ($source) { | ||||||
|  |             $source->resume(); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         $end = isset($options['end']) ? $options['end'] : true; | ||||||
|  |         if ($end && $source !== $dest) { | ||||||
|  |             $source->on('end', function () use ($dest) { | ||||||
|  |                 $dest->end(); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static function forwardEvents($source, $target, array $events) | ||||||
|  |     { | ||||||
|  |         foreach ($events as $event) { | ||||||
|  |             $source->on($event, function () use ($event, $target) { | ||||||
|  |                 $target->emit($event, func_get_args()); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								libs/React/Stream/WritableStream.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								libs/React/Stream/WritableStream.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Stream; | ||||||
|  |  | ||||||
|  | use Evenement\EventEmitter; | ||||||
|  |  | ||||||
|  | class WritableStream extends EventEmitter implements WritableStreamInterface | ||||||
|  | { | ||||||
|  |     protected $closed = false; | ||||||
|  |  | ||||||
|  |     public function write($data) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function end($data = null) | ||||||
|  |     { | ||||||
|  |         if (null !== $data) { | ||||||
|  |             $this->write($data); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->close(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function isWritable() | ||||||
|  |     { | ||||||
|  |         return !$this->closed; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function close() | ||||||
|  |     { | ||||||
|  |         if ($this->closed) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->closed = true; | ||||||
|  |         $this->emit('end', array($this)); | ||||||
|  |         $this->emit('close', array($this)); | ||||||
|  |         $this->removeAllListeners(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								libs/React/Stream/WritableStreamInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								libs/React/Stream/WritableStreamInterface.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace React\Stream; | ||||||
|  |  | ||||||
|  | use Evenement\EventEmitterInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @event drain | ||||||
|  |  * @event error | ||||||
|  |  * @event close | ||||||
|  |  * @event pipe | ||||||
|  |  */ | ||||||
|  | interface WritableStreamInterface extends EventEmitterInterface | ||||||
|  | { | ||||||
|  |     public function isWritable(); | ||||||
|  |     public function write($data); | ||||||
|  |     public function end($data = null); | ||||||
|  |     public function close(); | ||||||
|  | } | ||||||
| @@ -121,7 +121,7 @@ class ContainerAwareEventDispatcher extends EventDispatcher | |||||||
|     public function getListeners($eventName = null) |     public function getListeners($eventName = null) | ||||||
|     { |     { | ||||||
|         if (null === $eventName) { |         if (null === $eventName) { | ||||||
|             foreach (array_keys($this->listenerIds) as $serviceEventName) { |             foreach ($this->listenerIds as $serviceEventName => $args) { | ||||||
|                 $this->lazyLoad($serviceEventName); |                 $this->lazyLoad($serviceEventName); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|   | |||||||
| @@ -31,6 +31,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface | |||||||
|  |  | ||||||
|     private $called; |     private $called; | ||||||
|     private $dispatcher; |     private $dispatcher; | ||||||
|  |     private $wrappedListeners; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Constructor. |      * Constructor. | ||||||
| @@ -45,6 +46,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface | |||||||
|         $this->stopwatch = $stopwatch; |         $this->stopwatch = $stopwatch; | ||||||
|         $this->logger = $logger; |         $this->logger = $logger; | ||||||
|         $this->called = array(); |         $this->called = array(); | ||||||
|  |         $this->wrappedListeners = array(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -68,6 +70,16 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface | |||||||
|      */ |      */ | ||||||
|     public function removeListener($eventName, $listener) |     public function removeListener($eventName, $listener) | ||||||
|     { |     { | ||||||
|  |         if (isset($this->wrappedListeners[$eventName])) { | ||||||
|  |             foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) { | ||||||
|  |                 if ($wrappedListener->getWrappedListener() === $listener) { | ||||||
|  |                     $listener = $wrappedListener; | ||||||
|  |                     unset($this->wrappedListeners[$eventName][$index]); | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         return $this->dispatcher->removeListener($eventName, $listener); |         return $this->dispatcher->removeListener($eventName, $listener); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -146,7 +158,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface | |||||||
|             $allListeners = $this->getListeners(); |             $allListeners = $this->getListeners(); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             if (null !== $this->logger) { |             if (null !== $this->logger) { | ||||||
|                 $this->logger->info(sprintf('An exception was thrown while getting the uncalled listeners (%s)', $e->getMessage()), array('exception' => $e)); |                 $this->logger->info('An exception was thrown while getting the uncalled listeners.', array('exception' => $e)); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // unable to retrieve the uncalled listeners |             // unable to retrieve the uncalled listeners | ||||||
| @@ -216,12 +228,15 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface | |||||||
|             $this->dispatcher->removeListener($eventName, $listener); |             $this->dispatcher->removeListener($eventName, $listener); | ||||||
|             $info = $this->getListenerInfo($listener, $eventName); |             $info = $this->getListenerInfo($listener, $eventName); | ||||||
|             $name = isset($info['class']) ? $info['class'] : $info['type']; |             $name = isset($info['class']) ? $info['class'] : $info['type']; | ||||||
|             $this->dispatcher->addListener($eventName, new WrappedListener($listener, $name, $this->stopwatch)); |             $wrappedListener = new WrappedListener($listener, $name, $this->stopwatch, $this); | ||||||
|  |             $this->wrappedListeners[$eventName][] = $wrappedListener; | ||||||
|  |             $this->dispatcher->addListener($eventName, $wrappedListener); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private function postProcess($eventName) |     private function postProcess($eventName) | ||||||
|     { |     { | ||||||
|  |         unset($this->wrappedListeners[$eventName]); | ||||||
|         $skipped = false; |         $skipped = false; | ||||||
|         foreach ($this->dispatcher->getListeners($eventName) as $listener) { |         foreach ($this->dispatcher->getListeners($eventName) as $listener) { | ||||||
|             if (!$listener instanceof WrappedListener) { // #12845: a new listener was added during dispatch. |             if (!$listener instanceof WrappedListener) { // #12845: a new listener was added during dispatch. | ||||||
| @@ -259,7 +274,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Returns information about the listener |      * Returns information about the listener. | ||||||
|      * |      * | ||||||
|      * @param object $listener  The listener |      * @param object $listener  The listener | ||||||
|      * @param string $eventName The event name |      * @param string $eventName The event name | ||||||
|   | |||||||
| @@ -25,12 +25,14 @@ class WrappedListener | |||||||
|     private $called; |     private $called; | ||||||
|     private $stoppedPropagation; |     private $stoppedPropagation; | ||||||
|     private $stopwatch; |     private $stopwatch; | ||||||
|  |     private $dispatcher; | ||||||
|  |  | ||||||
|     public function __construct($listener, $name, Stopwatch $stopwatch) |     public function __construct($listener, $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null) | ||||||
|     { |     { | ||||||
|         $this->listener = $listener; |         $this->listener = $listener; | ||||||
|         $this->name = $name; |         $this->name = $name; | ||||||
|         $this->stopwatch = $stopwatch; |         $this->stopwatch = $stopwatch; | ||||||
|  |         $this->dispatcher = $dispatcher; | ||||||
|         $this->called = false; |         $this->called = false; | ||||||
|         $this->stoppedPropagation = false; |         $this->stoppedPropagation = false; | ||||||
|     } |     } | ||||||
| @@ -56,7 +58,7 @@ class WrappedListener | |||||||
|  |  | ||||||
|         $e = $this->stopwatch->start($this->name, 'event_listener'); |         $e = $this->stopwatch->start($this->name, 'event_listener'); | ||||||
|  |  | ||||||
|         call_user_func($this->listener, $event, $eventName, $dispatcher); |         call_user_func($this->listener, $event, $eventName, $this->dispatcher ?: $dispatcher); | ||||||
|  |  | ||||||
|         if ($e->isStarted()) { |         if ($e->isStarted()) { | ||||||
|             $e->stop(); |             $e->stop(); | ||||||
|   | |||||||
| @@ -91,8 +91,12 @@ class RegisterListenersPass implements CompilerPassInterface | |||||||
|                 throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event subscribers are lazy-loaded.', $id)); |                 throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event subscribers are lazy-loaded.', $id)); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             if ($def->isAbstract()) { | ||||||
|  |                 throw new \InvalidArgumentException(sprintf('The service "%s" must not be abstract as event subscribers are lazy-loaded.', $id)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|             // We must assume that the class value has been correctly filled, even if the service is created by a factory |             // We must assume that the class value has been correctly filled, even if the service is created by a factory | ||||||
|             $class = $def->getClass(); |             $class = $container->getParameterBag()->resolveValue($def->getClass()); | ||||||
|  |  | ||||||
|             $refClass = new \ReflectionClass($class); |             $refClass = new \ReflectionClass($class); | ||||||
|             $interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface'; |             $interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface'; | ||||||
|   | |||||||
| @@ -77,7 +77,7 @@ class Event | |||||||
|      * |      * | ||||||
|      * @param EventDispatcherInterface $dispatcher |      * @param EventDispatcherInterface $dispatcher | ||||||
|      * |      * | ||||||
|      * @deprecated Deprecated in 2.4, to be removed in 3.0. The event dispatcher is passed to the listener call. |      * @deprecated since version 2.4, to be removed in 3.0. The event dispatcher is passed to the listener call. | ||||||
|      * |      * | ||||||
|      * @api |      * @api | ||||||
|      */ |      */ | ||||||
| @@ -91,12 +91,14 @@ class Event | |||||||
|      * |      * | ||||||
|      * @return EventDispatcherInterface |      * @return EventDispatcherInterface | ||||||
|      * |      * | ||||||
|      * @deprecated Deprecated in 2.4, to be removed in 3.0. The event dispatcher is passed to the listener call. |      * @deprecated since version 2.4, to be removed in 3.0. The event dispatcher is passed to the listener call. | ||||||
|      * |      * | ||||||
|      * @api |      * @api | ||||||
|      */ |      */ | ||||||
|     public function getDispatcher() |     public function getDispatcher() | ||||||
|     { |     { | ||||||
|  |         @trigger_error('The '.__METHOD__.' method is deprecated since version 2.4 and will be removed in 3.0. The event dispatcher instance can be received in the listener call instead.', E_USER_DEPRECATED); | ||||||
|  |  | ||||||
|         return $this->dispatcher; |         return $this->dispatcher; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -105,12 +107,14 @@ class Event | |||||||
|      * |      * | ||||||
|      * @return string |      * @return string | ||||||
|      * |      * | ||||||
|      * @deprecated Deprecated in 2.4, to be removed in 3.0. The event name is passed to the listener call. |      * @deprecated since version 2.4, to be removed in 3.0. The event name is passed to the listener call. | ||||||
|      * |      * | ||||||
|      * @api |      * @api | ||||||
|      */ |      */ | ||||||
|     public function getName() |     public function getName() | ||||||
|     { |     { | ||||||
|  |         @trigger_error('The '.__METHOD__.' method is deprecated since version 2.4 and will be removed in 3.0. The event name can be received in the listener call instead.', E_USER_DEPRECATED); | ||||||
|  |  | ||||||
|         return $this->name; |         return $this->name; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -119,7 +123,7 @@ class Event | |||||||
|      * |      * | ||||||
|      * @param string $name The event name. |      * @param string $name The event name. | ||||||
|      * |      * | ||||||
|      * @deprecated Deprecated in 2.4, to be removed in 3.0. The event name is passed to the listener call. |      * @deprecated since version 2.4, to be removed in 3.0. The event name is passed to the listener call. | ||||||
|      * |      * | ||||||
|      * @api |      * @api | ||||||
|      */ |      */ | ||||||
|   | |||||||
| @@ -68,7 +68,7 @@ class EventDispatcher implements EventDispatcherInterface | |||||||
|             return $this->sorted[$eventName]; |             return $this->sorted[$eventName]; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         foreach (array_keys($this->listeners) as $eventName) { |         foreach ($this->listeners as $eventName => $eventListeners) { | ||||||
|             if (!isset($this->sorted[$eventName])) { |             if (!isset($this->sorted[$eventName])) { | ||||||
|                 $this->sortListeners($eventName); |                 $this->sortListeners($eventName); | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -77,7 +77,7 @@ interface EventDispatcherInterface | |||||||
|     public function removeSubscriber(EventSubscriberInterface $subscriber); |     public function removeSubscriber(EventSubscriberInterface $subscriber); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Gets the listeners of a specific event or all listeners. |      * Gets the listeners of a specific event or all listeners sorted by descending priority. | ||||||
|      * |      * | ||||||
|      * @param string $eventName The name of the event |      * @param string $eventName The name of the event | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -71,7 +71,7 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate | |||||||
|             return $this->arguments[$key]; |             return $this->arguments[$key]; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         throw new \InvalidArgumentException(sprintf('%s not found in %s', $key, $this->getName())); |         throw new \InvalidArgumentException(sprintf('Argument "%s" not found.', $key)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -23,5 +23,5 @@ Resources | |||||||
| You can run the unit tests with the following command: | You can run the unit tests with the following command: | ||||||
|  |  | ||||||
|     $ cd path/to/Symfony/Component/EventDispatcher/ |     $ cd path/to/Symfony/Component/EventDispatcher/ | ||||||
|     $ composer.phar install |     $ composer install | ||||||
|     $ phpunit |     $ phpunit | ||||||
|   | |||||||
| @@ -118,10 +118,21 @@ abstract class AbstractEventDispatcherTest extends \PHPUnit_Framework_TestCase | |||||||
|         $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(self::preFoo)); |         $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(self::preFoo)); | ||||||
|         $event = new Event(); |         $event = new Event(); | ||||||
|         $return = $this->dispatcher->dispatch(self::preFoo, $event); |         $return = $this->dispatcher->dispatch(self::preFoo, $event); | ||||||
|         $this->assertEquals('pre.foo', $event->getName()); |  | ||||||
|         $this->assertSame($event, $return); |         $this->assertSame($event, $return); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @group legacy | ||||||
|  |      */ | ||||||
|  |     public function testLegacyDispatch() | ||||||
|  |     { | ||||||
|  |         $this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED); | ||||||
|  |  | ||||||
|  |         $event = new Event(); | ||||||
|  |         $return = $this->dispatcher->dispatch(self::preFoo, $event); | ||||||
|  |         $this->assertEquals('pre.foo', $event->getName()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public function testDispatchForClosure() |     public function testDispatchForClosure() | ||||||
|     { |     { | ||||||
|         $invoked = 0; |         $invoked = 0; | ||||||
| @@ -239,8 +250,13 @@ abstract class AbstractEventDispatcherTest extends \PHPUnit_Framework_TestCase | |||||||
|         $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); |         $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function testEventReceivesTheDispatcherInstance() |     /** | ||||||
|  |      * @group legacy | ||||||
|  |      */ | ||||||
|  |     public function testLegacyEventReceivesTheDispatcherInstance() | ||||||
|     { |     { | ||||||
|  |         $this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED); | ||||||
|  |  | ||||||
|         $dispatcher = null; |         $dispatcher = null; | ||||||
|         $this->dispatcher->addListener('test', function ($event) use (&$dispatcher) { |         $this->dispatcher->addListener('test', function ($event) use (&$dispatcher) { | ||||||
|             $dispatcher = $event->getDispatcher(); |             $dispatcher = $event->getDispatcher(); | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ | |||||||
| namespace Symfony\Component\EventDispatcher\Tests\Debug; | namespace Symfony\Component\EventDispatcher\Tests\Debug; | ||||||
|  |  | ||||||
| use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher; | use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher; | ||||||
|  | use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||||||
| use Symfony\Component\EventDispatcher\EventSubscriberInterface; | use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||||||
| use Symfony\Component\EventDispatcher\EventDispatcher; | use Symfony\Component\EventDispatcher\EventDispatcher; | ||||||
| use Symfony\Component\EventDispatcher\Event; | use Symfony\Component\EventDispatcher\Event; | ||||||
| @@ -86,6 +87,20 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase | |||||||
|         $this->assertEquals(array(), $tdispatcher->getNotCalledListeners()); |         $this->assertEquals(array(), $tdispatcher->getNotCalledListeners()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function testGetCalledListenersNested() | ||||||
|  |     { | ||||||
|  |         $tdispatcher = null; | ||||||
|  |         $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); | ||||||
|  |         $dispatcher->addListener('foo', function (Event $event, $eventName, $dispatcher) use (&$tdispatcher) { | ||||||
|  |             $tdispatcher = $dispatcher; | ||||||
|  |             $dispatcher->dispatch('bar'); | ||||||
|  |         }); | ||||||
|  |         $dispatcher->addListener('bar', function (Event $event) {}); | ||||||
|  |         $dispatcher->dispatch('foo'); | ||||||
|  |         $this->assertSame($dispatcher, $tdispatcher); | ||||||
|  |         $this->assertCount(2, $dispatcher->getCalledListeners()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public function testLogger() |     public function testLogger() | ||||||
|     { |     { | ||||||
|         $logger = $this->getMock('Psr\Log\LoggerInterface'); |         $logger = $this->getMock('Psr\Log\LoggerInterface'); | ||||||
| @@ -160,6 +175,19 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase | |||||||
|         $dispatcher->dispatch('foo'); |         $dispatcher->dispatch('foo'); | ||||||
|         $this->assertTrue($nestedCall); |         $this->assertTrue($nestedCall); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function testListenerCanRemoveItselfWhenExecuted() | ||||||
|  |     { | ||||||
|  |         $eventDispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); | ||||||
|  |         $listener1 = function ($event, $eventName, EventDispatcherInterface $dispatcher) use (&$listener1) { | ||||||
|  |             $dispatcher->removeListener('foo', $listener1); | ||||||
|  |         }; | ||||||
|  |         $eventDispatcher->addListener('foo', $listener1); | ||||||
|  |         $eventDispatcher->addListener('foo', function () {}); | ||||||
|  |         $eventDispatcher->dispatch('foo'); | ||||||
|  |  | ||||||
|  |         $this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed'); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| class EventSubscriber implements EventSubscriberInterface | class EventSubscriber implements EventSubscriberInterface | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user