diff options
Diffstat (limited to 'api/logic')
-rw-r--r-- | api/logic/CMakeLists.txt | 2 | ||||
-rw-r--r-- | api/logic/minecraft/World.cpp | 192 | ||||
-rw-r--r-- | api/logic/minecraft/World.h | 26 | ||||
-rw-r--r-- | api/logic/minecraft/WorldList.cpp | 2 |
4 files changed, 152 insertions, 70 deletions
diff --git a/api/logic/CMakeLists.txt b/api/logic/CMakeLists.txt index 15916bb5..be4318a8 100644 --- a/api/logic/CMakeLists.txt +++ b/api/logic/CMakeLists.txt @@ -526,7 +526,7 @@ set_target_properties(MultiMC_logic PROPERTIES CXX_VISIBILITY_PRESET hidden VISI generate_export_header(MultiMC_logic) # Link -target_link_libraries(MultiMC_logic systeminfo MultiMC_quazip MultiMC_classparser ${NBT_NAME} ${ZLIB_LIBRARIES} BuildConfig) +target_link_libraries(MultiMC_logic systeminfo MultiMC_quazip MultiMC_classparser ${NBT_NAME} ${ZLIB_LIBRARIES} optional-bare BuildConfig) target_link_libraries(MultiMC_logic Qt5::Core Qt5::Xml Qt5::Network Qt5::Concurrent) # Mark and export headers diff --git a/api/logic/minecraft/World.cpp b/api/logic/minecraft/World.cpp index 06a6080a..ad06bb83 100644 --- a/api/logic/minecraft/World.cpp +++ b/api/logic/minecraft/World.cpp @@ -32,7 +32,36 @@ #include <QCoreApplication> -QString gameTypeToString(GameType type) +#include <nonstd/optional> + +using nonstd::optional; +using nonstd::nullopt; + +GameType::GameType(nonstd::optional<int> original): + original(original) +{ + if(!original) { + return; + } + switch(*original) { + case 0: + type = GameType::Survival; + break; + case 1: + type = GameType::Creative; + break; + case 2: + type = GameType::Adventure; + break; + case 3: + type = GameType::Spectator; + break; + default: + break; + } +} + +QString GameType::toTranslatedString() const { switch (type) { @@ -47,7 +76,31 @@ QString gameTypeToString(GameType type) default: break; } - return QObject::tr("Unknown"); + if(original) { + return QCoreApplication::translate("GameType", "Unknown (%1)").arg(*original); + } + return QCoreApplication::translate("GameType", "Undefined"); +} + +QString GameType::toLogString() const +{ + switch (type) + { + case GameType::Survival: + return "Survival"; + case GameType::Creative: + return "Creative"; + case GameType::Adventure: + return "Adventure"; + case GameType::Spectator: + return "Spectator"; + default: + break; + } + if(original) { + return QString("Unknown (%1)").arg(*original); + } + return "Undefined"; } std::unique_ptr <nbt::tag_compound> parseLevelDat(QByteArray data) @@ -58,15 +111,22 @@ std::unique_ptr <nbt::tag_compound> parseLevelDat(QByteArray data) return nullptr; } std::istringstream foo(std::string(output.constData(), output.size())); - auto pair = nbt::io::read_compound(foo); + try { + auto pair = nbt::io::read_compound(foo); - if(pair.first != "") - return nullptr; + if(pair.first != "") + return nullptr; - if(pair.second == nullptr) - return nullptr; + if(pair.second == nullptr) + return nullptr; - return std::move(pair.second); + return std::move(pair.second); + } + catch (const nbt::io::input_error &e) + { + qWarning() << "Unable to parse level.dat:" << e.what(); + return nullptr; + } } QByteArray serializeLevelDat(nbt::tag_compound * levelInfo) @@ -288,14 +348,16 @@ bool World::rename(const QString &newName) return true; } -static QString read_string (nbt::value& parent, const char * name, const QString & fallback = QString()) +namespace { + +optional<QString> read_string (nbt::value& parent, const char * name) { try { auto &namedValue = parent.at(name); if(namedValue.get_type() != nbt::tag_type::String) { - return fallback; + return nullopt; } auto & tag_str = namedValue.as<nbt::tag_string>(); return QString::fromStdString(tag_str.get()); @@ -303,25 +365,25 @@ static QString read_string (nbt::value& parent, const char * name, const QString catch (const std::out_of_range &e) { // fallback for old world formats - qWarning() << "String NBT tag" << name << "could not be found. Defaulting to" << fallback; - return fallback; + qWarning() << "String NBT tag" << name << "could not be found."; + return nullopt; } catch (const std::bad_cast &e) { // type mismatch - qWarning() << "NBT tag" << name << "could not be converted to string. Defaulting to" << fallback; - return fallback; + qWarning() << "NBT tag" << name << "could not be converted to string."; + return nullopt; } } -static int64_t read_long (nbt::value& parent, const char * name, const int64_t & fallback = 0) +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) { - return fallback; + return nullopt; } auto & tag_str = namedValue.as<nbt::tag_long>(); return tag_str.get(); @@ -329,25 +391,25 @@ static int64_t read_long (nbt::value& parent, const char * name, const int64_t & catch (const std::out_of_range &e) { // fallback for old world formats - qWarning() << "Long NBT tag" << name << "could not be found. Defaulting to" << fallback; - return fallback; + qWarning() << "Long NBT tag" << name << "could not be found."; + return nullopt; } catch (const std::bad_cast &e) { // type mismatch - qWarning() << "NBT tag" << name << "could not be converted to long. Defaulting to" << fallback; - return fallback; + qWarning() << "NBT tag" << name << "could not be converted to long."; + return nullopt; } } -static int read_int (nbt::value& parent, const char * name, const int & fallback = 0) +optional<int> read_int (nbt::value& parent, const char * name) { try { auto &namedValue = parent.at(name); if(namedValue.get_type() != nbt::tag_type::Int) { - return fallback; + return nullopt; } auto & tag_str = namedValue.as<nbt::tag_int>(); return tag_str.get(); @@ -355,62 +417,72 @@ static int read_int (nbt::value& parent, const char * name, const int & fallback catch (const std::out_of_range &e) { // fallback for old world formats - qWarning() << "Int NBT tag" << name << "could not be found. Defaulting to" << fallback; - return fallback; + qWarning() << "Int NBT tag" << name << "could not be found."; + return nullopt; } catch (const std::bad_cast &e) { // type mismatch - qWarning() << "NBT tag" << name << "could not be converted to int. Defaulting to" << fallback; - return fallback; + qWarning() << "NBT tag" << name << "could not be converted to int."; + return nullopt; } } +GameType read_gametype(nbt::value& parent, const char * name) { + return GameType(read_int(parent, name)); +} + +} + void World::loadFromLevelDat(QByteArray data) { - try + auto levelData = parseLevelDat(data); + if(!levelData) { - auto levelData = parseLevelDat(data); - if(!levelData) - { - is_valid = false; - return; - } - - auto &val = levelData->at("Data"); - is_valid = val.get_type() == nbt::tag_type::Compound; - if(!is_valid) - return; + is_valid = false; + return; + } - m_actualName = read_string(val, "LevelName", m_folderName); + nbt::value * valPtr = nullptr; + try { + valPtr = &levelData->at("Data"); + } + 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; + is_valid = val.get_type() == nbt::tag_type::Compound; + if(!is_valid) + return; - int64_t temp = read_long(val, "LastPlayed", 0); - if(temp == 0) - { - m_lastPlayed = levelDatTime; - } - else - { - m_lastPlayed = QDateTime::fromMSecsSinceEpoch(temp); - } + auto name = read_string(val, "LevelName"); + m_actualName = name ? *name : m_folderName; - int GameType_val = read_int(val, "GameType", 0); - m_gameType = (GameType) GameType_val; + auto timestamp = read_long(val, "LastPlayed"); + m_lastPlayed = timestamp ? QDateTime::fromMSecsSinceEpoch(*timestamp) : levelDatTime; - m_randomSeed = read_long(val, "RandomSeed", 0); + m_gameType = read_gametype(val, "GameType"); - qDebug() << "World Name:" << m_actualName; - qDebug() << "Last Played:" << m_lastPlayed.toString(); - qDebug() << "Seed:" << m_randomSeed; - qDebug() << "GameMode:" << GameType_val; + optional<int64_t> randomSeed; + try { + auto &WorldGen_val = val.at("WorldGenSettings"); + randomSeed = read_long(WorldGen_val, "seed"); } - catch (const nbt::io::input_error &e) - { - qWarning() << "Unable to load" << m_folderName << ":" << e.what(); - is_valid = false; - return; + catch (std::out_of_range) {} + 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) { + qDebug() << "Seed:" << *randomSeed; } + qDebug() << "GameType:" << m_gameType.toLogString(); } bool World::replace(World &with) diff --git a/api/logic/minecraft/World.h b/api/logic/minecraft/World.h index d04c1040..ba7c357c 100644 --- a/api/logic/minecraft/World.h +++ b/api/logic/minecraft/World.h @@ -16,17 +16,27 @@ #pragma once #include <QFileInfo> #include <QDateTime> +#include <nonstd/optional> #include "multimc_logic_export.h" -enum class GameType -{ - Survival, - Creative, - Adventure, - Spectator +struct MULTIMC_LOGIC_EXPORT GameType { + GameType() = default; + GameType (nonstd::optional<int> original); + + QString toTranslatedString() const; + QString toLogString() const; + + enum + { + Unknown = -1, + Survival = 0, + Creative, + Adventure, + Spectator + } type = Unknown; + nonstd::optional<int> original; }; -QString MULTIMC_LOGIC_EXPORT gameTypeToString(GameType type); class MULTIMC_LOGIC_EXPORT World { @@ -98,6 +108,6 @@ protected: QDateTime levelDatTime; QDateTime m_lastPlayed; int64_t m_randomSeed = 0; - GameType m_gameType = GameType::Survival; + GameType m_gameType; bool is_valid = false; }; diff --git a/api/logic/minecraft/WorldList.cpp b/api/logic/minecraft/WorldList.cpp index 94b59da4..7bb9ab76 100644 --- a/api/logic/minecraft/WorldList.cpp +++ b/api/logic/minecraft/WorldList.cpp @@ -175,7 +175,7 @@ QVariant WorldList::data(const QModelIndex &index, int role) const return world.name(); case GameModeColumn: - return gameTypeToString(world.gameType()); + return world.gameType().toTranslatedString(); case LastPlayedColumn: return world.lastPlayed(); |