aboutsummaryrefslogtreecommitdiff
path: root/launcher
diff options
context:
space:
mode:
authorRachel Powers <508861+Ryex@users.noreply.github.com>2023-02-06 23:05:06 -0800
committerRachel Powers <508861+Ryex@users.noreply.github.com>2023-03-20 14:56:27 -0700
commitf794e49bb6eadd70c52683e60a700a1d7e9cd17b (patch)
tree1f5de4708a17937fa1721b73bf8c1c56542f2f72 /launcher
parent6dcf34acdc8ec3dcbb094e4981ef136cd6a99913 (diff)
downloadPrismLauncher-f794e49bb6eadd70c52683e60a700a1d7e9cd17b.tar.gz
PrismLauncher-f794e49bb6eadd70c52683e60a700a1d7e9cd17b.tar.bz2
PrismLauncher-f794e49bb6eadd70c52683e60a700a1d7e9cd17b.zip
we want to make links!
Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
Diffstat (limited to 'launcher')
-rw-r--r--launcher/CMakeLists.txt52
-rw-r--r--launcher/FileSystem.cpp87
-rw-r--r--launcher/FileSystem.h68
-rw-r--r--launcher/InstanceCopyPrefs.cpp30
-rw-r--r--launcher/InstanceCopyPrefs.h9
-rw-r--r--launcher/filelink/FileLink.cpp119
-rw-r--r--launcher/filelink/FileLink.h52
-rw-r--r--launcher/filelink/filelink.exe.manifest28
-rw-r--r--launcher/filelink/main.cpp31
-rw-r--r--launcher/ui/dialogs/CopyInstanceDialog.cpp19
-rw-r--r--launcher/ui/dialogs/CopyInstanceDialog.h3
-rw-r--r--launcher/ui/dialogs/CopyInstanceDialog.ui200
12 files changed, 627 insertions, 71 deletions
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 074570e3..2216aa1b 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -559,6 +559,11 @@ set(ATLAUNCHER_SOURCES
modplatform/atlauncher/ATLShareCode.h
)
+set(LINKDAEMON_SOURCES
+ filelink/FileLink.h
+ filelink/FileLink.cpp
+)
+
######## Logging categories ########
ecm_qt_declare_logging_category(CORE_SOURCES
@@ -1107,6 +1112,53 @@ install(TARGETS ${Launcher_Name}
FRAMEWORK DESTINATION ${FRAMEWORK_DEST_DIR} COMPONENT Runtime
)
+if(WIN32)
+ add_library(filelink_logic STATIC ${LINKDAEMON_SOURCES})
+ target_include_directories(filelink_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+ target_link_libraries(filelink_logic
+ systeminfo
+ BuildConfig
+ Qt${QT_VERSION_MAJOR}::Widgets
+ ghcFilesystem::ghc_filesystem
+ )
+ target_link_libraries(filelink_logic
+ Qt${QT_VERSION_MAJOR}::Core
+ Qt${QT_VERSION_MAJOR}::Xml
+ Qt${QT_VERSION_MAJOR}::Network
+ Qt${QT_VERSION_MAJOR}::Concurrent
+ Qt${QT_VERSION_MAJOR}::Gui
+ Qt${QT_VERSION_MAJOR}::Widgets
+ ${Launcher_QT_LIBS}
+ )
+
+ add_executable("${Launcher_Name}_filelink" WIN32 filelink/main.cpp)
+
+ target_sources("${Launcher_Name}_filelink" PRIVATE filelink/filelink.exe.manifest)
+
+ target_link_libraries("${Launcher_Name}_filelink" filelink_logic)
+
+ if(DEFINED Launcher_APP_BINARY_NAME)
+ set_target_properties("${Launcher_Name}_filelink" PROPERTIES OUTPUT_NAME "${Launcher_APP_BINARY_NAME}_filelink")
+ endif()
+ if(DEFINED Launcher_BINARY_RPATH)
+ SET_TARGET_PROPERTIES("${Launcher_Name}_filelink" PROPERTIES INSTALL_RPATH "${Launcher_BINARY_RPATH}")
+ endif()
+
+ if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ SET_TARGET_PROPERTIES("${Launcher_Name}_filelink" PROPERTIES LINK_FLAGS "/level='requireAdministrator' /uiAccess='false' /SUBSYSTEM:CONSOLE")
+ else()
+ SET_TARGET_PROPERTIES("${Launcher_Name}_filelink" PROPERTIES LINK_FLAGS "/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\" /SUBSYSTEM:CONSOLE")
+ endif()
+
+
+ install(TARGETS "${Launcher_Name}_filelink"
+ BUNDLE DESTINATION "." COMPONENT Runtime
+ LIBRARY DESTINATION ${LIBRARY_DEST_DIR} COMPONENT Runtime
+ RUNTIME DESTINATION ${BINARY_DEST_DIR} COMPONENT Runtime
+ FRAMEWORK DESTINATION ${FRAMEWORK_DEST_DIR} COMPONENT Runtime
+ )
+endif()
+
if (UNIX AND APPLE)
# Add Sparkle updater
# It has to be copied here instead of just allowing fixup_bundle to install it, otherwise essential parts of
diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp
index aee5245d..ec4af98c 100644
--- a/launcher/FileSystem.cpp
+++ b/launcher/FileSystem.cpp
@@ -152,9 +152,11 @@ bool ensureFolderPathExists(QString foldernamepath)
return success;
}
-/// @brief Copies a directory and it's contents from src to dest
-/// @param offset subdirectory form src to copy to dest
-/// @return if there was an error during the filecopy
+/**
+ * @brief Copies a directory and it's contents from src to dest
+ * @param offset subdirectory form src to copy to dest
+ * @return if there was an error during the filecopy
+ */
bool copy::operator()(const QString& offset, bool dryRun)
{
using copy_opts = fs::copy_options;
@@ -215,6 +217,85 @@ bool copy::operator()(const QString& offset, bool dryRun)
return err.value() == 0;
}
+
+/**
+ * @brief links a directory and it's contents from src to dest
+ * @param offset subdirectory form src to link to dest
+ * @return if there was an error during the attempt to link
+ */
+bool create_link::operator()(const QString& offset, bool dryRun)
+{
+ m_linked = 0; // reset counter
+
+ auto src = PathCombine(m_src.absolutePath(), offset);
+ auto dst = PathCombine(m_dst.absolutePath(), offset);
+
+ std::error_code err;
+
+ // you can't hard link a directory so make sure if we deal with a directory we do so recursively
+ if (m_useHardLinks)
+ m_recursive = true;
+
+ // Function that'll do the actual linking
+ auto link_file = [&](QString src_path, QString relative_dst_path) {
+ if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist))
+ return;
+
+ auto dst_path = PathCombine(dst, relative_dst_path);
+ if (!dryRun) {
+
+ ensureFilePathExists(dst_path);
+ if (m_useHardLinks) {
+ if (m_debug)
+ qDebug() << "making hard link:" << src_path << "to" << dst_path;
+ fs::create_hard_link(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), err);
+ } else if (fs::is_directory(StringUtils::toStdString(src_path))) {
+ if (m_debug)
+ qDebug() << "making directory_symlink:" << src_path << "to" << dst_path;
+ fs::create_directory_symlink(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), err);
+ } else {
+ if (m_debug)
+ qDebug() << "making symlink:" << src_path << "to" << dst_path;
+ fs::create_symlink(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), err);
+ }
+
+ }
+ if (err) {
+ qWarning() << "Failed to link files:" << QString::fromStdString(err.message());
+ qDebug() << "Source file:" << src_path;
+ qDebug() << "Destination file:" << dst_path;
+ qDebug() << "Error catagory:" << err.category().name();
+ qDebug() << "Error code:" << err.value();
+ m_last_os_err = err.value();
+ emit linkFailed(src_path, dst_path, err);
+ } else {
+ m_linked++;
+ emit fileLinked(relative_dst_path);
+ }
+
+ };
+
+ if ((!m_recursive) || !fs::is_directory(StringUtils::toStdString(src))) {
+ if (m_debug)
+ qDebug() << "linking single file or dir:" << src << "to" << dst;
+ link_file(src, "");
+ } else {
+ if (m_debug)
+ qDebug() << "linking recursivly:" << src << "to" << dst;
+ QDir src_dir(src);
+ QDirIterator source_it(src, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::Subdirectories);
+
+ while (source_it.hasNext()) {
+ auto src_path = source_it.next();
+ auto relative_path = src_dir.relativeFilePath(src_path);
+
+ link_file(src_path, relative_path);
+ }
+ }
+
+ return err.value() == 0;
+}
+
bool move(const QString& source, const QString& dest)
{
std::error_code err;
diff --git a/launcher/FileSystem.h b/launcher/FileSystem.h
index f083f3c7..98f55f96 100644
--- a/launcher/FileSystem.h
+++ b/launcher/FileSystem.h
@@ -77,7 +77,9 @@ bool ensureFilePathExists(QString filenamepath);
*/
bool ensureFolderPathExists(QString filenamepath);
-/// @brief Copies a directory and it's contents from src to dest
+/**
+ * @brief Copies a directory and it's contents from src to dest
+ */
class copy : public QObject {
Q_OBJECT
public:
@@ -123,6 +125,70 @@ class copy : public QObject {
};
/**
+ * @brief Copies a directory and it's contents from src to dest
+ */
+class create_link : public QObject {
+ Q_OBJECT
+ public:
+ create_link(const QString& src, const QString& dst, QObject* parent = nullptr) : QObject(parent)
+ {
+ m_src.setPath(src);
+ m_dst.setPath(dst);
+ }
+ create_link& useHardLinks(const bool useHard)
+ {
+ m_useHardLinks = useHard;
+ return *this;
+ }
+ create_link& matcher(const IPathMatcher* filter)
+ {
+ m_matcher = filter;
+ return *this;
+ }
+ create_link& whitelist(bool whitelist)
+ {
+ m_whitelist = whitelist;
+ return *this;
+ }
+ create_link& linkRecursively(bool recursive)
+ {
+ m_recursive = recursive;
+ return *this;
+ }
+ create_link& debug(bool d)
+ {
+ m_debug = d;
+ return *this;
+ }
+
+ int getLastOSError() {
+ return m_last_os_err;
+ }
+
+ bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
+
+ int totalLinked() { return m_linked; }
+
+ signals:
+ void fileLinked(const QString& relativeName);
+ void linkFailed(const QString& srcName, const QString& dstName, std::error_code err);
+
+ private:
+ bool operator()(const QString& offset, bool dryRun = false);
+
+ private:
+ bool m_useHardLinks = false;
+ const IPathMatcher* m_matcher = nullptr;
+ bool m_whitelist = false;
+ bool m_recursive = true;
+ QDir m_src;
+ QDir m_dst;
+ int m_linked;
+ bool m_debug = false;
+ int m_last_os_err = 0;
+};
+
+/**
* @brief moves a file by renaming it
* @param source source file path
* @param dest destination filepath
diff --git a/launcher/InstanceCopyPrefs.cpp b/launcher/InstanceCopyPrefs.cpp
index 7b93a516..18a6d704 100644
--- a/launcher/InstanceCopyPrefs.cpp
+++ b/launcher/InstanceCopyPrefs.cpp
@@ -93,6 +93,21 @@ bool InstanceCopyPrefs::isCopyScreenshotsEnabled() const
return copyScreenshots;
}
+bool InstanceCopyPrefs::isLinkFilesEnabled() const
+{
+ return linkFiles;
+}
+
+bool InstanceCopyPrefs::isUseHardLinksEnabled() const
+{
+ return useHardLinks;
+}
+
+bool InstanceCopyPrefs::isLinkWorldsEnabled() const
+{
+ return linkWorlds;
+}
+
// ======= Setters =======
void InstanceCopyPrefs::enableCopySaves(bool b)
{
@@ -133,3 +148,18 @@ void InstanceCopyPrefs::enableCopyScreenshots(bool b)
{
copyScreenshots = b;
}
+
+void InstanceCopyPrefs::enableLinkFiles(bool b)
+{
+ linkFiles = b;
+}
+
+void InstanceCopyPrefs::enableUseHardLinks(bool b)
+{
+ useHardLinks = b;
+}
+
+void InstanceCopyPrefs::enableLinkWorlds(bool b)
+{
+ linkWorlds = b;
+}
diff --git a/launcher/InstanceCopyPrefs.h b/launcher/InstanceCopyPrefs.h
index 6988b2df..25c0f3fc 100644
--- a/launcher/InstanceCopyPrefs.h
+++ b/launcher/InstanceCopyPrefs.h
@@ -19,6 +19,9 @@ struct InstanceCopyPrefs {
[[nodiscard]] bool isCopyServersEnabled() const;
[[nodiscard]] bool isCopyModsEnabled() const;
[[nodiscard]] bool isCopyScreenshotsEnabled() const;
+ [[nodiscard]] bool isLinkFilesEnabled() const;
+ [[nodiscard]] bool isUseHardLinksEnabled() const;
+ [[nodiscard]] bool isLinkWorldsEnabled() const;
// Setters
void enableCopySaves(bool b);
void enableKeepPlaytime(bool b);
@@ -28,6 +31,9 @@ struct InstanceCopyPrefs {
void enableCopyServers(bool b);
void enableCopyMods(bool b);
void enableCopyScreenshots(bool b);
+ void enableLinkFiles(bool b);
+ void enableUseHardLinks(bool b);
+ void enableLinkWorlds(bool b);
protected: // data
bool copySaves = true;
@@ -38,4 +44,7 @@ struct InstanceCopyPrefs {
bool copyServers = true;
bool copyMods = true;
bool copyScreenshots = true;
+ bool linkFiles = false;
+ bool useHardLinks = false;
+ bool linkWorlds = true;
};
diff --git a/launcher/filelink/FileLink.cpp b/launcher/filelink/FileLink.cpp
new file mode 100644
index 00000000..9b5589ab
--- /dev/null
+++ b/launcher/filelink/FileLink.cpp
@@ -0,0 +1,119 @@
+// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
+//
+// SPDX-License-Identifier: GPL-3.0-only
+
+/*
+ * Prism Launcher - Minecraft Launcher
+ * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "FileLink.h"
+#include "BuildConfig.h"
+
+
+#include <iostream>
+
+#include <QAccessible>
+#include <QCommandLineParser>
+
+#include <QDebug>
+
+
+#include <FileSystem.h>
+#include <DesktopServices.h>
+
+#include <sys.h>
+
+#if defined Q_OS_WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <stdio.h>
+#endif
+
+
+
+
+FileLinkApp::FileLinkApp(int &argc, char **argv) : QCoreApplication(argc, argv)
+{
+#if defined Q_OS_WIN32
+ // attach the parent console
+ if(AttachConsole(ATTACH_PARENT_PROCESS))
+ {
+ // if attach succeeds, reopen and sync all the i/o
+ if(freopen("CON", "w", stdout))
+ {
+ std::cout.sync_with_stdio();
+ }
+ if(freopen("CON", "w", stderr))
+ {
+ std::cerr.sync_with_stdio();
+ }
+ if(freopen("CON", "r", stdin))
+ {
+ std::cin.sync_with_stdio();
+ }
+ auto out = GetStdHandle (STD_OUTPUT_HANDLE);
+ DWORD written;
+ const char * endline = "\n";
+ WriteConsole(out, endline, strlen(endline), &written, NULL);
+ consoleAttached = true;
+ }
+#endif
+ setOrganizationName(BuildConfig.LAUNCHER_NAME);
+ setOrganizationDomain(BuildConfig.LAUNCHER_DOMAIN);
+ setApplicationName(BuildConfig.LAUNCHER_NAME + "FileLink");
+ setApplicationVersion(BuildConfig.printableVersionString() + "\n" + BuildConfig.GIT_COMMIT);
+
+ // Commandline parsing
+ QCommandLineParser parser;
+ parser.setApplicationDescription(QObject::tr("a batch MKLINK program for windows to be useed with prismlauncher"));
+
+ parser.addOptions({
+
+ });
+ parser.addHelpOption();
+ parser.addVersionOption();
+
+ parser.process(arguments());
+
+ qDebug() << "link program launched";
+
+}
+
+
+FileLinkApp::~FileLinkApp()
+{
+ qDebug() << "link program shutting down";
+ // Shut down logger by setting the logger function to nothing
+ qInstallMessageHandler(nullptr);
+
+#if defined Q_OS_WIN32
+ // Detach from Windows console
+ if(consoleAttached)
+ {
+ fclose(stdout);
+ fclose(stdin);
+ fclose(stderr);
+ FreeConsole();
+ }
+#endif
+}
+
+
+
+
diff --git a/launcher/filelink/FileLink.h b/launcher/filelink/FileLink.h
new file mode 100644
index 00000000..253d1394
--- /dev/null
+++ b/launcher/filelink/FileLink.h
@@ -0,0 +1,52 @@
+// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
+//
+// SPDX-License-Identifier: GPL-3.0-only
+
+/*
+ * Prism Launcher - Minecraft Launcher
+ * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <QtCore>
+
+#include <QApplication>
+#include <memory>
+#include <QDebug>
+#include <QFlag>
+#include <QIcon>
+#include <QDateTime>
+#include <QUrl>
+#include <QDateTime>
+
+class FileLinkApp : public QCoreApplication
+{
+ // friends for the purpose of limiting access to deprecated stuff
+ Q_OBJECT
+public:
+
+ FileLinkApp(int &argc, char **argv);
+ virtual ~FileLinkApp();
+
+private:
+ QDateTime m_startTime;
+
+#if defined Q_OS_WIN32
+ // used on Windows to attach the standard IO streams
+ bool consoleAttached = false;
+#endif
+};
diff --git a/launcher/filelink/filelink.exe.manifest b/launcher/filelink/filelink.exe.manifest
new file mode 100644
index 00000000..a4e16264
--- /dev/null
+++ b/launcher/filelink/filelink.exe.manifest
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <application xmlns="urn:schemas-microsoft-com:asm.v3">
+ <windowsSettings>
+ </windowsSettings>
+ </application>
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!-- Windows 10, Windows 11 -->
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+ <!-- Windows 8.1 -->
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+ <!-- Windows 8 -->
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+ <!-- Windows 7 -->
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ </application>
+ </compatibility>
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel
+ level="requireAdministrator"
+ uiAccess="false"/>
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+</assembly> \ No newline at end of file
diff --git a/launcher/filelink/main.cpp b/launcher/filelink/main.cpp
new file mode 100644
index 00000000..7f06795e
--- /dev/null
+++ b/launcher/filelink/main.cpp
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
+//
+// SPDX-License-Identifier: GPL-3.0-only
+
+/*
+ * Prism Launcher - Minecraft Launcher
+ * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "FileLink.h"
+
+int main(int argc, char *argv[])
+{
+
+ FileLinkApp ldh(argc, argv);
+
+ return ldh.exec();
+} \ No newline at end of file
diff --git a/launcher/ui/dialogs/CopyInstanceDialog.cpp b/launcher/ui/dialogs/CopyInstanceDialog.cpp
index 3f5122f6..981352ae 100644
--- a/launcher/ui/dialogs/CopyInstanceDialog.cpp
+++ b/launcher/ui/dialogs/CopyInstanceDialog.cpp
@@ -85,6 +85,10 @@ CopyInstanceDialog::CopyInstanceDialog(InstancePtr original, QWidget *parent)
ui->copyServersCheckbox->setChecked(m_selectedOptions.isCopyServersEnabled());
ui->copyModsCheckbox->setChecked(m_selectedOptions.isCopyModsEnabled());
ui->copyScreenshotsCheckbox->setChecked(m_selectedOptions.isCopyScreenshotsEnabled());
+
+ ui->linkFilesGroup->setChecked(m_selectedOptions.isLinkFilesEnabled());
+ ui->hardLinksCheckbox->setChecked(m_selectedOptions.isUseHardLinksEnabled());
+ ui->linkWorldsCheckbox->setChecked(m_selectedOptions.isLinkWorldsEnabled());
}
CopyInstanceDialog::~CopyInstanceDialog()
@@ -220,3 +224,18 @@ void CopyInstanceDialog::on_copyScreenshotsCheckbox_stateChanged(int state)
m_selectedOptions.enableCopyScreenshots(state == Qt::Checked);
updateSelectAllCheckbox();
}
+
+void CopyInstanceDialog::on_linkFilesGroup_toggled(bool checked)
+{
+ m_selectedOptions.enableLinkFiles(checked);
+}
+
+void CopyInstanceDialog::on_hardLinksCheckbox_stateChanged(int state)
+{
+ m_selectedOptions.enableUseHardLinks(state == Qt::Checked);
+}
+
+void CopyInstanceDialog::on_linkWorldsCheckbox_stateChanged(int state)
+{
+ m_selectedOptions.enableLinkWorlds(state == Qt::Checked);
+}
diff --git a/launcher/ui/dialogs/CopyInstanceDialog.h b/launcher/ui/dialogs/CopyInstanceDialog.h
index 884501d1..a80faab9 100644
--- a/launcher/ui/dialogs/CopyInstanceDialog.h
+++ b/launcher/ui/dialogs/CopyInstanceDialog.h
@@ -55,6 +55,9 @@ slots:
void on_copyServersCheckbox_stateChanged(int state);
void on_copyModsCheckbox_stateChanged(int state);
void on_copyScreenshotsCheckbox_stateChanged(int state);
+ void on_linkFilesGroup_toggled(bool checked);
+ void on_hardLinksCheckbox_stateChanged(int state);
+ void on_linkWorldsCheckbox_stateChanged(int state);
private:
void checkAllCheckboxes(const bool& b);
diff --git a/launcher/ui/dialogs/CopyInstanceDialog.ui b/launcher/ui/dialogs/CopyInstanceDialog.ui
index b7828fe3..e41ad526 100644
--- a/launcher/ui/dialogs/CopyInstanceDialog.ui
+++ b/launcher/ui/dialogs/CopyInstanceDialog.ui
@@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>341</width>
- <height>399</height>
+ <width>525</width>
+ <height>581</height>
</rect>
</property>
<property name="windowTitle">
@@ -136,70 +136,126 @@
</layout>
</item>
<item>
- <layout class="QGridLayout" name="copyOptionsLayout">
- <item row="6" column="1">
- <widget class="QCheckBox" name="copyModsCheckbox">
- <property name="toolTip">
- <string>Disabling this will still keep the mod loader (ex: Fabric, Quilt, etc.) but erase the mods folder and their configs.</string>
- </property>
- <property name="text">
- <string>Copy mods</string>
- </property>
- </widget>
- </item>
- <item row="5" column="0">
- <widget class="QCheckBox" name="copyGameOptionsCheckbox">
+ <widget class="QGroupBox" name="copyOptionsGroup">
+ <property name="title">
+ <string>Instance copy options</string>
+ </property>
+ <layout class="QGridLayout" name="copyOptionsLayout">
+ <item row="6" column="1">
+ <widget class="QCheckBox" name="copyModsCheckbox">
+ <property name="toolTip">
+ <string>Disabling this will still keep the mod loader (ex: Fabric, Quilt, etc.) but erase the mods folder and their configs.</string>
+ </property>
+ <property name="text">
+ <string>Copy mods</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QCheckBox" name="copyGameOptionsCheckbox">
+ <property name="toolTip">
+ <string>Copy the in-game options like FOV, max framerate, etc.</string>
+ </property>
+ <property name="text">
+ <string>Copy game options</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QCheckBox" name="copySavesCheckbox">
+ <property name="text">
+ <string>Copy saves</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QCheckBox" name="copyShaderPacksCheckbox">
+ <property name="text">
+ <string>Copy shader packs</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QCheckBox" name="copyServersCheckbox">
+ <property name="text">
+ <string>Copy servers</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QCheckBox" name="copyResPacksCheckbox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Copy resource packs</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QCheckBox" name="keepPlaytimeCheckbox">
+ <property name="text">
+ <string>Keep play time</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QCheckBox" name="copyScreenshotsCheckbox">
+ <property name="text">
+ <string>Copy screenshots</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="copyModeLayout">
+ <item>
+ <widget class="QGroupBox" name="linkFilesGroup">
<property name="toolTip">
- <string>Copy the in-game options like FOV, max framerate, etc.</string>
+ <string>Use symbolic links instead of copying files.</string>
</property>
- <property name="text">
- <string>Copy game options</string>
+ <property name="title">
+ <string>Link files instead of copying them</string>
</property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QCheckBox" name="copySavesCheckbox">
- <property name="text">
- <string>Copy saves</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QCheckBox" name="copyShaderPacksCheckbox">
- <property name="text">
- <string>Copy shader packs</string>
- </property>
- </widget>
- </item>
- <item row="5" column="1">
- <widget class="QCheckBox" name="copyServersCheckbox">
- <property name="text">
- <string>Copy servers</string>
+ <property name="flat">
+ <bool>false</bool>
</property>
- </widget>
- </item>
- <item row="6" column="0">
- <widget class="QCheckBox" name="copyResPacksCheckbox">
- <property name="enabled">
+ <property name="checkable">
<bool>true</bool>
</property>
- <property name="text">
- <string>Copy resource packs</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QCheckBox" name="keepPlaytimeCheckbox">
- <property name="text">
- <string>Keep play time</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QCheckBox" name="copyScreenshotsCheckbox">
- <property name="text">
- <string>Copy screenshots</string>
+ <property name="checked">
+ <bool>false</bool>
</property>
+ <layout class="QVBoxLayout" name="linkOptionsLayout">
+ <item>
+ <widget class="QCheckBox" name="hardLinksCheckbox">
+ <property name="toolTip">
+ <string>Use hard links instead of symbolic links</string>
+ </property>
+ <property name="text">
+ <string>Use hard links</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="linkWorldsCheckbox">
+ <property name="toolTip">
+ <string>World save data will be linked and thus shared between instances.</string>
+ </property>
+ <property name="text">
+ <string>Link worlds</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
</widget>
</item>
</layout>
@@ -210,7 +266,7 @@
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
@@ -220,10 +276,20 @@
<tabstop>iconButton</tabstop>
<tabstop>instNameTextBox</tabstop>
<tabstop>groupBox</tabstop>
+ <tabstop>selectAllCheckbox</tabstop>
+ <tabstop>keepPlaytimeCheckbox</tabstop>
+ <tabstop>copyScreenshotsCheckbox</tabstop>
+ <tabstop>copySavesCheckbox</tabstop>
+ <tabstop>copyShaderPacksCheckbox</tabstop>
+ <tabstop>copyGameOptionsCheckbox</tabstop>
+ <tabstop>copyServersCheckbox</tabstop>
+ <tabstop>copyResPacksCheckbox</tabstop>
+ <tabstop>copyModsCheckbox</tabstop>
+ <tabstop>linkFilesGroup</tabstop>
+ <tabstop>hardLinksCheckbox</tabstop>
+ <tabstop>linkWorldsCheckbox</tabstop>
</tabstops>
- <resources>
- <include location="../../graphics.qrc"/>
- </resources>
+ <resources/>
<connections>
<connection>
<sender>buttonBox</sender>
@@ -232,8 +298,8 @@
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
- <x>254</x>
- <y>316</y>
+ <x>263</x>
+ <y>571</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
@@ -248,8 +314,8 @@
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
- <x>322</x>
- <y>316</y>
+ <x>331</x>
+ <y>571</y>
</hint>
<hint type="destinationlabel">
<x>286</x>