mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-12 16:59:44 +00:00
AvailableCommandsPacket: encode & decode for enum value constraints
This is a peculiarly overengineered system that is used for restricting access to enum members under certain conditions, e.g. to disallow changing specific gamerules in survival.
This commit is contained in:
parent
6f08853b29
commit
363556e9b6
@ -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{
|
||||
|
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\protocol\types;
|
||||
|
||||
class CommandEnumConstraint{
|
||||
/** @var CommandEnum */
|
||||
private $enum;
|
||||
/** @var int */
|
||||
private $valueOffset;
|
||||
/** @var int[] */
|
||||
private $constraints; //TODO: find constants
|
||||
|
||||
/**
|
||||
* @param CommandEnum $enum
|
||||
* @param int $valueOffset
|
||||
* @param int[] $constraints
|
||||
*/
|
||||
public function __construct(CommandEnum $enum, int $valueOffset, array $constraints){
|
||||
(static function(int ...$_){})(...$constraints);
|
||||
if(!isset($enum->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;
|
||||
}
|
||||
}
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user