diff options
Diffstat (limited to 'Minecraft.World/DirectoryLevelStorage.cpp')
| -rw-r--r-- | Minecraft.World/DirectoryLevelStorage.cpp | 824 |
1 files changed, 824 insertions, 0 deletions
diff --git a/Minecraft.World/DirectoryLevelStorage.cpp b/Minecraft.World/DirectoryLevelStorage.cpp new file mode 100644 index 00000000..27514c9b --- /dev/null +++ b/Minecraft.World/DirectoryLevelStorage.cpp @@ -0,0 +1,824 @@ +#include "stdafx.h" +#include "System.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.chunk.storage.h" +#include "net.minecraft.world.level.dimension.h" +#include "com.mojang.nbt.h" +#include "File.h" +#include "DataInputStream.h" +#include "FileInputStream.h" +#include "LevelData.h" +#include "DirectoryLevelStorage.h" +#include "ConsoleSaveFileIO.h" + +const wstring DirectoryLevelStorage::sc_szPlayerDir(L"players/"); + +_MapDataMappings::_MapDataMappings() +{ +#ifndef _DURANGO + ZeroMemory(xuids,sizeof(PlayerUID)*MAXIMUM_MAP_SAVE_DATA); +#endif + ZeroMemory(dimensions,sizeof(byte)*(MAXIMUM_MAP_SAVE_DATA/4)); +} + +int _MapDataMappings::getDimension(int id) +{ + int offset = (2*(id%4)); + int val = (dimensions[id>>2] & (3 << offset))>>offset; + + int returnVal=0; + + switch(val) + { + case 0: + returnVal = 0; // Overworld + break; + case 1: + returnVal = -1; // Nether + break; + case 2: + returnVal = 1; // End + break; + default: +#ifndef _CONTENT_PACKAGE + printf("Read invalid dimension from MapDataMapping\n"); + __debugbreak(); +#endif + break; + } + return returnVal; +} + +void _MapDataMappings::setMapping(int id, PlayerUID xuid, int dimension) +{ + xuids[id] = xuid; + + int offset = (2*(id%4)); + + // Reset it first + dimensions[id>>2] &= ~( 2 << offset ); + switch(dimension) + { + case 0: // Overworld + //dimensions[id>>2] &= ~( 2 << offset ); + break; + case -1: // Nether + dimensions[id>>2] |= ( 1 << offset ); + break; + case 1: // End + dimensions[id>>2] |= ( 2 << offset ); + break; + default: +#ifndef _CONTENT_PACKAGE + printf("Trinyg to set a MapDataMapping for an invalid dimension.\n"); + __debugbreak(); +#endif + break; + } +} + +// Old version the only used 1 bit for dimension indexing +_MapDataMappings_old::_MapDataMappings_old() +{ +#ifndef _DURANGO + ZeroMemory(xuids,sizeof(PlayerUID)*MAXIMUM_MAP_SAVE_DATA); +#endif + ZeroMemory(dimensions,sizeof(byte)*(MAXIMUM_MAP_SAVE_DATA/8)); +} + +int _MapDataMappings_old::getDimension(int id) +{ + return dimensions[id>>3] & (128 >> (id%8) ) ? -1 : 0; +} + +void _MapDataMappings_old::setMapping(int id, PlayerUID xuid, int dimension) +{ + xuids[id] = xuid; + if( dimension == 0 ) + { + dimensions[id>>3] &= ~( 128 >> (id%8) ); + } + else + { + dimensions[id>>3] |= ( 128 >> (id%8) ); + } +} + +#ifdef _LARGE_WORLDS +void DirectoryLevelStorage::PlayerMappings::addMapping(int id, int centreX, int centreZ, int dimension, int scale) +{ + __int64 index = ( ((__int64)(centreZ & 0x1FFFFFFF)) << 34) | ( ((__int64)(centreX & 0x1FFFFFFF)) << 5) | ( (scale & 0x7) << 2) | (dimension & 0x3); + m_mappings[index] = id; + //app.DebugPrintf("Adding mapping: %d - (%d,%d)/%d/%d [%I64d - 0x%016llx]\n", id, centreX, centreZ, dimension, scale, index, index); +} + +bool DirectoryLevelStorage::PlayerMappings::getMapping(int &id, int centreX, int centreZ, int dimension, int scale) +{ + //__int64 zMasked = centreZ & 0x1FFFFFFF; + //__int64 xMasked = centreX & 0x1FFFFFFF; + //__int64 zShifted = zMasked << 34; + //__int64 xShifted = xMasked << 5; + //app.DebugPrintf("xShifted = %d (0x%016x), zShifted = %I64d (0x%016llx)\n", xShifted, xShifted, zShifted, zShifted); + __int64 index = ( ((__int64)(centreZ & 0x1FFFFFFF)) << 34) | ( ((__int64)(centreX & 0x1FFFFFFF)) << 5) | ( (scale & 0x7) << 2) | (dimension & 0x3); + AUTO_VAR(it,m_mappings.find(index)); + if(it != m_mappings.end()) + { + id = it->second; + //app.DebugPrintf("Found mapping: %d - (%d,%d)/%d/%d [%I64d - 0x%016llx]\n", id, centreX, centreZ, dimension, scale, index, index); + return true; + } + else + { + //app.DebugPrintf("Failed to find mapping: (%d,%d)/%d/%d [%I64d - 0x%016llx]\n", centreX, centreZ, dimension, scale, index, index); + return false; + } +} + +void DirectoryLevelStorage::PlayerMappings::writeMappings(DataOutputStream *dos) +{ + dos->writeInt(m_mappings.size()); + for(AUTO_VAR(it, m_mappings.begin()); it != m_mappings.end(); ++it) + { + app.DebugPrintf(" -- %lld (0x%016llx) = %d\n", it->first, it->first, it->second); + dos->writeLong(it->first); + dos->writeInt(it->second); + } +} + +void DirectoryLevelStorage::PlayerMappings::readMappings(DataInputStream *dis) +{ + int count = dis->readInt(); + for(unsigned int i = 0; i < count; ++i) + { + __int64 index = dis->readLong(); + int id = dis->readInt(); + m_mappings[index] = id; + app.DebugPrintf(" -- %lld (0x%016llx) = %d\n", index, index, id); + } +} +#endif + +DirectoryLevelStorage::DirectoryLevelStorage(ConsoleSaveFile *saveFile, const File dir, const wstring& levelId, bool createPlayerDir) : sessionId( System::currentTimeMillis() ), + dir( L"" ), playerDir( sc_szPlayerDir ), dataDir( wstring(L"data/") ), levelId(levelId) +{ + m_saveFile = saveFile; + m_bHasLoadedMapDataMappings = false; + +#ifdef _LARGE_WORLDS + m_usedMappings = byteArray(MAXIMUM_MAP_SAVE_DATA/8); +#endif +} + +DirectoryLevelStorage::~DirectoryLevelStorage() +{ + delete m_saveFile; + + for(AUTO_VAR(it,m_cachedSaveData.begin()); it != m_cachedSaveData.end(); ++it) + { + delete it->second; + } + +#ifdef _LARGE_WORLDS + delete m_usedMappings.data; +#endif +} + +void DirectoryLevelStorage::initiateSession() +{ + // 4J Jev, removed try/catch. + + File dataFile = File( dir, wstring(L"session.lock") ); + FileOutputStream fos = FileOutputStream(dataFile); + DataOutputStream dos = DataOutputStream(&fos); + dos.writeLong(sessionId); + dos.close(); + +} + +File DirectoryLevelStorage::getFolder() +{ + return dir; +} + +void DirectoryLevelStorage::checkSession() +{ + // 4J-PB - Not in the Xbox game + + /* + File dataFile = File( dir, wstring(L"session.lock")); + FileInputStream fis = FileInputStream(dataFile); + DataInputStream dis = DataInputStream(&fis); + dis.close(); + */ +} + +ChunkStorage *DirectoryLevelStorage::createChunkStorage(Dimension *dimension) +{ + // 4J Jev, removed try/catch. + + if (dynamic_cast<HellDimension *>(dimension) != NULL) + { + File dir2 = File(dir, LevelStorage::NETHER_FOLDER); + //dir2.mkdirs(); // 4J Removed + return new OldChunkStorage(dir2, true); + } + if (dynamic_cast<TheEndDimension *>(dimension) != NULL) + { + File dir2 = File(dir, LevelStorage::ENDER_FOLDER); + //dir2.mkdirs(); // 4J Removed + return new OldChunkStorage(dir2, true); + } + + return new OldChunkStorage(dir, true); +} + +LevelData *DirectoryLevelStorage::prepareLevel() +{ + // 4J Stu Added +#ifdef _LARGE_WORLDS + ConsoleSavePath mapFile = getDataFile(L"largeMapDataMappings"); +#else + ConsoleSavePath mapFile = getDataFile(L"mapDataMappings"); +#endif + if (!m_bHasLoadedMapDataMappings && !mapFile.getName().empty() && getSaveFile()->doesFileExist( mapFile )) + { + DWORD NumberOfBytesRead; + FileEntry *fileEntry = getSaveFile()->createFile(mapFile); + +#ifdef __PS3__ + // 4J Stu - This version changed happened before initial release + if(getSaveFile()->getSaveVersion() < SAVE_FILE_VERSION_CHANGE_MAP_DATA_MAPPING_SIZE) + { + // Delete the old file + if(fileEntry) getSaveFile()->deleteFile( fileEntry ); + + // Save a new, blank version + saveMapIdLookup(); + } + else +#elif defined(_DURANGO) + // 4J Stu - This version changed happened before initial release + if(getSaveFile()->getSaveVersion() < SAVE_FILE_VERSION_DURANGO_CHANGE_MAP_DATA_MAPPING_SIZE) + { + // Delete the old file + if(fileEntry) getSaveFile()->deleteFile( fileEntry ); + + // Save a new, blank version + saveMapIdLookup(); + } + else +#endif + { + getSaveFile()->setFilePointer(fileEntry,0,NULL, FILE_BEGIN); + +#ifdef _LARGE_WORLDS + byteArray data(fileEntry->getFileSize()); + getSaveFile()->readFile( fileEntry, data.data, fileEntry->getFileSize(), &NumberOfBytesRead); + assert( NumberOfBytesRead == fileEntry->getFileSize() ); + + ByteArrayInputStream bais(data); + DataInputStream dis(&bais); + int count = dis.readInt(); + app.DebugPrintf("Loading %d mappings\n", count); + for(unsigned int i = 0; i < count; ++i) + { + PlayerUID playerUid = dis.readPlayerUID(); +#ifdef _WINDOWS64 + app.DebugPrintf(" -- %d\n", playerUid); +#else + app.DebugPrintf(" -- %ls\n", playerUid.toString().c_str()); +#endif + m_playerMappings[playerUid].readMappings(&dis); + } + dis.readFully(m_usedMappings); +#else + + if(getSaveFile()->getSaveVersion() < END_DIMENSION_MAP_MAPPINGS_SAVE_VERSION) + { + MapDataMappings_old oldMapDataMappings; + getSaveFile()->readFile( fileEntry, + &oldMapDataMappings, // data buffer + sizeof(MapDataMappings_old), // number of bytes to read + &NumberOfBytesRead // number of bytes read + ); + assert( NumberOfBytesRead == sizeof(MapDataMappings_old) ); + + for(unsigned int i = 0; i < MAXIMUM_MAP_SAVE_DATA; ++i) + { + m_saveableMapDataMappings.setMapping(i,oldMapDataMappings.xuids[i],oldMapDataMappings.getDimension(i)); + } + } + else + { + getSaveFile()->readFile( fileEntry, + &m_saveableMapDataMappings, // data buffer + sizeof(MapDataMappings), // number of bytes to read + &NumberOfBytesRead // number of bytes read + ); + assert( NumberOfBytesRead == sizeof(MapDataMappings) ); + } + + memcpy(&m_mapDataMappings,&m_saveableMapDataMappings,sizeof(MapDataMappings)); +#endif + + + // Write out our changes now + if(getSaveFile()->getSaveVersion() < END_DIMENSION_MAP_MAPPINGS_SAVE_VERSION) saveMapIdLookup(); + } + + m_bHasLoadedMapDataMappings = true; + } + + // 4J Jev, removed try/catch + + ConsoleSavePath dataFile = ConsoleSavePath( wstring( L"level.dat" ) ); + + if ( m_saveFile->doesFileExist( dataFile ) ) + { + ConsoleSaveFileInputStream fis = ConsoleSaveFileInputStream(m_saveFile, dataFile); + CompoundTag *root = NbtIo::readCompressed(&fis); + CompoundTag *tag = root->getCompound(L"Data"); + LevelData *ret = new LevelData(tag); + delete root; + return ret; + } + + return NULL; +} + +void DirectoryLevelStorage::saveLevelData(LevelData *levelData, vector<shared_ptr<Player> > *players) +{ + // 4J Jev, removed try/catch + + CompoundTag *dataTag = levelData->createTag(players); + + CompoundTag *root = new CompoundTag(); + root->put(L"Data", dataTag); + + ConsoleSavePath currentFile = ConsoleSavePath( wstring( L"level.dat" ) ); + + ConsoleSaveFileOutputStream fos = ConsoleSaveFileOutputStream( m_saveFile, currentFile ); + NbtIo::writeCompressed(root, &fos); + + delete root; +} + +void DirectoryLevelStorage::saveLevelData(LevelData *levelData) +{ + // 4J Jev, removed try/catch + + CompoundTag *dataTag = levelData->createTag(); + + CompoundTag *root = new CompoundTag(); + root->put(L"Data", dataTag); + + ConsoleSavePath currentFile = ConsoleSavePath( wstring( L"level.dat" ) ); + + ConsoleSaveFileOutputStream fos = ConsoleSaveFileOutputStream( m_saveFile, currentFile ); + NbtIo::writeCompressed(root, &fos); + + delete root; +} + +void DirectoryLevelStorage::save(shared_ptr<Player> player) +{ + // 4J Jev, removed try/catch. + PlayerUID playerXuid = player->getXuid(); +#if defined(__PS3__) || defined(__ORBIS__) + if( playerXuid != INVALID_XUID ) +#else + if( playerXuid != INVALID_XUID && !player->isGuest() ) +#endif + { + CompoundTag *tag = new CompoundTag(); + player->saveWithoutId(tag); +#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) + ConsoleSavePath realFile = ConsoleSavePath( m_saveFile->getPlayerDataFilenameForSave(playerXuid).c_str() ); +#elif defined(_DURANGO) + ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + player->getXuid().toString() + L".dat" ); +#else + ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + _toString( player->getXuid() ) + L".dat" ); +#endif + // If saves are disabled (e.g. because we are writing the save buffer to disk) then cache this player data + if(StorageManager.GetSaveDisabled()) + { + ByteArrayOutputStream *bos = new ByteArrayOutputStream(); + NbtIo::writeCompressed(tag,bos); + + AUTO_VAR(it, m_cachedSaveData.find(realFile.getName())); + if(it != m_cachedSaveData.end() ) + { + delete it->second; + } + m_cachedSaveData[realFile.getName()] = bos; + app.DebugPrintf("Cached saving of file %ls due to saves being disabled\n", realFile.getName().c_str() ); + } + else + { + ConsoleSaveFileOutputStream fos = ConsoleSaveFileOutputStream( m_saveFile, realFile ); + NbtIo::writeCompressed(tag, &fos); + } + delete tag; + } + else if( playerXuid != INVALID_XUID ) + { + app.DebugPrintf("Not saving player as their XUID is a guest\n"); + dontSaveMapMappingForPlayer(playerXuid); + } +} + + // 4J Changed return val to bool to check if new player or loaded player +bool DirectoryLevelStorage::load(shared_ptr<Player> player) +{ + bool newPlayer = true; + CompoundTag *tag = loadPlayerDataTag( player->getXuid() ); + if (tag != NULL) + { + newPlayer = false; + player->load(tag); + delete tag; + } + return newPlayer; +} + +CompoundTag *DirectoryLevelStorage::loadPlayerDataTag(PlayerUID xuid) +{ + // 4J Jev, removed try/catch. +#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) + ConsoleSavePath realFile = ConsoleSavePath( m_saveFile->getPlayerDataFilenameForLoad(xuid).c_str() ); +#elif defined(_DURANGO) + ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + xuid.toString() + L".dat" ); +#else + ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + _toString( xuid ) + L".dat" ); +#endif + AUTO_VAR(it, m_cachedSaveData.find(realFile.getName())); + if(it != m_cachedSaveData.end() ) + { + ByteArrayOutputStream *bos = it->second; + ByteArrayInputStream bis(bos->buf, 0, bos->size()); + CompoundTag *tag = NbtIo::readCompressed(&bis); + bis.reset(); + app.DebugPrintf("Loaded player data from cached file %ls\n", realFile.getName().c_str() ); + return tag; + } + else if ( m_saveFile->doesFileExist( realFile ) ) + { + ConsoleSaveFileInputStream fis = ConsoleSaveFileInputStream(m_saveFile, realFile); + return NbtIo::readCompressed(&fis); + } + return NULL; +} + +// 4J Added function +void DirectoryLevelStorage::clearOldPlayerFiles() +{ + if(StorageManager.GetSaveDisabled() ) return; + +#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) + vector<FileEntry *> *playerFiles = m_saveFile->getValidPlayerDatFiles(); +#else + vector<FileEntry *> *playerFiles = m_saveFile->getFilesWithPrefix( playerDir.getName() ); +#endif + + if( playerFiles != NULL ) + { +#ifndef _FINAL_BUILD + if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_DistributableSave)) + { + for(unsigned int i = 0; i < playerFiles->size(); ++i ) + { + FileEntry *file = playerFiles->at(i); + wstring xuidStr = replaceAll( replaceAll(file->data.filename,playerDir.getName(),L""),L".dat",L""); +#if defined(__PS3__) || defined(__ORBIS__) || defined(_DURANGO) + PlayerUID xuid(xuidStr); +#else + PlayerUID xuid = _fromString<PlayerUID>(xuidStr); +#endif + deleteMapFilesForPlayer(xuid); + m_saveFile->deleteFile( playerFiles->at(i) ); + } + } + else +#endif + if( playerFiles->size() > MAX_PLAYER_DATA_SAVES ) + { + sort(playerFiles->begin(), playerFiles->end(), FileEntry::newestFirst ); + + for(unsigned int i = MAX_PLAYER_DATA_SAVES; i < playerFiles->size(); ++i ) + { + FileEntry *file = playerFiles->at(i); + wstring xuidStr = replaceAll( replaceAll(file->data.filename,playerDir.getName(),L""),L".dat",L""); +#if defined(__PS3__) || defined(__ORBIS__) || defined(_DURANGO) + PlayerUID xuid(xuidStr); +#else + PlayerUID xuid = _fromString<PlayerUID>(xuidStr); +#endif + deleteMapFilesForPlayer(xuid); + m_saveFile->deleteFile( playerFiles->at(i) ); + } + } + + delete playerFiles; + } +} + +PlayerIO *DirectoryLevelStorage::getPlayerIO() +{ + return this; +} + +void DirectoryLevelStorage::closeAll() +{ +} + +ConsoleSavePath DirectoryLevelStorage::getDataFile(const wstring& id) +{ + return ConsoleSavePath( dataDir.getName() + id + L".dat" ); +} + +wstring DirectoryLevelStorage::getLevelId() +{ + return levelId; +} + +void DirectoryLevelStorage::flushSaveFile(bool autosave) +{ +#ifndef _CONTENT_PACKAGE + if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_DistributableSave)) + { + // Delete gamerules files if it exists + ConsoleSavePath gameRulesFiles(GAME_RULE_SAVENAME); + if(m_saveFile->doesFileExist(gameRulesFiles)) + { + FileEntry *fe = m_saveFile->createFile(gameRulesFiles); + m_saveFile->deleteFile( fe ); + } + } +#endif + m_saveFile->Flush(autosave); +} + +// 4J Added +void DirectoryLevelStorage::resetNetherPlayerPositions() +{ + if(app.GetResetNether()) + { +#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) + vector<FileEntry *> *playerFiles = m_saveFile->getValidPlayerDatFiles(); +#else + vector<FileEntry *> *playerFiles = m_saveFile->getFilesWithPrefix( playerDir.getName() ); +#endif + + if( playerFiles != NULL ) + { + for( AUTO_VAR(it, playerFiles->begin()); it != playerFiles->end(); ++it) + { + FileEntry * realFile = *it; + ConsoleSaveFileInputStream fis = ConsoleSaveFileInputStream(m_saveFile, realFile); + CompoundTag *tag = NbtIo::readCompressed(&fis); + if (tag != NULL) + { + // If the player is in the nether, set their y position above the top of the nether + // This will force the player to be spawned in a valid position in the overworld when they are loaded + if(tag->contains(L"Dimension") && tag->getInt(L"Dimension") == LevelData::DIMENSION_NETHER && tag->contains(L"Pos")) + { + ListTag<DoubleTag> *pos = (ListTag<DoubleTag> *) tag->getList(L"Pos"); + pos->get(1)->data = DBL_MAX; + + ConsoleSaveFileOutputStream fos = ConsoleSaveFileOutputStream( m_saveFile, realFile ); + NbtIo::writeCompressed(tag, &fos); + } + delete tag; + } + } + delete playerFiles; + } + } +} + +int DirectoryLevelStorage::getAuxValueForMap(PlayerUID xuid, int dimension, int centreXC, int centreZC, int scale) +{ + int mapId = -1; + bool foundMapping = false; + +#ifdef _LARGE_WORLDS + AUTO_VAR(it, m_playerMappings.find(xuid) ); + if(it != m_playerMappings.end()) + { + foundMapping = it->second.getMapping(mapId, centreXC, centreZC, dimension, scale); + } + + if(!foundMapping) + { + for(unsigned int i = 0; i < m_usedMappings.length; ++i) + { + if(m_usedMappings[i] < 0xFF) + { + unsigned int offset = 0; + for(; offset < 8; ++offset) + { + if( !(m_usedMappings[i] & (1<<offset)) ) + { + break; + } + } + mapId = (i*8) + offset; + m_playerMappings[xuid].addMapping(mapId, centreXC, centreZC, dimension, scale); + m_usedMappings[i] |= (1<<offset); + break; + } + } + } +#else + for(unsigned int i = 0; i < MAXIMUM_MAP_SAVE_DATA; ++i) + { + if(m_mapDataMappings.xuids[i] == xuid && m_mapDataMappings.getDimension(i) == dimension) + { + foundMapping = true; + mapId = i; + break; + } + if( mapId < 0 && m_mapDataMappings.xuids[i] == INVALID_XUID ) + { + mapId = i; + } + } + if( !foundMapping && mapId >= 0 && mapId < MAXIMUM_MAP_SAVE_DATA ) + { + m_mapDataMappings.setMapping(mapId, xuid, dimension); + m_saveableMapDataMappings.setMapping(mapId, xuid, dimension); + + // If we had an old map file for a mapping that is no longer valid, delete it + std::wstring id = wstring( L"map_" ) + _toString(mapId); + ConsoleSavePath file = getDataFile(id); + + if(m_saveFile->doesFileExist(file) ) + { + AUTO_VAR(it, find(m_mapFilesToDelete.begin(), m_mapFilesToDelete.end(), mapId)); + if(it != m_mapFilesToDelete.end()) m_mapFilesToDelete.erase(it); + + m_saveFile->deleteFile( m_saveFile->createFile(file) ); + } + } +#endif + return mapId; +} + +void DirectoryLevelStorage::saveMapIdLookup() +{ + if(StorageManager.GetSaveDisabled() ) return; + +#ifdef _LARGE_WORLDS + ConsoleSavePath file = getDataFile(L"largeMapDataMappings"); +#else + ConsoleSavePath file = getDataFile(L"mapDataMappings"); +#endif + + if (!file.getName().empty()) + { + DWORD NumberOfBytesWritten; + FileEntry *fileEntry = m_saveFile->createFile(file); + m_saveFile->setFilePointer(fileEntry,0,NULL, FILE_BEGIN); + +#ifdef _LARGE_WORLDS + ByteArrayOutputStream baos; + DataOutputStream dos(&baos); + dos.writeInt(m_playerMappings.size()); + app.DebugPrintf("Saving %d mappings\n", m_playerMappings.size()); + for(AUTO_VAR(it,m_playerMappings.begin()); it != m_playerMappings.end(); ++it) + { +#ifdef _WINDOWS64 + app.DebugPrintf(" -- %d\n", it->first); +#else + app.DebugPrintf(" -- %ls\n", it->first.toString().c_str()); +#endif + dos.writePlayerUID(it->first); + it->second.writeMappings(&dos); + } + dos.write(m_usedMappings); + m_saveFile->writeFile( fileEntry, + baos.buf.data, // data buffer + baos.size(), // number of bytes to write + &NumberOfBytesWritten // number of bytes written + ); +#else + m_saveFile->writeFile( fileEntry, + &m_saveableMapDataMappings, // data buffer + sizeof(MapDataMappings), // number of bytes to write + &NumberOfBytesWritten // number of bytes written + ); + assert( NumberOfBytesWritten == sizeof(MapDataMappings) ); +#endif + } +} + +void DirectoryLevelStorage::dontSaveMapMappingForPlayer(PlayerUID xuid) +{ +#ifdef _LARGE_WORLDS + AUTO_VAR(it, m_playerMappings.find(xuid) ); + if(it != m_playerMappings.end()) + { + for(AUTO_VAR(itMap, it->second.m_mappings.begin()); itMap != it->second.m_mappings.end(); ++itMap) + { + int index = itMap->second / 8; + int offset = itMap->second % 8; + m_usedMappings[index] &= ~(1<<offset); + } + m_playerMappings.erase(it); + } +#else + for(unsigned int i = 0; i < MAXIMUM_MAP_SAVE_DATA; ++i) + { + if(m_saveableMapDataMappings.xuids[i] == xuid) + { + m_saveableMapDataMappings.setMapping(i,INVALID_XUID,0); + } + } +#endif +} + +void DirectoryLevelStorage::deleteMapFilesForPlayer(shared_ptr<Player> player) +{ + PlayerUID playerXuid = player->getXuid(); + if(playerXuid != INVALID_XUID) deleteMapFilesForPlayer(playerXuid); +} + +void DirectoryLevelStorage::deleteMapFilesForPlayer(PlayerUID xuid) +{ +#ifdef _LARGE_WORLDS + AUTO_VAR(it, m_playerMappings.find(xuid) ); + if(it != m_playerMappings.end()) + { + for(AUTO_VAR(itMap, it->second.m_mappings.begin()); itMap != it->second.m_mappings.end(); ++itMap) + { + std::wstring id = wstring( L"map_" ) + _toString(itMap->second); + ConsoleSavePath file = getDataFile(id); + + if(m_saveFile->doesFileExist(file) ) + { + // If we can't actually delete this file, store the name so we can delete it later + if(StorageManager.GetSaveDisabled()) m_mapFilesToDelete.push_back(itMap->second); + else m_saveFile->deleteFile( m_saveFile->createFile(file) ); + } + + int index = itMap->second / 8; + int offset = itMap->second % 8; + m_usedMappings[index] &= ~(1<<offset); + } + m_playerMappings.erase(it); + } +#else + bool changed = false; + for(unsigned int i = 0; i < MAXIMUM_MAP_SAVE_DATA; ++i) + { + if(m_mapDataMappings.xuids[i] == xuid) + { + changed = true; + + std::wstring id = wstring( L"map_" ) + _toString(i); + ConsoleSavePath file = getDataFile(id); + + if(m_saveFile->doesFileExist(file) ) + { + // If we can't actually delete this file, store the name so we can delete it later + if(StorageManager.GetSaveDisabled()) m_mapFilesToDelete.push_back(i); + else m_saveFile->deleteFile( m_saveFile->createFile(file) ); + } + m_mapDataMappings.setMapping(i,INVALID_XUID,0); + m_saveableMapDataMappings.setMapping(i,INVALID_XUID,0); + break; + } + } +#endif +} + +void DirectoryLevelStorage::saveAllCachedData() +{ + if(StorageManager.GetSaveDisabled() ) return; + + // Save any files that were saved while saving was disabled + for(AUTO_VAR(it, m_cachedSaveData.begin()); it != m_cachedSaveData.end(); ++it) + { + ByteArrayOutputStream *bos = it->second; + + ConsoleSavePath realFile = ConsoleSavePath( it->first ); + ConsoleSaveFileOutputStream fos = ConsoleSaveFileOutputStream( m_saveFile, realFile ); + + app.DebugPrintf("Actually writing cached file %ls\n",it->first.c_str() ); + fos.write(bos->buf, 0, bos->size() ); + delete bos; + } + m_cachedSaveData.clear(); + + for(AUTO_VAR(it, m_mapFilesToDelete.begin()); it != m_mapFilesToDelete.end(); ++it) + { + std::wstring id = wstring( L"map_" ) + _toString(*it); + ConsoleSavePath file = getDataFile(id); + if(m_saveFile->doesFileExist(file) ) + { + m_saveFile->deleteFile( m_saveFile->createFile(file) ); + } + } + m_mapFilesToDelete.clear(); +} |
