diff --git a/src/pocketmine/network/mcpe/NetworkSession.php b/src/pocketmine/network/mcpe/NetworkSession.php index 818eb8a7c..391944094 100644 --- a/src/pocketmine/network/mcpe/NetworkSession.php +++ b/src/pocketmine/network/mcpe/NetworkSession.php @@ -668,30 +668,28 @@ class NetworkSession{ continue; } - $data = new CommandData(); - //TODO: commands containing uppercase letters in the name crash 1.9.0 client - $data->commandName = strtolower($command->getName()); - $data->commandDescription = $this->server->getLanguage()->translateString($command->getDescription()); - $data->flags = 0; - $data->permission = 0; - - $parameter = new CommandParameter(); - $parameter->paramName = "args"; - $parameter->paramType = AvailableCommandsPacket::ARG_FLAG_VALID | AvailableCommandsPacket::ARG_TYPE_RAWTEXT; - $parameter->isOptional = true; - $data->overloads[0][0] = $parameter; - + $lname = strtolower($command->getName()); $aliases = $command->getAliases(); + $aliasObj = null; if(!empty($aliases)){ - if(!in_array($data->commandName, $aliases, true)){ + if(!in_array($lname, $aliases, true)){ //work around a client bug which makes the original name not show when aliases are used - $aliases[] = $data->commandName; + $aliases[] = $lname; } - $data->aliases = new CommandEnum(); - $data->aliases->enumName = ucfirst($command->getName()) . "Aliases"; - $data->aliases->enumValues = $aliases; + $aliasObj = new CommandEnum(ucfirst($command->getName()) . "Aliases", $aliases); } + $data = new CommandData( + $lname, //TODO: commands containing uppercase letters in the name crash 1.9.0 client + $this->server->getLanguage()->translateString($command->getDescription()), + 0, + 0, + $aliasObj, + [ + [CommandParameter::standard("args", AvailableCommandsPacket::ARG_TYPE_RAWTEXT, true)] + ] + ); + $pk->commandData[$command->getName()] = $data; } diff --git a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php index 587541f11..13f087fee 100644 --- a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php +++ b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php @@ -129,8 +129,8 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{ * @throws BinaryDataException */ protected function getEnum(array $enumValueList) : CommandEnum{ - $retval = new CommandEnum(); - $retval->enumName = $this->getString(); + $enumName = $this->getString(); + $enumValues = []; $listSize = count($enumValueList); @@ -140,10 +140,10 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{ throw new BadPacketException("Invalid enum value index $index"); } //Get the enum value from the initial pile of mess - $retval->enumValues[] = $enumValueList[$index]; + $enumValues[] = $enumValueList[$index]; } - return $retval; + return new CommandEnum($enumName, $enumValues); } /** @@ -151,15 +151,15 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{ * @throws BinaryDataException */ protected function getSoftEnum() : CommandEnum{ - $retval = new CommandEnum(); - $retval->enumName = $this->getString(); + $enumName = $this->getString(); + $enumValues = []; for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ //Get the enum value from the initial pile of mess - $retval->enumValues[] = $this->getString(); + $enumValues[] = $this->getString(); } - return $retval; + return new CommandEnum($enumName, $enumValues); } /** @@ -167,11 +167,12 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{ * @param string[] $enumValueMap */ protected function putEnum(CommandEnum $enum, array $enumValueMap) : void{ - $this->putString($enum->enumName); + $this->putString($enum->getName()); - $this->putUnsignedVarInt(count($enum->enumValues)); + $values = $enum->getValues(); + $this->putUnsignedVarInt(count($values)); $listSize = count($enumValueMap); - foreach($enum->enumValues as $value){ + foreach($values as $value){ $index = $enumValueMap[$value] ?? -1; if($index === -1){ throw new \InvalidStateException("Enum value '$value' not found"); @@ -181,10 +182,11 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{ } protected function putSoftEnum(CommandEnum $enum) : void{ - $this->putString($enum->enumName); + $this->putString($enum->getName()); - $this->putUnsignedVarInt(count($enum->enumValues)); - foreach($enum->enumValues as $value){ + $values = $enum->getValues(); + $this->putUnsignedVarInt(count($values)); + foreach($values as $value){ $this->putString($value); } } @@ -224,12 +226,12 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{ * @throws BinaryDataException */ protected function getCommandData(array $enums, array $postfixes) : CommandData{ - $retval = new CommandData(); - $retval->commandName = $this->getString(); - $retval->commandDescription = $this->getString(); - $retval->flags = $this->getByte(); - $retval->permission = $this->getByte(); - $retval->aliases = $enums[$this->getLInt()] ?? null; + $name = $this->getString(); + $description = $this->getString(); + $flags = $this->getByte(); + $permission = $this->getByte(); + $aliases = $enums[$this->getLInt()] ?? null; + $overloads = []; for($overloadIndex = 0, $overloadCount = $this->getUnsignedVarInt(); $overloadIndex < $overloadCount; ++$overloadIndex){ for($paramIndex = 0, $paramCount = $this->getUnsignedVarInt(); $paramIndex < $paramCount; ++$paramIndex){ @@ -243,23 +245,23 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{ $index = ($parameter->paramType & 0xffff); $parameter->enum = $enums[$index] ?? null; if($parameter->enum === null){ - throw new BadPacketException("deserializing $retval->commandName parameter $parameter->paramName: expected enum at $index, but got none"); + throw new BadPacketException("deserializing $name parameter $parameter->paramName: expected enum at $index, but got none"); } }elseif($parameter->paramType & self::ARG_FLAG_POSTFIX){ $index = ($parameter->paramType & 0xffff); $parameter->postfix = $postfixes[$index] ?? null; if($parameter->postfix === null){ - throw new BadPacketException("deserializing $retval->commandName parameter $parameter->paramName: expected postfix at $index, but got none"); + throw new BadPacketException("deserializing $name parameter $parameter->paramName: expected postfix at $index, but got none"); } }elseif(($parameter->paramType & self::ARG_FLAG_VALID) === 0){ - throw new BadPacketException("deserializing $retval->commandName parameter $parameter->paramName: Invalid parameter type 0x" . dechex($parameter->paramType)); + throw new BadPacketException("deserializing $name parameter $parameter->paramName: Invalid parameter type 0x" . dechex($parameter->paramType)); } - $retval->overloads[$overloadIndex][$paramIndex] = $parameter; + $overloads[$overloadIndex][$paramIndex] = $parameter; } } - return $retval; + return new CommandData($name, $description, $flags, $permission, $aliases, $overloads); } /** @@ -268,13 +270,13 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{ * @param int[] $postfixIndexes */ protected function putCommandData(CommandData $data, array $enumIndexes, array $postfixIndexes) : void{ - $this->putString($data->commandName); - $this->putString($data->commandDescription); + $this->putString($data->name); + $this->putString($data->description); $this->putByte($data->flags); $this->putByte($data->permission); if($data->aliases !== null){ - $this->putLInt($enumIndexes[$data->aliases->enumName] ?? -1); + $this->putLInt($enumIndexes[$data->aliases->getName()] ?? -1); }else{ $this->putLInt(-1); } @@ -287,7 +289,7 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{ $this->putString($parameter->paramName); if($parameter->enum !== null){ - $type = self::ARG_FLAG_ENUM | self::ARG_FLAG_VALID | ($enumIndexes[$parameter->enum->enumName] ?? -1); + $type = self::ARG_FLAG_ENUM | self::ARG_FLAG_VALID | ($enumIndexes[$parameter->enum->getName()] ?? -1); }elseif($parameter->postfix !== null){ $key = $postfixIndexes[$parameter->postfix] ?? -1; if($key === -1){ @@ -353,15 +355,18 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{ $enumIndexes = []; /** @var CommandEnum[] $enums */ $enums = []; + + $addEnumFn = static function(CommandEnum $enum) use(&$enums, &$enumIndexes, &$enumValueIndexes){ + if(!isset($enumIndexes[$enum->getName()])){ + $enums[$enumIndexes[$enum->getName()] = count($enumIndexes)] = $enum; + } + foreach($enum->getValues() as $str){ + $enumValueIndexes[$str] = $enumValueIndexes[$str] ?? count($enumValueIndexes); //latest index + } + }; foreach($this->commandData as $commandData){ if($commandData->aliases !== null){ - if(!isset($enumIndexes[$commandData->aliases->enumName])){ - $enums[$enumIndexes[$commandData->aliases->enumName] = count($enumIndexes)] = $commandData->aliases; - } - - foreach($commandData->aliases->enumValues as $str){ - $enumValueIndexes[$str] = $enumValueIndexes[$str] ?? count($enumValueIndexes); //latest index - } + $addEnumFn($commandData->aliases); } foreach($commandData->overloads as $overload){ @@ -371,12 +376,7 @@ class AvailableCommandsPacket extends DataPacket implements ClientboundPacket{ */ foreach($overload as $parameter){ if($parameter->enum !== null){ - if(!isset($enumIndexes[$parameter->enum->enumName])){ - $enums[$enumIndexes[$parameter->enum->enumName] = count($enumIndexes)] = $parameter->enum; - } - foreach($parameter->enum->enumValues as $str){ - $enumValueIndexes[$str] = $enumValueIndexes[$str] ?? count($enumValueIndexes); - } + $addEnumFn($parameter->enum); } if($parameter->postfix !== null){ diff --git a/src/pocketmine/network/mcpe/protocol/types/CommandData.php b/src/pocketmine/network/mcpe/protocol/types/CommandData.php index cf98b90fc..95bab2253 100644 --- a/src/pocketmine/network/mcpe/protocol/types/CommandData.php +++ b/src/pocketmine/network/mcpe/protocol/types/CommandData.php @@ -25,9 +25,9 @@ namespace pocketmine\network\mcpe\protocol\types; class CommandData{ /** @var string */ - public $commandName; + public $name; /** @var string */ - public $commandDescription; + public $description; /** @var int */ public $flags; /** @var int */ @@ -37,4 +37,67 @@ class CommandData{ /** @var CommandParameter[][] */ public $overloads = []; + /** + * @param string $name + * @param string $description + * @param int $flags + * @param int $permission + * @param CommandEnum|null $aliases + * @param CommandParameter[][] $overloads + */ + public function __construct(string $name, string $description, int $flags, int $permission, ?CommandEnum $aliases, array $overloads){ + (function(array ...$overloads){ + foreach($overloads as $overload){ + (function(CommandParameter ...$parameters){})(...$overload); + } + })(...$overloads); + $this->name = $name; + $this->description = $description; + $this->flags = $flags; + $this->permission = $permission; + $this->aliases = $aliases; + $this->overloads = $overloads; + } + + /** + * @return string + */ + public function getName() : string{ + return $this->name; + } + + /** + * @return string + */ + public function getDescription() : string{ + return $this->description; + } + + /** + * @return int + */ + public function getFlags() : int{ + return $this->flags; + } + + /** + * @return int + */ + public function getPermission() : int{ + return $this->permission; + } + + /** + * @return CommandEnum|null + */ + public function getAliases() : ?CommandEnum{ + return $this->aliases; + } + + /** + * @return CommandParameter[][] + */ + public function getOverloads() : array{ + return $this->overloads; + } } diff --git a/src/pocketmine/network/mcpe/protocol/types/CommandEnum.php b/src/pocketmine/network/mcpe/protocol/types/CommandEnum.php index e6621c7a4..02597e90e 100644 --- a/src/pocketmine/network/mcpe/protocol/types/CommandEnum.php +++ b/src/pocketmine/network/mcpe/protocol/types/CommandEnum.php @@ -25,8 +25,30 @@ namespace pocketmine\network\mcpe\protocol\types; class CommandEnum{ /** @var string */ - public $enumName; + private $enumName; /** @var string[] */ - public $enumValues = []; + private $enumValues = []; + /** + * @param string $enumName + * @param string[] $enumValues + */ + public function __construct(string $enumName, array $enumValues){ + $this->enumName = $enumName; + $this->enumValues = $enumValues; + } + + /** + * @return string + */ + public function getName() : string{ + return $this->enumName; + } + + /** + * @return string[] + */ + public function getValues() : array{ + return $this->enumValues; + } } diff --git a/src/pocketmine/network/mcpe/protocol/types/CommandParameter.php b/src/pocketmine/network/mcpe/protocol/types/CommandParameter.php index 2c26ac9bf..d19c7b9a8 100644 --- a/src/pocketmine/network/mcpe/protocol/types/CommandParameter.php +++ b/src/pocketmine/network/mcpe/protocol/types/CommandParameter.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\protocol\types; +use pocketmine\network\mcpe\protocol\AvailableCommandsPacket; + class CommandParameter{ /** @var string */ public $paramName; @@ -36,4 +38,29 @@ class CommandParameter{ public $enum; /** @var string|null */ public $postfix; + + private static function baseline(string $name, int $type, bool $optional) : self{ + $result = new self; + $result->paramName = $name; + $result->paramType = $type; + $result->isOptional = $optional; + return $result; + } + + public static function standard(string $name, int $type, bool $optional = false) : self{ + return self::baseline($name, AvailableCommandsPacket::ARG_FLAG_VALID | $type, $optional); + } + + public static function postfixed(string $name, string $postfix, bool $optional = false) : self{ + $result = self::baseline($name, AvailableCommandsPacket::ARG_FLAG_POSTFIX, $optional); + $result->postfix = $postfix; + return $result; + } + + public static function enum(string $name, CommandEnum $enum, int $flags, bool $optional = false) : self{ + $result = self::baseline($name, AvailableCommandsPacket::ARG_FLAG_ENUM | AvailableCommandsPacket::ARG_FLAG_VALID, $optional); + $result->enum = $enum; + $result->byte1 = $flags; + return $result; + } }