diff --git a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php index 5a32a277c..ba3fa2abf 100644 --- a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php +++ b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php @@ -28,6 +28,7 @@ namespace pocketmine\network\mcpe\protocol; use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\protocol\types\CommandData; use pocketmine\network\mcpe\protocol\types\CommandEnum; +use pocketmine\network\mcpe\protocol\types\CommandEnumConstraint; use pocketmine\network\mcpe\protocol\types\CommandParameter; use pocketmine\utils\BinaryDataException; use function count; @@ -92,6 +93,12 @@ class AvailableCommandsPacket extends DataPacket{ */ public $softEnums = []; + /** + * @var CommandEnumConstraint[] + * List of constraints for enum members. Used to constrain gamerules that can bechanged in nocheats mode and more. + */ + public $enumConstraints = []; + protected function decodePayload(){ /** @var string[] $enumValues */ $enumValues = []; @@ -118,6 +125,10 @@ class AvailableCommandsPacket extends DataPacket{ for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ $this->softEnums[] = $this->getSoftEnum(); } + + for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ + $this->enumConstraints[] = $this->getEnumConstraint($enums, $enumValues); + } } /** @@ -210,6 +221,50 @@ class AvailableCommandsPacket extends DataPacket{ } } + /** + * @param CommandEnum[] $enums + * @param string[] $enumValues + * + * @return CommandEnumConstraint + */ + protected function getEnumConstraint(array $enums, array $enumValues) : CommandEnumConstraint{ + //wtf, what was wrong with an offset inside the enum? :( + $valueIndex = $this->getLInt(); + if(!isset($enumValues[$valueIndex])){ + throw new \UnexpectedValueException("Enum constraint refers to unknown enum value index $valueIndex"); + } + $enumIndex = $this->getLInt(); + if(!isset($enums[$enumIndex])){ + throw new \UnexpectedValueException("Enum constraint refers to unknown enum index $enumIndex"); + } + $enum = $enums[$enumIndex]; + $valueOffset = array_search($enumValues[$valueIndex], $enum->enumValues, true); + if($valueOffset === false){ + throw new \UnexpectedValueException("Value \"" . $enumValues[$valueIndex] . "\" does not belong to enum \"$enum->enumName\""); + } + + $constraintIds = []; + for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ + $constraintIds[] = $this->getByte(); + } + + return new CommandEnumConstraint($enum, $valueOffset, $constraintIds); + } + + /** + * @param CommandEnumConstraint $value + * @param int[] $enumIndexes string enum name -> int index + * @param int[] $enumValueIndexes string value -> int index + */ + protected function putEnumConstraint(CommandEnumConstraint $constraint, array $enumIndexes, array $enumValueIndexes) : void{ + $this->putLInt($enumValueIndexes[$constraint->getAffectedValue()]); + $this->putLInt($enumIndexes[$constraint->getEnum()->enumName]); + $this->putUnsignedVarInt(count($constraint->getConstraints())); + foreach($constraint->getConstraints() as $v){ + $this->putByte($v); + } + } + /** * @param CommandEnum[] $enums * @param string[] $postfixes @@ -407,7 +462,10 @@ class AvailableCommandsPacket extends DataPacket{ $this->putSoftEnum($enum); } - $this->putUnsignedVarInt(0); //TODO + $this->putUnsignedVarInt(count($this->enumConstraints)); + foreach($this->enumConstraints as $constraint){ + $this->putEnumConstraint($constraint, $enumIndexes, $enumValueIndexes); + } } public function handle(NetworkSession $session) : bool{ diff --git a/src/pocketmine/network/mcpe/protocol/types/CommandEnumConstraint.php b/src/pocketmine/network/mcpe/protocol/types/CommandEnumConstraint.php new file mode 100644 index 000000000..a97bb9cda --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/types/CommandEnumConstraint.php @@ -0,0 +1,67 @@ +enumValues[$valueOffset])){ + throw new \InvalidArgumentException("Invalid enum value offset $valueOffset"); + } + $this->enum = $enum; + $this->valueOffset = $valueOffset; + $this->constraints = $constraints; + } + + public function getEnum() : CommandEnum{ + return $this->enum; + } + + public function getValueOffset() : int{ + return $this->valueOffset; + } + + public function getAffectedValue() : string{ + return $this->enum->enumValues[$this->valueOffset]; + } + + /** + * @return int[] + */ + public function getConstraints() : array{ + return $this->constraints; + } +} diff --git a/src/pocketmine/network/mcpe/protocol/types/CommandParameter.php b/src/pocketmine/network/mcpe/protocol/types/CommandParameter.php index b1a00137b..a2f1a26ed 100644 --- a/src/pocketmine/network/mcpe/protocol/types/CommandParameter.php +++ b/src/pocketmine/network/mcpe/protocol/types/CommandParameter.php @@ -24,6 +24,9 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\protocol\types; class CommandParameter{ + public const FLAG_FORCE_COLLAPSE_ENUM = 0x1; + public const FLAG_HAS_ENUM_CONSTRAINT = 0x2; + /** @var string */ public $paramName; /** @var int */