PocketMine-MP 5.15.1 git-ed158f8a1b0cfe334ac5f45febc0f633602014f2
tile/Chest.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\block\tile;
25
33use function abs;
34
35class Chest extends Spawnable implements Container, Nameable{
36 use NameableTrait {
37 addAdditionalSpawnData as addNameSpawnData;
38 }
39 use ContainerTrait {
40 onBlockDestroyedHook as containerTraitBlockDestroyedHook;
41 }
42
43 public const TAG_PAIRX = "pairx";
44 public const TAG_PAIRZ = "pairz";
45 public const TAG_PAIR_LEAD = "pairlead";
46
47 protected ChestInventory $inventory;
48 protected ?DoubleChestInventory $doubleInventory = null;
49
50 private ?int $pairX = null;
51 private ?int $pairZ = null;
52
53 public function __construct(World $world, Vector3 $pos){
54 parent::__construct($world, $pos);
55 $this->inventory = new ChestInventory($this->position);
56 }
57
58 public function readSaveData(CompoundTag $nbt) : void{
59 if(($pairXTag = $nbt->getTag(self::TAG_PAIRX)) instanceof IntTag && ($pairZTag = $nbt->getTag(self::TAG_PAIRZ)) instanceof IntTag){
60 $pairX = $pairXTag->getValue();
61 $pairZ = $pairZTag->getValue();
62 if(
63 ($this->position->x === $pairX && abs($this->position->z - $pairZ) === 1) ||
64 ($this->position->z === $pairZ && abs($this->position->x - $pairX) === 1)
65 ){
66 $this->pairX = $pairX;
67 $this->pairZ = $pairZ;
68 }else{
69 $this->pairX = $this->pairZ = null;
70 }
71 }
72 $this->loadName($nbt);
73 $this->loadItems($nbt);
74 }
75
76 protected function writeSaveData(CompoundTag $nbt) : void{
77 if($this->isPaired()){
78 $nbt->setInt(self::TAG_PAIRX, $this->pairX);
79 $nbt->setInt(self::TAG_PAIRZ, $this->pairZ);
80 }
81 $this->saveName($nbt);
82 $this->saveItems($nbt);
83 }
84
85 public function getCleanedNBT() : ?CompoundTag{
86 $tag = parent::getCleanedNBT();
87 if($tag !== null){
88 //TODO: replace this with a purpose flag on writeSaveData()
89 $tag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ);
90 }
91 return $tag;
92 }
93
94 public function close() : void{
95 if(!$this->closed){
96 $this->inventory->removeAllViewers();
97
98 if($this->doubleInventory !== null){
99 if($this->isPaired() && $this->position->getWorld()->isChunkLoaded($this->pairX >> Chunk::COORD_BIT_SIZE, $this->pairZ >> Chunk::COORD_BIT_SIZE)){
100 $this->doubleInventory->removeAllViewers();
101 if(($pair = $this->getPair()) !== null){
102 $pair->doubleInventory = null;
103 }
104 }
105 $this->doubleInventory = null;
106 }
107
108 parent::close();
109 }
110 }
111
112 protected function onBlockDestroyedHook() : void{
113 $this->unpair();
114 $this->containerTraitBlockDestroyedHook();
115 }
116
117 public function getInventory() : ChestInventory|DoubleChestInventory{
118 if($this->isPaired() && $this->doubleInventory === null){
119 $this->checkPairing();
120 }
121 return $this->doubleInventory instanceof DoubleChestInventory ? $this->doubleInventory : $this->inventory;
122 }
123
124 public function getRealInventory() : ChestInventory{
125 return $this->inventory;
126 }
127
128 protected function checkPairing() : void{
129 if($this->isPaired() && !$this->position->getWorld()->isInLoadedTerrain(new Vector3($this->pairX, $this->position->y, $this->pairZ))){
130 //paired to a tile in an unloaded chunk
131 $this->doubleInventory = null;
132
133 }elseif(($pair = $this->getPair()) instanceof Chest){
134 if(!$pair->isPaired()){
135 $pair->createPair($this);
136 $pair->checkPairing();
137 }
138 if($this->doubleInventory === null){
139 if($pair->doubleInventory !== null){
140 $this->doubleInventory = $pair->doubleInventory;
141 }else{
142 if(($pair->position->x + ($pair->position->z << 15)) > ($this->position->x + ($this->position->z << 15))){ //Order them correctly
143 $this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($pair->inventory, $this->inventory);
144 }else{
145 $this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($this->inventory, $pair->inventory);
146 }
147 }
148 }
149 }else{
150 $this->doubleInventory = null;
151 $this->pairX = $this->pairZ = null;
152 }
153 }
154
155 public function getDefaultName() : string{
156 return "Chest";
157 }
158
159 public function isPaired() : bool{
160 return $this->pairX !== null && $this->pairZ !== null;
161 }
162
163 public function getPair() : ?Chest{
164 if($this->isPaired()){
165 $tile = $this->position->getWorld()->getTileAt($this->pairX, $this->position->y, $this->pairZ);
166 if($tile instanceof Chest){
167 return $tile;
168 }
169 }
170
171 return null;
172 }
173
174 public function pairWith(Chest $tile) : bool{
175 if($this->isPaired() || $tile->isPaired()){
176 return false;
177 }
178
179 $this->createPair($tile);
180
181 $this->clearSpawnCompoundCache();
182 $tile->clearSpawnCompoundCache();
183 $this->checkPairing();
184
185 return true;
186 }
187
188 private function createPair(Chest $tile) : void{
189 $this->pairX = $tile->getPosition()->x;
190 $this->pairZ = $tile->getPosition()->z;
191
192 $tile->pairX = $this->getPosition()->x;
193 $tile->pairZ = $this->getPosition()->z;
194 }
195
196 public function unpair() : bool{
197 if(!$this->isPaired()){
198 return false;
199 }
200
201 $tile = $this->getPair();
202 $this->pairX = $this->pairZ = null;
203
204 $this->clearSpawnCompoundCache();
205
206 if($tile instanceof Chest){
207 $tile->pairX = $tile->pairZ = null;
208 $tile->checkPairing();
209 $tile->clearSpawnCompoundCache();
210 }
211 $this->checkPairing();
212
213 return true;
214 }
215
216 protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
217 if($this->isPaired()){
218 $nbt->setInt(self::TAG_PAIRX, $this->pairX);
219 $nbt->setInt(self::TAG_PAIRZ, $this->pairZ);
220 }
221
222 $this->addNameSpawnData($nbt);
223 }
224}
writeSaveData(CompoundTag $nbt)
Definition: tile/Chest.php:76
addAdditionalSpawnData(CompoundTag $nbt)
Definition: tile/Chest.php:216
setInt(string $name, int $value)
removeTag(string ... $names)