PocketMine-MP 5.24.1 git-9d6a0cc7385976fb350f6f919ecc5580b508a783
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 func_num_args;
32use function get_class;
33use function iterator_to_array;
34use function str_repeat;
35
39final class ListTag extends Tag implements \Countable, \IteratorAggregate{
40 use NoDynamicFieldsTrait;
41
43 private $tagType;
48 private $value;
49
53 public function __construct(array $value = [], int $tagType = NBT::TAG_End){
54 self::restrictArgCount(__METHOD__, func_num_args(), 2);
55 $this->tagType = $tagType;
56 $this->value = new \SplDoublyLinkedList();
57 foreach($value as $tag){
58 $this->push($tag);
59 }
60 }
61
66 public function getValue() : array{
67 $value = [];
68 foreach($this->value as $v){
69 $value[] = $v;
70 }
71
72 return $value;
73 }
74
80 public function getAllValues() : array{
81 $result = [];
82 foreach($this->value as $tag){
83 $result[] = $tag->getValue();
84 }
85
86 return $result;
87 }
88
89 public function count() : int{
90 return $this->value->count();
91 }
92
93 public function getCount() : int{
94 return $this->value->count();
95 }
96
100 public function push(Tag $tag) : void{
101 $this->checkTagType($tag);
102 $this->value->push($tag);
103 }
104
108 public function pop() : Tag{
109 return $this->value->pop();
110 }
111
115 public function unshift(Tag $tag) : void{
116 $this->checkTagType($tag);
117 $this->value->unshift($tag);
118 }
119
123 public function shift() : Tag{
124 return $this->value->shift();
125 }
126
134 public function insert(int $offset, Tag $tag){
135 $this->checkTagType($tag);
136 $this->value->add($offset, $tag);
137 }
138
142 public function remove(int $offset) : void{
143 unset($this->value[$offset]);
144 }
145
151 public function get(int $offset) : Tag{
152 if(!isset($this->value[$offset])){
153 throw new \OutOfRangeException("No such tag at offset $offset");
154 }
155 return $this->value[$offset];
156 }
157
161 public function first() : Tag{
162 return $this->value->bottom();
163 }
164
168 public function last() : Tag{
169 return $this->value->top();
170 }
171
177 public function set(int $offset, Tag $tag) : void{
178 $this->checkTagType($tag);
179 $this->value[$offset] = $tag;
180 }
181
185 public function isset(int $offset) : bool{
186 return isset($this->value[$offset]);
187 }
188
192 public function empty() : bool{
193 return $this->value->isEmpty();
194 }
195
196 protected function getTypeName() : string{
197 return "List";
198 }
199
200 public function getType() : int{
201 return NBT::TAG_List;
202 }
203
207 public function getTagType() : int{
208 return $this->tagType;
209 }
210
218 public function setTagType(int $type){
219 if(!$this->value->isEmpty()){
220 throw new \LogicException("Cannot change tag type of non-empty ListTag");
221 }
222 $this->tagType = $type;
223 }
224
230 private function checkTagType(Tag $tag) : void{
231 $type = $tag->getType();
232 if($type !== $this->tagType){
233 if($this->tagType === NBT::TAG_End){
234 $this->tagType = $type;
235 }else{
236 //TODO: reintroduce type info
237 throw new \TypeError("Invalid tag of type " . get_class($tag) . " assigned to ListTag");
238 }
239 }
240 }
241
242 public static function read(NbtStreamReader $reader, ReaderTracker $tracker) : self{
243 $value = [];
244 $tagType = $reader->readByte();
245 $size = $reader->readInt();
246
247 if($size > 0){
248 if($tagType === NBT::TAG_End){
249 throw new NbtDataException("Unexpected non-empty list of TAG_End");
250 }
251
252 $tracker->protectDepth(static function() use($size, $tagType, $reader, $tracker, &$value) : void{
253 for($i = 0; $i < $size; ++$i){
254 $value[] = NBT::createTag($tagType, $reader, $tracker);
255 }
256 });
257 }else{
258 $tagType = NBT::TAG_End; //Some older NBT implementations used TAG_Byte for empty lists.
259 }
260 return new self($value, $tagType);
261 }
262
263 public function write(NbtStreamWriter $writer) : void{
264 $writer->writeByte($this->tagType);
265 $writer->writeInt($this->value->count());
267 foreach($this->value as $tag){
268 $tag->write($writer);
269 }
270 }
271
272 protected function stringifyValue(int $indentation) : string{
273 $str = "{\n";
275 foreach($this->value as $tag){
276 $str .= str_repeat(" ", $indentation + 1) . $tag->toString($indentation + 1) . "\n";
277 }
278 return $str . str_repeat(" ", $indentation) . "}";
279 }
280
281 public function __clone(){
283 $new = new \SplDoublyLinkedList();
284
285 foreach($this->value as $tag){
286 $new->push($tag->safeClone());
287 }
288
289 $this->value = $new;
290 }
291
292 protected function makeCopy(){
293 return clone $this;
294 }
295
300 public function getIterator() : \Generator{
301 //we technically don't need iterator_to_array() here, but I don't feel comfortable relying on "yield from" to
302 //copy the underlying dataset referenced by SplDoublyLinkedList
303 yield from iterator_to_array($this->value, true);
304 }
305
306 public function equals(Tag $that) : bool{
307 if(!($that instanceof $this) or $this->count() !== $that->count()){
308 return false;
309 }
310
311 foreach($this as $k => $v){
312 if(!$v->equals($that->get($k))){
313 return false;
314 }
315 }
316
317 return true;
318 }
319}
__construct(array $value=[], int $tagType=NBT::TAG_End)
Definition ListTag.php:53
insert(int $offset, Tag $tag)
Definition ListTag.php:134