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 "System.h"
3#include "net.minecraft.world.entity.player.h"
4#include "net.minecraft.world.level.h"
5#include "net.minecraft.world.level.chunk.storage.h"
6#include "net.minecraft.world.level.dimension.h"
7#include "com.mojang.nbt.h"
8#include "File.h"
9#include "DataInputStream.h"
10#include "FileInputStream.h"
11#include "LevelData.h"
12#include "DirectoryLevelStorage.h"
13#include "ConsoleSaveFileIO.h"
14
15const wstring DirectoryLevelStorage::sc_szPlayerDir(L"players/");
16
17_MapDataMappings::_MapDataMappings()
18{
19#ifndef _DURANGO
20 ZeroMemory(xuids,sizeof(PlayerUID)*MAXIMUM_MAP_SAVE_DATA);
21#endif
22 ZeroMemory(dimensions,sizeof(byte)*(MAXIMUM_MAP_SAVE_DATA/4));
23}
24
25int _MapDataMappings::getDimension(int id)
26{
27 int offset = (2*(id%4));
28 int val = (dimensions[id>>2] & (3 << offset))>>offset;
29
30 int returnVal=0;
31
32 switch(val)
33 {
34 case 0:
35 returnVal = 0; // Overworld
36 break;
37 case 1:
38 returnVal = -1; // Nether
39 break;
40 case 2:
41 returnVal = 1; // End
42 break;
43 default:
44#ifndef _CONTENT_PACKAGE
45 printf("Read invalid dimension from MapDataMapping\n");
46 __debugbreak();
47#endif
48 break;
49 }
50 return returnVal;
51}
52
53void _MapDataMappings::setMapping(int id, PlayerUID xuid, int dimension)
54{
55 xuids[id] = xuid;
56
57 int offset = (2*(id%4));
58
59 // Reset it first
60 dimensions[id>>2] &= ~( 2 << offset );
61 switch(dimension)
62 {
63 case 0: // Overworld
64 //dimensions[id>>2] &= ~( 2 << offset );
65 break;
66 case -1: // Nether
67 dimensions[id>>2] |= ( 1 << offset );
68 break;
69 case 1: // End
70 dimensions[id>>2] |= ( 2 << offset );
71 break;
72 default:
73#ifndef _CONTENT_PACKAGE
74 printf("Trinyg to set a MapDataMapping for an invalid dimension.\n");
75 __debugbreak();
76#endif
77 break;
78 }
79}
80
81// Old version the only used 1 bit for dimension indexing
82_MapDataMappings_old::_MapDataMappings_old()
83{
84#ifndef _DURANGO
85 ZeroMemory(xuids,sizeof(PlayerUID)*MAXIMUM_MAP_SAVE_DATA);
86#endif
87 ZeroMemory(dimensions,sizeof(byte)*(MAXIMUM_MAP_SAVE_DATA/8));
88}
89
90int _MapDataMappings_old::getDimension(int id)
91{
92 return dimensions[id>>3] & (128 >> (id%8) ) ? -1 : 0;
93}
94
95void _MapDataMappings_old::setMapping(int id, PlayerUID xuid, int dimension)
96{
97 xuids[id] = xuid;
98 if( dimension == 0 )
99 {
100 dimensions[id>>3] &= ~( 128 >> (id%8) );
101 }
102 else
103 {
104 dimensions[id>>3] |= ( 128 >> (id%8) );
105 }
106}
107
108#ifdef _LARGE_WORLDS
109void DirectoryLevelStorage::PlayerMappings::addMapping(int id, int centreX, int centreZ, int dimension, int scale)
110{
111 __int64 index = ( ((__int64)(centreZ & 0x1FFFFFFF)) << 34) | ( ((__int64)(centreX & 0x1FFFFFFF)) << 5) | ( (scale & 0x7) << 2) | (dimension & 0x3);
112 m_mappings[index] = id;
113 //app.DebugPrintf("Adding mapping: %d - (%d,%d)/%d/%d [%I64d - 0x%016llx]\n", id, centreX, centreZ, dimension, scale, index, index);
114}
115
116bool DirectoryLevelStorage::PlayerMappings::getMapping(int &id, int centreX, int centreZ, int dimension, int scale)
117{
118 //__int64 zMasked = centreZ & 0x1FFFFFFF;
119 //__int64 xMasked = centreX & 0x1FFFFFFF;
120 //__int64 zShifted = zMasked << 34;
121 //__int64 xShifted = xMasked << 5;
122 //app.DebugPrintf("xShifted = %d (0x%016x), zShifted = %I64d (0x%016llx)\n", xShifted, xShifted, zShifted, zShifted);
123 __int64 index = ( ((__int64)(centreZ & 0x1FFFFFFF)) << 34) | ( ((__int64)(centreX & 0x1FFFFFFF)) << 5) | ( (scale & 0x7) << 2) | (dimension & 0x3);
124 AUTO_VAR(it,m_mappings.find(index));
125 if(it != m_mappings.end())
126 {
127 id = it->second;
128 //app.DebugPrintf("Found mapping: %d - (%d,%d)/%d/%d [%I64d - 0x%016llx]\n", id, centreX, centreZ, dimension, scale, index, index);
129 return true;
130 }
131 else
132 {
133 //app.DebugPrintf("Failed to find mapping: (%d,%d)/%d/%d [%I64d - 0x%016llx]\n", centreX, centreZ, dimension, scale, index, index);
134 return false;
135 }
136}
137
138void DirectoryLevelStorage::PlayerMappings::writeMappings(DataOutputStream *dos)
139{
140 dos->writeInt(m_mappings.size());
141 for(AUTO_VAR(it, m_mappings.begin()); it != m_mappings.end(); ++it)
142 {
143 app.DebugPrintf(" -- %lld (0x%016llx) = %d\n", it->first, it->first, it->second);
144 dos->writeLong(it->first);
145 dos->writeInt(it->second);
146 }
147}
148
149void DirectoryLevelStorage::PlayerMappings::readMappings(DataInputStream *dis)
150{
151 int count = dis->readInt();
152 for(unsigned int i = 0; i < count; ++i)
153 {
154 __int64 index = dis->readLong();
155 int id = dis->readInt();
156 m_mappings[index] = id;
157 app.DebugPrintf(" -- %lld (0x%016llx) = %d\n", index, index, id);
158 }
159}
160#endif
161
162DirectoryLevelStorage::DirectoryLevelStorage(ConsoleSaveFile *saveFile, const File dir, const wstring& levelId, bool createPlayerDir) : sessionId( System::currentTimeMillis() ),
163 dir( L"" ), playerDir( sc_szPlayerDir ), dataDir( wstring(L"data/") ), levelId(levelId)
164{
165 m_saveFile = saveFile;
166 m_bHasLoadedMapDataMappings = false;
167
168#ifdef _LARGE_WORLDS
169 m_usedMappings = byteArray(MAXIMUM_MAP_SAVE_DATA/8);
170#endif
171}
172
173DirectoryLevelStorage::~DirectoryLevelStorage()
174{
175 delete m_saveFile;
176
177 for(AUTO_VAR(it,m_cachedSaveData.begin()); it != m_cachedSaveData.end(); ++it)
178 {
179 delete it->second;
180 }
181
182#ifdef _LARGE_WORLDS
183 delete m_usedMappings.data;
184#endif
185}
186
187void DirectoryLevelStorage::initiateSession()
188{
189 // 4J Jev, removed try/catch.
190
191 File dataFile = File( dir, wstring(L"session.lock") );
192 FileOutputStream fos = FileOutputStream(dataFile);
193 DataOutputStream dos = DataOutputStream(&fos);
194 dos.writeLong(sessionId);
195 dos.close();
196
197}
198
199File DirectoryLevelStorage::getFolder()
200{
201 return dir;
202}
203
204void DirectoryLevelStorage::checkSession()
205{
206 // 4J-PB - Not in the Xbox game
207
208 /*
209 File dataFile = File( dir, wstring(L"session.lock"));
210 FileInputStream fis = FileInputStream(dataFile);
211 DataInputStream dis = DataInputStream(&fis);
212 dis.close();
213 */
214}
215
216ChunkStorage *DirectoryLevelStorage::createChunkStorage(Dimension *dimension)
217{
218 // 4J Jev, removed try/catch.
219
220 if (dynamic_cast<HellDimension *>(dimension) != NULL)
221 {
222 File dir2 = File(dir, LevelStorage::NETHER_FOLDER);
223 //dir2.mkdirs(); // 4J Removed
224 return new OldChunkStorage(dir2, true);
225 }
226 if (dynamic_cast<TheEndDimension *>(dimension) != NULL)
227 {
228 File dir2 = File(dir, LevelStorage::ENDER_FOLDER);
229 //dir2.mkdirs(); // 4J Removed
230 return new OldChunkStorage(dir2, true);
231 }
232
233 return new OldChunkStorage(dir, true);
234}
235
236LevelData *DirectoryLevelStorage::prepareLevel()
237{
238 // 4J Stu Added
239#ifdef _LARGE_WORLDS
240 ConsoleSavePath mapFile = getDataFile(L"largeMapDataMappings");
241#else
242 ConsoleSavePath mapFile = getDataFile(L"mapDataMappings");
243#endif
244 if (!m_bHasLoadedMapDataMappings && !mapFile.getName().empty() && getSaveFile()->doesFileExist( mapFile ))
245 {
246 DWORD NumberOfBytesRead;
247 FileEntry *fileEntry = getSaveFile()->createFile(mapFile);
248
249#ifdef __PS3__
250 // 4J Stu - This version changed happened before initial release
251 if(getSaveFile()->getSaveVersion() < SAVE_FILE_VERSION_CHANGE_MAP_DATA_MAPPING_SIZE)
252 {
253 // Delete the old file
254 if(fileEntry) getSaveFile()->deleteFile( fileEntry );
255
256 // Save a new, blank version
257 saveMapIdLookup();
258 }
259 else
260#elif defined(_DURANGO)
261 // 4J Stu - This version changed happened before initial release
262 if(getSaveFile()->getSaveVersion() < SAVE_FILE_VERSION_DURANGO_CHANGE_MAP_DATA_MAPPING_SIZE)
263 {
264 // Delete the old file
265 if(fileEntry) getSaveFile()->deleteFile( fileEntry );
266
267 // Save a new, blank version
268 saveMapIdLookup();
269 }
270 else
271#endif
272 {
273 getSaveFile()->setFilePointer(fileEntry,0,NULL, FILE_BEGIN);
274
275#ifdef _LARGE_WORLDS
276 byteArray data(fileEntry->getFileSize());
277 getSaveFile()->readFile( fileEntry, data.data, fileEntry->getFileSize(), &NumberOfBytesRead);
278 assert( NumberOfBytesRead == fileEntry->getFileSize() );
279
280 ByteArrayInputStream bais(data);
281 DataInputStream dis(&bais);
282 int count = dis.readInt();
283 app.DebugPrintf("Loading %d mappings\n", count);
284 for(unsigned int i = 0; i < count; ++i)
285 {
286 PlayerUID playerUid = dis.readPlayerUID();
287#ifdef _WINDOWS64
288 app.DebugPrintf(" -- %d\n", playerUid);
289#else
290 app.DebugPrintf(" -- %ls\n", playerUid.toString().c_str());
291#endif
292 m_playerMappings[playerUid].readMappings(&dis);
293 }
294 dis.readFully(m_usedMappings);
295#else
296
297 if(getSaveFile()->getSaveVersion() < END_DIMENSION_MAP_MAPPINGS_SAVE_VERSION)
298 {
299 MapDataMappings_old oldMapDataMappings;
300 getSaveFile()->readFile( fileEntry,
301 &oldMapDataMappings, // data buffer
302 sizeof(MapDataMappings_old), // number of bytes to read
303 &NumberOfBytesRead // number of bytes read
304 );
305 assert( NumberOfBytesRead == sizeof(MapDataMappings_old) );
306
307 for(unsigned int i = 0; i < MAXIMUM_MAP_SAVE_DATA; ++i)
308 {
309 m_saveableMapDataMappings.setMapping(i,oldMapDataMappings.xuids[i],oldMapDataMappings.getDimension(i));
310 }
311 }
312 else
313 {
314 getSaveFile()->readFile( fileEntry,
315 &m_saveableMapDataMappings, // data buffer
316 sizeof(MapDataMappings), // number of bytes to read
317 &NumberOfBytesRead // number of bytes read
318 );
319 assert( NumberOfBytesRead == sizeof(MapDataMappings) );
320 }
321
322 memcpy(&m_mapDataMappings,&m_saveableMapDataMappings,sizeof(MapDataMappings));
323#endif
324
325
326 // Write out our changes now
327 if(getSaveFile()->getSaveVersion() < END_DIMENSION_MAP_MAPPINGS_SAVE_VERSION) saveMapIdLookup();
328 }
329
330 m_bHasLoadedMapDataMappings = true;
331 }
332
333 // 4J Jev, removed try/catch
334
335 ConsoleSavePath dataFile = ConsoleSavePath( wstring( L"level.dat" ) );
336
337 if ( m_saveFile->doesFileExist( dataFile ) )
338 {
339 ConsoleSaveFileInputStream fis = ConsoleSaveFileInputStream(m_saveFile, dataFile);
340 CompoundTag *root = NbtIo::readCompressed(&fis);
341 CompoundTag *tag = root->getCompound(L"Data");
342 LevelData *ret = new LevelData(tag);
343 delete root;
344 return ret;
345 }
346
347 return NULL;
348}
349
350void DirectoryLevelStorage::saveLevelData(LevelData *levelData, vector<shared_ptr<Player> > *players)
351{
352 // 4J Jev, removed try/catch
353
354 CompoundTag *dataTag = levelData->createTag(players);
355
356 CompoundTag *root = new CompoundTag();
357 root->put(L"Data", dataTag);
358
359 ConsoleSavePath currentFile = ConsoleSavePath( wstring( L"level.dat" ) );
360
361 ConsoleSaveFileOutputStream fos = ConsoleSaveFileOutputStream( m_saveFile, currentFile );
362 NbtIo::writeCompressed(root, &fos);
363
364 delete root;
365}
366
367void DirectoryLevelStorage::saveLevelData(LevelData *levelData)
368{
369 // 4J Jev, removed try/catch
370
371 CompoundTag *dataTag = levelData->createTag();
372
373 CompoundTag *root = new CompoundTag();
374 root->put(L"Data", dataTag);
375
376 ConsoleSavePath currentFile = ConsoleSavePath( wstring( L"level.dat" ) );
377
378 ConsoleSaveFileOutputStream fos = ConsoleSaveFileOutputStream( m_saveFile, currentFile );
379 NbtIo::writeCompressed(root, &fos);
380
381 delete root;
382}
383
384void DirectoryLevelStorage::save(shared_ptr<Player> player)
385{
386 // 4J Jev, removed try/catch.
387 PlayerUID playerXuid = player->getXuid();
388#if defined(__PS3__) || defined(__ORBIS__)
389 if( playerXuid != INVALID_XUID )
390#else
391 if( playerXuid != INVALID_XUID && !player->isGuest() )
392#endif
393 {
394 CompoundTag *tag = new CompoundTag();
395 player->saveWithoutId(tag);
396#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__)
397 ConsoleSavePath realFile = ConsoleSavePath( m_saveFile->getPlayerDataFilenameForSave(playerXuid).c_str() );
398#elif defined(_DURANGO)
399 ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + player->getXuid().toString() + L".dat" );
400#else
401 ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + _toString( player->getXuid() ) + L".dat" );
402#endif
403 // If saves are disabled (e.g. because we are writing the save buffer to disk) then cache this player data
404 if(StorageManager.GetSaveDisabled())
405 {
406 ByteArrayOutputStream *bos = new ByteArrayOutputStream();
407 NbtIo::writeCompressed(tag,bos);
408
409 AUTO_VAR(it, m_cachedSaveData.find(realFile.getName()));
410 if(it != m_cachedSaveData.end() )
411 {
412 delete it->second;
413 }
414 m_cachedSaveData[realFile.getName()] = bos;
415 app.DebugPrintf("Cached saving of file %ls due to saves being disabled\n", realFile.getName().c_str() );
416 }
417 else
418 {
419 ConsoleSaveFileOutputStream fos = ConsoleSaveFileOutputStream( m_saveFile, realFile );
420 NbtIo::writeCompressed(tag, &fos);
421 }
422 delete tag;
423 }
424 else if( playerXuid != INVALID_XUID )
425 {
426 app.DebugPrintf("Not saving player as their XUID is a guest\n");
427 dontSaveMapMappingForPlayer(playerXuid);
428 }
429}
430
431// 4J Changed return val to bool to check if new player or loaded player
432CompoundTag *DirectoryLevelStorage::load(shared_ptr<Player> player)
433{
434 CompoundTag *tag = loadPlayerDataTag( player->getXuid() );
435 if (tag != NULL)
436 {
437 player->load(tag);
438 }
439 return tag;
440}
441
442CompoundTag *DirectoryLevelStorage::loadPlayerDataTag(PlayerUID xuid)
443{
444 // 4J Jev, removed try/catch.
445#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__)
446 ConsoleSavePath realFile = ConsoleSavePath( m_saveFile->getPlayerDataFilenameForLoad(xuid).c_str() );
447#elif defined(_DURANGO)
448 ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + xuid.toString() + L".dat" );
449#else
450 ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + _toString( xuid ) + L".dat" );
451#endif
452 AUTO_VAR(it, m_cachedSaveData.find(realFile.getName()));
453 if(it != m_cachedSaveData.end() )
454 {
455 ByteArrayOutputStream *bos = it->second;
456 ByteArrayInputStream bis(bos->buf, 0, bos->size());
457 CompoundTag *tag = NbtIo::readCompressed(&bis);
458 bis.reset();
459 app.DebugPrintf("Loaded player data from cached file %ls\n", realFile.getName().c_str() );
460 return tag;
461 }
462 else if ( m_saveFile->doesFileExist( realFile ) )
463 {
464 ConsoleSaveFileInputStream fis = ConsoleSaveFileInputStream(m_saveFile, realFile);
465 return NbtIo::readCompressed(&fis);
466 }
467 return NULL;
468}
469
470// 4J Added function
471void DirectoryLevelStorage::clearOldPlayerFiles()
472{
473 if(StorageManager.GetSaveDisabled() ) return;
474
475#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__)
476 vector<FileEntry *> *playerFiles = m_saveFile->getValidPlayerDatFiles();
477#else
478 vector<FileEntry *> *playerFiles = m_saveFile->getFilesWithPrefix( playerDir.getName() );
479#endif
480
481 if( playerFiles != NULL )
482 {
483#ifndef _FINAL_BUILD
484 if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_DistributableSave))
485 {
486 for(unsigned int i = 0; i < playerFiles->size(); ++i )
487 {
488 FileEntry *file = playerFiles->at(i);
489 wstring xuidStr = replaceAll( replaceAll(file->data.filename,playerDir.getName(),L""),L".dat",L"");
490#if defined(__PS3__) || defined(__ORBIS__) || defined(_DURANGO)
491 PlayerUID xuid(xuidStr);
492#else
493 PlayerUID xuid = _fromString<PlayerUID>(xuidStr);
494#endif
495 deleteMapFilesForPlayer(xuid);
496 m_saveFile->deleteFile( playerFiles->at(i) );
497 }
498 }
499 else
500#endif
501 if( playerFiles->size() > MAX_PLAYER_DATA_SAVES )
502 {
503 sort(playerFiles->begin(), playerFiles->end(), FileEntry::newestFirst );
504
505 for(unsigned int i = MAX_PLAYER_DATA_SAVES; i < playerFiles->size(); ++i )
506 {
507 FileEntry *file = playerFiles->at(i);
508 wstring xuidStr = replaceAll( replaceAll(file->data.filename,playerDir.getName(),L""),L".dat",L"");
509#if defined(__PS3__) || defined(__ORBIS__) || defined(_DURANGO)
510 PlayerUID xuid(xuidStr);
511#else
512 PlayerUID xuid = _fromString<PlayerUID>(xuidStr);
513#endif
514 deleteMapFilesForPlayer(xuid);
515 m_saveFile->deleteFile( playerFiles->at(i) );
516 }
517 }
518
519 delete playerFiles;
520 }
521}
522
523PlayerIO *DirectoryLevelStorage::getPlayerIO()
524{
525 return this;
526}
527
528void DirectoryLevelStorage::closeAll()
529{
530}
531
532ConsoleSavePath DirectoryLevelStorage::getDataFile(const wstring& id)
533{
534 return ConsoleSavePath( dataDir.getName() + id + L".dat" );
535}
536
537wstring DirectoryLevelStorage::getLevelId()
538{
539 return levelId;
540}
541
542void DirectoryLevelStorage::flushSaveFile(bool autosave)
543{
544#ifndef _CONTENT_PACKAGE
545 if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_DistributableSave))
546 {
547 // Delete gamerules files if it exists
548 ConsoleSavePath gameRulesFiles(GAME_RULE_SAVENAME);
549 if(m_saveFile->doesFileExist(gameRulesFiles))
550 {
551 FileEntry *fe = m_saveFile->createFile(gameRulesFiles);
552 m_saveFile->deleteFile( fe );
553 }
554 }
555#endif
556 m_saveFile->Flush(autosave);
557}
558
559// 4J Added
560void DirectoryLevelStorage::resetNetherPlayerPositions()
561{
562 if(app.GetResetNether())
563 {
564#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__)
565 vector<FileEntry *> *playerFiles = m_saveFile->getValidPlayerDatFiles();
566#else
567 vector<FileEntry *> *playerFiles = m_saveFile->getFilesWithPrefix( playerDir.getName() );
568#endif
569
570 if( playerFiles != NULL )
571 {
572 for( AUTO_VAR(it, playerFiles->begin()); it != playerFiles->end(); ++it)
573 {
574 FileEntry * realFile = *it;
575 ConsoleSaveFileInputStream fis = ConsoleSaveFileInputStream(m_saveFile, realFile);
576 CompoundTag *tag = NbtIo::readCompressed(&fis);
577 if (tag != NULL)
578 {
579 // If the player is in the nether, set their y position above the top of the nether
580 // This will force the player to be spawned in a valid position in the overworld when they are loaded
581 if(tag->contains(L"Dimension") && tag->getInt(L"Dimension") == LevelData::DIMENSION_NETHER && tag->contains(L"Pos"))
582 {
583 ListTag<DoubleTag> *pos = (ListTag<DoubleTag> *) tag->getList(L"Pos");
584 pos->get(1)->data = DBL_MAX;
585
586 ConsoleSaveFileOutputStream fos = ConsoleSaveFileOutputStream( m_saveFile, realFile );
587 NbtIo::writeCompressed(tag, &fos);
588 }
589 delete tag;
590 }
591 }
592 delete playerFiles;
593 }
594 }
595}
596
597int DirectoryLevelStorage::getAuxValueForMap(PlayerUID xuid, int dimension, int centreXC, int centreZC, int scale)
598{
599 int mapId = -1;
600 bool foundMapping = false;
601
602#ifdef _LARGE_WORLDS
603 AUTO_VAR(it, m_playerMappings.find(xuid) );
604 if(it != m_playerMappings.end())
605 {
606 foundMapping = it->second.getMapping(mapId, centreXC, centreZC, dimension, scale);
607 }
608
609 if(!foundMapping)
610 {
611 for(unsigned int i = 0; i < m_usedMappings.length; ++i)
612 {
613 if(m_usedMappings[i] < 0xFF)
614 {
615 unsigned int offset = 0;
616 for(; offset < 8; ++offset)
617 {
618 if( !(m_usedMappings[i] & (1<<offset)) )
619 {
620 break;
621 }
622 }
623 mapId = (i*8) + offset;
624 m_playerMappings[xuid].addMapping(mapId, centreXC, centreZC, dimension, scale);
625 m_usedMappings[i] |= (1<<offset);
626 break;
627 }
628 }
629 }
630#else
631 for(unsigned int i = 0; i < MAXIMUM_MAP_SAVE_DATA; ++i)
632 {
633 if(m_mapDataMappings.xuids[i] == xuid && m_mapDataMappings.getDimension(i) == dimension)
634 {
635 foundMapping = true;
636 mapId = i;
637 break;
638 }
639 if( mapId < 0 && m_mapDataMappings.xuids[i] == INVALID_XUID )
640 {
641 mapId = i;
642 }
643 }
644 if( !foundMapping && mapId >= 0 && mapId < MAXIMUM_MAP_SAVE_DATA )
645 {
646 m_mapDataMappings.setMapping(mapId, xuid, dimension);
647 m_saveableMapDataMappings.setMapping(mapId, xuid, dimension);
648
649 // If we had an old map file for a mapping that is no longer valid, delete it
650 std::wstring id = wstring( L"map_" ) + _toString(mapId);
651 ConsoleSavePath file = getDataFile(id);
652
653 if(m_saveFile->doesFileExist(file) )
654 {
655 AUTO_VAR(it, find(m_mapFilesToDelete.begin(), m_mapFilesToDelete.end(), mapId));
656 if(it != m_mapFilesToDelete.end()) m_mapFilesToDelete.erase(it);
657
658 m_saveFile->deleteFile( m_saveFile->createFile(file) );
659 }
660 }
661#endif
662 return mapId;
663}
664
665void DirectoryLevelStorage::saveMapIdLookup()
666{
667 if(StorageManager.GetSaveDisabled() ) return;
668
669#ifdef _LARGE_WORLDS
670 ConsoleSavePath file = getDataFile(L"largeMapDataMappings");
671#else
672 ConsoleSavePath file = getDataFile(L"mapDataMappings");
673#endif
674
675 if (!file.getName().empty())
676 {
677 DWORD NumberOfBytesWritten;
678 FileEntry *fileEntry = m_saveFile->createFile(file);
679 m_saveFile->setFilePointer(fileEntry,0,NULL, FILE_BEGIN);
680
681#ifdef _LARGE_WORLDS
682 ByteArrayOutputStream baos;
683 DataOutputStream dos(&baos);
684 dos.writeInt(m_playerMappings.size());
685 app.DebugPrintf("Saving %d mappings\n", m_playerMappings.size());
686 for(AUTO_VAR(it,m_playerMappings.begin()); it != m_playerMappings.end(); ++it)
687 {
688#ifdef _WINDOWS64
689 app.DebugPrintf(" -- %d\n", it->first);
690#else
691 app.DebugPrintf(" -- %ls\n", it->first.toString().c_str());
692#endif
693 dos.writePlayerUID(it->first);
694 it->second.writeMappings(&dos);
695 }
696 dos.write(m_usedMappings);
697 m_saveFile->writeFile( fileEntry,
698 baos.buf.data, // data buffer
699 baos.size(), // number of bytes to write
700 &NumberOfBytesWritten // number of bytes written
701 );
702#else
703 m_saveFile->writeFile( fileEntry,
704 &m_saveableMapDataMappings, // data buffer
705 sizeof(MapDataMappings), // number of bytes to write
706 &NumberOfBytesWritten // number of bytes written
707 );
708 assert( NumberOfBytesWritten == sizeof(MapDataMappings) );
709#endif
710 }
711}
712
713void DirectoryLevelStorage::dontSaveMapMappingForPlayer(PlayerUID xuid)
714{
715#ifdef _LARGE_WORLDS
716 AUTO_VAR(it, m_playerMappings.find(xuid) );
717 if(it != m_playerMappings.end())
718 {
719 for(AUTO_VAR(itMap, it->second.m_mappings.begin()); itMap != it->second.m_mappings.end(); ++itMap)
720 {
721 int index = itMap->second / 8;
722 int offset = itMap->second % 8;
723 m_usedMappings[index] &= ~(1<<offset);
724 }
725 m_playerMappings.erase(it);
726 }
727#else
728 for(unsigned int i = 0; i < MAXIMUM_MAP_SAVE_DATA; ++i)
729 {
730 if(m_saveableMapDataMappings.xuids[i] == xuid)
731 {
732 m_saveableMapDataMappings.setMapping(i,INVALID_XUID,0);
733 }
734 }
735#endif
736}
737
738void DirectoryLevelStorage::deleteMapFilesForPlayer(shared_ptr<Player> player)
739{
740 PlayerUID playerXuid = player->getXuid();
741 if(playerXuid != INVALID_XUID) deleteMapFilesForPlayer(playerXuid);
742}
743
744void DirectoryLevelStorage::deleteMapFilesForPlayer(PlayerUID xuid)
745{
746#ifdef _LARGE_WORLDS
747 AUTO_VAR(it, m_playerMappings.find(xuid) );
748 if(it != m_playerMappings.end())
749 {
750 for(AUTO_VAR(itMap, it->second.m_mappings.begin()); itMap != it->second.m_mappings.end(); ++itMap)
751 {
752 std::wstring id = wstring( L"map_" ) + _toString(itMap->second);
753 ConsoleSavePath file = getDataFile(id);
754
755 if(m_saveFile->doesFileExist(file) )
756 {
757 // If we can't actually delete this file, store the name so we can delete it later
758 if(StorageManager.GetSaveDisabled()) m_mapFilesToDelete.push_back(itMap->second);
759 else m_saveFile->deleteFile( m_saveFile->createFile(file) );
760 }
761
762 int index = itMap->second / 8;
763 int offset = itMap->second % 8;
764 m_usedMappings[index] &= ~(1<<offset);
765 }
766 m_playerMappings.erase(it);
767 }
768#else
769 bool changed = false;
770 for(unsigned int i = 0; i < MAXIMUM_MAP_SAVE_DATA; ++i)
771 {
772 if(m_mapDataMappings.xuids[i] == xuid)
773 {
774 changed = true;
775
776 std::wstring id = wstring( L"map_" ) + _toString(i);
777 ConsoleSavePath file = getDataFile(id);
778
779 if(m_saveFile->doesFileExist(file) )
780 {
781 // If we can't actually delete this file, store the name so we can delete it later
782 if(StorageManager.GetSaveDisabled()) m_mapFilesToDelete.push_back(i);
783 else m_saveFile->deleteFile( m_saveFile->createFile(file) );
784 }
785 m_mapDataMappings.setMapping(i,INVALID_XUID,0);
786 m_saveableMapDataMappings.setMapping(i,INVALID_XUID,0);
787 break;
788 }
789 }
790#endif
791}
792
793void DirectoryLevelStorage::saveAllCachedData()
794{
795 if(StorageManager.GetSaveDisabled() ) return;
796
797 // Save any files that were saved while saving was disabled
798 for(AUTO_VAR(it, m_cachedSaveData.begin()); it != m_cachedSaveData.end(); ++it)
799 {
800 ByteArrayOutputStream *bos = it->second;
801
802 ConsoleSavePath realFile = ConsoleSavePath( it->first );
803 ConsoleSaveFileOutputStream fos = ConsoleSaveFileOutputStream( m_saveFile, realFile );
804
805 app.DebugPrintf("Actually writing cached file %ls\n",it->first.c_str() );
806 fos.write(bos->buf, 0, bos->size() );
807 delete bos;
808 }
809 m_cachedSaveData.clear();
810
811 for(AUTO_VAR(it, m_mapFilesToDelete.begin()); it != m_mapFilesToDelete.end(); ++it)
812 {
813 std::wstring id = wstring( L"map_" ) + _toString(*it);
814 ConsoleSavePath file = getDataFile(id);
815 if(m_saveFile->doesFileExist(file) )
816 {
817 m_saveFile->deleteFile( m_saveFile->createFile(file) );
818 }
819 }
820 m_mapFilesToDelete.clear();
821}