aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World/McRegionLevelStorageSource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Minecraft.World/McRegionLevelStorageSource.cpp')
-rw-r--r--Minecraft.World/McRegionLevelStorageSource.cpp365
1 files changed, 365 insertions, 0 deletions
diff --git a/Minecraft.World/McRegionLevelStorageSource.cpp b/Minecraft.World/McRegionLevelStorageSource.cpp
new file mode 100644
index 00000000..0652ad84
--- /dev/null
+++ b/Minecraft.World/McRegionLevelStorageSource.cpp
@@ -0,0 +1,365 @@
+#include "stdafx.h"
+#include "JavaMath.h"
+#include "BasicTypeContainers.h"
+#if 0
+// 4J - not required anymore
+#include "Matcher.h"
+#endif
+#include "ProgressListener.h"
+#include "net.minecraft.world.level.chunk.storage.h"
+#include "net.minecraft.world.level.chunk.h"
+#include "LevelSummary.h"
+#include "McRegionLevelStorage.h"
+#include "File.h"
+#include "LevelData.h"
+#include "McRegionLevelStorageSource.h"
+
+#include "ConsoleSaveFileIO.h"
+
+#if 0
+// 4J - not required anymore
+// These were Pattern class objects, using the c++0x regex class instead
+const std::tr1::wregex McRegionLevelStorageSource::FolderFilter::chunkFolderPattern = std::tr1::wregex(L"[0-9a-z]|([0-9a-z][0-9a-z])");
+const std::tr1::wregex McRegionLevelStorageSource::ChunkFilter::chunkFilePattern = std::tr1::wregex(L"c\\.(-?[0-9a-z]+)\\.(-?[0-9a-z]+)\\.dat");
+#endif
+
+McRegionLevelStorageSource::McRegionLevelStorageSource(File dir) : DirectoryLevelStorageSource(dir)
+{
+}
+
+wstring McRegionLevelStorageSource::getName()
+{
+ return L"Scaevolus' McRegion";
+}
+
+vector<LevelSummary *> *McRegionLevelStorageSource::getLevelList()
+{
+ // 4J Stu - We don't need to do directory lookups with the xbox save files
+ vector<LevelSummary *> *levels = new vector<LevelSummary *>;
+#if 0
+ vector<File *> *subFolders = baseDir.listFiles();
+ File *file;
+ AUTO_VAR(itEnd, subFolders->end());
+ for (AUTO_VAR(it, subFolders->begin()); it != itEnd; it++)
+ {
+ file = *it; //subFolders->at(i);
+
+ if (file->isDirectory())
+ {
+ continue;
+ }
+
+ wstring levelId = file->getName();
+
+ LevelData *levelData = getDataTagFor(levelId);
+ if (levelData != NULL)
+ {
+ bool requiresConversion = levelData->getVersion() != McRegionLevelStorage::MCREGION_VERSION_ID;
+ wstring levelName = levelData->getLevelName();
+
+ if (levelName.empty()) // 4J Jev TODO: levelName can't be NULL? if (levelName == NULL || isEmpty(levelName))
+ {
+ levelName = levelId;
+ }
+ // long size = getLevelSize(folder);
+ long size = 0;
+ levels->push_back(new LevelSummary(levelId, levelName, levelData->getLastPlayed(), size, requiresConversion, levelData->isHardcore()));
+ }
+ }
+#endif
+ return levels;
+}
+
+void McRegionLevelStorageSource::clearAll()
+{
+}
+
+shared_ptr<LevelStorage> McRegionLevelStorageSource::selectLevel(ConsoleSaveFile *saveFile, const wstring& levelId, bool createPlayerDir)
+{
+ // return new LevelStorageProfilerDecorator(new McRegionLevelStorage(baseDir, levelId, createPlayerDir));
+ return shared_ptr<LevelStorage>(new McRegionLevelStorage(saveFile, baseDir, levelId, createPlayerDir));
+}
+
+bool McRegionLevelStorageSource::isConvertible(ConsoleSaveFile *saveFile, const wstring& levelId)
+{
+ // check if there is old file format level data
+ LevelData *levelData = getDataTagFor(saveFile, levelId);
+ if (levelData == NULL || levelData->getVersion() != 0)
+ {
+ delete levelData;
+ return false;
+ }
+ delete levelData;
+
+ return true;
+}
+
+bool McRegionLevelStorageSource::requiresConversion(ConsoleSaveFile *saveFile, const wstring& levelId)
+{
+ LevelData *levelData = getDataTagFor(saveFile, levelId);
+ if (levelData == NULL || levelData->getVersion() != 0)
+ {
+ delete levelData;
+ return false;
+ }
+ delete levelData;
+
+ return true;
+}
+
+bool McRegionLevelStorageSource::convertLevel(ConsoleSaveFile *saveFile, const wstring& levelId, ProgressListener *progress)
+{
+ assert(false);
+ // I removed this while updating the saves to use the single save file
+ // Will we ever use this convertLevel function anyway? The main issue is the check
+ // for the hellFolder.exists() which would require a slight change to the way our
+ // save files are structured
+#if 0
+ progress->progressStagePercentage(0);
+
+ vector<ChunkFile *> *normalRegions = new vector<ChunkFile *>;
+ vector<File *> *normalBaseFolders = new vector<File *>;
+ vector<ChunkFile *> *netherRegions = new vector<ChunkFile *>;
+ vector<File *> *netherBaseFolders = new vector<File *>;
+ ArrayList<ChunkFile> enderRegions = new ArrayList<ChunkFile>();
+ ArrayList<File> enderBaseFolders = new ArrayList<File>();
+
+ //File baseFolder = File(baseDir, levelId);
+ //File netherFolder = File(baseFolder, LevelStorage::HELL_FOLDER);
+ //File enderFolder = new File(baseFolder, LevelStorage.ENDER_FOLDER);
+ ConsoleSaveFile saveFile = ConsoleSaveFile( levelId );
+
+ // System.out.println("Scanning folders..."); 4J Jev, TODO how do we println ?
+
+ // find normal world
+ addRegions(baseFolder, normalRegions, normalBaseFolders);
+
+ // find hell world
+ if (netherFolder.exists())
+ {
+ addRegions(netherFolder, netherRegions, netherBaseFolders);
+ }
+ if (enderFolder.exists())
+ {
+ addRegions(enderFolder, enderRegions, enderBaseFolders);
+ }
+
+ int totalCount = normalRegions->size() + netherRegions->size() + enderRegions.size() + normalBaseFolders->size() + netherBaseFolders->size() + enderBaseFolders.size();
+
+ // System.out.println("Total conversion count is " + totalCount); 4J Jev, TODO
+
+ // convert normal world
+ convertRegions(baseFolder, normalRegions, 0, totalCount, progress);
+ // convert hell world
+ convertRegions(netherFolder, netherRegions, normalRegions->size(), totalCount, progress);
+ // convert hell world
+ convertRegions(enderFolder, enderRegions, normalRegions.size() + netherRegions.size(), totalCount, progress);
+
+ LevelData *levelData = getDataTagFor(levelId);
+ levelData->setVersion(McRegionLevelStorage::MCREGION_VERSION_ID);
+
+ LevelStorage *levelStorage = selectLevel(levelId, false);
+ levelStorage->saveLevelData(levelData);
+
+ // erase old files
+ eraseFolders(normalBaseFolders, normalRegions->size() + netherRegions->size(), totalCount, progress);
+ if (netherFolder.exists())
+ {
+ eraseFolders(netherBaseFolders, normalRegions->size() + netherRegions->size() + normalBaseFolders->size(), totalCount, progress);
+ }
+#endif
+ return true;
+}
+
+#if 0
+// 4J - not required anymore
+void McRegionLevelStorageSource::addRegions(File &baseFolder, vector<ChunkFile *> *dest, vector<File *> *firstLevelFolders)
+{
+ FolderFilter folderFilter;
+ ChunkFilter chunkFilter;
+
+ File *folder1;
+ vector<File *> *folderLevel1 = baseFolder.listFiles((FileFilter *) &folderFilter);
+ AUTO_VAR(itEnd, folderLevel1->end());
+ for (AUTO_VAR(it, folderLevel1->begin()); it != itEnd; it++)
+ {
+ folder1 = *it; //folderLevel1->at(i1);
+
+ // keep this for the clean-up process later on
+ firstLevelFolders->push_back(folder1);
+
+ File *folder2;
+ vector<File *> *folderLevel2 = folder1->listFiles(&folderFilter);
+ AUTO_VAR(itEnd2, folderLevel2->end());
+ for (AUTO_VAR(it2, folderLevel2->begin()); it2 != itEnd; it2++)
+ {
+ folder2 = *it2; //folderLevel2->at(i2);
+
+ vector<File *> *chunkFiles = folder2->listFiles((FileFilter *) &chunkFilter);
+
+ File *chunk;
+ AUTO_VAR(itEndFile, chunkFiles->end());
+ for (AUTO_VAR(itFile, chunkFiles->begin()); itFile != itEndFile; itFile++)
+ {
+ chunk = *itFile; //chunkFiles->at(i3);
+
+ dest->push_back(new ChunkFile(chunk));
+ }
+ }
+ }
+}
+#endif
+
+void McRegionLevelStorageSource::convertRegions(File &baseFolder, vector<ChunkFile *> *chunkFiles, int currentCount, int totalCount, ProgressListener *progress)
+{
+ assert( false );
+
+ // 4J Stu - Removed, see comment in convertLevel above
+#if 0
+ //Collections::sort(chunkFiles);
+ std::sort( chunkFiles->begin(), chunkFiles->end() );
+
+ byteArray buffer = byteArray(4096);
+
+ ChunkFile *chunkFile;
+ AUTO_VAR(itEnd, chunkFiles->end());
+ for (AUTO_VAR(it, chunkFiles->begin()); it != itEnd; it++)
+ {
+ chunkFile = *it; //chunkFiles->at(i1);
+
+ // Matcher matcher = ChunkFilter.chunkFilePattern.matcher(chunkFile.getName());
+ // if (!matcher.matches()) {
+ // continue;
+ // }
+ // int x = Integer.parseInt(matcher.group(1), 36);
+ // int z = Integer.parseInt(matcher.group(2), 36);
+
+ int x = chunkFile->getX();
+ int z = chunkFile->getZ();
+
+ RegionFile *region = RegionFileCache::getRegionFile(baseFolder, x, z);
+ if (!region->hasChunk(x & 31, z & 31))
+ {
+ FileInputStream fis = new BufferedInputStream(FileInputStream(*chunkFile->getFile()));
+ DataInputStream istream = DataInputStream(&fis); // 4J - was new GZIPInputStream as well
+
+ DataOutputStream *out = region->getChunkDataOutputStream(x & 31, z & 31);
+
+ int length = 0;
+ while ( (length = istream.read(buffer)) != -1 )
+ {
+ out->write(buffer, 0, length);
+ }
+
+ out->close();
+ istream.close();
+
+ // 4J Stu - getChunkDataOutputStream makes a new DataOutputStream that points to a new ChunkBuffer( ByteArrayOutputStream )
+ // We should clean these up when we are done
+ out->deleteChildStream();
+ delete out;
+ }
+
+ currentCount++;
+ int percent = (int) Math::round(100.0 * (double) currentCount / (double) totalCount);
+ progress->progressStagePercentage(percent);
+ }
+ RegionFileCache::clear();
+#endif
+
+}
+
+void McRegionLevelStorageSource::eraseFolders(vector<File *> *folders, int currentCount, int totalCount, ProgressListener *progress)
+{
+ File *folder;
+ AUTO_VAR(itEnd, folders->end());
+ for (AUTO_VAR(it, folders->begin()); it != itEnd; it++)
+ {
+ folder = *it; //folders->at(i);
+
+ vector<File *> *files = folder->listFiles();
+ deleteRecursive(files);
+ folder->_delete();
+
+ currentCount++;
+ int percent = (int) Math::round(100.0 * (double) currentCount / (double) totalCount);
+ progress->progressStagePercentage(percent);
+ }
+}
+
+#if 0
+// 4J - not required anymore
+bool McRegionLevelStorageSource::FolderFilter::accept(File *file)
+{
+ if (file->isDirectory())
+ {
+ Matcher matcher( chunkFolderPattern, file->getName() );
+ return matcher.matches();
+ }
+ return false;
+}
+
+
+bool McRegionLevelStorageSource::ChunkFilter::accept(File *dir, const wstring& name)
+{
+ Matcher matcher( chunkFilePattern, name );
+ return matcher.matches();
+}
+
+
+McRegionLevelStorageSource::ChunkFile::ChunkFile(File *file)
+{
+ this->file = file;
+
+ Matcher matcher( ChunkFilter::chunkFilePattern, file->getName() );
+ if (matcher.matches())
+ {
+ x = Integer::parseInt(matcher.group(1), 36);
+ z = Integer::parseInt(matcher.group(2), 36);
+ }
+ else
+ {
+ x = 0;
+ z = 0;
+ }
+}
+
+//Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
+int McRegionLevelStorageSource::ChunkFile::compareTo(ChunkFile *rhs)
+{
+ // sort chunk files so that they are placed according to their
+ // region position
+ int rx = x >> 5;
+ int rhsrx = rhs->x >> 5;
+ if (rx == rhsrx)
+ {
+ int rz = z >> 5;
+ int rhsrz = rhs->z >> 5;
+ return rz - rhsrz;
+ }
+
+ return rx - rhsrx;
+}
+
+// 4J Stu Added so we can use std::sort instead of the java Collections::sort
+// a < b
+bool McRegionLevelStorageSource::ChunkFile::operator<( ChunkFile *b )
+{
+ return compareTo( b ) < 0;
+}
+
+File *McRegionLevelStorageSource::ChunkFile::getFile()
+{
+ return (File *) file;
+}
+
+int McRegionLevelStorageSource::ChunkFile::getX()
+{
+ return x;
+}
+
+int McRegionLevelStorageSource::ChunkFile::getZ()
+{
+ return z;
+}
+#endif \ No newline at end of file