diff options
Diffstat (limited to 'api')
| -rw-r--r-- | api/gui/icons/IconList.cpp | 8 | ||||
| -rw-r--r-- | api/gui/icons/IconList.h | 11 | ||||
| -rw-r--r-- | api/logic/BaseInstance.cpp | 41 | ||||
| -rw-r--r-- | api/logic/BaseInstance.h | 37 | ||||
| -rw-r--r-- | api/logic/BaseInstanceProvider.h | 57 | ||||
| -rw-r--r-- | api/logic/CMakeLists.txt | 11 | ||||
| -rw-r--r-- | api/logic/FolderInstanceProvider.cpp | 356 | ||||
| -rw-r--r-- | api/logic/FolderInstanceProvider.h | 63 | ||||
| -rw-r--r-- | api/logic/InstanceCopyTask.cpp | 53 | ||||
| -rw-r--r-- | api/logic/InstanceCopyTask.h | 34 | ||||
| -rw-r--r-- | api/logic/InstanceCreationTask.cpp | 46 | ||||
| -rw-r--r-- | api/logic/InstanceCreationTask.h | 31 | ||||
| -rw-r--r-- | api/logic/InstanceImportTask.cpp | 146 | ||||
| -rw-r--r-- | api/logic/InstanceImportTask.h | 40 | ||||
| -rw-r--r-- | api/logic/InstanceList.cpp | 508 | ||||
| -rw-r--r-- | api/logic/InstanceList.h | 111 | ||||
| -rw-r--r-- | api/logic/icons/IIconList.h | 8 | ||||
| -rw-r--r-- | api/logic/minecraft/ftb/FTBInstanceProvider.cpp | 278 | ||||
| -rw-r--r-- | api/logic/minecraft/ftb/FTBInstanceProvider.h | 45 | ||||
| -rw-r--r-- | api/logic/minecraft/ftb/FTBPlugin.cpp | 286 | ||||
| -rw-r--r-- | api/logic/minecraft/ftb/FTBPlugin.h | 1 | ||||
| -rw-r--r-- | api/logic/tasks/ThreadTask.h | 3 |
22 files changed, 1402 insertions, 772 deletions
diff --git a/api/gui/icons/IconList.cpp b/api/gui/icons/IconList.cpp index 4f9fb09f..b6be007f 100644 --- a/api/gui/icons/IconList.cpp +++ b/api/gui/icons/IconList.cpp @@ -243,7 +243,7 @@ int IconList::rowCount(const QModelIndex &parent) const return icons.size(); } -void IconList::installIcons(QStringList iconFiles) +void IconList::installIcons(const QStringList &iconFiles) { for (QString file : iconFiles) { @@ -261,7 +261,7 @@ void IconList::installIcons(QStringList iconFiles) } } -bool IconList::iconFileExists(QString key) +bool IconList::iconFileExists(const QString &key) const { auto iconEntry = icon(key); if(!iconEntry) @@ -271,7 +271,7 @@ bool IconList::iconFileExists(QString key) return iconEntry->has(IconType::FileBased); } -const MMCIcon *IconList::icon(QString key) +const MMCIcon *IconList::icon(const QString &key) const { int iconIdx = getIconIndex(key); if (iconIdx == -1) @@ -279,7 +279,7 @@ const MMCIcon *IconList::icon(QString key) return &icons[iconIdx]; } -bool IconList::deleteIcon(QString key) +bool IconList::deleteIcon(const QString &key) { int iconIdx = getIconIndex(key); if (iconIdx == -1) diff --git a/api/gui/icons/IconList.h b/api/gui/icons/IconList.h index 7aeb7067..24ff4454 100644 --- a/api/gui/icons/IconList.h +++ b/api/gui/icons/IconList.h @@ -44,18 +44,19 @@ public: virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; - virtual bool addIcon(QString key, QString name, QString path, IconType type) override; - bool deleteIcon(QString key); - bool iconFileExists(QString key); + bool addIcon(const QString &key, const QString &name, const QString &path, const IconType type) override; + void saveIcon(const QString &key, const QString &path, const char * format) const override; + bool deleteIcon(const QString &key) override; + bool iconFileExists(const QString &key) const override; virtual QStringList mimeTypes() const override; virtual Qt::DropActions supportedDropActions() const override; virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; virtual Qt::ItemFlags flags(const QModelIndex &index) const override; - void installIcons(QStringList iconFiles); + void installIcons(const QStringList &iconFiles) override; - const MMCIcon * icon(QString key); + const MMCIcon * icon(const QString &key) const; void startWatching(); void stopWatching(); diff --git a/api/logic/BaseInstance.cpp b/api/logic/BaseInstance.cpp index 9dee2c38..452e657a 100644 --- a/api/logic/BaseInstance.cpp +++ b/api/logic/BaseInstance.cpp @@ -17,6 +17,7 @@ #include <QFileInfo> #include <QDir> +#include <QDebug> #include "settings/INISettingsObject.h" #include "settings/Setting.h" @@ -74,10 +75,32 @@ void BaseInstance::iconUpdated(QString key) } } +void BaseInstance::invalidate() +{ + changeStatus(Status::Gone); + qDebug() << "Instance" << id() << "has been invalidated."; +} + void BaseInstance::nuke() { + changeStatus(Status::Gone); + qDebug() << "Instance" << id() << "has been deleted by MultiMC."; FS::deletePath(instanceRoot()); - emit nuked(this); +} + +void BaseInstance::changeStatus(BaseInstance::Status newStatus) +{ + Status status = currentStatus(); + if(status != newStatus) + { + m_status = newStatus; + emit statusChanged(status, newStatus); + } +} + +BaseInstance::Status BaseInstance::currentStatus() const +{ + return m_status; } QString BaseInstance::id() const @@ -278,3 +301,19 @@ std::shared_ptr<LaunchTask> BaseInstance::getLaunchTask() { return m_launchProcess; } + +void BaseInstance::setProvider(BaseInstanceProvider* provider) +{ + // only once. + assert(!m_provider); + if(m_provider) + { + qWarning() << "Provider set more than once for instance" << id(); + } + m_provider = provider; +} + +BaseInstanceProvider* BaseInstance::provider() const +{ + return m_provider; +} diff --git a/api/logic/BaseInstance.h b/api/logic/BaseInstance.h index ebaaeb83..56d3d6cb 100644 --- a/api/logic/BaseInstance.h +++ b/api/logic/BaseInstance.h @@ -14,6 +14,7 @@ */ #pragma once +#include <cassert> #include <QObject> #include "QObjectPtr.h" @@ -35,6 +36,7 @@ class QDir; class Task; class LaunchTask; class BaseInstance; +class BaseInstanceProvider; // pointer for lazy people typedef std::shared_ptr<BaseInstance> InstancePtr; @@ -54,6 +56,13 @@ protected: /// no-touchy! BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir); +public: /* types */ + enum class Status + { + Present, + Gone // either nuked or invalidated + }; + public: /// virtual destructor to make sure the destruction is COMPLETE virtual ~BaseInstance() {}; @@ -66,6 +75,14 @@ public: /// responsible of cleaning up the husk void nuke(); + /*** + * the instance has been invalidated - it is no longer tracked by MultiMC for some reason, + * but it has not necessarily been deleted. + * + * Happens when the instance folder changes to some other location, or the instance is removed by external means. + */ + void invalidate(); + /// The instance's ID. The ID SHALL be determined by MMC internally. The ID IS guaranteed to /// be unique. virtual QString id() const; @@ -75,6 +92,9 @@ public: int64_t totalTimePlayed() const; void resetTimePlayed(); + void setProvider(BaseInstanceProvider * provider); + BaseInstanceProvider * provider() const; + /// get the type of this instance QString instanceType() const; @@ -219,6 +239,11 @@ public: */ virtual QStringList verboseDescription(AuthSessionPtr session) = 0; + Status currentStatus() const; + +protected: + void changeStatus(Status newStatus); + signals: /*! * \brief Signal emitted when properties relevant to the instance view change @@ -228,10 +253,6 @@ signals: * \brief Signal emitted when groups are affected in any way */ void groupChanged(); - /*! - * \brief The instance just got nuked. Hurray! - */ - void nuked(BaseInstance *inst); void flagsChanged(); @@ -239,10 +260,12 @@ signals: void runningStatusChanged(bool running); + void statusChanged(Status from, Status to); + protected slots: void iconUpdated(QString key); -protected: +protected: /* data */ QString m_rootDir; QString m_group; SettingsObjectPtr m_settings; @@ -250,6 +273,10 @@ protected: bool m_isRunning = false; std::shared_ptr<LaunchTask> m_launchProcess; QDateTime m_timeStarted; + BaseInstanceProvider * m_provider = nullptr; + +private: /* data */ + Status m_status = Status::Present; }; Q_DECLARE_METATYPE(std::shared_ptr<BaseInstance>) diff --git a/api/logic/BaseInstanceProvider.h b/api/logic/BaseInstanceProvider.h new file mode 100644 index 00000000..f6833650 --- /dev/null +++ b/api/logic/BaseInstanceProvider.h @@ -0,0 +1,57 @@ +#pragma once + +#include <QObject> +#include <QString> +#include "BaseInstance.h" +#include "settings/SettingsObject.h" + +#include "multimc_logic_export.h" + +using InstanceId = QString; +using InstanceLocator = std::pair<InstancePtr, int>; + +enum class InstCreateError +{ + NoCreateError = 0, + NoSuchVersion, + UnknownCreateError, + InstExists, + CantCreateDir +}; + +class MULTIMC_LOGIC_EXPORT BaseInstanceProvider : public QObject +{ + Q_OBJECT +public: + BaseInstanceProvider(SettingsObjectPtr settings) : m_globalSettings(settings) + { + // nil + } +public: + virtual QList<InstanceId> discoverInstances() = 0; + virtual InstancePtr loadInstance(const InstanceId &id) = 0; + virtual void loadGroupList() = 0; + virtual void saveGroupList() = 0; + + virtual QString getStagedInstancePath() + { + return QString(); + } + virtual bool commitStagedInstance(const QString & keyPath, const QString & path, const QString& instanceName, const QString & groupName) + { + return false; + } + virtual bool destroyStagingPath(const QString & path) + { + return true; + } + +signals: + // Emit this when the list of provided instances changed + void instancesChanged(); + // Emit when the set of groups your provider supplies changes. + void groupsChanged(QSet<QString> groups); + +protected: + SettingsObjectPtr m_globalSettings; +}; diff --git a/api/logic/CMakeLists.txt b/api/logic/CMakeLists.txt index c430b53f..0741fb1a 100644 --- a/api/logic/CMakeLists.txt +++ b/api/logic/CMakeLists.txt @@ -8,8 +8,17 @@ set(CORE_SOURCES BaseInstaller.cpp BaseVersionList.h BaseVersionList.cpp + InstanceCreationTask.h + InstanceCreationTask.cpp + InstanceCopyTask.h + InstanceCopyTask.cpp + InstanceImportTask.h + InstanceImportTask.cpp InstanceList.h InstanceList.cpp + BaseInstanceProvider.h + FolderInstanceProvider.h + FolderInstanceProvider.cpp BaseVersion.h BaseInstance.h BaseInstance.cpp @@ -276,6 +285,8 @@ set(MINECRAFT_SOURCES minecraft/ftb/LegacyFTBInstance.cpp minecraft/ftb/FTBProfileStrategy.h minecraft/ftb/FTBProfileStrategy.cpp + minecraft/ftb/FTBInstanceProvider.cpp + minecraft/ftb/FTBInstanceProvider.h minecraft/ftb/FTBPlugin.h minecraft/ftb/FTBPlugin.cpp diff --git a/api/logic/FolderInstanceProvider.cpp b/api/logic/FolderInstanceProvider.cpp new file mode 100644 index 00000000..a1f3f1f2 --- /dev/null +++ b/api/logic/FolderInstanceProvider.cpp @@ -0,0 +1,356 @@ +#include "FolderInstanceProvider.h" +#include "settings/INISettingsObject.h" +#include "FileSystem.h" +#include "minecraft/onesix/OneSixInstance.h" +#include "minecraft/legacy/LegacyInstance.h" +#include "NullInstance.h" + +#include <QDir> +#include <QDirIterator> +#include <QFileSystemWatcher> +#include <QJsonDocument> +#include <QJsonObject> +#include <QJsonArray> +#include <QUuid> + +const static int GROUP_FILE_FORMAT_VERSION = 1; + +struct WatchLock +{ + WatchLock(QFileSystemWatcher * watcher, const QString& instDir) + : m_watcher(watcher), m_instDir(instDir) + { + m_watcher->removePath(m_instDir); + } + ~WatchLock() + { + m_watcher->addPath(m_instDir); + } + QFileSystemWatcher * m_watcher; + QString m_instDir; +}; + +FolderInstanceProvider::FolderInstanceProvider(SettingsObjectPtr settings, const QString& instDir) + : BaseInstanceProvider(settings) +{ + m_instDir = instDir; + if (!QDir::current().exists(m_instDir)) + { + QDir::current().mkpath(m_instDir); + } + m_watcher = new QFileSystemWatcher(this); + connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &FolderInstanceProvider::instanceDirContentsChanged); + m_watcher->addPath(m_instDir); +} + +QList< InstanceId > FolderInstanceProvider::discoverInstances() +{ + QList<InstanceId> out; + QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable, QDirIterator::FollowSymlinks); + while (iter.hasNext()) + { + QString subDir = iter.next(); + QFileInfo dirInfo(subDir); + if (!QFileInfo(FS::PathCombine(subDir, "instance.cfg")).exists()) + continue; + // if it is a symlink, ignore it if it goes to the instance folder + if(dirInfo.isSymLink()) + { + QFileInfo targetInfo(dirInfo.symLinkTarget()); + QFileInfo instDirInfo(m_instDir); + if(targetInfo.canonicalPath() == instDirInfo.canonicalFilePath()) + { + qDebug() << "Ignoring symlink" << subDir << "that leads into the instances folder"; + continue; + } + } + auto id = dirInfo.fileName(); + out.append(id); + qDebug() << "Found instance ID" << id; + } + return out; +} + +InstancePtr FolderInstanceProvider::loadInstance(const InstanceId& id) +{ + if(!m_groupsLoaded) + { + loadGroupList(); + } + + auto instanceRoot = FS::PathCombine(m_instDir, id); + auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(instanceRoot, "instance.cfg")); + InstancePtr inst; + + instanceSettings->registerSetting("InstanceType", "Legacy"); + + QString inst_type = instanceSettings->get("InstanceType").toString(); + + if (inst_type == "OneSix" || inst_type == "Nostalgia") + { + inst.reset(new OneSixInstance(m_globalSettings, instanceSettings, instanceRoot)); + } + else if (inst_type == "Legacy") + { + inst.reset(new LegacyInstance(m_globalSettings, instanceSettings, instanceRoot)); + } + else + { + inst.reset(new NullInstance(m_globalSettings, instanceSettings, instanceRoot)); + } + inst->init(); + inst->setProvider(this); + auto iter = groupMap.find(id); + if (iter != groupMap.end()) + { + inst->setGroupInitial((*iter)); + } + connect(inst.get(), &BaseInstance::groupChanged, this, &FolderInstanceProvider::groupChanged); + qDebug() << "Loaded instance " << inst->name() << " from " << inst->instanceRoot(); + return inst; +} + +#include "InstanceImportTask.h" +Task * FolderInstanceProvider::zipImportTask(const QUrl sourceUrl, const QString& instName, const QString& instGroup, const QString& instIcon) +{ + return new InstanceImportTask(m_globalSettings, sourceUrl, this, instName, instGroup, instIcon); +} + +#include "InstanceCreationTask.h" +Task * FolderInstanceProvider::creationTask(BaseVersionPtr version, const QString& instName, const QString& instGroup, const QString& instIcon) +{ + return new InstanceCreationTask(m_globalSettings, this, version, instName, instIcon, instGroup); +} + +#include "InstanceCopyTask.h" +Task * FolderInstanceProvider::copyTask(const InstancePtr& oldInstance, const QString& instName, const QString& instGroup, const QString& instIcon, bool copySaves) +{ + return new InstanceCopyTask(m_globalSettings, this, oldInstance, instName, instIcon, instGroup, copySaves); +} + +void FolderInstanceProvider::saveGroupList() +{ + WatchLock foo(m_watcher, m_instDir); + QString groupFileName = m_instDir + "/instgroups.json"; + QMap<QString, QSet<QString>> reverseGroupMap; + for (auto iter = groupMap.begin(); iter != groupMap.end(); iter++) + { + QString id = iter.key(); + QString group = iter.value(); + if (group.isEmpty()) + continue; + + if (!reverseGroupMap.count(group)) + { + QSet<QString> set; + set.insert(id); + reverseGroupMap[group] = set; + } + else + { + QSet<QString> &set = reverseGroupMap[group]; + set.insert(id); + } + } + QJsonObject toplevel; + toplevel.insert("formatVersion", QJsonValue(QString("1"))); + QJsonObject groupsArr; + for (auto iter = reverseGroupMap.begin(); iter != reverseGroupMap.end(); iter++) + { + auto list = iter.value(); + auto name = iter.key(); + QJsonObject groupObj; + QJsonArray instanceArr; + groupObj.insert("hidden", QJsonValue(QString("false"))); + for (auto item : list) + { + instanceArr.append(QJsonValue(item)); + } + groupObj.insert("instances", instanceArr); + groupsArr.insert(name, groupObj); + } + toplevel.insert("groups", groupsArr); + QJsonDocument doc(toplevel); + try + { + FS::write(groupFileName, doc.toJson()); + } + catch(FS::FileSystemException & e) + { + qCritical() << "Failed to write instance group file :" << e.cause(); + } +} + +void FolderInstanceProvider::loadGroupList() +{ + QSet<QString> groupSet; + + QString groupFileName = m_instDir + "/instgroups.json"; + + // if there's no group file, fail + if (!QFileInfo(groupFileName).exists()) + return; + + QByteArray jsonData; + try + { + jsonData = FS::read(groupFileName); + } + catch (FS::FileSystemException & e) + { + qCritical() << "Failed to read instance group file :" << e.cause(); + return; + } + + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &error); + + // if the json was bad, fail + if (error.error != QJsonParseError::NoError) + { + qCritical() << QString("Failed to parse instance group file: %1 at offset %2") + .arg(error.errorString(), QString::number(error.offset)) + .toUtf8(); + return; + } + + // if the root of the json wasn't an object, fail + if (!jsonDoc.isObject()) + { + qWarning() << "Invalid group file. Root entry should be an object."; + return; + } + + QJsonObject rootObj = jsonDoc.object(); + + // Make sure the format version matches, otherwise fail. + if (rootObj.value("formatVersion").toVariant().toInt() != GROUP_FILE_FORMAT_VERSION) + return; + + // Get the groups. if it's not an object, fail + if (!rootObj.value("groups").isObject()) + { + qWarning() << "Invalid group list JSON: 'groups' should be an object."; + return; + } + + groupMap.clear(); + + // Iterate through all the groups. + QJsonObject groupMapping = rootObj.value("groups").toObject(); + for (QJsonObject::iterator iter = groupMapping.begin(); iter != groupMapping.end(); iter++) + { + QString groupName = iter.key(); + + // If not an object, complain and skip to the next one. + if (!iter.value().isObject()) + { + qWarning() << QString("Group '%1' in the group list should " + "be an object.") + .arg(groupName) + .toUtf8(); + continue; + } + + QJsonObject groupObj = iter.value().toObject(); + if (!groupObj.value("instances").isArray()) + { + qWarning() << QString("Group '%1' in the group list is invalid. " + "It should contain an array " + "called 'instances'.") + .arg(groupName) + .toUtf8(); + continue; + } + + // keep a list/set of groups for choosing + groupSet.insert(groupName); + + // Iterate through the list of instances in the group. + QJsonArray instancesArray = groupObj.value("instances").toArray(); + + for (QJsonArray::iterator iter2 = instancesArray.begin(); iter2 != instancesArray.end(); + iter2++) + { + groupMap[(*iter2).toString()] = groupName; + } + } + m_groupsLoaded = true; + emit groupsChanged(groupSet); +} + +void FolderInstanceProvider::groupChanged() +{ + // save the groups. save all of them. + auto instance = (BaseInstance *) QObject::sender(); + auto id = instance->id(); + groupMap[id] = instance->group(); + emit groupsChanged({instance->group()}); + saveGroupList(); +} + + +void FolderInstanceProvider::instanceDirContentsChanged(const QString& path) +{ + Q_UNUSED(path); + emit instancesChanged(); +} + +void FolderInstanceProvider::on_InstFolderChanged(const Setting &setting, QVariant value) +{ + QString newInstDir = value.toString(); + if(newInstDir != m_instDir) + { + if(m_groupsLoaded) + { + saveGroupList(); + } + m_instDir = newInstDir; + m_groupsLoaded = false; + emit instancesChanged(); + } +} + +QString FolderInstanceProvider::getStagedInstancePath() +{ + QString key = QUuid::createUuid().toString(); + QString relPath = FS::PathCombine("_MMC_TEMP/" , key); + QDir rootPath(m_instDir); + auto path = FS::PathCombine(m_instDir, relPath); + if(!rootPath.mkpath(relPath)) + { + return QString(); + } + return path; +} + +bool FolderInstanceProvider::commitStagedInstance(const QString& keyPath, const QString& path, const QString& instanceName, + const QString& groupName) +{ + if(!path.contains(keyPath)) + { + qWarning() << "It is not possible to commit" << path << "because it is not in" << keyPath; + return false; + } + QDir dir; + QString instID = FS::DirNameFromString(instanceName, m_instDir); + { + WatchLock lock(m_watcher, m_instDir); + if(!dir.rename(path, FS::PathCombine(m_instDir, instID))) + { + destroyStagingPath(keyPath); + return false; + } + groupMap[instID] = groupName; + emit groupsChanged({groupName}); + emit instancesChanged(); + } + saveGroupList(); + return destroyStagingPath(keyPath); +} + +bool FolderInstanceProvider::destroyStagingPath(const QString& keyPath) +{ + return FS::deletePath(keyPath); +} + diff --git a/api/logic/FolderInstanceProvider.h b/api/logic/FolderInstanceProvider.h new file mode 100644 index 00000000..f350a96d --- /dev/null +++ b/api/logic/FolderInstanceProvider.h @@ -0,0 +1,63 @@ +#pragma once + +#include "BaseInstanceProvider.h" +#include <QMap> + +class QFileSystemWatcher; + +class MULTIMC_LOGIC_EXPORT FolderInstanceProvider : public BaseInstanceProvider +{ + Q_OBJECT +public: + FolderInstanceProvider(SettingsObjectPtr settings, const QString & instDir); + +public: + /// used by InstanceList to @return a list of plausible IDs to probe for + QList<InstanceId> discoverInstances() override; + + /// used by InstanceList to (re)load an instance with the given @id. + InstancePtr loadInstance(const InstanceId& id) override; + + + // create instance in this provider + Task * creationTask(BaseVersionPtr version, const QString &instName, const QString &instGroup, const QString &instIcon); + + // copy instance to this provider + Task * copyTask(const InstancePtr &oldInstance, const QString& instName, const QString& instGroup, const QString& instIcon, bool copySaves); + + // import zipped instance into this provider + Task * zipImportTask(const QUrl sourceUrl, const QString &instName, const QString &instGroup, const QString &instIcon); + + /** + * Create a new empty staging area for instance creation and @return a path/key top commit it later. + * Used by instance manipulation tasks. + */ + QString getStagedInstancePath() override; + /** + * Commit the staging area given by @keyPath to the provider - used when creation succeeds. + * Used by instance manipulation tasks. + */ + bool commitStagedInstance(const QString & keyPath, const QString & path, const QString& instanceName, const QString & groupName) override; + /** + * Destroy a previously created staging area given by @keyPath - used when creation fails. + * Used by instance manipulation tasks. + */ + bool destroyStagingPath(const QString & keyPath) override; + +public slots: + void on_InstFolderChanged(const Setting &setting, QVariant value); + +private slots: + void instanceDirContentsChanged(const QString &path); + void groupChanged(); + +private: /* methods */ + void loadGroupList() override; + void saveGroupList() override; + +private: /* data */ + QString m_instDir; + QFileSystemWatcher * m_watcher; + QMap<QString, QString> groupMap; + bool m_groupsLoaded = false; +}; diff --git a/api/logic/InstanceCopyTask.cpp b/api/logic/InstanceCopyTask.cpp new file mode 100644 index 00000000..1e231478 --- /dev/null +++ b/api/logic/InstanceCopyTask.cpp @@ -0,0 +1,53 @@ +#include "InstanceCopyTask.h" +#include "BaseInstanceProvider.h" +#include "settings/INISettingsObject.h" +#include "FileSystem.h" +#include "NullInstance.h" +#include "pathmatcher/RegexpMatcher.h" + +InstanceCopyTask::InstanceCopyTask(SettingsObjectPtr settings, BaseInstanceProvider* target, InstancePtr origInstance, const QString& instName, const QString& instIcon, const QString& instGroup, bool copySaves) +{ + m_globalSettings = settings; + m_target = target; + m_origInstance = origInstance; + m_instName = instName; + m_instIcon = instIcon; + m_instGroup = instGroup; + m_copySaves = copySaves; +} + +void InstanceCopyTask::executeTask() +{ + setStatus(tr("Copying instance %1").arg(m_origInstance->name())); + std::unique_ptr<IPathMatcher> matcher; + if(!m_copySaves) + { + // FIXME: get this from the original instance type... + auto matcherReal = new RegexpMatcher("[.]?minecraft/saves"); + matcherReal->caseSensitive(false); + matcher.reset(matcherReal); + } + + QString stagingPath = m_target->getStagedInstancePath(); + FS::copy folderCopy(m_origInstance->instanceRoot(), stagingPath); + folderCopy.followSymlinks(false).blacklist(matcher.get()); + if (!folderCopy()) + { + m_target->destroyStagingPath(stagingPath); + emitFailed(tr("Instance folder copy failed.")); + return; + } + + // FIXME: shouldn't this be able to report errors? + auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(stagingPath, "instance.cfg")); + instanceSettings->registerSetting("InstanceType", "Legacy"); + + // FIXME: and this too? errors??? + m_origInstance->copy(stagingPath); + + InstancePtr inst(new NullInstance(m_globalSettings, instanceSettings, stagingPath)); + inst->setName(m_instName); + inst->setIconKey(m_instIcon); + m_target->commitStagedInstance(stagingPath, stagingPath, m_instName, m_instGroup); + emitSucceeded(); +} diff --git a/api/logic/InstanceCopyTask.h b/api/logic/InstanceCopyTask.h new file mode 100644 index 00000000..a663ddbd --- /dev/null +++ b/api/logic/InstanceCopyTask.h @@ -0,0 +1,34 @@ +#pragma once + +#include "tasks/Task.h" +#include "multimc_logic_export.h" +#include "net/NetJob.h" +#include <QUrl> +#include "settings/SettingsObject.h" +#include "BaseVersion.h" +#include "BaseInstance.h" + +class BaseInstanceProvider; + +class MULTIMC_LOGIC_EXPORT InstanceCopyTask : public Task +{ + Q_OBJECT +public: + explicit InstanceCopyTask(SettingsObjectPtr settings, BaseInstanceProvider * target, InstancePtr origInstance, const QString &instName, + const QString &instIcon, const QString &instGroup, bool copySaves); + +protected: + //! Entry point for tasks. + virtual void executeTask() override; + +private: /* data */ + SettingsObjectPtr m_globalSettings; + BaseInstanceProvider * m_target = nullptr; + InstancePtr m_origInstance; + QString m_instName; + QString m_instIcon; + QString m_instGroup; + bool m_copySaves = false; +}; + + diff --git a/api/logic/InstanceCreationTask.cpp b/api/logic/InstanceCreationTask.cpp new file mode 100644 index 00000000..00156701 --- /dev/null +++ b/api/logic/InstanceCreationTask.cpp @@ -0,0 +1,46 @@ +#include "InstanceCreationTask.h" +#include "BaseInstanceProvider.h" +#include "settings/INISettingsObject.h" +#include "FileSystem.h" + +//FIXME: remove this +#include "minecraft/MinecraftVersion.h" +#include "minecraft/onesix/OneSixInstance.h" + +InstanceCreationTask::InstanceCreationTask(SettingsObjectPtr settings, BaseInstanceProvider* target, BaseVersionPtr version, + const QString& instName, const QString& instIcon, const QString& instGroup) +{ + m_globalSettings = settings; + m_target = target; + m_instName = instName; + m_instIcon = instIcon; + m_instGroup = instGroup; + m_version = version; +} + +void InstanceCreationTask::executeTask() +{ + setStatus(tr("Creating instance from version %1").arg(m_version->name())); + auto minecraftVersion = std::dynamic_pointer_cast<MinecraftVersion>(m_version); + if(!minecraftVersion) + { + emitFailed(tr("The supplied version is not a Minecraft version.")); + return ; + } + + QString stagingPath = m_target->getStagedInstancePath(); + QDir rootDir(stagingPath); + + auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(stagingPath, "instance.cfg")); + instanceSettings->registerSetting("InstanceType", "Legacy"); + + auto mcVer = std::dynamic_pointer_cast<MinecraftVersion>(m_version); + instanceSettings->set("InstanceType", "OneSix"); + InstancePtr inst(new OneSixInstance(m_globalSettings, instanceSettings, stagingPath)); + inst->setIntendedVersionId(m_version->descriptor()); + inst->setName(m_instName); + inst->setIconKey(m_instIcon); + inst->init(); + m_target->commitStagedInstance(stagingPath, stagingPath, m_instName, m_instGroup); + emitSucceeded(); +} diff --git a/api/logic/InstanceCreationTask.h b/api/logic/InstanceCreationTask.h new file mode 100644 index 00000000..b4ade320 --- /dev/null +++ b/api/logic/InstanceCreationTask.h @@ -0,0 +1,31 @@ +#pragma once + +#include "tasks/Task.h" +#include "multimc_logic_export.h" +#include "net/NetJob.h" +#include <QUrl> +#include "settings/SettingsObject.h" +#include "BaseVersion.h" + +class BaseInstanceProvider; + +class MULTIMC_LOGIC_EXPORT InstanceCreationTask : public Task +{ + Q_OBJECT +public: + explicit InstanceCreationTask(SettingsObjectPtr settings, BaseInstanceProvider * target, BaseVersionPtr version, const QString &instName, + const QString &instIcon, const QString &instGroup); + +protected: + //! Entry point for tasks. + virtual void executeTask() override; + +private: /* data */ + SettingsObjectPtr m_globalSettings; + BaseInstanceProvider * m_target; + BaseVersionPtr m_version; + QString m_instName; + QString m_instIcon; + QString m_instGroup; +}; + diff --git a/api/logic/InstanceImportTask.cpp b/api/logic/InstanceImportTask.cpp new file mode 100644 index 00000000..99f2553f --- /dev/null +++ b/api/logic/InstanceImportTask.cpp @@ -0,0 +1,146 @@ + +#include "InstanceImportTask.h" +#include "BaseInstance.h" +#include "BaseInstanceProvider.h" +#include "FileSystem.h" |
