PocketMine-MP 5.28.3 git-94fb5d95b92604840dabb719f04327efa559cf94
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
47final class ListTag extends Tag implements \Countable, \IteratorAggregate{
48 use NoDynamicFieldsTrait;
49
51 private $tagType;
56 private $value = [];
57
61 public function __construct(array $value = [], int $tagType = NBT::TAG_End){
62 self::restrictArgCount(__METHOD__, func_num_args(), 2);
63 $this->tagType = $tagType;
64 foreach($value as $tag){
65 $this->push($tag); //ensure types get checked
66 }
67 }
68
73 public function getValue() : array{
74 return $this->value;
75 }
76
82 public function getAllValues() : array{
83 return array_map(fn(Tag $t) => $t->getValue(), $this->value);
84 }
85
86 public function count() : int{
87 return count($this->value);
88 }
89
90 public function getCount() : int{
91 return count($this->value);
92 }
93
97 public function push(Tag $tag) : void{
98 $this->checkTagType($tag);
99 $this->value[] = $tag;
100 }
101
105 public function pop() : Tag{
106 if(count($this->value) === 0){
107 throw new \LogicException("List is empty");
108 }
109 return array_pop($this->value);
110 }
111
115 public function unshift(Tag $tag) : void{
116 $this->checkTagType($tag);
117 array_unshift($this->value, $tag);
118 }
119
123 public function shift() : Tag{
124 if(count($this->value) === 0){
125 throw new \LogicException("List is empty");
126 }
127 return array_shift($this->value);
128 }
129
137 public function insert(int $offset, Tag $tag){
138 $this->checkTagType($tag);
139 if($offset < 0 || $offset > count($this->value)){
140 throw new \OutOfRangeException("Offset cannot be negative or larger than the list's current size");
141 }
142 $newValue = array_slice($this->value, 0, $offset);
143 $newValue[] = $tag;
144 array_push($newValue, ...array_slice($this->value, $offset));
145 $this->value = $newValue;
146 }
147
151 public function remove(int $offset) : void{
152 //to keep phpstan happy we can't directly unset from $this->value
153 $newValue = $this->value;
154 unset($newValue[$offset]);
155 $this->value = array_values($newValue);
156 }
157
163 public function get(int $offset) : Tag{
164 if(!isset($this->value[$offset])){
165 throw new \OutOfRangeException("No such tag at offset $offset");
166 }
167 return $this->value[$offset];
168 }
169
173 public function first() : Tag{
174 if(count($this->value) === 0){
175 throw new \LogicException("List is empty");
176 }
177 return $this->value[0];
178 }
179
183 public function last() : Tag{
184 if(count($this->value) === 0){
185 throw new \LogicException("List is empty");
186 }
187 return $this->value[array_key_last($this->value)];
188 }
189
195 public function set(int $offset, Tag $tag) : void{
196 $this->checkTagType($tag);
197 if($offset < 0 || $offset > count($this->value)){ //allow setting the end offset
198 throw new \OutOfRangeException("Offset cannot be negative or larger than the list's current size");
199 }
200 $this->value[$offset] = $tag;
201 }
202
206 public function isset(int $offset) : bool{
207 return isset($this->value[$offset]);
208 }
209
213 public function empty() : bool{
214 return count($this->value) === 0;
215 }
216
217 protected function getTypeName() : string{
218 return "List";
219 }
220
221 public function getType() : int{
222 return NBT::TAG_List;
223 }
224
228 public function getTagType() : int{
229 return $this->tagType;
230 }
231
242 public function setTagType(int $type){
243 if(count($this->value) > 0){
244 throw new \LogicException("Cannot change tag type of non-empty ListTag");
245 }
246 $this->tagType = $type;
247 }
248
254 private function checkTagType(Tag $tag) : void{
255 $type = $tag->getType();
256 if($type !== $this->tagType){
257 if(count($this->value) === 0){
258 $this->tagType = $type;
259 }else{
260 throw new \TypeError("Invalid tag of type " . get_class($tag) . " assigned to ListTag, expected " . get_class($this->value[0]));
261 }
262 }
263 }
264
265 public static function read(NbtStreamReader $reader, ReaderTracker $tracker) : self{
266 $value = [];
267 $tagType = $reader->readByte();
268 $size = $reader->readInt();
269
270 if($size > 0){
271 if($tagType === NBT::TAG_End){
272 throw new NbtDataException("Unexpected non-empty list of TAG_End");
273 }
274
275 $tracker->protectDepth(static function() use($size, $tagType, $reader, $tracker, &$value) : void{
276 for($i = 0; $i < $size; ++$i){
277 $value[] = NBT::createTag($tagType, $reader, $tracker);
278 }
279 });
280 }
281 return new self($value, $tagType);
282 }
283
284 public function write(NbtStreamWriter $writer) : void{
285 $writer->writeByte($this->tagType);
286 $writer->writeInt(count($this->value));
287 foreach($this->value as $tag){
288 $tag->write($writer);
289 }
290 }
291
292 protected function stringifyValue(int $indentation) : string{
293 $str = "{\n";
294 foreach($this->value as $tag){
295 $str .= str_repeat(" ", $indentation + 1) . $tag->toString($indentation + 1) . "\n";
296 }
297 return $str . str_repeat(" ", $indentation) . "}";
298 }
299
300 public function __clone(){
301 $this->value = array_map(fn(Tag $t) => $t->safeClone(), $this->value);
302 }
303
304 protected function makeCopy(){
305 return clone $this;
306 }
307
312 public function getIterator() : \Generator{
313 yield from $this->value;
314 }
315
316 public function equals(Tag $that) : bool{
317 if(!($that instanceof $this) or count($this->value) !== count($that->value)){
318 return false;
319 }
320
321 foreach($this->value as $k => $v){
322 if(!$v->equals($that->value[$k])){
323 return false;
324 }
325 }
326
327 return true;
328 }
329}
__construct(array $value=[], int $tagType=NBT::TAG_End)
Definition ListTag.php:61
insert(int $offset, Tag $tag)
Definition ListTag.php:137