the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "com.mojang.nbt.h"
3#include "net.minecraft.world.h"
4#include "net.minecraft.world.level.h"
5#include "TileEntity.h"
6#include "net.minecraft.world.entity.item.h"
7#include "net.minecraft.world.entity.player.h"
8#include "net.minecraft.world.item.h"
9#include "net.minecraft.world.inventory.h"
10#include "net.minecraft.world.level.tile.h"
11#include "net.minecraft.world.phys.h"
12#include "ChestTileEntity.h"
13#include "ContainerOpenPacket.h"
14#include "SoundTypes.h"
15
16int ChestTileEntity::getContainerType()
17{
18 if (isBonusChest) return ContainerOpenPacket::BONUS_CHEST;
19 else return ContainerOpenPacket::CONTAINER;
20}
21
22void ChestTileEntity::_init(bool isBonusChest)
23{
24 items = new ItemInstanceArray(9 * 4);
25
26 hasCheckedNeighbors = false;
27 this->isBonusChest = isBonusChest;
28
29 openness = 0.0f;
30 oOpenness = 0.0f;
31 openCount = 0;
32 tickInterval = 0;
33
34 type = -1;
35 name = L"";
36}
37
38ChestTileEntity::ChestTileEntity(bool isBonusChest/* = false*/) : TileEntity()
39{
40 _init(isBonusChest);
41}
42
43ChestTileEntity::ChestTileEntity(int type, bool isBonusChest/* = false*/) : TileEntity()
44{
45 _init(isBonusChest);
46
47 this->type = type;
48}
49
50ChestTileEntity::~ChestTileEntity()
51{
52 delete[] items->data;
53 delete items;
54}
55
56unsigned int ChestTileEntity::getContainerSize()
57{
58 return 9 * 3;
59}
60
61shared_ptr<ItemInstance> ChestTileEntity::getItem(unsigned int slot)
62{
63 return items->data[slot];
64}
65
66shared_ptr<ItemInstance> ChestTileEntity::removeItem(unsigned int slot, int count)
67{
68 if (items->data[slot] != NULL)
69 {
70 if (items->data[slot]->count <= count)
71 {
72 shared_ptr<ItemInstance> item = items->data[slot];
73 items->data[slot] = nullptr;
74 setChanged();
75 // 4J Stu - Fix for duplication glitch
76 if(item->count <= 0) return nullptr;
77 return item;
78 }
79 else
80 {
81 shared_ptr<ItemInstance> i = items->data[slot]->remove(count);
82 if (items->data[slot]->count == 0) items->data[slot] = nullptr;
83 setChanged();
84 // 4J Stu - Fix for duplication glitch
85 if(i->count <= 0) return nullptr;
86 return i;
87 }
88 }
89 return nullptr;
90}
91
92shared_ptr<ItemInstance> ChestTileEntity::removeItemNoUpdate(int slot)
93{
94 if (items->data[slot] != NULL)
95 {
96 shared_ptr<ItemInstance> item = items->data[slot];
97 items->data[slot] = nullptr;
98 return item;
99 }
100 return nullptr;
101}
102
103void ChestTileEntity::setItem(unsigned int slot, shared_ptr<ItemInstance> item)
104{
105 items->data[slot] = item;
106 if (item != NULL && item->count > getMaxStackSize()) item->count = getMaxStackSize();
107 this->setChanged();
108}
109
110wstring ChestTileEntity::getName()
111{
112 return hasCustomName() ? name : app.GetString(IDS_TILE_CHEST);
113}
114
115wstring ChestTileEntity::getCustomName()
116{
117 return hasCustomName() ? name : L"";
118}
119
120bool ChestTileEntity::hasCustomName()
121{
122 return !name.empty();
123}
124
125void ChestTileEntity::setCustomName(const wstring &name)
126{
127 this->name = name;
128}
129
130void ChestTileEntity::load(CompoundTag *base)
131{
132 TileEntity::load(base);
133 ListTag<CompoundTag> *inventoryList = (ListTag<CompoundTag> *) base->getList(L"Items");
134 if( items )
135 {
136 delete [] items->data;
137 delete items;
138 }
139 items = new ItemInstanceArray(getContainerSize());
140 if (base->contains(L"CustomName")) name = base->getString(L"CustomName");
141 for (int i = 0; i < inventoryList->size(); i++)
142 {
143 CompoundTag *tag = inventoryList->get(i);
144 unsigned int slot = tag->getByte(L"Slot") & 0xff;
145 if (slot >= 0 && slot < items->length) (*items)[slot] = ItemInstance::fromTag(tag);
146 }
147 isBonusChest = base->getBoolean(L"bonus");
148}
149
150void ChestTileEntity::save(CompoundTag *base)
151{
152 TileEntity::save(base);
153 ListTag<CompoundTag> *listTag = new ListTag<CompoundTag>;
154
155 for (unsigned int i = 0; i < items->length; i++)
156 {
157 if (items->data[i] != NULL)
158 {
159 CompoundTag *tag = new CompoundTag();
160 tag->putByte(L"Slot", (byte) i);
161 items->data[i]->save(tag);
162 listTag->add(tag);
163 }
164 }
165 base->put(L"Items", listTag);
166 if (hasCustomName()) base->putString(L"CustomName", name);
167 base->putBoolean(L"bonus", isBonusChest);
168}
169
170int ChestTileEntity::getMaxStackSize() const
171{
172 return Container::LARGE_MAX_STACK_SIZE;
173}
174
175bool ChestTileEntity::stillValid(shared_ptr<Player> player)
176{
177 if (level->getTileEntity(x, y, z) != shared_from_this() ) return false;
178 if (player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) > 8 * 8) return false;
179 return true;
180}
181
182void ChestTileEntity::setChanged()
183{
184 TileEntity::setChanged();
185}
186
187void ChestTileEntity::clearCache()
188{
189 TileEntity::clearCache();
190 hasCheckedNeighbors = false;
191}
192
193void ChestTileEntity::heyImYourNeighbor(shared_ptr<ChestTileEntity> neighbor, int from)
194{
195 if (neighbor->isRemoved())
196 {
197 hasCheckedNeighbors = false;
198 }
199 else if (hasCheckedNeighbors)
200 {
201 switch (from)
202 {
203 case Direction::NORTH:
204 if (n.lock() != neighbor) hasCheckedNeighbors = false;
205 break;
206 case Direction::SOUTH:
207 if (s.lock() != neighbor) hasCheckedNeighbors = false;
208 break;
209 case Direction::EAST:
210 if (e.lock() != neighbor) hasCheckedNeighbors = false;
211 break;
212 case Direction::WEST:
213 if (w.lock() != neighbor) hasCheckedNeighbors = false;
214 break;
215 }
216 }
217}
218
219void ChestTileEntity::checkNeighbors()
220{
221 if (hasCheckedNeighbors) return;
222
223 hasCheckedNeighbors = true;
224 n = weak_ptr<ChestTileEntity>();
225 e = weak_ptr<ChestTileEntity>();
226 w = weak_ptr<ChestTileEntity>();
227 s = weak_ptr<ChestTileEntity>();
228
229 if (isSameChest(x - 1, y, z))
230 {
231 w = dynamic_pointer_cast<ChestTileEntity>(level->getTileEntity(x - 1, y, z));
232 }
233 if (isSameChest(x + 1, y, z))
234 {
235 e = dynamic_pointer_cast<ChestTileEntity>(level->getTileEntity(x + 1, y, z));
236 }
237 if (isSameChest(x, y, z - 1))
238 {
239 n = dynamic_pointer_cast<ChestTileEntity>(level->getTileEntity(x, y, z - 1));
240 }
241 if (isSameChest(x, y, z + 1))
242 {
243 s = dynamic_pointer_cast<ChestTileEntity>(level->getTileEntity(x, y, z + 1));
244 }
245
246 shared_ptr<ChestTileEntity> cteThis = dynamic_pointer_cast<ChestTileEntity>(shared_from_this());
247 if (n.lock() != NULL) n.lock()->heyImYourNeighbor(cteThis, Direction::SOUTH);
248 if (s.lock() != NULL) s.lock()->heyImYourNeighbor(cteThis, Direction::NORTH);
249 if (e.lock() != NULL) e.lock()->heyImYourNeighbor(cteThis, Direction::WEST);
250 if (w.lock() != NULL) w.lock()->heyImYourNeighbor(cteThis, Direction::EAST);
251}
252
253bool ChestTileEntity::isSameChest(int x, int y, int z)
254{
255 Tile *tile = Tile::tiles[level->getTile(x, y, z)];
256 if (tile == NULL || !(dynamic_cast<ChestTile *>(tile) != NULL)) return false;
257 return ((ChestTile *) tile)->type == getType();
258}
259
260void ChestTileEntity::tick()
261{
262 TileEntity::tick();
263 checkNeighbors();
264
265 ++tickInterval;
266 if (!level->isClientSide && openCount != 0 && (tickInterval + x + y + z) % (SharedConstants::TICKS_PER_SECOND * 10) == 0)
267 {
268 // level.tileEvent(x, y, z, Tile.chest.id, ChestTile.EVENT_SET_OPEN_COUNT, openCount);
269
270 openCount = 0;
271
272 float range = 5;
273 vector<shared_ptr<Entity> > *players = level->getEntitiesOfClass(typeid(Player), AABB::newTemp(x - range, y - range, z - range, x + 1 + range, y + 1 + range, z + 1 + range));
274 for (AUTO_VAR(it,players->begin()); it != players->end(); ++it)
275 {
276 shared_ptr<Player> player = dynamic_pointer_cast<Player>(*it);
277
278 ContainerMenu *containerMenu = dynamic_cast<ContainerMenu*>(player->containerMenu);
279 if (containerMenu != NULL)
280 {
281 shared_ptr<Container> container = containerMenu->getContainer();
282 shared_ptr<Container> thisContainer = dynamic_pointer_cast<Container>(shared_from_this());
283 shared_ptr<CompoundContainer> compoundContainer = dynamic_pointer_cast<CompoundContainer>( container );
284 if ( (container == thisContainer) || (compoundContainer != NULL && compoundContainer->contains(thisContainer)) )
285 {
286 openCount++;
287 }
288 }
289 }
290 delete players;
291 }
292
293 oOpenness = openness;
294
295 float speed = 0.10f;
296 if (openCount > 0 && openness == 0)
297 {
298 if (n.lock() == NULL && w.lock() == NULL)
299 {
300 double xc = x + 0.5;
301 double zc = z + 0.5;
302 if (s.lock() != NULL) zc += 0.5;
303 if (e.lock() != NULL) xc += 0.5;
304
305 // 4J-PB - Seems the chest open volume is much louder than other sounds from user reports. We'll tone it down a bit
306 level->playSound(xc, y + 0.5, zc, eSoundType_RANDOM_CHEST_OPEN, 0.2f, level->random->nextFloat() * 0.1f + 0.9f);
307 }
308 }
309 if ((openCount == 0 && openness > 0) || (openCount > 0 && openness < 1))
310 {
311 float oldOpen = openness;
312 if (openCount > 0) openness += speed;
313 else openness -= speed;
314 if (openness > 1)
315 {
316 openness = 1;
317 }
318 float lim = 0.5f;
319 if (openness < lim && oldOpen >= lim)
320 {
321 // Fix for #64546 - Customer Encountered: TU7: Chests placed by the Player are closing too fast.
322 //openness = 0;
323 if (n.lock() == NULL && w.lock() == NULL)
324 {
325 double xc = x + 0.5;
326 double zc = z + 0.5;
327 if (s.lock() != NULL) zc += 0.5;
328 if (e.lock() != NULL) xc += 0.5;
329
330 // 4J-PB - Seems the chest open volume is much louder than other sounds from user reports. We'll tone it down a bit
331 level->playSound(xc, y + 0.5, zc, eSoundType_RANDOM_CHEST_CLOSE, 0.2f, level->random->nextFloat() * 0.1f + 0.9f);
332 }
333 }
334 if (openness < 0)
335 {
336 openness = 0;
337 }
338 }
339
340}
341
342bool ChestTileEntity::triggerEvent(int b0, int b1)
343{
344 if (b0 == ChestTile::EVENT_SET_OPEN_COUNT)
345 {
346 openCount = b1;
347 return true;
348 }
349 return TileEntity::triggerEvent(b0, b1);
350}
351
352void ChestTileEntity::startOpen()
353{
354 if (openCount < 0)
355 {
356 openCount = 0;
357 }
358 openCount++;
359 level->tileEvent(x, y, z, getTile()->id, ChestTile::EVENT_SET_OPEN_COUNT, openCount);
360 level->updateNeighborsAt(x, y, z, getTile()->id);
361 level->updateNeighborsAt(x, y - 1, z, getTile()->id);
362}
363
364void ChestTileEntity::stopOpen()
365{
366 if (getTile() == NULL || !( dynamic_cast<ChestTile *>( getTile() ) != NULL)) return;
367 openCount--;
368 level->tileEvent(x, y, z, getTile()->id, ChestTile::EVENT_SET_OPEN_COUNT, openCount);
369 level->updateNeighborsAt(x, y, z, getTile()->id);
370 level->updateNeighborsAt(x, y - 1, z, getTile()->id);
371}
372
373bool ChestTileEntity::canPlaceItem(int slot, shared_ptr<ItemInstance> item)
374{
375 return true;
376}
377
378void ChestTileEntity::setRemoved()
379{
380 TileEntity::setRemoved();
381 clearCache();
382 checkNeighbors();
383}
384
385int ChestTileEntity::getType()
386{
387 if (type == -1)
388 {
389 if (level != NULL && dynamic_cast<ChestTile *>( getTile() ) != NULL)
390 {
391 type = ((ChestTile *) getTile())->type;
392 }
393 else
394 {
395 return ChestTile::TYPE_BASIC;
396 }
397 }
398
399 return type;
400}
401
402// 4J Added
403shared_ptr<TileEntity> ChestTileEntity::clone()
404{
405 shared_ptr<ChestTileEntity> result = shared_ptr<ChestTileEntity>( new ChestTileEntity() );
406 TileEntity::clone(result);
407
408 for (unsigned int i = 0; i < items->length; i++)
409 {
410 if (items->data[i] != NULL)
411 {
412 result->items->data[i] = ItemInstance::clone(items->data[i]);
413 }
414 }
415 return result;
416}