diff options
Diffstat (limited to 'launcher/minecraft/World.cpp')
-rw-r--r-- | launcher/minecraft/World.cpp | 280 |
1 files changed, 110 insertions, 170 deletions
diff --git a/launcher/minecraft/World.cpp b/launcher/minecraft/World.cpp index 54fb9434..1a680ac5 100644 --- a/launcher/minecraft/World.cpp +++ b/launcher/minecraft/World.cpp @@ -34,23 +34,23 @@ * limitations under the License. */ -#include <QDir> -#include <QString> +#include "World.h" #include <QDebug> -#include <QSaveFile> +#include <QDir> #include <QDirIterator> -#include "World.h" +#include <QSaveFile> +#include <QString> -#include "GZip.h" -#include <MMCZip.h> #include <FileSystem.h> -#include <sstream> +#include <MMCZip.h> #include <io/stream_reader.h> -#include <tag_string.h> -#include <tag_primitive.h> #include <quazip/quazip.h> -#include <quazip/quazipfile.h> #include <quazip/quazipdir.h> +#include <quazip/quazipfile.h> +#include <tag_primitive.h> +#include <tag_string.h> +#include <sstream> +#include "GZip.h" #include <QCoreApplication> @@ -58,16 +58,15 @@ #include "FileSystem.h" -using std::optional; using std::nullopt; +using std::optional; -GameType::GameType(std::optional<int> original): - original(original) +GameType::GameType(std::optional<int> original) : original(original) { - if(!original) { + if (!original) { return; } - switch(*original) { + switch (*original) { case 0: type = GameType::Survival; break; @@ -87,8 +86,7 @@ GameType::GameType(std::optional<int> original): QString GameType::toTranslatedString() const { - switch (type) - { + switch (type) { case GameType::Survival: return QCoreApplication::translate("GameType", "Survival"); case GameType::Creative: @@ -100,7 +98,7 @@ QString GameType::toTranslatedString() const default: break; } - if(original) { + if (original) { return QCoreApplication::translate("GameType", "Unknown (%1)").arg(*original); } return QCoreApplication::translate("GameType", "Undefined"); @@ -108,8 +106,7 @@ QString GameType::toTranslatedString() const QString GameType::toLogString() const { - switch (type) - { + switch (type) { case GameType::Survival: return "Survival"; case GameType::Creative: @@ -121,108 +118,94 @@ QString GameType::toLogString() const default: break; } - if(original) { + if (original) { return QString("Unknown (%1)").arg(*original); } return "Undefined"; } -std::unique_ptr <nbt::tag_compound> parseLevelDat(QByteArray data) +std::unique_ptr<nbt::tag_compound> parseLevelDat(QByteArray data) { QByteArray output; - if(!GZip::unzip(data, output)) - { + if (!GZip::unzip(data, output)) { return nullptr; } std::istringstream foo(std::string(output.constData(), output.size())); try { auto pair = nbt::io::read_compound(foo); - if(pair.first != "") + if (pair.first != "") return nullptr; - if(pair.second == nullptr) + if (pair.second == nullptr) return nullptr; return std::move(pair.second); - } - catch (const nbt::io::input_error &e) - { + } catch (const nbt::io::input_error& e) { qWarning() << "Unable to parse level.dat:" << e.what(); return nullptr; } } -QByteArray serializeLevelDat(nbt::tag_compound * levelInfo) +QByteArray serializeLevelDat(nbt::tag_compound* levelInfo) { std::ostringstream s; nbt::io::write_tag("", *levelInfo, s); - QByteArray val( s.str().data(), (int) s.str().size() ); + QByteArray val(s.str().data(), (int)s.str().size()); return val; } -QString getLevelDatFromFS(const QFileInfo &file) +QString getLevelDatFromFS(const QFileInfo& file) { QDir worldDir(file.filePath()); - if(!file.isDir() || !worldDir.exists("level.dat")) - { + if (!file.isDir() || !worldDir.exists("level.dat")) { return QString(); } return worldDir.absoluteFilePath("level.dat"); } -QByteArray getLevelDatDataFromFS(const QFileInfo &file) +QByteArray getLevelDatDataFromFS(const QFileInfo& file) { auto fullFilePath = getLevelDatFromFS(file); - if(fullFilePath.isNull()) - { + if (fullFilePath.isNull()) { return QByteArray(); } QFile f(fullFilePath); - if(!f.open(QIODevice::ReadOnly)) - { + if (!f.open(QIODevice::ReadOnly)) { return QByteArray(); } return f.readAll(); } -bool putLevelDatDataToFS(const QFileInfo &file, QByteArray & data) +bool putLevelDatDataToFS(const QFileInfo& file, QByteArray& data) { - auto fullFilePath = getLevelDatFromFS(file); - if(fullFilePath.isNull()) - { + auto fullFilePath = getLevelDatFromFS(file); + if (fullFilePath.isNull()) { return false; } QSaveFile f(fullFilePath); - if(!f.open(QIODevice::WriteOnly)) - { + if (!f.open(QIODevice::WriteOnly)) { return false; } QByteArray compressed; - if(!GZip::zip(data, compressed)) - { + if (!GZip::zip(data, compressed)) { return false; } - if(f.write(compressed) != compressed.size()) - { + if (f.write(compressed) != compressed.size()) { f.cancelWriting(); return false; } return f.commit(); } -int64_t calculateWorldSize(const QFileInfo &file) +int64_t calculateWorldSize(const QFileInfo& file) { - if (file.isFile() && file.suffix() == "zip") - { + if (file.isFile() && file.suffix() == "zip") { return file.size(); - } - else if(file.isDir()) - { + } else if (file.isDir()) { QDirIterator it(file.absoluteFilePath(), QDir::Files, QDirIterator::Subdirectories); int64_t total = 0; - while (it.hasNext()) - { + while (it.hasNext()) { total += it.fileInfo().size(); it.next(); } @@ -231,25 +214,22 @@ int64_t calculateWorldSize(const QFileInfo &file) return -1; } -World::World(const QFileInfo &file) +World::World(const QFileInfo& file) { repath(file); } -void World::repath(const QFileInfo &file) +void World::repath(const QFileInfo& file) { m_containerFile = file; m_folderName = file.fileName(); m_size = calculateWorldSize(file); - if(file.isFile() && file.suffix() == "zip") - { + if (file.isFile() && file.suffix() == "zip") { m_iconFile = QString(); readFromZip(file); - } - else if(file.isDir()) - { + } else if (file.isDir()) { QFileInfo assumedIconPath(file.absoluteFilePath() + "/icon.png"); - if(assumedIconPath.exists()) { + if (assumedIconPath.exists()) { m_iconFile = assumedIconPath.absoluteFilePath(); } readFromFS(file); @@ -258,21 +238,20 @@ void World::repath(const QFileInfo &file) bool World::resetIcon() { - if(m_iconFile.isNull()) { + if (m_iconFile.isNull()) { return false; } - if(QFile(m_iconFile).remove()) { + if (QFile(m_iconFile).remove()) { m_iconFile = QString(); return true; } return false; } -void World::readFromFS(const QFileInfo &file) +void World::readFromFS(const QFileInfo& file) { auto bytes = getLevelDatDataFromFS(file); - if(bytes.isEmpty()) - { + if (bytes.isEmpty()) { is_valid = false; return; } @@ -280,104 +259,88 @@ void World::readFromFS(const QFileInfo &file) levelDatTime = file.lastModified(); } -void World::readFromZip(const QFileInfo &file) +void World::readFromZip(const QFileInfo& file) { QuaZip zip(file.absoluteFilePath()); is_valid = zip.open(QuaZip::mdUnzip); - if (!is_valid) - { + if (!is_valid) { return; } auto location = MMCZip::findFolderOfFileInZip(&zip, "level.dat"); is_valid = !location.isEmpty(); - if (!is_valid) - { + if (!is_valid) { return; } m_containerOffsetPath = location; QuaZipFile zippedFile(&zip); // read the install profile is_valid = zip.setCurrentFile(location + "level.dat"); - if (!is_valid) - { + if (!is_valid) { return; } is_valid = zippedFile.open(QIODevice::ReadOnly); QuaZipFileInfo64 levelDatInfo; zippedFile.getFileInfo(&levelDatInfo); auto modTime = levelDatInfo.getNTFSmTime(); - if(!modTime.isValid()) - { + if (!modTime.isValid()) { modTime = levelDatInfo.dateTime; } levelDatTime = modTime; - if (!is_valid) - { + if (!is_valid) { return; } loadFromLevelDat(zippedFile.readAll()); zippedFile.close(); } -bool World::install(const QString &to, const QString &name) +bool World::install(const QString& to, const QString& name) { auto finalPath = FS::PathCombine(to, FS::DirNameFromString(m_actualName, to)); - if(!FS::ensureFolderPathExists(finalPath)) - { + if (!FS::ensureFolderPathExists(finalPath)) { return false; } bool ok = false; - if(m_containerFile.isFile()) - { + if (m_containerFile.isFile()) { QuaZip zip(m_containerFile.absoluteFilePath()); - if (!zip.open(QuaZip::mdUnzip)) - { + if (!zip.open(QuaZip::mdUnzip)) { return false; } ok = !MMCZip::extractSubDir(&zip, m_containerOffsetPath, finalPath); - } - else if(m_containerFile.isDir()) - { + } else if (m_containerFile.isDir()) { QString from = m_containerFile.filePath(); ok = FS::copy(from, finalPath)(); } - if(ok && !name.isEmpty() && m_actualName != name) - { + if (ok && !name.isEmpty() && m_actualName != name) { QFileInfo finalPathInfo(finalPath); World newWorld(finalPathInfo); - if(newWorld.isValid()) - { + if (newWorld.isValid()) { newWorld.rename(name); } } return ok; } -bool World::rename(const QString &newName) +bool World::rename(const QString& newName) { - if(m_containerFile.isFile()) - { + if (m_containerFile.isFile()) { return false; } auto data = getLevelDatDataFromFS(m_containerFile); - if(data.isEmpty()) - { + if (data.isEmpty()) { return false; } auto worldData = parseLevelDat(data); - if(!worldData) - { + if (!worldData) { return false; } - auto &val = worldData->at("Data"); - if(val.get_type() != nbt::tag_type::Compound) - { + auto& val = worldData->at("Data"); + if (val.get_type() != nbt::tag_type::Compound) { return false; } - auto &dataCompound = val.as<nbt::tag_compound>(); + auto& dataCompound = val.as<nbt::tag_compound>(); dataCompound.put("LevelName", nbt::value_initializer(newName.toUtf8().data())); data = serializeLevelDat(worldData.get()); @@ -396,112 +359,93 @@ bool World::rename(const QString &newName) namespace { -optional<QString> read_string (nbt::value& parent, const char * name) +optional<QString> read_string(nbt::value& parent, const char* name) { - try - { - auto &namedValue = parent.at(name); - if(namedValue.get_type() != nbt::tag_type::String) - { + try { + auto& namedValue = parent.at(name); + if (namedValue.get_type() != nbt::tag_type::String) { return nullopt; } - auto & tag_str = namedValue.as<nbt::tag_string>(); + auto& tag_str = namedValue.as<nbt::tag_string>(); return QString::fromStdString(tag_str.get()); - } - catch (const std::out_of_range &e) - { + } catch ([[maybe_unused]] const std::out_of_range& e) { // fallback for old world formats qWarning() << "String NBT tag" << name << "could not be found."; return nullopt; - } - catch (const std::bad_cast &e) - { + } catch ([[maybe_unused]] const std::bad_cast& e) { // type mismatch qWarning() << "NBT tag" << name << "could not be converted to string."; return nullopt; } } -optional<int64_t> read_long (nbt::value& parent, const char * name) +optional<int64_t> read_long(nbt::value& parent, const char* name) { - try - { - auto &namedValue = parent.at(name); - if(namedValue.get_type() != nbt::tag_type::Long) - { + try { + auto& namedValue = parent.at(name); + if (namedValue.get_type() != nbt::tag_type::Long) { return nullopt; } - auto & tag_str = namedValue.as<nbt::tag_long>(); + auto& tag_str = namedValue.as<nbt::tag_long>(); return tag_str.get(); - } - catch (const std::out_of_range &e) - { + } catch ([[maybe_unused]] const std::out_of_range& e) { // fallback for old world formats qWarning() << "Long NBT tag" << name << "could not be found."; return nullopt; - } - catch (const std::bad_cast &e) - { + } catch ([[maybe_unused]] const std::bad_cast& e) { // type mismatch qWarning() << "NBT tag" << name << "could not be converted to long."; return nullopt; } } -optional<int> read_int (nbt::value& parent, const char * name) +optional<int> read_int(nbt::value& parent, const char* name) { - try - { - auto &namedValue = parent.at(name); - if(namedValue.get_type() != nbt::tag_type::Int) - { + try { + auto& namedValue = parent.at(name); + if (namedValue.get_type() != nbt::tag_type::Int) { return nullopt; } - auto & tag_str = namedValue.as<nbt::tag_int>(); + auto& tag_str = namedValue.as<nbt::tag_int>(); return tag_str.get(); - } - catch (const std::out_of_range &e) - { + } catch ([[maybe_unused]] const std::out_of_range& e) { // fallback for old world formats qWarning() << "Int NBT tag" << name << "could not be found."; return nullopt; - } - catch (const std::bad_cast &e) - { + } catch ([[maybe_unused]] const std::bad_cast& e) { // type mismatch qWarning() << "NBT tag" << name << "could not be converted to int."; return nullopt; } } -GameType read_gametype(nbt::value& parent, const char * name) { +GameType read_gametype(nbt::value& parent, const char* name) +{ return GameType(read_int(parent, name)); } -} +} // namespace void World::loadFromLevelDat(QByteArray data) { auto levelData = parseLevelDat(data); - if(!levelData) - { + if (!levelData) { is_valid = false; return; } - nbt::value * valPtr = nullptr; + nbt::value* valPtr = nullptr; try { valPtr = &levelData->at("Data"); - } - catch (const std::out_of_range &e) { + } catch (const std::out_of_range& e) { qWarning() << "Unable to read NBT tags from " << m_folderName << ":" << e.what(); is_valid = false; return; } - nbt::value &val = *valPtr; + nbt::value& val = *valPtr; is_valid = val.get_type() == nbt::tag_type::Compound; - if(!is_valid) + if (!is_valid) return; auto name = read_string(val, "LevelName"); @@ -514,31 +458,30 @@ void World::loadFromLevelDat(QByteArray data) optional<int64_t> randomSeed; try { - auto &WorldGen_val = val.at("WorldGenSettings"); + auto& WorldGen_val = val.at("WorldGenSettings"); randomSeed = read_long(WorldGen_val, "seed"); + } catch (const std::out_of_range&) { } - catch (const std::out_of_range &) {} - if(!randomSeed) { + if (!randomSeed) { randomSeed = read_long(val, "RandomSeed"); } m_randomSeed = randomSeed ? *randomSeed : 0; qDebug() << "World Name:" << m_actualName; qDebug() << "Last Played:" << m_lastPlayed.toString(); - if(randomSeed) { + if (randomSeed) { qDebug() << "Seed:" << *randomSeed; } qDebug() << "Size:" << m_size; qDebug() << "GameType:" << m_gameType.toLogString(); } -bool World::replace(World &with) +bool World::replace(World& with) { if (!destroy()) return false; bool success = FS::copy(with.m_containerFile.filePath(), m_containerFile.path())(); - if (success) - { + if (success) { m_folderName = with.m_folderName; m_containerFile.refresh(); } @@ -547,25 +490,23 @@ bool World::replace(World &with) bool World::destroy() { - if(!is_valid) return false; + if (!is_valid) + return false; if (FS::trash(m_containerFile.filePath())) return true; - if (m_containerFile.isDir()) - { + if (m_containerFile.isDir()) { QDir d(m_containerFile.filePath()); return d.removeRecursively(); - } - else if(m_containerFile.isFile()) - { + } else if (m_containerFile.isFile()) { QFile file(m_containerFile.absoluteFilePath()); return file.remove(); } return true; } -bool World::operator==(const World &other) const +bool World::operator==(const World& other) const { return is_valid == other.is_valid && folderName() == other.folderName(); } @@ -585,8 +526,7 @@ bool World::isSymLinkUnder(const QString& instPath) const bool World::isMoreThanOneHardLink() const { - if (m_containerFile.isDir()) - { + if (m_containerFile.isDir()) { return FS::hardLinkCount(QDir(m_containerFile.absoluteFilePath()).filePath("level.dat")) > 1; } return FS::hardLinkCount(m_containerFile.absoluteFilePath()) > 1; |