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 "File.h"
3#include "InputOutputStream.h"
4#include "net.minecraft.world.entity.h"
5#include "net.minecraft.world.level.h"
6#include "net.minecraft.world.level.chunk.h"
7#include "net.minecraft.world.level.tile.entity.h"
8#include "net.minecraft.world.level.storage.h"
9#include "FileHeader.h"
10#include "OldChunkStorage.h"
11DWORD OldChunkStorage::tlsIdx = 0;
12OldChunkStorage::ThreadStorage *OldChunkStorage::tlsDefault = NULL;
13
14OldChunkStorage::ThreadStorage::ThreadStorage()
15{
16 blockData = byteArray(Level::CHUNK_TILE_COUNT);
17 dataData = byteArray(Level::HALF_CHUNK_TILE_COUNT);
18 skyLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT);
19 blockLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT);
20}
21
22OldChunkStorage::ThreadStorage::~ThreadStorage()
23{
24 delete [] blockData.data;
25 delete [] dataData.data;
26 delete [] skyLightData.data;
27 delete [] blockLightData.data;
28}
29
30void OldChunkStorage::CreateNewThreadStorage()
31{
32 ThreadStorage *tls = new ThreadStorage();
33 if(tlsDefault == NULL )
34 {
35 tlsIdx = TlsAlloc();
36 tlsDefault = tls;
37 }
38 TlsSetValue(tlsIdx, tls);
39}
40
41void OldChunkStorage::UseDefaultThreadStorage()
42{
43 TlsSetValue(tlsIdx, tlsDefault);
44}
45
46void OldChunkStorage::ReleaseThreadStorage()
47{
48 ThreadStorage *tls = (ThreadStorage *)TlsGetValue(tlsIdx);
49 if( tls == tlsDefault ) return;
50
51 delete tls;
52}
53
54OldChunkStorage::OldChunkStorage(File dir, bool create)
55{
56 this->dir = dir;
57 this->create = create;
58}
59
60File OldChunkStorage::getFile(int x, int z)
61{
62 wchar_t name[MAX_PATH_SIZE];
63 wchar_t path1[MAX_PATH_SIZE];
64 wchar_t path2[MAX_PATH_SIZE];
65
66 wchar_t xRadix36[64];
67 wchar_t zRadix36[64];
68#if ( defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ )
69 assert(0); // need a gcc verison of _itow ?
70#else
71 _itow(x,xRadix36,36);
72 _itow(z,zRadix36,36);
73 swprintf(name,MAX_PATH_SIZE,L"c.%ls.%ls.dat",xRadix36,zRadix36);
74 _itow(x & 63,path1,36);
75 _itow(z & 63,path2,36);
76#endif
77 //sprintf(file,"%s\\%s",dir,path1);
78 File file( dir, wstring( path1 ) );
79 if( !file.exists() )
80 {
81 if(create) file.mkdir();
82 else
83 {
84 return File(L"");
85 }
86 }
87
88 //strcat(file,"\\");
89 //strcat(file,path2);
90 file = File( file, wstring( path2 ) );
91 if( !file.exists() )
92 {
93 if(create) file.mkdir();
94 else
95 {
96 return File(L"");
97 }
98 }
99
100 //strcat(file,"\\");
101 //strcat(file,name);
102 //sprintf(file,"%s\\%s",file,name);
103 file = File( file, wstring( name ) );
104 if ( !file.exists() )
105 {
106 if (!create)
107 {
108 return File(L"");
109 }
110 }
111 return file;
112}
113
114LevelChunk *OldChunkStorage::load(Level *level, int x, int z)
115{
116 File file = getFile(x, z);
117 if (!file.getPath().empty() && file.exists())
118 {
119 // 4J - removed try/catch
120 // try {
121 // System.out.println("Loading chunk "+x+", "+z);
122 FileInputStream fis = FileInputStream(file);
123 CompoundTag *tag = NbtIo::readCompressed(&fis);
124 if (!tag->contains(L"Level"))
125 {
126 char buf[256];
127 sprintf(buf,"Chunk file at %d, %d is missing level data, skipping\n",x,z);
128 app.DebugPrintf(buf);
129 return NULL;
130 }
131 if (!tag->getCompound(L"Level")->contains(L"Blocks"))
132 {
133 char buf[256];
134 sprintf(buf,"Chunk file at %d, %d is missing block data, skipping\n",x,z);
135 app.DebugPrintf(buf);
136 return NULL;
137 }
138 LevelChunk *levelChunk = OldChunkStorage::load(level, tag->getCompound(L"Level"));
139 if (!levelChunk->isAt(x, z))
140 {
141 char buf[256];
142 sprintf(buf,"Chunk fileat %d, %d is in the wrong location; relocating. Expected %d, %d, got %d, %d\n",
143 x, z, x, z, levelChunk->x, levelChunk->z);
144 app.DebugPrintf(buf);
145 tag->putInt(L"xPos", x);
146 tag->putInt(L"zPos", z);
147 levelChunk = OldChunkStorage::load(level, tag->getCompound(L"Level"));
148 }
149
150 return levelChunk;
151 // } catch (Exception e) {
152 // e.printStackTrace();
153 // }
154 }
155 return NULL;
156}
157
158void OldChunkStorage::save(Level *level, LevelChunk *levelChunk)
159{
160 level->checkSession();
161 File file = getFile(levelChunk->x, levelChunk->z);
162 if (file.exists())
163 {
164 LevelData *levelData = level->getLevelData();
165 levelData->setSizeOnDisk( levelData->getSizeOnDisk() - file.length() );
166 }
167
168 // 4J - removed try/catch
169 // try {
170 //char tmpFileName[MAX_PATH_SIZE];
171 //sprintf(tmpFileName,"%s\\%s",dir,"tmp_chunk.dat");
172 File tmpFile( dir, L"tmp_chunk.dat" );
173 // System.out.println("Saving chunk "+levelChunk.x+", "+levelChunk.z);
174
175 FileOutputStream fos = FileOutputStream(tmpFile);
176 CompoundTag *tag = new CompoundTag();
177 CompoundTag *levelData = new CompoundTag();
178 tag->put(L"Level", levelData);
179 OldChunkStorage::save(levelChunk, level, levelData);
180 NbtIo::writeCompressed(tag, &fos);
181 fos.close();
182
183 if (file.exists())
184 {
185 //DeleteFile(file);
186 file._delete();
187 }
188 //MoveFile(tmpFile,file);
189 tmpFile.renameTo( file );
190
191 LevelData *levelInfo = level->getLevelData();
192 levelInfo->setSizeOnDisk(levelInfo->getSizeOnDisk() + file.length() );
193 // } catch (Exception e) {
194 // e.printStackTrace();
195 // }
196}
197
198bool OldChunkStorage::saveEntities(LevelChunk *lc, Level *level, CompoundTag *tag)
199{
200 // If we saved and it had no entities, and nothing has been added since skip this one
201 if(!lc->lastSaveHadEntities) return false;
202
203 lc->lastSaveHadEntities = false;
204 ListTag<CompoundTag> *entityTags = new ListTag<CompoundTag>();
205
206#ifdef _ENTITIES_RW_SECTION
207 EnterCriticalRWSection(&lc->m_csEntities, true);
208#else
209 EnterCriticalSection(&lc->m_csEntities);
210#endif
211 for (int i = 0; i < lc->ENTITY_BLOCKS_LENGTH; i++)
212 {
213 AUTO_VAR(itEnd, lc->entityBlocks[i]->end());
214 for( vector<shared_ptr<Entity> >::iterator it = lc->entityBlocks[i]->begin(); it != itEnd; it++ )
215 {
216 shared_ptr<Entity> e = *it;
217 lc->lastSaveHadEntities = true;
218 CompoundTag *teTag = new CompoundTag();
219 if (e->save(teTag))
220 {
221 entityTags->add(teTag);
222 }
223
224 }
225 }
226#ifdef _ENTITIES_RW_SECTION
227 LeaveCriticalRWSection(&lc->m_csEntities, true);
228#else
229 LeaveCriticalSection(&lc->m_csEntities);
230#endif
231
232 tag->put(L"Entities", entityTags);
233
234 return lc->lastSaveHadEntities;
235}
236
237void OldChunkStorage::save(LevelChunk *lc, Level *level, DataOutputStream *dos)
238{
239 dos->writeShort(SAVE_FILE_VERSION_NUMBER);
240 dos->writeInt(lc->x);
241 dos->writeInt(lc->z);
242 dos->writeLong(level->getGameTime());
243 dos->writeLong(lc->inhabitedTime);
244
245 PIXBeginNamedEvent(0,"Getting block data");
246 lc->writeCompressedBlockData(dos);
247 PIXEndNamedEvent();
248
249 PIXBeginNamedEvent(0,"Getting data data");
250 lc->writeCompressedDataData(dos);
251 PIXEndNamedEvent();
252
253 PIXBeginNamedEvent(0,"Getting sky and block light data");
254 lc->writeCompressedSkyLightData(dos);
255 lc->writeCompressedBlockLightData(dos);
256 PIXEndNamedEvent();
257
258 dos->write(lc->heightmap);
259 dos->writeShort(lc->terrainPopulated);
260 dos->write(lc->getBiomes());
261
262 PIXBeginNamedEvent(0,"Saving entities");
263 CompoundTag *tag = new CompoundTag();
264#ifndef SPLIT_SAVES
265 saveEntities(lc, level, tag);
266#endif
267
268 PIXBeginNamedEvent(0,"Saving tile entities");
269 ListTag<CompoundTag> *tileEntityTags = new ListTag<CompoundTag>();
270
271 AUTO_VAR(itEnd, lc->tileEntities.end());
272 for( unordered_map<TilePos, shared_ptr<TileEntity>, TilePosKeyHash, TilePosKeyEq>::iterator it = lc->tileEntities.begin();
273 it != itEnd; it++)
274 {
275 shared_ptr<TileEntity> te = it->second;
276 CompoundTag *teTag = new CompoundTag();
277 te->save(teTag);
278 tileEntityTags->add(teTag);
279 }
280 tag->put(L"TileEntities", tileEntityTags);
281 PIXEndNamedEvent();
282
283 PIXBeginNamedEvent(0,"Saving tile tick data");
284 vector<TickNextTickData > *ticksInChunk = level->fetchTicksInChunk(lc, false);
285 if (ticksInChunk != NULL)
286 {
287 __int64 levelTime = level->getGameTime();
288
289 ListTag<CompoundTag> *tickTags = new ListTag<CompoundTag>();
290 for( int i = 0; i < ticksInChunk->size(); i++ )
291 {
292 TickNextTickData td = ticksInChunk->at(i);
293 CompoundTag *teTag = new CompoundTag();
294 teTag->putInt(L"i", td.tileId);
295 teTag->putInt(L"x", td.x);
296 teTag->putInt(L"y", td.y);
297 teTag->putInt(L"z", td.z);
298 teTag->putInt(L"t", (int) (td.m_delay - levelTime));
299
300 tickTags->add(teTag);
301 }
302 tag->put(L"TileTicks", tickTags);
303 }
304 delete ticksInChunk;
305 PIXEndNamedEvent();
306
307 NbtIo::write(tag,dos);
308 delete tag;
309 PIXEndNamedEvent();
310}
311
312void OldChunkStorage::save(LevelChunk *lc, Level *level, CompoundTag *tag)
313{
314 level->checkSession();
315 tag->putInt(L"xPos", lc->x);
316 tag->putInt(L"zPos", lc->z);
317 tag->putLong(L"LastUpdate", level->getGameTime());
318 tag->putLong(L"InhabitedTime", lc->inhabitedTime);
319 // 4J - changes here for new storage. Now have static storage for getting lighting data for block, data, and sky & block lighting. This
320 // wasn't required in the original version as we could just reference the information in the level itself, but with our new storage system
321 // the full data doesn't normally exist & so getSkyLightData/getBlockLightData etc. need somewhere to output this data. Making this static so
322 // that we aren't dynamically allocating memory in the server thread when writing chunks as this causes serious stalling on the main thread.
323 // Will be fine so long as we only actually create tags for once chunk at a time.
324
325 // 4J Stu - As we now save on multiple threads, the static data has been moved to TLS
326 ThreadStorage *tls = (ThreadStorage *)TlsGetValue(tlsIdx);
327
328 PIXBeginNamedEvent(0,"Getting block data");
329 //static byteArray blockData = byteArray(32768);
330 lc->getBlockData(tls->blockData);
331 tag->putByteArray(L"Blocks", tls->blockData);
332 PIXEndNamedEvent();
333
334 PIXBeginNamedEvent(0,"Getting data data");
335 //static byteArray dataData = byteArray(16384);
336 lc->getDataData(tls->dataData);
337 tag->putByteArray(L"Data", tls->dataData);
338 PIXEndNamedEvent();
339
340 PIXBeginNamedEvent(0,"Getting sky and block light data");
341 //static byteArray skyLightData = byteArray(16384);
342 //static byteArray blockLightData = byteArray(16384);
343 lc->getSkyLightData(tls->skyLightData);
344 lc->getBlockLightData(tls->blockLightData);
345 tag->putByteArray(L"SkyLight", tls->skyLightData);
346 tag->putByteArray(L"BlockLight", tls->blockLightData);
347 PIXEndNamedEvent();
348
349 tag->putByteArray(L"HeightMap", lc->heightmap);
350 tag->putShort(L"TerrainPopulatedFlags", lc->terrainPopulated); // 4J - changed from "TerrainPopulated" to "TerrainPopulatedFlags" as now stores a bitfield, java stores a bool
351 tag->putByteArray(L"Biomes", lc->getBiomes());
352
353 PIXBeginNamedEvent(0,"Saving entities");
354#ifndef SPLIT_SAVES
355 saveEntities(lc, level, tag);
356#endif
357
358 PIXBeginNamedEvent(0,"Saving tile entities");
359 ListTag<CompoundTag> *tileEntityTags = new ListTag<CompoundTag>();
360
361 AUTO_VAR(itEnd, lc->tileEntities.end());
362 for( unordered_map<TilePos, shared_ptr<TileEntity>, TilePosKeyHash, TilePosKeyEq>::iterator it = lc->tileEntities.begin();
363 it != itEnd; it++)
364 {
365 shared_ptr<TileEntity> te = it->second;
366 CompoundTag *teTag = new CompoundTag();
367 te->save(teTag);
368 tileEntityTags->add(teTag);
369 }
370 tag->put(L"TileEntities", tileEntityTags);
371 PIXEndNamedEvent();
372
373 PIXBeginNamedEvent(0,"Saving tile tick data");
374 vector<TickNextTickData > *ticksInChunk = level->fetchTicksInChunk(lc, false);
375 if (ticksInChunk != NULL)
376 {
377 __int64 levelTime = level->getGameTime();
378
379 ListTag<CompoundTag> *tickTags = new ListTag<CompoundTag>();
380 for( int i = 0; i < ticksInChunk->size(); i++ )
381 {
382 TickNextTickData td = ticksInChunk->at(i);
383 CompoundTag *teTag = new CompoundTag();
384 teTag->putInt(L"i", td.tileId);
385 teTag->putInt(L"x", td.x);
386 teTag->putInt(L"y", td.y);
387 teTag->putInt(L"z", td.z);
388 teTag->putInt(L"t", (int) (td.m_delay - levelTime));
389 teTag->putInt(L"p", td.priorityTilt);
390
391 tickTags->add(teTag);
392 }
393 tag->put(L"TileTicks", tickTags);
394 }
395 delete ticksInChunk;
396 PIXEndNamedEvent();
397 PIXEndNamedEvent();
398}
399
400void OldChunkStorage::loadEntities(LevelChunk *lc, Level *level, CompoundTag *tag)
401{
402 ListTag<CompoundTag> *entityTags = (ListTag<CompoundTag> *) tag->getList(L"Entities");
403 if (entityTags != NULL)
404 {
405 for (int i = 0; i < entityTags->size(); i++)
406 {
407 CompoundTag *teTag = entityTags->get(i);
408 shared_ptr<Entity> te = EntityIO::loadStatic(teTag, level);
409 lc->lastSaveHadEntities = true;
410 if (te != NULL)
411 {
412 lc->addEntity(te);
413 }
414 }
415 }
416
417 ListTag<CompoundTag> *tileEntityTags = (ListTag<CompoundTag> *) tag->getList(L"TileEntities");
418 if (tileEntityTags != NULL)
419 {
420 for (int i = 0; i < tileEntityTags->size(); i++)
421 {
422 CompoundTag *teTag = tileEntityTags->get(i);
423 shared_ptr<TileEntity> te = TileEntity::loadStatic(teTag);
424 if (te != NULL)
425 {
426 lc->addTileEntity(te);
427 }
428 }
429 }
430}
431
432LevelChunk *OldChunkStorage::load(Level *level, DataInputStream *dis)
433{
434 PIXBeginNamedEvent(0,"Loading chunk");
435 short version = dis->readShort();
436 int x = dis->readInt();
437 int z = dis->readInt();
438 int time = dis->readLong();
439
440 LevelChunk *levelChunk = new LevelChunk(level, x, z);
441
442 if (version >= SAVE_FILE_VERSION_CHUNK_INHABITED_TIME)
443 {
444 levelChunk->inhabitedTime = dis->readLong();
445 }
446
447 levelChunk->readCompressedBlockData(dis);
448 levelChunk->readCompressedDataData(dis);
449 levelChunk->readCompressedSkyLightData(dis);
450 levelChunk->readCompressedBlockLightData(dis);
451
452 dis->readFully(levelChunk->heightmap);
453
454 levelChunk->terrainPopulated = dis->readShort();
455 // If all neighbours have been post-processed, then we should have done the post-post-processing now. Check that this is set as if it isn't then we won't be able
456 // to send network data for chunks, and we won't ever try and set it again as all the directional flags are now already set - should only be an issue for old maps
457 // before this flag was added.
458 if( ( levelChunk->terrainPopulated & LevelChunk::sTerrainPopulatedAllNeighbours ) == LevelChunk::sTerrainPopulatedAllNeighbours )
459 {
460 levelChunk->terrainPopulated |= LevelChunk::sTerrainPostPostProcessed;
461 }
462
463#ifndef _CONTENT_PACKAGE
464 if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_EnableBiomeOverride))
465 {
466 // Read the biome data from the stream, but don't use it
467 byteArray dummyBiomes(levelChunk->biomes.length);
468 dis->readFully(dummyBiomes);
469 delete [] dummyBiomes.data;
470 }
471 else
472#endif
473 {
474 dis->readFully(levelChunk->biomes);
475 }
476
477 CompoundTag *tag = NbtIo::read(dis);
478
479 loadEntities(levelChunk, level, tag);
480
481 if (tag->contains(L"TileTicks"))
482 {
483 PIXBeginNamedEvent(0,"Loading TileTicks");
484 ListTag<CompoundTag> *tileTicks = (ListTag<CompoundTag> *) tag->getList(L"TileTicks");
485
486 if (tileTicks != NULL)
487 {
488 for (int i = 0; i < tileTicks->size(); i++)
489 {
490 CompoundTag *teTag = tileTicks->get(i);
491
492 level->forceAddTileTick(teTag->getInt(L"x"), teTag->getInt(L"y"), teTag->getInt(L"z"), teTag->getInt(L"i"), teTag->getInt(L"t"), teTag->getInt(L"p"));
493 }
494 }
495 PIXEndNamedEvent();
496 }
497
498 delete tag;
499
500 PIXEndNamedEvent();
501
502 return levelChunk;
503}
504
505LevelChunk *OldChunkStorage::load(Level *level, CompoundTag *tag)
506{
507 int x = tag->getInt(L"xPos");
508 int z = tag->getInt(L"zPos");
509
510 LevelChunk *levelChunk = new LevelChunk(level, x, z);
511 // 4J - the original code uses the data in the tag directly, but this is now just used as a source when creating the compressed data, so
512 // we need to free up the data in the tag once we are done
513 levelChunk->setBlockData(tag->getByteArray(L"Blocks"));
514 delete [] tag->getByteArray(L"Blocks").data;
515 // levelChunk->blocks = tag->getByteArray(L"Blocks");
516
517 // 4J - the original code uses the data in the tag directly, but this is now just used as a source when creating the compressed data, so
518 // we need to free up the data in the tag once we are done
519 levelChunk->setDataData(tag->getByteArray(L"Data"));
520 delete [] tag->getByteArray(L"Data").data;
521
522 // 4J - changed to use our new methods for accessing lighting
523 levelChunk->setSkyLightData(tag->getByteArray(L"SkyLight"));
524 levelChunk->setBlockLightData(tag->getByteArray(L"BlockLight"));
525
526 // In the original code (commented out below) constructing DataLayers from these arrays uses the data directly and so it doesn't need deleted. The new
527 // setSkyLightData/setBlockLightData take a copy of the data so we need to delete the local one now
528 delete [] tag->getByteArray(L"SkyLight").data;
529 delete [] tag->getByteArray(L"BlockLight").data;
530
531 // levelChunk->skyLight = new DataLayer(tag->getByteArray(L"SkyLight"), level->depthBits);
532 // levelChunk->blockLight = new DataLayer(tag->getByteArray(L"BlockLight"), level->depthBits);
533
534 delete [] levelChunk->heightmap.data;
535 levelChunk->heightmap = tag->getByteArray(L"HeightMap");
536 // 4J - TerrainPopulated was a bool (java), then changed to be a byte bitfield, then replaced with TerrainPopulatedShort to store a wider bitfield
537 if( tag->get(L"TerrainPopulated") )
538 {
539 // Java bool type or byte bitfield
540 levelChunk->terrainPopulated = tag->getByte(L"TerrainPopulated");
541 if( levelChunk->terrainPopulated >= 1 ) levelChunk->terrainPopulated = LevelChunk::sTerrainPopulatedAllNeighbours | LevelChunk::sTerrainPostPostProcessed; // Convert from old bool type to new bitfield
542 }
543 else
544 {
545 // New style short
546 levelChunk->terrainPopulated = tag->getShort(L"TerrainPopulatedFlags");
547 // If all neighbours have been post-processed, then we should have done the post-post-processing now. Check that this is set as if it isn't then we won't be able
548 // to send network data for chunks, and we won't ever try and set it again as all the directional flags are now already set - should only be an issue for old maps
549 // before this flag was added.
550 if( ( levelChunk->terrainPopulated & LevelChunk::sTerrainPopulatedAllNeighbours ) == LevelChunk::sTerrainPopulatedAllNeighbours )
551 {
552 levelChunk->terrainPopulated |= LevelChunk::sTerrainPostPostProcessed;
553 }
554 }
555
556#if 0
557 // 4J - removed - we shouldn't need this any more
558 if (!levelChunk->data->isValid())
559 {
560 levelChunk->data = new DataLayer(LevelChunk::BLOCKS_LENGTH, level->depthBits); // 4J - BLOCKS_LENGTH was levelChunk->blocks.length
561 }
562#endif
563
564 // 4J removed - we shouldn't need this any more
565#if 0
566 if (levelChunk->heightmap.data == NULL || !levelChunk->skyLight->isValid())
567 {
568 static int chunksUpdated = 0;
569 delete [] levelChunk->heightmap.data;
570 levelChunk->heightmap = byteArray(16 * 16);
571 delete levelChunk->skyLight;
572 levelChunk->skyLight = new DataLayer(levelChunk->blocks.length, level->depthBits);
573 levelChunk->recalcHeightmap();
574 }
575
576 if (!levelChunk->blockLight->isValid())
577 {
578 delete levelChunk->blockLight;
579 levelChunk->blockLight = new DataLayer(levelChunk->blocks.length, level->depthBits);
580 levelChunk->recalcBlockLights();
581 }
582#endif
583
584#ifndef _CONTENT_PACKAGE
585 if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_EnableBiomeOverride))
586 {
587 // Do nothing
588 }
589 else
590#endif
591 {
592 if (tag->contains(L"Biomes"))
593 {
594 levelChunk->setBiomes(tag->getByteArray(L"Biomes"));
595 }
596 }
597
598 loadEntities(levelChunk, level, tag);
599
600 if (tag->contains(L"TileTicks"))
601 {
602 ListTag<CompoundTag> *tileTicks = (ListTag<CompoundTag> *) tag->getList(L"TileTicks");
603
604 if (tileTicks != NULL)
605 {
606 for (int i = 0; i < tileTicks->size(); i++)
607 {
608 CompoundTag *teTag = tileTicks->get(i);
609
610 level->forceAddTileTick(teTag->getInt(L"x"), teTag->getInt(L"y"), teTag->getInt(L"z"), teTag->getInt(L"i"), teTag->getInt(L"t"), teTag->getInt(L"p"));
611 }
612 }
613 }
614
615 return levelChunk;
616}
617
618void OldChunkStorage::tick()
619{
620}
621
622void OldChunkStorage::flush()
623{
624}
625
626void OldChunkStorage::saveEntities(Level *level, LevelChunk *levelChunk)
627{
628}