45final class CompoundTag extends Tag implements \Countable, \IteratorAggregate{
 
   46    use NoDynamicFieldsTrait;
 
   51    public function __construct(){
 
   52        self::restrictArgCount(__METHOD__, func_num_args(), 0);
 
   58    public static function create() : self{
 
 
   62    public function count() : int{
 
   63        return count($this->value);
 
   70        return count($this->value);
 
 
   88        return $this->value[$name] ?? null;
 
 
  102        $tag = $this->getTag($name);
 
  107            $casted = $tag->cast($tagClass);
 
  108            if($casted === 
null){
 
 
  121        $tag = $this->getTag($name);
 
  122        if($tag !== 
null && !($tag instanceof 
CompoundTag)){
 
 
  134        if(strlen($name) > 
Limits::INT16_MAX){
 
  135            throw new \InvalidArgumentException(sprintf(
"Tag name must be at most %d bytes, but got %d bytes", Limits::INT16_MAX, strlen($name)));
 
  137        $this->value[$name] = $tag;
 
 
  146        foreach($names as $name){
 
  147            unset($this->value[$name]);
 
 
  165    private function getTagValue(
string $name, 
string $expectedClass, $default = 
null){
 
  166        $tag = $this->getTag($name);
 
  167        if($tag instanceof $expectedClass){
 
  168            return $tag->getValue();
 
  171            throw new UnexpectedTagTypeException(
"Expected a tag of type $expectedClass, got " . get_class($tag));
 
  174        if($default === 
null){
 
  175            throw new NoSuchTagException(
"Tag \"$name\" does not exist");
 
  185    public function getByte(
string $name, ?
int $default = 
null) : int{
 
  186        return $this->getTagValue($name, ByteTag::class, $default);
 
  189    public function getShort(
string $name, ?
int $default = 
null) : int{
 
  190        return $this->getTagValue($name, ShortTag::class, $default);
 
  193    public function getInt(
string $name, ?
int $default = 
null) : int{
 
  194        return $this->getTagValue($name, IntTag::class, $default);
 
  197    public function getLong(
string $name, ?
int $default = 
null) : int{
 
  198        return $this->getTagValue($name, LongTag::class, $default);
 
  201    public function getFloat(
string $name, ?
float $default = 
null) : float{
 
  202        return $this->getTagValue($name, FloatTag::class, $default);
 
  205    public function getDouble(
string $name, ?
float $default = 
null) : float{
 
  206        return $this->getTagValue($name, DoubleTag::class, $default);
 
  209    public function getByteArray(
string $name, ?
string $default = 
null) : string{
 
  210        return $this->getTagValue($name, ByteArrayTag::class, $default);
 
  213    public function getString(
string $name, ?
string $default = 
null) : string{
 
  214        return $this->getTagValue($name, StringTag::class, $default);
 
  222    public function getIntArray(
string $name, ?array $default = 
null) : array{
 
  223        return $this->getTagValue($name, 
IntArrayTag::class, $default);
 
 
  233    public function setByte(
string $name, 
int $value) : self{
 
  234        return $this->setTag($name, new 
ByteTag($value));
 
 
  240    public function setShort(
string $name, 
int $value) : self{
 
  241        return $this->setTag($name, new 
ShortTag($value));
 
 
  247    public function setInt(
string $name, 
int $value) : self{
 
  248        return $this->setTag($name, new 
IntTag($value));
 
 
  254    public function setLong(
string $name, 
int $value) : self{
 
  255        return $this->setTag($name, new 
LongTag($value));
 
 
  261    public function setFloat(
string $name, 
float $value) : self{
 
  262        return $this->setTag($name, new 
FloatTag($value));
 
 
  268    public function setDouble(
string $name, 
float $value) : self{
 
  269        return $this->setTag($name, new 
DoubleTag($value));
 
 
  282    public function setString(
string $name, 
string $value) : self{
 
  283        return $this->setTag($name, new 
StringTag($value));
 
 
  293        return $this->setTag($name, new 
IntArrayTag($value));
 
 
  296    protected function getTypeName() : string{
 
  300    public function getType() : int{
 
  301        return 
NBT::TAG_Compound;
 
  304    public static function read(NbtStreamReader $reader, ReaderTracker $tracker) : self{
 
  306        $tracker->protectDepth(
static function() use($reader, $tracker, $result) : 
void{
 
  307            for($type = $reader->readByte(); $type !== NBT::TAG_End; $type = $reader->readByte()){
 
  308                $name = $reader->readString();
 
  309                $tag = NBT::createTag($type, $reader, $tracker);
 
  310                if($result->getTag($name) !== 
null){
 
  318                $result->setTag($name, $tag);
 
  324    public function write(NbtStreamWriter $writer) : void{
 
  325        foreach($this->value as $name => $tag){
 
  329                $name = (string) $name;
 
  331            $writer->writeByte($tag->getType());
 
  332            $writer->writeString($name);
 
  333            $tag->write($writer);
 
  335        $writer->writeByte(NBT::TAG_End);
 
  338    protected function stringifyValue(
int $indentation) : string{
 
  340        foreach($this->value as $name => $tag){
 
  341            $str .= str_repeat(
"  ", $indentation + 1) . 
"\"$name\" => " . $tag->toString($indentation + 1) . 
"\n";
 
  343        return $str . str_repeat(
"  ", $indentation) . 
"}";
 
  346    public function __clone(){
 
  347        foreach($this->value as $key => $tag){
 
  348            $this->value[$key] = $tag->safeClone();
 
  361        foreach($this->value as $name => $tag){
 
  364            yield strval($name) => $tag;
 
 
  369        if(!($that instanceof $this) or count($this->value) !== count($that->value)){
 
  373        foreach($this->value as $k => $v){
 
  374            $other = $that->value[$k] ?? 
null;
 
  375            if($other === 
null or !$v->equals($other)){
 
 
  392        foreach($other as $k => $namedTag){
 
  393            $new->setTag($k, clone $namedTag);