PocketMine-MP 5.37.4 git-0c453f585430c41919390ec01ffeb1e004b5334b
Loading...
Searching...
No Matches
ListTag.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20*/
21
22declare(strict_types=1);
23
24namespace pocketmine\nbt\tag;
25
31use function array_key_last;
32use function array_map;
33use function array_pop;
34use function array_push;
35use function array_shift;
36use function array_slice;
37use function array_unshift;
38use function array_values;
39use function count;
40use function func_num_args;
41use function get_class;
42use function str_repeat;
43
48final class ListTag extends Tag implements \Countable, \IteratorAggregate{
49 use NoDynamicFieldsTrait;
50
52 private $tagType;
57 private $value = [];
58
63 public function __construct(array $value = [], int $tagType = NBT::TAG_End){
64 self::restrictArgCount(__METHOD__, func_num_args(), 2);
65 $this->tagType = $tagType;
66 foreach($value as $tag){
67 $this->push($tag); //ensure types get checked
68 }
69 }
70
75 public function getValue() : array{
76 return $this->value;
77 }
78
84 public function getAllValues() : array{
85 return array_map(fn(Tag $t) => $t->getValue(), $this->value);
86 }
87
93 private function checkTagClass(string $tagClass) : bool{
94 return count($this->value) === 0 || $this->first() instanceof $tagClass;
95 }
96
109 public function cast(string $tagClass) : ?self{
110 return $this->checkTagClass($tagClass) ? $this : null;
111 }
112
113 public function count() : int{
114 return count($this->value);
115 }
116
117 public function getCount() : int{
118 return count($this->value);
119 }
120
128 public function push(Tag $tag) : void{
129 $this->checkTagType($tag);
130 $this->value[] = $tag;
131 }
132
137 public function pop() : Tag{
138 if(count($this->value) === 0){
139 throw new \LogicException("List is empty");
140 }
141 return array_pop($this->value);
142 }
143
151 public function unshift(Tag $tag) : void{
152 $this->checkTagType($tag);
153 array_unshift($this->value, $tag);
154 }
155
160 public function shift() : Tag{
161 if(count($this->value) === 0){
162 throw new \LogicException("List is empty");
163 }
164 return array_shift($this->value);
165 }
166
178 public function insert(int $offset, Tag $tag){
179 $this->checkTagType($tag);
180 if($offset < 0 || $offset > count($this->value)){
181 throw new \OutOfRangeException("Offset cannot be negative or larger than the list's current size");
182 }
183 $newValue = array_slice($this->value, 0, $offset);
184 $newValue[] = $tag;
185 array_push($newValue, ...array_slice($this->value, $offset));
186 $this->value = $newValue;
187 }
188
192 public function remove(int $offset) : void{
193 //to keep phpstan happy we can't directly unset from $this->value
194 $newValue = $this->value;
195 unset($newValue[$offset]);
196 $this->value = array_values($newValue);
197 }
198
206 public function get(int $offset) : Tag{
207 if(!isset($this->value[$offset])){
208 throw new \OutOfRangeException("No such tag at offset $offset");
209 }
210 return $this->value[$offset];
211 }
212
217 public function first() : Tag{
218 if(count($this->value) === 0){
219 throw new \LogicException("List is empty");
220 }
221 return $this->value[0];
222 }
223
228 public function last() : Tag{
229 if(count($this->value) === 0){
230 throw new \LogicException("List is empty");
231 }
232 return $this->value[array_key_last($this->value)];
233 }
234
244 public function set(int $offset, Tag $tag) : void{
245 $this->checkTagType($tag);
246 if($offset < 0 || $offset > count($this->value)){ //allow setting the end offset
247 throw new \OutOfRangeException("Offset cannot be negative or larger than the list's current size");
248 }
249 $this->value[$offset] = $tag;
250 }
251
255 public function isset(int $offset) : bool{
256 return isset($this->value[$offset]);
257 }
258
262 public function empty() : bool{
263 return count($this->value) === 0;
264 }
265
266 protected function getTypeName() : string{
267 return "List";
268 }
269
270 public function getType() : int{
271 return NBT::TAG_List;
272 }
273
277 public function getTagType() : int{
278 return $this->tagType;
279 }
280
292 public function setTagType(int $type){
293 if(count($this->value) > 0){
294 throw new \LogicException("Cannot change tag type of non-empty ListTag");
295 }
296 $this->tagType = $type;
297 }
298
304 private function checkTagType(Tag $tag) : void{
305 $type = $tag->getType();
306 if($type !== $this->tagType){
307 if(count($this->value) === 0){
308 $this->tagType = $type;
309 }else{
310 throw new \TypeError("Invalid tag of type " . get_class($tag) . " assigned to ListTag, expected " . get_class($this->value[0]));
311 }
312 }
313 }
314
315 public static function read(NbtStreamReader $reader, ReaderTracker $tracker) : self{
316 $value = [];
317 $tagType = $reader->readByte();
318 $size = $reader->readInt();
319
320 if($size > 0){
321 if($tagType === NBT::TAG_End){
322 throw new NbtDataException("Unexpected non-empty list of TAG_End");
323 }
324
325 $tracker->protectDepth(static function() use($size, $tagType, $reader, $tracker, &$value) : void{
326 for($i = 0; $i < $size; ++$i){
327 $value[] = NBT::createTag($tagType, $reader, $tracker);
328 }
329 });
330 }
331 return new self($value, $tagType);
332 }
333
334 public function write(NbtStreamWriter $writer) : void{
335 $writer->writeByte($this->tagType);
336 $writer->writeInt(count($this->value));
337 foreach($this->value as $tag){
338 $tag->write($writer);
339 }
340 }
341
342 protected function stringifyValue(int $indentation) : string{
343 $str = "{\n";
344 foreach($this->value as $tag){
345 $str .= str_repeat(" ", $indentation + 1) . $tag->toString($indentation + 1) . "\n";
346 }
347 return $str . str_repeat(" ", $indentation) . "}";
348 }
349
350 public function __clone(){
351 $this->value = array_map(fn(Tag $t) => $t->safeClone(), $this->value);
352 }
353
354 protected function makeCopy(){
355 return clone $this;
356 }
357
362 public function getIterator() : \Generator{
363 yield from $this->value;
364 }
365
366 public function equals(Tag $that) : bool{
367 if(!($that instanceof $this) or count($this->value) !== count($that->value)){
368 return false;
369 }
370
371 foreach($this->value as $k => $v){
372 if(!$v->equals($that->value[$k])){
373 return false;
374 }
375 }
376
377 return true;
378 }
379}
__construct(array $value=[], int $tagType=NBT::TAG_End)
Definition ListTag.php:63
insert(int $offset, Tag $tag)
Definition ListTag.php:178
cast(string $tagClass)
Definition ListTag.php:109