the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 299 lines 8.6 kB view raw
1#include "stdafx.h" 2#include "net.minecraft.world.level.chunk.storage.h" 3#include "net.minecraft.world.level.storage.h" 4#include "ConsoleSaveFileIO.h" 5#include "ConsoleSaveFileConverter.h" 6#include "ProgressListener.h" 7 8void ConsoleSaveFileConverter::ProcessSimpleFile(ConsoleSaveFile *sourceSave, FileEntry *sourceFileEntry, ConsoleSaveFile *targetSave, FileEntry *targetFileEntry) 9{ 10 DWORD numberOfBytesRead = 0; 11 DWORD numberOfBytesWritten = 0; 12 13 byte *data = new byte[sourceFileEntry->getFileSize()]; 14 15 // Read from source 16 sourceSave->readFile(sourceFileEntry, data, sourceFileEntry->getFileSize(), &numberOfBytesRead); 17 18 // Write back to target 19 targetSave->writeFile(targetFileEntry, data, numberOfBytesRead, &numberOfBytesWritten); 20 21 delete [] data; 22} 23 24void ConsoleSaveFileConverter::ProcessStandardRegionFile(ConsoleSaveFile *sourceSave, File sourceFile, ConsoleSaveFile *targetSave, File targetFile) 25{ 26 DWORD numberOfBytesWritten = 0; 27 DWORD numberOfBytesRead = 0; 28 29 RegionFile sourceRegionFile(sourceSave, &sourceFile); 30 RegionFile targetRegionFile(targetSave, &targetFile); 31 32 for(unsigned int x = 0; x < 32; ++x) 33 { 34 for(unsigned int z = 0; z < 32; ++z) 35 { 36 DataInputStream *dis = sourceRegionFile.getChunkDataInputStream(x,z); 37 38 if(dis) 39 { 40 int read = dis->read(); 41 DataOutputStream *dos = targetRegionFile.getChunkDataOutputStream(x,z); 42 while(read != -1) 43 { 44 45 dos->write( read & 0xff ); 46 47 read = dis->read(); 48 } 49 dos->close(); 50 dos->deleteChildStream(); 51 delete dos; 52 } 53 54 delete dis; 55 } 56 } 57} 58 59void ConsoleSaveFileConverter::ConvertSave(ConsoleSaveFile *sourceSave, ConsoleSaveFile *targetSave, ProgressListener *progress) 60{ 61 // Process level.dat 62 ConsoleSavePath ldatPath( wstring(L"level.dat") ); 63 FileEntry *sourceLdatFe = sourceSave->createFile( ldatPath ); 64 FileEntry *targetLdatFe = targetSave->createFile( ldatPath ); 65 app.DebugPrintf("Processing level.dat\n"); 66 ProcessSimpleFile(sourceSave, sourceLdatFe, targetSave, targetLdatFe); 67 68 // Process game rules 69 { 70 ConsoleSavePath gameRulesPath( GAME_RULE_SAVENAME ); 71 if(sourceSave->doesFileExist(gameRulesPath) ) 72 { 73 FileEntry *sourceFe = sourceSave->createFile( gameRulesPath ); 74 FileEntry *targetFe = targetSave->createFile( gameRulesPath ); 75 app.DebugPrintf("Processing game rules\n"); 76 ProcessSimpleFile(sourceSave, sourceFe, targetSave, targetFe); 77 } 78 } 79 80 // MGH added - find any player data files and copy them across 81#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) 82 vector<FileEntry *>* playerFiles = sourceSave->getValidPlayerDatFiles(); 83#else 84 vector<FileEntry *> *playerFiles = sourceSave->getFilesWithPrefix( DirectoryLevelStorage::getPlayerDir() ); 85#endif 86 87 if(playerFiles != NULL) 88 { 89 for(int fileIdx = 0; fileIdx < playerFiles->size();fileIdx++) 90 { 91 ConsoleSavePath sourcePlayerDatPath( playerFiles->at(fileIdx)->data.filename ); 92#ifdef _XBOX_ONE 93 // 4J Stu - As the XUIDs on X360 and X1 are different, we don't want to transfer these over. However as the first player 94 // file should be the owner of the save, we can move their data over to the current players XUID 95 if(fileIdx > 0) break; 96 PlayerUID xuid; 97 ProfileManager.GetXUID(ProfileManager.GetPrimaryPad(), &xuid, false); 98 ConsoleSavePath targetPlayerDatPath( L"players/" + xuid.toString() + L".dat" ); 99#else 100 ConsoleSavePath targetPlayerDatPath( playerFiles->at(fileIdx)->data.filename ); 101#endif 102 { 103 FileEntry *sourceFe = sourceSave->createFile( sourcePlayerDatPath ); 104 FileEntry *targetFe = targetSave->createFile( targetPlayerDatPath ); 105 app.DebugPrintf("Processing player dat file %s\n", playerFiles->at(fileIdx)->data.filename); 106 ProcessSimpleFile(sourceSave, sourceFe, targetSave, targetFe); 107 108 targetFe->data.lastModifiedTime = sourceFe->data.lastModifiedTime; 109 } 110 } 111 delete playerFiles; 112 } 113 114 115#ifdef SPLIT_SAVES 116 int xzSize = LEVEL_LEGACY_WIDTH; 117 int hellScale = HELL_LEVEL_LEGACY_SCALE; 118 if ( sourceSave->doesFileExist( ldatPath ) ) 119 { 120 ConsoleSaveFileInputStream fis = ConsoleSaveFileInputStream(sourceSave, ldatPath); 121 CompoundTag *root = NbtIo::readCompressed(&fis); 122 CompoundTag *tag = root->getCompound(L"Data"); 123 LevelData ret(tag); 124 125 xzSize = ret.getXZSize(); 126 hellScale = ret.getHellScale(); 127 128 delete root; 129 } 130 131 RegionFileCache sourceCache; 132 RegionFileCache targetCache; 133 134 if(progress) 135 { 136#ifndef _WINDOWS64 137 progress->progressStage(IDS_SAVETRANSFER_STAGE_CONVERTING); 138#endif 139 } 140 141 // Overworld 142 { 143 app.DebugPrintf("Processing the overworld\n"); 144 int halfXZSize = xzSize / 2; 145 146 int progressTarget = (xzSize) * (xzSize); 147 int currentProgress = 0; 148 if(progress) progress->progressStagePercentage((currentProgress*100)/progressTarget); 149 150 for(int x = -halfXZSize; x < halfXZSize; ++x) 151 { 152 for(int z = -halfXZSize; z < halfXZSize; ++z) 153 { 154 //app.DebugPrintf("Processing overworld chunk %d,%d\n",x,z); 155 DataInputStream *dis = sourceCache._getChunkDataInputStream(sourceSave,L"",x,z); 156 157 if(dis) 158 { 159 int read = dis->read(); 160 DataOutputStream *dos = targetCache._getChunkDataOutputStream(targetSave,L"",x,z); 161 BufferedOutputStream bos(dos, 1024 * 1024); 162 while(read != -1) 163 { 164 165 bos.write( read & 0xff ); 166 167 read = dis->read(); 168 } 169 bos.flush(); 170 dos->close(); 171 dos->deleteChildStream(); 172 delete dos; 173 dis->deleteChildStream(); 174 delete dis; 175 } 176 177 178 ++currentProgress; 179 if(progress) progress->progressStagePercentage( (currentProgress*100)/progressTarget); 180 181 } 182 } 183 } 184 185 // Nether 186 { 187 app.DebugPrintf("Processing the nether\n"); 188 int hellSize = xzSize / hellScale; 189 int halfXZSize = hellSize / 2; 190 191 int progressTarget = (hellSize) * (hellSize); 192 int currentProgress = 0; 193 if(progress) progress->progressStagePercentage((currentProgress*100)/progressTarget); 194 195 for(int x = -halfXZSize; x < halfXZSize; ++x) 196 { 197 for(int z = -halfXZSize; z < halfXZSize; ++z) 198 { 199 //app.DebugPrintf("Processing nether chunk %d,%d\n",x,z); 200 DataInputStream *dis = sourceCache._getChunkDataInputStream(sourceSave,L"DIM-1",x,z); 201 202 if(dis) 203 { 204 int read = dis->read(); 205 DataOutputStream *dos = targetCache._getChunkDataOutputStream(targetSave,L"DIM-1",x,z); 206 BufferedOutputStream bos(dos, 1024 * 1024); 207 while(read != -1) 208 { 209 210 bos.write( read & 0xff ); 211 212 read = dis->read(); 213 } 214 bos.flush(); 215 dos->close(); 216 dos->deleteChildStream(); 217 delete dos; 218 dis->deleteChildStream(); 219 delete dis; 220 } 221 222 223 ++currentProgress; 224 if(progress) progress->progressStagePercentage((currentProgress*100)/progressTarget); 225 } 226 } 227 } 228 229 // End 230 { 231 app.DebugPrintf("Processing the end\n"); 232 int halfXZSize = END_LEVEL_MAX_WIDTH / 2; 233 234 int progressTarget = (END_LEVEL_MAX_WIDTH) * (END_LEVEL_MAX_WIDTH); 235 int currentProgress = 0; 236 if(progress) progress->progressStagePercentage((currentProgress*100)/progressTarget); 237 238 for(int x = -halfXZSize; x < halfXZSize; ++x) 239 { 240 for(int z = -halfXZSize; z < halfXZSize; ++z) 241 { 242 //app.DebugPrintf("Processing end chunk %d,%d\n",x,z); 243 DataInputStream *dis = sourceCache._getChunkDataInputStream(sourceSave,L"DIM1/",x,z); 244 245 if(dis) 246 { 247 int read = dis->read(); 248 DataOutputStream *dos = targetCache._getChunkDataOutputStream(targetSave,L"DIM1/",x,z); 249 BufferedOutputStream bos(dos, 1024 * 1024); 250 while(read != -1) 251 { 252 253 bos.write( read & 0xff ); 254 255 read = dis->read(); 256 } 257 bos.flush(); 258 dos->close(); 259 dos->deleteChildStream(); 260 delete dos; 261 dis->deleteChildStream(); 262 delete dis; 263 } 264 265 266 ++currentProgress; 267 if(progress) progress->progressStagePercentage((currentProgress*100)/progressTarget); 268 } 269 } 270 } 271 272#else 273 // 4J Stu - Old version that just changes the compression of chunks, not usable for XboxOne style split saves or compressed tile formats 274 // Process region files 275 vector<FileEntry *> *allFilesInSave = sourceSave->getFilesWithPrefix(wstring(L"")); 276 for(AUTO_VAR(it, allFilesInSave->begin()); it < allFilesInSave->end(); ++it) 277 { 278 FileEntry *fe = *it; 279 if( fe != sourceLdatFe ) 280 { 281 wstring fName( fe->data.filename ); 282 wstring suffix(L".mcr"); 283 if( fName.compare(fName.length() - suffix.length(), suffix.length(), suffix) == 0 ) 284 { 285#ifndef _CONTENT_PACKAGE 286 wprintf(L"Processing a region file: %s\n", fe->data.filename); 287#endif 288 ProcessStandardRegionFile(sourceSave, File(fe->data.filename), targetSave, File(fe->data.filename) ); 289 } 290 else 291 { 292#ifndef _CONTENT_PACKAGE 293 wprintf(L"%s is not a region file, ignoring\n", fe->data.filename); 294#endif 295 } 296 } 297 } 298#endif 299}