diff --git a/src/dominate/Command.php b/src/dominate/Command.php index 62c0b29..9ce8cb6 100755 --- a/src/dominate/Command.php +++ b/src/dominate/Command.php @@ -1,469 +1,557 @@ -. - */ -namespace dominate; - -use pocketmine\command\Command as PocketMineCommand; -use pocketmine\command\PluginIdentifiableCommand; -use pocketmine\command\CommandSender; -use pocketmine\plugin\Plugin; - -use dominate\parameter\Parameter; -use dominate\requirement\Requirement; - -use localizer\Localizer; - -class Command extends PocketMineCommand implements PluginIdentifiableCommand { - - /** - * @var Command - */ - protected $parent; - - /** - * @var Requirement[] - */ - protected $requirements = []; - - /** - * @var Command[] - */ - protected $childs = []; - - /** - * @var Parameter[] - */ - protected $parameters = []; - - /** - * Values from each parameter - * @var mixed[] - */ - protected $values = []; - - /** - * @var Command - */ - protected $endPoint = null; - - // Last execution parameters - - /** @var CommandSender */ - protected $sender; - - /** @var string[] */ - protected $args = []; - - /** @var string */ - protected $label; - - /** @var Plugin */ - protected $plugin; - - /** - * @param string $name - * @param string $description = "" - * @param string[] $aliases = [] - * @param Parameter[] $parameters = [] - * @param Command[] $childs = [] - */ - public function __construct(Plugin $plugin, string $name, string $description = "", string $permission, array $aliases = [], array $parameters = [], array $childs = []){ - parent::__construct($name, $description, "", $aliases); - $this->setPermission($permission); - $this->plugin = $plugin; - $this->parameters = $parameters; - $this->childs = $childs; - - $this->setup(); - $this->setUsage($this->getUsage()); - } - - /** - * Add requirements, permissions and parameters here - */ - public function setup() {} - - /* - * ---------------------------------------------------------- - * CHILD (Sub Command) - * ---------------------------------------------------------- - */ - - /** - * @return Command|null - */ - public function getRoot() { - return $this->getChain()[0]; - } - - /** - * @return Command[] - */ - public function getChain() : array { - $chain = [$this]; - if(!$this->isChild()) return $chain; - $parent = $this->parent; - $chain[] = $parent; - while($parent->isChild()) { - $parent = $parent->getParent(); - $chain[] = $parent; - } - return array_reverse($chain); - } - - /** - * @return Command[] - */ - public function getChildsByToken(string $token) : array - { - $matches = []; - foreach($this->childs as $child) { - if($token === ($name = $child->getName())) { - $matches[] = $child; - break; - } - $hay = [0 => $name]; - $hay = array_merge($child->getAliases(), $hay); - foreach($hay as $al) { - if(($p = strpos($al, $token)) === 0) { - $matches[$al] = $child; - break; - } - } - } - ksort($matches); - return array_values($matches); - } - - /** - * Get single command object by name - */ - public function getChild(string $name) { - return $this->getChildsByToken($name)[0] ?? null; - } - - /** - * Registers new subcommand or replaces existing one - * - * @param Command $command - * @param int $index if null then the child will be added at the end of array - */ - public function addChild(Command $command, int $index = null) { - if($this->contains($command)) - throw new \InvalidArgumentException("command '{$command->getName()}' is already a child of '{$this->getName()}'"); - if($this->getParent() === $command) - throw new \LogicException("parent can not be child"); - if($command->contains($this)) - throw new \LogicException("parent '{$command->getName()}' can't be child of child"); - $this->childs[($index ?? count($this->childs))] = $command; - $command->setParent($this); - } - - /** - * @var Command[] - */ - public function addChilds(array $childs) { - foreach($childs as $child) { - $this->addChild($child); - } - } - - /** - * @var Command[] - */ - public function setChilds(array $childs) { - foreach($this->childs as $child) { - $this->removeChild($child); - } - foreach($childs as $child) { - $this->addChild($child); - } - } - - public function contains(Command $command) : bool { - return in_array($command, $this->childs, true); - } - - public function removeChild(Command $command) { - if($this->contains($command)) { - unset($this->childs[array_search($command, $this->childs, true)]); - $command->setParent(null); - } - } - - public function getChilds() : array { - return $this->childs; - } - - public function isChild() : bool { - return $this->parent instanceof Command; - } - - public function isParent() : bool { - return !empty($this->childs); - } - - public function getParent() { - return $this->parent; - } - - public function setParent(Command $command) { - if($this === $command) throw new \LogicException("command can not be parent of self"); - // TODO: other logic checks - $this->parent = $command; - $command->removeChild($command); - } - - /* - * ---------------------------------------------------------- - * PARAMETER - * ---------------------------------------------------------- - */ - - public function addParameter(Parameter $arg) { - $this->parameters[] = $arg; - $arg->setIndex($this->getParameterIndex($arg)); - } - - public function removeParameter(Parameter $arg) { - if(($i = $this->getParameterIndex($arg)) >= 0) { - unset($this->parameters[$i]); - } - } - - public function getParameterIndex(Parameter $arg) : int { - foreach($this->parameters as $i => $a) { - if($a === $arg) return $i; - } - return -1; - } - - public function getParameter(string $name) { - foreach ($this->parameters as $param) { - if($param->getName() === $name) return $param; - } - return null; - } - - public function getArgument(int $index) { - if(isset($this->parameters[$index])) { - return $this->parameters[$index]->getValue(); - } - return null; - } - - public function isArgumentSet(int $index) { - return isset($this->values[$index]); - } - - public function getRequiredParameterCount() : int { - $i = 0; - foreach ($this->parameters as $a) { - if($a->isRequired($this->sender)) $i++; - } - return $i; - } - - /* - * ---------------------------------------------------------- - * REQUIREMENTS - * ---------------------------------------------------------- - */ - - public function hasRequirement(Requirement $r) { - return in_array($r, $this->requirements, true); - } - - public function addRequirement(Requirement $r) { - $this->requirements[] = $r; - } - - public function testRequirements(CommandSender $sender = null) : bool { - $sender = $sender ?? $this->sender; - foreach($this->requirements as $requirement) { - if(!$requirement->hasMet($sender, false)) return false; - } - return true; - } - - /* - * ---------------------------------------------------------- - * USAGE - * ---------------------------------------------------------- - * - * Generate dynamic usage messages - * - */ - - public function getUsage() { - # TODO: Do this once - $sender = $this->sender; - $usage = "/"; - // add chain - $chain = $this->getChain(); - array_reverse($chain); - foreach($chain as $cmd) { - $usage .= $cmd->getName()." "; - } - foreach ($this->parameters as $param) { - $usage .= $param->getTemplate($sender)." "; - } - $usage = trim($usage); - $this->usage = $usage; - return $usage; - } - - public function sendUsage(CommandSender $sender = null) { - $sender = $sender ?? $this->sender; - if(!$sender) return; - $sender->sendMessage($this->getUsage()); - } - - /* - * ---------------------------------------------------------- - * EXECUTION - * ---------------------------------------------------------- - */ - - public function prepare(CommandSender $sender, $label, array $args) : bool { - return true; - } - - public function execute(CommandSender $sender, $label, array $args) { - $this->sender = $sender; - $this->label = $label; - $this->args = $args; - - if(!$this->prepare($sender, $label, $args)) { - return false; - } - if(!$this->testPermission($sender)) { - return false; - } - if(!$this->testRequirements()) { - return false; - } - if( ($argCount = count($args)) < $this->getRequiredParameterCount() ) { - $this->sendUsage($sender); - return false; - } - - foreach ($this->parameters as $i => $param) { - - if (!isset($args[$i]) and !$param->isDefaultValueSet()) { - break; - } - - $value = isset($args[$i]) ? $args[$i] : $param->getDefaultValue(); - if($param->getType() !== Parameter::TYPE_NULL && $value !== null) { - if($param->isPermissionSet()) { - if(!$param->testPermission($sender)) { - $sender->sendMessage(Localizer::translatable("parameter.permission-denied", [ - "param" => $param->getName() - ])); - return false; - } - } - $param->setValue($param->read($value, $sender)); - if(!$param->isValid($param->getValue(), $sender)) { - $sender->sendMessage($param->createErrorMessage($sender, $value)); - return false; - } - } - $this->values[$i] = $value; - } - - if (!empty($this->childs) and count($this->values) > 0) { - if($this->values[0] === "") { - $this->sendUsage($sender); - return false; - } - $matches = $this->getChildsByToken((string) $this->values[0]); - - if( ($matchCount = count($matches)) === 1 ) { - array_shift($args); - $matches[0]->execute($sender, $label, $args); - $this->endPoint = $matches[0]->endPoint; - return true; - } else { - $this->endPoint = $this; - // Token was too ambiguous - if($matchCount > 8) { - $sender->sendMessage(Localizer::trans("command-too-ambiguous", ["token" => $this->values[0]])); - return false; - } - // No commands by token was found - if($matchCount === 0) { - $sender->sendMessage(Localizer::trans("command-child-none", ["token" => $this->values[0]])); - return false; - } - // Few commands by token was found an suggestion table will be created - $sender->sendMessage(Localizer::trans("command-suggestion-header", ["token" => $this->values[0]])); - foreach($matches as $match) { - $sender->sendMessage(Localizer::trans("command-suggestion", ["match" => $match->getName(), "usage" => $match->getUsage($sender), "desc" => $match->getDescription()])); - } - return false; - } - } - - try { - $return = $this->perform($sender, $label, $args); - if(is_string($return)) { - $sender->sendMessage(Localizer::translatable($return)); - } elseif(is_array($return)) { - switch (count($return)) { - case 0: - break; - case 1: - $msg = $return[0]; - $params = []; - default: - $msg = $return[0]; - $params = array_pop($return); - if(!is_array($params)) $params = [$params]; - } - if(isset($msg)) { - $sender->sendMessage(Localizer::translatable($msg, $params)); - } - } - } catch(\Message $e) { - $sender->sendMessage($e->getMessage()); - } - $this->reset(); - return true; - } - - public function perform(CommandSender $sender, $label, array $args) { - return true; - } - - public function reset() { - $this->sender = null; - $this->label = ""; - $this->args = []; - $this->values = []; - foreach ($this->parameters as $param) { - $param->unset(); - } - } - - public function getPlugin() { - return $this->plugin; - } - -} \ No newline at end of file +. + */ +namespace dominate; + +use Message; +use pocketmine\command\Command as PocketMineCommand; +use pocketmine\command\PluginIdentifiableCommand; +use pocketmine\command\CommandSender; +use pocketmine\plugin\Plugin; + +use dominate\parameter\Parameter; +use dominate\requirement\Requirement; + +use localizer\Localizer; + +class Command extends PocketMineCommand implements PluginIdentifiableCommand { + + /** + * @var Command + */ + protected $parent; + + /** + * @var Requirement[] + */ + protected $requirements = []; + + /** + * @var Command[] + */ + protected $childs = []; + + /** + * @var Parameter[] + */ + protected $parameters = []; + + + + /** + * Values from each parameter + * @var mixed[] + */ + protected $values = []; + + /** + * @var Command + */ + protected $endPoint = null; + + /** + * Send error messagem if arguments > parameter count + * @var bool + */ + protected $overflowSensitive = true; + + /** + * Swap arguments if given in wrong order + * @var bool + */ + protected $swap = true; + + /** + * Give sender suggestions if more than command met token + * @var bool + */ + protected $smart = true; + + // Last execution parameters + + /** @var CommandSender */ + protected $sender; + + /** @var string[] */ + protected $args = []; + + /** @var string */ + protected $label; + + /** @var Plugin */ + protected $plugin; + + + /** + * @param Plugin|Command $owner + * @param string $name + * @param string $description = "" + * @param string $permission + * @param string[] $aliases = [] + * @param Parameter[] $parameters = [] + * @param Command[] $childs = [] + */ + public function __construct($owner, string $name, string $description = "", string $permission, array $aliases = [], array $parameters = [], array $childs = []){ + parent::__construct($name, $description, "", $aliases); + $this->setPermission($permission); + $this->plugin = $owner instanceof Command ? $owner->getPlugin() : $owner; + if($owner instanceof Command) { + $this->setParent($owner); + } + $this->parameters = $parameters; + $this->setChilds($childs); + + $this->setup(); + $this->setUsage($this->getUsage()); + } + + /** + * Add requirements, permissions and parameters here + */ + public function setup() {} + + /* + * ---------------------------------------------------------- + * CHILD (Sub Command) + * ---------------------------------------------------------- + */ + + /** + * @return Command|null + */ + public function getRoot() { + return $this->getChain()[0]; + } + + /** + * Super command being the first element of array + * @return Command[] + */ + public function getChain() : array { + $chain = [$this]; + if(!$this->isChild()) return $chain; + $parent = $this->parent; + $chain[] = $parent; + while($parent->isChild()) { + $parent = $parent->getParent(); + $chain[] = $parent; + } + return array_reverse($chain); + } + + /** + * @return Command[] + */ + public function getChildsByToken(string $token) : array + { + $matches = []; + $token = strtolower($token); + foreach($this->childs as $child) { + if($token === (strtolower($name = $child->getName()))) { + $matches[] = $child; + break; + } + $hay = [0 => $name]; + $hay = array_merge($child->getAliases(), $hay); + foreach($hay as $al) { + if(($p = strpos($al, $token)) === 0) { + $matches[$al] = $child; + break; + } + } + } + ksort($matches); + return array_values($matches); + } + + /** + * Get single command object by name + */ + public function getChild(string $name) { + return $this->getChildsByToken($name)[0] ?? null; + } + + /** + * Registers new subcommand or replaces existing one + * + * @param Command $command + * @param int $index if null then the child will be added at the end of array + */ + public function addChild(Command $command, int $index = null) { + if($this->contains($command)) + throw new \InvalidArgumentException("command '{$command->getName()}' is already a child of '{$this->getName()}'"); + if($this->getParent() === $command) + throw new \LogicException("parent can not be child"); + if($command->contains($this)) + throw new \LogicException("parent '{$command->getName()}' can't be child of child"); + $this->childs[($index ?? count($this->childs))] = $command; + $command->setParent($this); + } + + /** + * @var Command[] + */ + public function addChilds(array $childs) { + foreach($childs as $child) { + $this->addChild($child); + } + } + + /** + * @var Command[] + */ + public function setChilds(array $childs) { + foreach($this->childs as $child) { + $this->removeChild($child); + } + foreach($childs as $child) { + $this->addChild($child); + } + } + + public function contains(Command $command) : bool { + return in_array($command, $this->childs, true); + } + + public function removeChild(Command $command) { + if($this->contains($command)) { + unset($this->childs[array_search($command, $this->childs, true)]); + $command->setParent(null); + } + } + + public function getChilds() : array { + return $this->childs; + } + + public function isChild() : bool { + return $this->parent instanceof Command; + } + + public function isParent() : bool { + return !empty($this->childs); + } + + public function getParent() { + return $this->parent; + } + + public function setParent(Command $command) { + if($this === $command) throw new \LogicException("command can not be parent of self"); + // TODO: other logic checks + $this->parent = $command; + } + + /* + * ---------------------------------------------------------- + * PARAMETER + * ---------------------------------------------------------- + */ + + public function addParameter(Parameter $arg) { + $this->parameters[] = $arg; + $arg->setIndex($this->getParameterIndex($arg)); + } + + public function removeParameter(Parameter $arg) { + if(($i = $this->getParameterIndex($arg)) >= 0) { + unset($this->parameters[$i]); + } + } + + public function getParameterIndex(Parameter $arg) : int { + foreach($this->parameters as $i => $a) { + if($a === $arg) return $i; + } + return -1; + } + + /** + * @param int $index + * @return Parameter|null + */ + public function getParameterAt(int $index) { + return $this->parameters[$index] ?? null; + } + + public function getParameter(string $name) { + foreach ($this->parameters as $param) { + if($param->getName() === $name) return $param; + } + return null; + } + + public function getArgument(int $index) { + if(isset($this->parameters[$index])) { + return $this->parameters[$index]->getValue(); + } + return null; + } + + public function isArgumentSet(int $index) { + return isset($this->values[$index]); + } + + public function getRequiredParameterCount() : int { + $i = 0; + foreach ($this->parameters as $a) { + if($a->isRequired($this->sender)) $i++; + } + return $i; + } + + /* + * ---------------------------------------------------------- + * REQUIREMENTS + * ---------------------------------------------------------- + */ + + public function hasRequirement(Requirement $r) { + return in_array($r, $this->requirements, true); + } + + public function addRequirement(Requirement $r) { + $this->requirements[] = $r; + } + + public function testRequirements(CommandSender $sender = null) : bool { + $sender = $sender ?? $this->sender; + foreach($this->requirements as $requirement) { + if(!$requirement->hasMet($sender, false)) return false; + } + return true; + } + + public function getUsage() { + $sender = $this->sender; + $usage = "/"; + // add chain + $chain = $this->getChain(); + array_reverse($chain); + foreach($chain as $cmd) { + $usage .= $cmd->getName()." "; + } + foreach ($this->parameters as $param) { + $usage .= $param->getTemplate($sender)." "; + } + if(empty($this->parameters) && !empty($this->getChilds())) { + $usage .= " "; + } + $usage = trim($usage); + $this->usage = $usage; + return $usage; + } + + public function sendUsage(CommandSender $sender = null) { + $sender = $sender ?? $this->sender; + if(!$sender) return; + if(class_exists("\\localizer\\Localizer")) { + if(($msg = Localizer::trans("command-usage", ["usage" => $this->getUsage()])) !== "command-usage") { + $sender->sendMessage($msg); + return; + } + } + $sender->sendMessage($this->getUsage()); + } + + /* + * ---------------------------------------------------------- + * EXECUTION + * ---------------------------------------------------------- + */ + + /** + * @param CommandSender $sender + * @param $label + * @param array $args + * @return bool + */ + public function prepare(CommandSender $sender, $label, array $args) : bool { + return true; + } + + public function execute(CommandSender $sender, $label, array $args) { + $this->sender = $sender; + $this->label = $label; + $this->args = $args; + + if(!$this->prepare($sender, $label, $args)) { + return false; + } + if(!$this->testPermission($sender)) { + return false; + } + if(!$this->testRequirements()) { + return false; + } + if( ($argCount = count($args)) < $this->getRequiredParameterCount() && $this->overflowSensitive ) { + $this->sendUsage($sender); + return false; + } + + if($this->swap) { + $this->swap(); + } + foreach ($this->parameters as $i => $param) { + + $args = $this->args; + if (!isset($args[$i]) and !$param->isDefaultValueSet()) { + break; + } + + $value = isset($args[$i]) ? $args[$i] : $param->getDefaultValue(); + if($param->getType() !== Parameter::TYPE_NULL && $value !== null) { + if($param->isPermissionSet() && $this->isArgumentSet($i)) { + if(!$param->testPermission($sender)) { + $sender->sendMessage(Localizer::translatable("parameter.permission-denied", [ + "param" => $param->getName() + ])); + return false; + } + } + $param->setValue($param->read($value, $sender)); + # If more than one param was validated at once, then which error message should we use? # TODO + if(!$param->isValid($param->getValue(), $sender) && !$param->getNextParameter()) { + $sender->sendMessage($param->createErrorMessage($sender, $value)); + return false; + } elseif ($param->getNextParameter()) { + while($param = $param->getNextParameter()) { + $param->setValue($param->read($value, $sender)); + if(!$param->isValid($param->getValue(), $sender) && !$param->getNextParameter()) { + $sender->sendMessage($param->createErrorMessage($sender, $value)); + } + } + } + } + $this->values[$i] = $value; + $this->args = $args; + } + + if (!empty($this->childs) and count($this->values) > 0) { + if($this->values[0] === "") { + $this->sendUsage($sender); + return false; + } + $matches = $this->getChildsByToken((string) $this->values[0]); + + if( ($matchCount = count($matches)) === 1 ) { + array_shift($args); + $matches[0]->execute($sender, $label, $args); + $this->endPoint = $matches[0]->endPoint; + return true; + } else { + $this->endPoint = $this; + // Token was too ambiguous + if($matchCount > 8) { + $sender->sendMessage(Localizer::trans("command-too-ambiguous", ["token" => $this->values[0]])); + return false; + } + // No commands by token was found + if($matchCount === 0) { + $sender->sendMessage(Localizer::trans("command-child-none", ["token" => $this->values[0]])); + return false; + } + // Few commands by token was found an suggestion table will be created + $sender->sendMessage(Localizer::trans("command-suggestion-header", ["token" => $this->values[0]])); + foreach($matches as $match) { + $sender->sendMessage(Localizer::trans("command-suggestion", ["match" => $match->getName(), "usage" => $match->getUsage($sender), "desc" => $match->getDescription()])); + } + return false; + } + } + + try { + $return = $this->perform($sender, $label, $args); + if(is_string($return)) { + $sender->sendMessage(Localizer::translatable($return)); + } elseif(is_array($return)) { + $params = []; + switch (count($return)) { + case 0: + break; + case 1: + $msg = $return[0]; + $params = []; + break; + default: + $msg = $return[0]; + $params = array_pop($return); + if(!is_array($params)) $params = [$params]; + } + if(isset($msg)) { + $sender->sendMessage(Localizer::translatable($msg, $params)); + } + } + } catch(ThrowableMessage $e) { + $sender->sendMessage(Localizer::translatable($e->getMessage(), $e->getParameters())); + } + $this->reset(); + return true; + } + + public function perform(CommandSender $sender, $label, array $args) { + return true; + } + + // SWAP + + private function swap() { + // TODO + } + + public function swappingEnabled(): bool { + return $this->swap; + } + + public function setSwapping(bool $value) { + $this->swap = $value; + } + + public function toggleSwapping() { + $this->swap = !$this->swap; + } + + // SMART + + public function isSmart(): bool { + return $this->smart; + } + + public function setSmart(bool $value) { + $this->smart = $value; + } + + public function toggleSmart() { + $this->smart = !$this->smart; + } + + public function reset() { + $this->sender = null; + $this->label = ""; + $this->args = []; + $this->values = []; + foreach ($this->parameters as $param) { + $param->unset(); + } + } + + public function getPlugin() { + return $this->plugin; + } + +} diff --git a/src/dominate/Link.php b/src/dominate/Link.php new file mode 100755 index 0000000..efe7cfd --- /dev/null +++ b/src/dominate/Link.php @@ -0,0 +1,58 @@ +. + */ + +namespace dominate; + +use pocketmine\command\CommandSender; + +/** + * Sometimes you want to make shortcuts for the commands eg. /f rank ChrisPrime promote => /f promote ChrisPrime + * + * @author ChrisPrime + */ +class Link extends Command { + + /** @var Command */ + protected $target; + + /** + * How passed arguments should pair with target command parameters + */ + protected $pairs; + + + public function __construct(Command $target, array $pairs) { + echo $target->getName().PHP_EOL; + return; + $this->target = $target; + $this->pairs = $pairs; + } + + public function getUsage(CommandSender $sender = null) { + $cmd = "/" . $this->target->getName(); + foreach($this->pairs as $local => $ext) { + $cmd .= " ".$this->getParameterAt($ext)->getTemplate($sender); + } + } + + public function execute(CommandSender $sender, $label, array $args) { + return true; + } + +} \ No newline at end of file diff --git a/src/dominate/Message.php b/src/dominate/ThrowableMessage.php old mode 100644 new mode 100755 similarity index 89% rename from src/dominate/Message.php rename to src/dominate/ThrowableMessage.php index 065cb4a..7b7eb37 --- a/src/dominate/Message.php +++ b/src/dominate/ThrowableMessage.php @@ -21,14 +21,15 @@ use localizer\Translatable; use localizer\Localizer; -class Message extends \Exception { +class ThrowableMessage extends \Exception { /** @var string|Translatable */ public $message; - /** - * @param string|Translatable - */ + /** + * @param string $message + * @internal param $ string|Translatable + */ public function __construct($message) { if(!$message instanceof Translatable) { if(($nm = Localizer::translatable($message))->getText() !== $message) { diff --git a/src/dominate/parameter/Parameter.php b/src/dominate/parameter/Parameter.php index 0a5ef03..80e09f9 100755 --- a/src/dominate/parameter/Parameter.php +++ b/src/dominate/parameter/Parameter.php @@ -18,6 +18,7 @@ */ namespace dominate\parameter; +use dominate\Command; use pocketmine\command\CommandSender; use pocketmine\Player; @@ -26,250 +27,283 @@ class Parameter { - const TYPE_STRING = 0x0; - const TYPE_INTEGER = 0x1; - const TYPE_NUMERIC = self::TYPE_INTEGER; - const TYPE_FLOAT = 0x2; - const TYPE_DOUBLE = self::TYPE_FLOAT; - const TYPE_REAL = self::TYPE_FLOAT; - const TYPE_BOOLEAN = 0x4; - const TYPE_BOOL = self::TYPE_BOOLEAN; - const TYPE_NULL = 0x5; - - /** @var string[] */ - public $ERROR_MESSAGES = [ - self::TYPE_STRING => "type-string", - self::TYPE_INTEGER => "type-integer", - self::TYPE_FLOAT => "type-float", - self::TYPE_BOOLEAN => "type-boolean", - self::TYPE_NULL => "type-null" - ]; - - const PRIMITIVE_TYPES = [ - self::TYPE_STRING, - self::TYPE_INTEGER, - self::TYPE_FLOAT, - self::TYPE_BOOLEAN, - self::TYPE_NULL, - ]; - - /** @var boolean */ - protected $hasDefault = false; - - /** @var string */ - protected $default; - protected $name; - - /** @var Command */ - protected $command; - - /** @var int */ - protected $type = self::TYPE_STRING; - protected $index = 0; - - /** @var mixed */ - protected $value; - - /** @var string */ - protected $permission; - - public function __construct(string $name, int $type = null, int $index = null) { - $this->type = $type ?? $this->type; - $this->name = $name; - $this->index = $index ?? $this->index; - - $this->setup(); - } - - /** - * Set error messages and other stuff. - */ - public function setup() {} - - public function setPermission(string $permission) : Parameter { - $this->permission = $permission; - return $this; - } - - public function getPermission() { - return $this->permission; - } - - public function testPermission(CommandSender $sender) { - return $sender->hasPermission($this->getPermission()); - } - - public function isPermissionSet() : bool { - return $this->permission !== null; - } - - public function getIndex() : int { - return $this->index; - } - - public function setIndex(int $i) { - $this->index = $i; - } - - public function setValue($value) { - $this->value = $value; - } - - public function getValue() { - return $this->value; - } - - public function isRequired(CommandSender $sender = null) : bool { - return !$this->isDefaultValueSet(); - } - - /** - * Set default value to null, if you want to set this parameter optional or handle default value yourself - * @param string|null $value - */ - public function setDefaultValue($value) : Parameter { - $this->default = $value; - $this->hasDefault = true; - return $this; - } - - public function isDefaultValueSet() : bool { - return $this->hasDefault; - } - - public function getDefaultValue() { - return $this->default; - } - - public function setCommand(Command $command) { - $this->command = $command; - } - - public function getName() { - return $this->name; - } - - public function getType() { - return $this->type; - } - - /** - * Will do checks only on primitive data types - * @return bool - */ - public static function validateInputType($input, int $type) : bool { - if(!isset(self::PRIMITIVE_TYPES[$type])) return false; + const TYPE_STRING = 0x0; + const TYPE_INTEGER = 0x1; + const TYPE_NUMERIC = self::TYPE_INTEGER; + const TYPE_FLOAT = 0x2; + const TYPE_DOUBLE = self::TYPE_FLOAT; + const TYPE_REAL = self::TYPE_FLOAT; + const TYPE_BOOLEAN = 0x4; + const TYPE_BOOL = self::TYPE_BOOLEAN; + const TYPE_NULL = 0x5; + + /** @var string[] */ + public $ERROR_MESSAGES = [ + self::TYPE_STRING => "type-string", + self::TYPE_INTEGER => "type-integer", + self::TYPE_FLOAT => "type-float", + self::TYPE_BOOLEAN => "type-boolean", + self::TYPE_NULL => "type-null" + ]; + + const PRIMITIVE_TYPES = [ + self::TYPE_STRING, + self::TYPE_INTEGER, + self::TYPE_FLOAT, + self::TYPE_BOOLEAN, + self::TYPE_NULL, + ]; + + /** @var boolean */ + protected $hasDefault = false; + + /** @var string */ + protected $default; + protected $name; + + /** @var Command */ + protected $command; + + /** @var int */ + protected $type = self::TYPE_STRING; + protected $index = 0; + + /** @var mixed */ + protected $value; + + /** @var string */ + protected $permission; + + /** + * If this parameter doesn't resolve into necessary value, then we will try this parameter + * @var Parameter + */ + protected $nextParameter; + + public function __construct(string $name, int $type = null, int $index = null) { + $this->type = $type ?? $this->type; + $this->name = $name; + $this->index = $index ?? $this->index; + + $this->setup(); + } + + public static function isSelfPointer($input): bool + { + return in_array($input, ["self", "me"], true); + } + + public function setNext(Parameter $param) : Parameter { + $this->nextParameter = $param; + return $this; + } + + /** + * @return Parameter|null + */ + public function getNextParameter() { + return $this->nextParameter; + } + + /** + * Set error messages and other stuff. + */ + public function setup() {} + + public function setPermission(string $permission) : Parameter { + $this->permission = $permission; + return $this; + } + + public function getPermission() { + return $this->permission; + } + + public function testPermission(CommandSender $sender) { + return $sender->hasPermission($this->getPermission()); + } + + public function isPermissionSet() : bool { + return $this->permission !== null; + } + + public function getIndex() : int { + return $this->index; + } + + public function setIndex(int $i) { + $this->index = $i; + } + + public function setValue($value) { + $this->value = $value; + } + + public function getValue() { + return $this->value; + } + + public function isRequired(CommandSender $sender = null) : bool { + return !$this->isDefaultValueSet(); + } + + /** + * Set default value to null, if you want to set this parameter optional or handle default value yourself + * @param string|null $value + */ + public function setDefaultValue($value) : Parameter { + $this->default = $value; + $this->hasDefault = true; + return $this; + } + + public function isDefaultValueSet() : bool { + return $this->hasDefault; + } + + public function getDefaultValue() { + return $this->default; + } + + public function setCommand(Command $command) { + $this->command = $command; + } + + public function getName() { + return $this->name; + } + + public function getType() { + return $this->type; + } + + /** + * Will do checks only on primitive data types + * @return bool + */ + public static function validateInputType($input, int $type) : bool { + if(!isset(self::PRIMITIVE_TYPES[$type])) return false; switch ($type) { - case self::TYPE_STRING: - return is_string($input); - case self::TYPE_BOOLEAN: - switch(strtolower($input)) { - case '1': - case 'true': - case 'yes': - case 'y': - case true: - - case '0': - case 'false': - case 'no': - case 'n': - case false: - return true; - default: - return false; - } - return false; - case self::TYPE_DOUBLE: - case self::TYPE_FLOAT: - if(strpos($input, ".") === false) return false; - return is_numeric($input); - case self::TYPE_INTEGER: - return is_numeric($input); - } + case self::TYPE_STRING: + return is_string($input); + case self::TYPE_BOOLEAN: + switch(strtolower($input)) { + case '1': + case 'true': + case 'yes': + case 'y': + case true: + + case '0': + case 'false': + case 'no': + case 'n': + case false: + return true; + default: + return false; + } + return false; + case self::TYPE_DOUBLE: + case self::TYPE_FLOAT: + if(strpos($input, ".") === false) return false; + return is_numeric($input); + case self::TYPE_INTEGER: + return is_numeric($input); + } return false; } - public function getTemplate(CommandSender $sender = null) { - $out = $this->getName(); - if($this->isDefaultValueSet() and $this->getDefaultValue() !== null) { - $out .= "=".$this->getDefaultValue(); - } - if($this->isRequired($sender)) - $out = "<".$out.">"; - else - $out = "[".$out."]"; - return $out; + public function getTemplate(CommandSender $sender = null) { + $out = $this->getName(); + if($this->isDefaultValueSet() and $this->getDefaultValue() !== null) { + $out .= "=".$this->getDefaultValue(); + } + if($this->isRequired($sender)) + $out = "<".$out.">"; + else + $out = "[".$out."]"; + return $out; + } + + public function createErrorMessage(CommandSender $sender, string $value) : Translatable { + $error = $this->ERROR_MESSAGES; + if(is_array($error)) { + $error = $this->ERROR_MESSAGES[$this->type] ?? "generic-error"; + } + return Localizer::translatable("".$error, [ + "sender" => ($sender instanceof Player ? $sender->getDisplayName() : $sender->getName()), + "value" => $value, + "n" => $this->getIndex() + 1 + ]); + } + + public function isPrimitive() : bool { + return isset(self::PRIMITIVE_TYPES[$this->type]); } - public function createErrorMessage(CommandSender $sender, string $value) : Translatable { - $error = $this->ERROR_MESSAGES; - if(is_array($error)) { - $error = $this->ERROR_MESSAGES[$this->type] ?? "generic-error"; - } - return Localizer::translatable("".$error, [ - "sender" => ($sender instanceof Player ? $sender->getDisplayName() : $sender->getName()), - "value" => $value, - "n" => $this->getIndex() + 1 - ]); - } - - public function isPrimitive() : bool { - return isset(self::PRIMITIVE_TYPES[$this->type]); - } - - /* - * ---------------------------------------------------------- - * ABSTRACT - * ---------------------------------------------------------- - */ - - /** - * @param string $input - * @return mixed - */ - public function read(string $input, CommandSender $sender = null) { - switch ($this->type) { - case self::TYPE_STRING: - return (string) $input; - case self::TYPE_INTEGER: - return (integer) $input; - case self::TYPE_FLOAT: - return (float) $input; - case self::TYPE_BOOLEAN: - switch ($input) { - case '1': - case 'true': - case 'yes': - case 'y': - return true; - case '0': - case 'false': - case 'no': - case 'n': - return false; - default: - return null; - } - default: - return null; - } - } - - public function isValid($input, CommandSender $sender = null) : bool { - return self::validateInputType($input, $this->type); - } - - public function isset($ignoreDefault = false) { - if($ignoreDefault) { - return $this->value === null; - } else { - return $this->value === $this->defaultValue; - } - } - - public function unset() { - $this->value = null; - } + /* + * ---------------------------------------------------------- + * ABSTRACT + * ---------------------------------------------------------- + */ + + /** + * @param string $input + * @param CommandSender $sender + * @return mixed + */ + public function read(string $input, CommandSender $sender = null) { + switch ($this->type) { + case self::TYPE_STRING: + return (string) $input; + case self::TYPE_INTEGER: + return (integer) $input; + case self::TYPE_FLOAT: + return (float) $input; + case self::TYPE_BOOLEAN: + switch ($input) { + case '1': + case 'true': + case 'yes': + case 'y': + return true; + case '0': + case 'false': + case 'no': + case 'n': + return false; + default: + return null; + } + default: + return null; + } + } + + /** + * @param $input + * @param CommandSender|null $sender + * @return bool + */ + public function isValid($input, CommandSender $sender = null) : bool { + return self::validateInputType($input, $this->type); + } + + public function hasDefault() : bool { + return $this->isDefaultValueSet(); + } + + public function isset($ignoreDefault = false) { + if($ignoreDefault && $this->hasDefault()) { + return $this->value !== null; + } else { + return $this->value !== $this->default; + } + } + + public function unset() { + $this->value = null; + } } \ No newline at end of file