139 for($i = 0, $enumValuesCount = VarInt::readUnsignedInt($in); $i < $enumValuesCount; ++$i){
140 $enumValues[] = CommonTypes::getString($in);
144 $chainedSubcommandValueNames = [];
145 for($i = 0, $count = VarInt::readUnsignedInt($in); $i < $count; ++$i){
146 $chainedSubcommandValueNames[] = CommonTypes::getString($in);
151 for($i = 0, $count = VarInt::readUnsignedInt($in); $i < $count; ++$i){
152 $postfixes[] = CommonTypes::getString($in);
157 for($i = 0, $count = VarInt::readUnsignedInt($in); $i < $count; ++$i){
158 $enums[] = $enum = $this->getEnum($enumValues, $in);
164 if(isset(self::HARDCODED_ENUM_NAMES[$enum->getName()])){
165 $this->hardcodedEnums[] = $enum;
169 $chainedSubCommandData = [];
170 for($i = 0, $count = VarInt::readUnsignedInt($in); $i < $count; ++$i){
171 $name = CommonTypes::getString($in);
173 for($j = 0, $valueCount = VarInt::readUnsignedInt($in); $j < $valueCount; ++$j){
174 $valueName = $chainedSubcommandValueNames[LE::readUnsignedShort($in)];
175 $valueType = LE::readUnsignedShort($in);
176 $values[] =
new ChainedSubCommandValue($valueName, $valueType);
178 $chainedSubCommandData[] =
new ChainedSubCommandData($name, $values);
181 for($i = 0, $count = VarInt::readUnsignedInt($in); $i < $count; ++$i){
182 $this->commandData[] = $this->getCommandData($enums, $postfixes, $chainedSubCommandData, $in);
185 for($i = 0, $count = VarInt::readUnsignedInt($in); $i < $count; ++$i){
186 $this->softEnums[] = $this->getSoftEnum($in);
189 $this->initSoftEnumsInCommandData();
191 for($i = 0, $count = VarInt::readUnsignedInt($in); $i < $count; ++$i){
192 $this->enumConstraints[] = $this->getEnumConstraint($enums, $enumValues, $in);
314 $valueIndex = LE::readUnsignedInt($in);
315 if(!isset($enumValues[$valueIndex])){
318 $enumIndex = LE::readUnsignedInt($in);
319 if(!isset($enums[$enumIndex])){
322 $enum = $enums[$enumIndex];
323 $valueOffset = array_search($enumValues[$valueIndex], $enum->getValues(),
true);
324 if($valueOffset ===
false){
325 throw new PacketDecodeException(
"Value \"" . $enumValues[$valueIndex] .
"\" does not belong to enum \"" . $enum->getName() .
"\"");
329 for($i = 0, $count = VarInt::readUnsignedInt($in); $i < $count; ++$i){
330 $constraintIds[] = Byte::readUnsigned($in);
333 return new CommandEnumConstraint($enum, $valueOffset, $constraintIds);
359 $description = CommonTypes::getString($in);
360 $flags = LE::readUnsignedShort($in);
361 $permission = Byte::readUnsigned($in);
362 $aliases = $enums[LE::readSignedInt($in)] ??
null;
364 $chainedSubCommandData = [];
365 for($i = 0, $count = VarInt::readUnsignedInt($in); $i < $count; ++$i){
366 $index = LE::readUnsignedShort($in);
367 $chainedSubCommandData[] = $allChainedSubCommandData[$index] ??
throw new PacketDecodeException(
"Unknown chained subcommand data index $index");
371 for($overloadIndex = 0, $overloadCount = VarInt::readUnsignedInt($in); $overloadIndex < $overloadCount; ++$overloadIndex){
373 $isChaining = CommonTypes::getBool($in);
374 for($paramIndex = 0, $paramCount = VarInt::readUnsignedInt($in); $paramIndex < $paramCount; ++$paramIndex){
376 $parameter->paramName = CommonTypes::getString($in);
377 $parameter->paramType = LE::readUnsignedInt($in);
378 $parameter->isOptional = CommonTypes::getBool($in);
379 $parameter->flags = Byte::readUnsigned($in);
381 if(($parameter->paramType & self::ARG_FLAG_ENUM) !== 0){
382 $index = ($parameter->paramType & 0xffff);
383 $parameter->enum = $enums[$index] ??
null;
384 if($parameter->enum ===
null){
385 throw new PacketDecodeException(
"deserializing $name parameter $parameter->paramName: expected enum at $index, but got none");
387 }elseif(($parameter->paramType & self::ARG_FLAG_POSTFIX) !== 0){
388 $index = ($parameter->paramType & 0xffff);
389 $parameter->postfix = $postfixes[$index] ??
null;
390 if($parameter->postfix ===
null){
391 throw new PacketDecodeException(
"deserializing $name parameter $parameter->paramName: expected postfix at $index, but got none");
393 }elseif(($parameter->paramType & self::ARG_FLAG_VALID) === 0){
394 throw new PacketDecodeException(
"deserializing $name parameter $parameter->paramName: Invalid parameter type 0x" . dechex($parameter->paramType));
397 $parameters[$paramIndex] = $parameter;
399 $overloads[$overloadIndex] =
new CommandOverload($isChaining, $parameters);
402 return new CommandData($name, $description, $flags, $permission, $aliases, $overloads, $chainedSubCommandData);
411 protected function putCommandData(
CommandData $data, array $enumIndexes, array $softEnumIndexes, array $postfixIndexes, array $chainedSubCommandDataIndexes, ByteBufferWriter $out) : void{
413 CommonTypes::putString($out, $data->description);
414 LE::writeUnsignedShort($out, $data->flags);
415 Byte::writeUnsigned($out, $data->permission);
417 if($data->aliases !==
null){
418 LE::writeSignedInt($out, $enumIndexes[$data->aliases->getName()] ?? -1);
420 LE::writeSignedInt($out, -1);
423 VarInt::writeUnsignedInt($out, count($data->chainedSubCommandData));
424 foreach($data->chainedSubCommandData as $chainedSubCommandData){
425 $index = $chainedSubCommandDataIndexes[$chainedSubCommandData->getName()] ??
426 throw new \LogicException(
"Chained subcommand data {$chainedSubCommandData->getName()} does not have an index (this should be impossible)");
427 LE::writeUnsignedShort($out, $index);
430 VarInt::writeUnsignedInt($out, count($data->overloads));
431 foreach($data->overloads as $overload){
432 CommonTypes::putBool($out, $overload->isChaining());
433 VarInt::writeUnsignedInt($out, count($overload->getParameters()));
434 foreach($overload->getParameters() as $parameter){
435 CommonTypes::putString($out, $parameter->paramName);
437 if($parameter->enum !==
null){
438 if($parameter->enum->isSoft()){
439 $type = self::ARG_FLAG_SOFT_ENUM | self::ARG_FLAG_VALID | ($softEnumIndexes[$parameter->enum->getName()] ?? -1);
441 $type = self::ARG_FLAG_ENUM | self::ARG_FLAG_VALID | ($enumIndexes[$parameter->enum->getName()] ?? -1);
443 }elseif($parameter->postfix !==
null){
444 if(!isset($postfixIndexes[$parameter->postfix])){
445 throw new \LogicException(
"Postfix '$parameter->postfix' not in postfixes array");
447 $type = self::ARG_FLAG_POSTFIX | $postfixIndexes[$parameter->postfix];
449 $type = $parameter->paramType;
452 LE::writeUnsignedInt($out, $type);
453 CommonTypes::putBool($out, $parameter->isOptional);
454 Byte::writeUnsigned($out, $parameter->flags);
464 $enumValueIndexes = [];
469 $postfixIndexes = [];
491 $softEnumIndexes = [];
497 $allChainedSubCommandData = [];
502 $chainedSubCommandDataIndexes = [];
508 $chainedSubCommandValueNameIndexes = [];
510 $addEnumFn =
static function(
CommandEnum $enum) use (
511 &$enums, &$softEnums, &$enumIndexes, &$softEnumIndexes, &$enumValueIndexes
513 $enumName = $enum->getName();
516 if(!isset($softEnumIndexes[$enumName])){
517 $softEnums[$softEnumIndexes[$enumName] = count($softEnumIndexes)] = $enum;
520 foreach($enum->getValues() as $str){
521 $enumValueIndexes[$str] = $enumValueIndexes[$str] ?? count($enumValueIndexes);
523 if(!isset($enumIndexes[$enumName])){
524 $enums[$enumIndexes[$enumName] = count($enumIndexes)] = $enum;
528 foreach($this->hardcodedEnums as $enum){
531 foreach($this->softEnums as $enum){
534 foreach($this->commandData as $commandData){
535 if($commandData->aliases !==
null){
536 $addEnumFn($commandData->aliases);
538 foreach($commandData->overloads as $overload){
539 foreach($overload->getParameters() as $parameter){
540 if($parameter->enum !==
null){
541 $addEnumFn($parameter->enum);
544 if($parameter->postfix !==
null){
545 $postfixIndexes[$parameter->postfix] = $postfixIndexes[$parameter->postfix] ?? count($postfixIndexes);
549 foreach($commandData->chainedSubCommandData as $chainedSubCommandData){
550 if(!isset($allChainedSubCommandData[$chainedSubCommandData->getName()])){
551 $allChainedSubCommandData[$chainedSubCommandData->getName()] = $chainedSubCommandData;
552 $chainedSubCommandDataIndexes[$chainedSubCommandData->getName()] = count($chainedSubCommandDataIndexes);
554 foreach($chainedSubCommandData->getValues() as $value){
555 $chainedSubCommandValueNameIndexes[$value->getName()] ??= count($chainedSubCommandValueNameIndexes);
561 VarInt::writeUnsignedInt($out, count($enumValueIndexes));
562 foreach($enumValueIndexes as $enumValue => $index){
563 CommonTypes::putString($out, (
string) $enumValue);
566 VarInt::writeUnsignedInt($out, count($chainedSubCommandValueNameIndexes));
567 foreach($chainedSubCommandValueNameIndexes as $chainedSubCommandValueName => $index){
568 CommonTypes::putString($out, (
string) $chainedSubCommandValueName);
571 VarInt::writeUnsignedInt($out, count($postfixIndexes));
572 foreach($postfixIndexes as $postfix => $index){
573 CommonTypes::putString($out, (
string) $postfix);
576 VarInt::writeUnsignedInt($out, count($enums));
577 foreach($enums as $enum){
578 $this->putEnum($enum, $enumValueIndexes, $out);
581 VarInt::writeUnsignedInt($out, count($allChainedSubCommandData));
582 foreach($allChainedSubCommandData as $chainedSubCommandData){
583 CommonTypes::putString($out, $chainedSubCommandData->getName());
584 VarInt::writeUnsignedInt($out, count($chainedSubCommandData->getValues()));
585 foreach($chainedSubCommandData->getValues() as $value){
586 $valueNameIndex = $chainedSubCommandValueNameIndexes[$value->getName()] ??
587 throw new \LogicException(
"Chained subcommand value name index for \"" . $value->getName() .
"\" not found (this should never happen)");
588 LE::writeUnsignedShort($out, $valueNameIndex);
589 LE::writeUnsignedShort($out, $value->getType());
593 VarInt::writeUnsignedInt($out, count($this->commandData));
594 foreach($this->commandData as $data){
595 $this->putCommandData($data, $enumIndexes, $softEnumIndexes, $postfixIndexes, $chainedSubCommandDataIndexes, $out);
598 VarInt::writeUnsignedInt($out, count($softEnums));
599 foreach($softEnums as $enum){
600 $this->putSoftEnum($enum, $out);
603 VarInt::writeUnsignedInt($out, count($this->enumConstraints));
604 foreach($this->enumConstraints as $constraint){
605 $this->putEnumConstraint($constraint, $enumIndexes, $enumValueIndexes, $out);