Created
August 25, 2019 15:33
-
-
Save rianorie/9b50eb5bb32a2dc4fa5dbb237feb68b4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Game; | |
use \Game\Connection\Interfaces\Connection; | |
use Game\Module\Interfaces\Command; | |
use InvalidArgumentException; | |
/** | |
* Game input handler | |
* | |
* @package Game | |
* @author Rian Orie <[email protected]> | |
* @version 1.0 | |
* @created 2015-07-23 | |
*/ | |
class Input | |
{ | |
const PRIORITY_LOW = 1; | |
const PRIORITY_NORMAL = 2; | |
const PRIORITY_HIGH = 3; | |
/** | |
* List of the registered commands | |
* | |
* @var array | |
*/ | |
private $commands; | |
/** | |
* @var Event | |
*/ | |
private $event; | |
/** | |
* Construct the input class | |
* | |
* @param Event $event The event handler | |
*/ | |
public function __construct(Event $event) | |
{ | |
$this->event = $event; | |
} | |
/** | |
* Register a command in the system | |
* | |
* @param string $command The command to register | |
* @param Command $callback Callable handler that works with the given input | |
* @param boolean $priority Give the command priority, pushing it to the front of the command list | |
* | |
* @throws Exception | |
*/ | |
public function registerCommand(string $command, Command $callback, $priority = self::PRIORITY_NORMAL) | |
{ | |
if ( ! preg_match('/^[a-z]+$/', $command)) { | |
throw new Exception('Command ' . $command . ' contains invalid characters! Only use a-z'); | |
} | |
// make sure we're not trying to register an already existing command | |
if (in_array($command, $this->getCommands())) { | |
throw new Exception('Command ' . $command . ' is already registered!'); | |
} | |
// call some events | |
$this->event->dispatch('input.before_register', ['command' => &$command, 'callback' => &$callback]); | |
$this->event->dispatch('input.before_register.' . $command, ['command' => &$command, 'callback' => &$callback]); | |
if ($callback instanceof Command) { | |
$callback = [$callback, 'execute']; | |
} | |
// and register the command | |
$this->commands[$priority][$command] = $callback; | |
ksort($this->commands[$priority]); | |
// and some events again | |
$this->event->dispatch('input.after_register', ['command' => $command, 'callback' => $callback]); | |
$this->event->dispatch('input.after_register.' . $command, ['command' => $command, 'callback' => $callback]); | |
} | |
/** | |
* Register commands by an associative array | |
* | |
* @param array $commandList | |
* @param bool $priority | |
* | |
* @throws Exception | |
*/ | |
public function registerCommands(array $commandList, $priority = self::PRIORITY_NORMAL) | |
{ | |
foreach($commandList as $command => $callback) { | |
if ( ! $callback instanceof Command) { | |
throw new InvalidArgumentException('Callback should implement the Command interface'); | |
} | |
$this->registerCommand($command, $callback, $priority); | |
} | |
} | |
/** | |
* Process the input from a connection | |
* | |
* @param Connection $connection The connection that added the input | |
* @param string $input The actual input | |
*/ | |
public function handle(Connection $connection, $input) | |
{ | |
// clean off anything that shouldn't be at the start of the line and then separate the input | |
$arguments = explode(' ', rtrim($input)); | |
$this->event->dispatch('input.before_process', ['connection' => $connection, 'input' => &$input, 'arguments' => &$arguments]); | |
if (isset($arguments[0])) { | |
// try and find the command | |
$command = $this->findCommand(ltrim($arguments[0])); | |
// if we can't find it, simply stop | |
if ( ! $command) { | |
if (trim($arguments[0]) == '') { | |
$this->event->dispatch('input.empty', ['connection' => $connection]); | |
return; | |
} | |
$this->event->dispatch('input.not_found', ['connection' => $connection, 'input' => $input]); | |
return; | |
} | |
// but if we did find the command, let the command handle the input | |
// clean the input. ltrim potential whitespaces, then ltrim the first argument then trim potential whitespaces again | |
$cleaned = trim(ltrim(ltrim($input), $arguments[0])); | |
// fire event handlers | |
$this->event->dispatch('input.before_command', ['connection' => $connection, 'command' => $command, 'input' => $input, 'cleaned' => $cleaned]); | |
$this->event->dispatch('input.before_command.' . $command, ['connection' => $connection, 'command' => $command, 'input' => $input, 'cleaned' => $cleaned]); | |
// execute the command | |
if (isset($this->commands[self::PRIORITY_HIGH][$command])) { | |
call_user_func_array($this->commands[self::PRIORITY_HIGH][$command], [$connection, $cleaned, $command, $input]); | |
} elseif (isset($this->commands[self::PRIORITY_NORMAL][$command])) { | |
call_user_func_array($this->commands[self::PRIORITY_NORMAL][$command], [$connection, $cleaned, $command, $input]); | |
} else { | |
call_user_func_array($this->commands[self::PRIORITY_LOW][$command], [$connection, $cleaned, $command, $input]); | |
} | |
// fire event handlers | |
$this->event->dispatch('input.after_command', ['connection' => $connection, 'command' => $command, 'input' => $input, 'cleaned' => $cleaned]); | |
$this->event->dispatch('input.after_command.' . $command, ['connection' => $connection, 'command' => $command, 'input' => $input, 'cleaned' => $cleaned]); | |
} | |
} | |
/** | |
* Retrieve an array of the currently registered commands | |
* | |
* @return array | |
*/ | |
public function getCommands() | |
{ | |
return array_merge( | |
(isset($this->commands[self::PRIORITY_HIGH]) ? array_keys($this->commands[self::PRIORITY_HIGH]) : []), | |
(isset($this->commands[self::PRIORITY_NORMAL]) ? array_keys($this->commands[self::PRIORITY_NORMAL]) : []), | |
(isset($this->commands[self::PRIORITY_LOW]) ? array_keys($this->commands[self::PRIORITY_LOW]) : []) | |
); | |
} | |
/** | |
* Find the closest matching command in the array of commands | |
* | |
* @param string $input The given command | |
* | |
* @return string|bool | |
*/ | |
protected function findCommand($input) | |
{ | |
// sanitize the input | |
$input = strtolower(trim($input)); | |
// if the command is empty | |
if (strlen($input) == 0) { | |
return false; | |
} | |
foreach ($this->getCommands() as $command) { | |
if (substr($command, 0, strlen($input)) == $input) { | |
return $command; | |
} | |
} | |
// if not, fail | |
return false; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Modules\CommandNotFound\Observer; | |
use Game\Module\Observer; | |
use stdClass; | |
class NotFound extends Observer | |
{ | |
public function fire(stdClass $data) | |
{ | |
$output = [ | |
'Wait, what? I have no idea what that means.', | |
'Soo.. that doesn\'t make any kind of sense.', | |
'Command not found.', | |
"I could not find that command.\nCheck your spelling and check the help files." | |
]; | |
$this->getOutput()->write($data->connection, ["%s\n", $output[rand(0, 3)]]); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment