summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt12
-rw-r--r--src/iuserinterface.h4
-rw-r--r--src/logbuffer.cpp20
-rw-r--r--src/logbuffer.h4
-rw-r--r--src/mainwindow.cpp58
-rw-r--r--src/mainwindow.h15
-rw-r--r--src/mainwindow.ui14
-rw-r--r--src/organizercore.cpp60
-rw-r--r--src/organizercore.h14
-rw-r--r--src/selfupdater.cpp3
-rw-r--r--src/shared/directoryentry.cpp4
-rw-r--r--src/shared/directoryentry.h9
-rw-r--r--src/spawn.cpp46
-rw-r--r--src/splash.pngbin230138 -> 273418 bytes
-rw-r--r--src/usvfsconnector.cpp141
-rw-r--r--src/usvfsconnector.h88
-rw-r--r--src/version.rc4
17 files changed, 327 insertions, 169 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 22b725de..c508df52 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -83,6 +83,7 @@ SET(organizer_SRCS
viewmarkingscrollbar.cpp
plugincontainer.cpp
organizercore.cpp
+ usvfsconnector.cpp
shared/inject.cpp
shared/windows_error.cpp
@@ -173,6 +174,7 @@ SET(organizer_HDRS
plugincontainer.h
organizercore.h
iuserinterface.h
+ usvfsconnector.h
shared/inject.h
shared/windows_error.h
@@ -278,19 +280,27 @@ INCLUDE_DIRECTORIES(${project_path}/uibase/src
${project_path}/bsatk/src
${project_path}/esptk/src
${project_path}/archive/src
- ${project_path}/plugin/game_features/src)
+ ${project_path}/plugin/game_features/src
+ ${project_path}/usvfs/usvfs)
INCLUDE_DIRECTORIES(shared ${ZLIB_INCLUDE_DIRS})
LINK_DIRECTORIES(${lib_path}
${project_path}/zlib/lib)
ADD_DEFINITIONS(-D_UNICODE -DUNICODE -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)
+IF("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
+ SET(usvfs_name usvfs_x64)
+ELSE()
+ SET(usvfs_name usvfs_x86)
+ENDIF()
+
ADD_EXECUTABLE(ModOrganizer WIN32 ${organizer_HDRS} ${organizer_SRCS} ${organizer_UIHDRS} ${organizer_RCS} ${organizer_RCCPPS})
TARGET_LINK_LIBRARIES(ModOrganizer
Qt5::Widgets Qt5::WinExtras Qt5::WebKitWidgets
${Boost_LIBRARIES}
zlibstatic
uibase esptk bsatk
+ ${usvfs_name}
Dbghelp advapi32 Version Shlwapi)
SET_TARGET_PROPERTIES(ModOrganizer PROPERTIES COMPILE_FLAGS /GL)
diff --git a/src/iuserinterface.h b/src/iuserinterface.h
index bcf800b7..e6b39ee1 100644
--- a/src/iuserinterface.h
+++ b/src/iuserinterface.h
@@ -26,10 +26,6 @@ public:
virtual void displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab) = 0;
- virtual void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives) = 0;
-
- virtual MOBase::DelayedFileWriterBase &archivesWriter() = 0;
-
virtual void lock() = 0;
virtual void unlock() = 0;
virtual bool unlockClicked() = 0;
diff --git a/src/logbuffer.cpp b/src/logbuffer.cpp
index a07ae264..2c3fc101 100644
--- a/src/logbuffer.cpp
+++ b/src/logbuffer.cpp
@@ -124,8 +124,6 @@ char LogBuffer::msgTypeID(QtMsgType type)
}
}
-#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
-
void LogBuffer::log(QtMsgType type, const QMessageLogContext &context, const QString &message)
{
// QMutexLocker doesn't support timeout...
@@ -141,6 +139,7 @@ void LogBuffer::log(QtMsgType type, const QMessageLogContext &context, const QSt
s_Instance->logMessage(type, message);
}
// fprintf(stdout, "(%s:%u) %s\n", context.file, context.line, qPrintable(message));
+
if (type == QtDebugMsg) {
fprintf(stdout, "%s [%c] %s\n", qPrintable(QTime::currentTime().toString()), msgTypeID(type), qPrintable(message));
} else {
@@ -154,21 +153,6 @@ void LogBuffer::log(QtMsgType type, const QMessageLogContext &context, const QSt
fflush(stdout);
}
-#else
-
-void LogBuffer::log(QtMsgType type, const char *message)
-{
- QMutexLocker guard(&s_Mutex);
- if (!s_Instance.isNull()) {
- s_Instance->logMessage(type, message);
- }
- fprintf(stdout, "%s [%c] %s\n", qPrintable(QTime::currentTime().toString()), msgTypeID(type), message);
- fflush(stdout);
-}
-
-#endif
-
-
QModelIndex LogBuffer::index(int row, int column, const QModelIndex&) const
{
return createIndex(row, column, row);
@@ -269,8 +253,6 @@ void log(const char *format, ...)
va_end(argList);
}
-
-
QString LogBuffer::Message::toString() const
{
return QString("%1 [%2] %3").arg(time.toString()).arg(msgTypeID(type)).arg(message);
diff --git a/src/logbuffer.h b/src/logbuffer.h
index 748aaf31..0cfecfa2 100644
--- a/src/logbuffer.h
+++ b/src/logbuffer.h
@@ -35,11 +35,7 @@ class LogBuffer : public QAbstractItemModel
public:
static void init(int messageCount, QtMsgType minMsgType, const QString &outputFileName);
-#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
static void log(QtMsgType type, const QMessageLogContext &context, const QString &message);
-#else
- static void log(QtMsgType type, const char *message);
-#endif
static void writeNow();
static void cleanQuit();
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 26ff4b98..e34d8b03 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -162,7 +162,6 @@ MainWindow::MainWindow(const QString &exeName
, m_OrganizerCore(organizerCore)
, m_PluginContainer(pluginContainer)
, m_DidUpdateMasterList(false)
- , m_ArchiveListWriter(std::bind(&MainWindow::saveArchiveList, this))
{
ui->setupUi(this);
updateWindowTitle(QString(), false);
@@ -265,8 +264,6 @@ MainWindow::MainWindow(const QString &exeName
connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), m_PluginListSortProxy, SLOT(updateFilter(QString)));
connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), this, SLOT(espFilterChanged(QString)));
- connect(ui->bsaList, SIGNAL(itemsMoved()), this, SLOT(bsaList_itemMoved()));
-
connect(ui->dataTree, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(expandDataTreeItem(QTreeWidgetItem*)));
connect(m_OrganizerCore.directoryRefresher(), SIGNAL(refreshed()), this, SLOT(directory_refreshed()));
@@ -1389,13 +1386,6 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString
} else if (hasAssociatedPlugin(fileInfo.fileName())) {
newItem->setCheckState(0, Qt::Checked);
newItem->setDisabled(true);
- } else {
- if (ui->manageArchivesBox->isChecked()) {
- newItem->setCheckState(0, (index != 0xFFFF) ? Qt::Checked : Qt::Unchecked);
- } else {
- newItem->setCheckState(0, Qt::Unchecked);
- newItem->setDisabled(true);
- }
}
if (index < 0) index = 0;
@@ -1557,10 +1547,6 @@ void MainWindow::readSettings()
if (settings.value("Settings/use_proxy", false).toBool()) {
activateProxy(true);
}
-
- ui->manageArchivesBox->blockSignals(true);
- ui->manageArchivesBox->setChecked(settings.value("manage_bsas", true).toBool());
- ui->manageArchivesBox->blockSignals(false);
}
@@ -1578,7 +1564,6 @@ void MainWindow::storeSettings(QSettings &settings)
settings.setValue("browser_geometry", m_IntegratedBrowser.saveGeometry());
settings.setValue("filters_visible", ui->displayCategoriesBtn->isChecked());
- settings.setValue("manage_bsas", ui->manageArchivesBox->isChecked());
settings.setValue("selected_executable", ui->executablesListBox->currentIndex());
}
@@ -1900,7 +1885,6 @@ void MainWindow::modorder_changed()
}
m_OrganizerCore.refreshBSAList();
m_OrganizerCore.currentProfile()->modlistWriter().write();
- m_ArchiveListWriter.write();
m_OrganizerCore.directoryStructure()->getFileRegister()->sortOrigins();
{ // refresh selection
@@ -2809,30 +2793,6 @@ void MainWindow::savePrimaryCategory()
}
}
-void MainWindow::saveArchiveList()
-{
- if (m_OrganizerCore.isArchivesInit()) {
- SafeWriteFile archiveFile(m_OrganizerCore.currentProfile()->getArchivesFileName());
- for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) {
- QTreeWidgetItem *tlItem = ui->bsaList->topLevelItem(i);
- for (int j = 0; j < tlItem->childCount(); ++j) {
- QTreeWidgetItem *item = tlItem->child(j);
- if (item->checkState(0) == Qt::Checked) {
- // in managed mode, "register" all enabled archives, otherwise register only the files registered in the ini
- if (ui->manageArchivesBox->isChecked()
- || item->data(0, Qt::UserRole).toBool()) {
- archiveFile->write(item->text(0).toUtf8().append("\r\n"));
- }
- }
- }
- }
- if (archiveFile.commitIfDifferent(m_ArchiveListHash)) {
- qDebug("%s saved", qPrintable(QDir::toNativeSeparators(m_OrganizerCore.currentProfile()->getArchivesFileName())));
- }
- } else {
- qWarning("archive list not initialised");
- }
-}
void MainWindow::checkModsForUpdates()
{
@@ -4075,19 +4035,6 @@ void MainWindow::on_bsaList_customContextMenuRequested(const QPoint &pos)
menu.exec(ui->bsaList->mapToGlobal(pos));
}
-void MainWindow::bsaList_itemMoved()
-{
- m_ArchiveListWriter.write();
- m_CheckBSATimer.start(500);
-}
-
-
-void MainWindow::on_bsaList_itemChanged(QTreeWidgetItem*, int)
-{
- m_ArchiveListWriter.write();
- m_CheckBSATimer.start(500);
-}
-
void MainWindow::on_actionProblems_triggered()
{
ProblemsDialog problems(m_PluginContainer.plugins<IPluginDiagnose>(), this);
@@ -4669,11 +4616,6 @@ void MainWindow::on_managedArchiveLabel_linkHovered(const QString&)
ui->managedArchiveLabel->toolTip());
}
-void MainWindow::on_manageArchivesBox_toggled(bool)
-{
- m_OrganizerCore.refreshBSAList();
-}
-
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
//Accept copy or move drags to the download window. Link drags are not
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 55ae40b9..279c8922 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -73,8 +73,8 @@ class MainWindow : public QMainWindow, public IUserInterface
friend class OrganizerProxy;
-
public:
+
explicit MainWindow(const QString &exeName, QSettings &initSettings,
OrganizerCore &organizerCore, PluginContainer &pluginContainer,
QWidget *parent = 0);
@@ -95,8 +95,6 @@ public:
void setModListSorting(int index);
void setESPListSorting(int index);
- void saveArchiveList();
-
void registerPluginTool(MOBase::IPluginTool *tool);
void registerModPage(MOBase::IPluginModPage *modPage);
@@ -119,9 +117,8 @@ public:
virtual bool closeWindow();
virtual void setWindowEnabled(bool enabled);
- virtual MOBase::DelayedFileWriterBase &archivesWriter() override { return m_ArchiveListWriter; }
-
void updateWindowTitle(const QString &accountName, bool premium);
+
public slots:
void displayColumnSelection(const QPoint &pos);
@@ -135,7 +132,6 @@ public slots:
signals:
-
/**
* @brief emitted after the information dialog has been closed
*/
@@ -319,14 +315,10 @@ private:
std::vector<QTreeWidgetItem*> m_RemoveWidget;
- QByteArray m_ArchiveListHash;
-
bool m_DidUpdateMasterList;
LockedDialog *m_LockDialog { nullptr };
- MOBase::DelayedFileWriter m_ArchiveListWriter;
-
enum class ShortcutType {
Toolbar,
Desktop,
@@ -503,7 +495,6 @@ private slots: // ui slots
void on_actionEndorseMO_triggered();
void on_bsaList_customContextMenuRequested(const QPoint &pos);
- void bsaList_itemMoved();
void on_btnRefreshData_clicked();
void on_categoriesList_customContextMenuRequested(const QPoint &pos);
void on_conflictsCheckBox_toggled(bool checked);
@@ -522,7 +513,6 @@ private slots: // ui slots
void on_categoriesList_itemSelectionChanged();
void on_linkButton_pressed();
void on_showHiddenBox_toggled(bool checked);
- void on_bsaList_itemChanged(QTreeWidgetItem *item, int column);
void on_bossButton_clicked();
void on_saveButton_clicked();
@@ -533,7 +523,6 @@ private slots: // ui slots
void on_categoriesAndBtn_toggled(bool checked);
void on_categoriesOrBtn_toggled(bool checked);
void on_managedArchiveLabel_linkHovered(const QString &link);
- void on_manageArchivesBox_toggled(bool checked);
};
diff --git a/src/mainwindow.ui b/src/mainwindow.ui
index ca93ea54..7d7eeca8 100644
--- a/src/mainwindow.ui
+++ b/src/mainwindow.ui
@@ -902,24 +902,14 @@ p, li { white-space: pre-wrap; }
<number>6</number>
</property>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout_9" stretch="0,1">
- <item>
- <widget class="QCheckBox" name="manageArchivesBox">
- <property name="text">
- <string/>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
+ <layout class="QHBoxLayout" name="horizontalLayout_9" stretch="0">
<item>
<widget class="QLabel" name="managedArchiveLabel">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;BSAs are bundles of game assets (textures, scripts, ...). By default, the engine loads these bundles in a separate step from loose files. MO can manage those archives to align their load order with that of loose files:&lt;/p&gt;&lt;p&gt;If archives are &lt;span style=&quot; font-weight:600;&quot;&gt;managed&lt;/span&gt;, their load order is specified by the priority of the corresponding mod (left pane), the same as the loose files. You can manually enable any BSA that has no corresponding plugin active.&lt;br/&gt;&lt;/p&gt;&lt;p&gt;If archives are &lt;span style=&quot; font-weight:600;&quot;&gt;not managed&lt;/span&gt; their load order is specified by the priority of the corresponding plugin (right pane, plugins tab). You can then not manually enable BSAs where the plugin isn't active.&lt;/p&gt;&lt;p&gt;In either case you can not disable archives if there is a matching plugin, the game will load them no matter what.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Have MO manage archives (&lt;a href=&quot;#&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;read more&lt;/span&gt;&lt;/a&gt;)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Archive order follows Plugin order.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index a9284e97..a5dc393d 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -990,6 +990,7 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, const QString &
// TODO: should also pass arguments
if (m_AboutToRun(binary.absoluteFilePath())) {
+ m_USVFS.updateMapping(fileMapping());
return startBinary(binary, arguments, profileName, m_Settings.logLevel(), currentDirectory, true);
} else {
qDebug("start of \"%s\" canceled by plugin", qPrintable(binary.absoluteFilePath()));
@@ -1185,10 +1186,6 @@ void OrganizerCore::refreshBSAList()
m_ActiveArchives = m_DefaultArchives;
}
- if (m_UserInterface != nullptr) {
- m_UserInterface->updateBSAList(m_DefaultArchives, m_ActiveArchives);
- }
-
m_ArchivesInit = true;
}
}
@@ -1247,9 +1244,7 @@ void OrganizerCore::updateModInDirectoryStructure(unsigned int index, ModInfo::P
updateModActiveState(index, true);
// now we need to refresh the bsa list and save it so there is no confusion about what archives are avaiable and active
refreshBSAList();
- if (m_UserInterface != nullptr) {
- m_UserInterface->archivesWriter().write();
- }
+
std::vector<QString> archives = enabledArchives();
m_DirectoryRefresher.setMods(m_CurrentProfile->getActiveMods(),
std::set<QString>(archives.begin(), archives.end()));
@@ -1394,9 +1389,6 @@ void OrganizerCore::modStatusChanged(unsigned int index)
FilesOrigin &origin = m_DirectoryStructure->getOriginByName(ToWString(modInfo->name()));
origin.enable(false);
}
- if (m_UserInterface != nullptr) {
- m_UserInterface->archivesWriter().write();
- }
}
modInfo->clearCaches();
@@ -1535,9 +1527,6 @@ bool OrganizerCore::saveCurrentLists()
try {
savePluginList();
- if (m_UserInterface != nullptr) {
- m_UserInterface->archivesWriter().write();
- }
} catch (const std::exception &e) {
reportError(tr("failed to save load order: %1").arg(e.what()));
}
@@ -1571,21 +1560,22 @@ void OrganizerCore::prepareStart() {
storeSettings();
}
-std::vector<std::pair<QString, QString>> OrganizerCore::fileMapping()
+std::vector<Mapping> OrganizerCore::fileMapping()
{
- IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>();
- return fileMapping(game->dataDirectory().absolutePath(),
- directoryStructure(),
- directoryStructure());
+ IPluginGame *game = qApp->property("managed_game").value<IPluginGame *>();
+ return fileMapping(
+ QDir::toNativeSeparators(game->dataDirectory().absolutePath()),
+ "\\",
+ directoryStructure(), directoryStructure());
}
-
-std::vector<std::pair<QString, QString>> OrganizerCore::fileMapping(
+std::vector<Mapping> OrganizerCore::fileMapping(
const QString &dataPath,
+ const QString &relPath,
const DirectoryEntry *base,
const DirectoryEntry *directoryEntry)
{
- std::vector<std::pair<QString, QString>> result;
+ std::vector<Mapping> result;
for (FileEntry::Ptr current : directoryEntry->getFiles()) {
bool isArchive = false;
@@ -1594,20 +1584,36 @@ std::vector<std::pair<QString, QString>> OrganizerCore::fileMapping(
continue;
}
- QString fileName = ToQString(current->getRelativePath());
- QString source = ToQString(base->getOriginByID(origin).getPath()) + fileName;
- QString target = QDir::toNativeSeparators(dataPath) + fileName;
- result.push_back(std::make_pair(source, target));
+ QString originPath
+ = QString::fromStdWString(base->getOriginByID(origin).getPath());
+ QString fileName = QString::fromStdWString(current->getName());
+ QString source = originPath + relPath + fileName;
+ QString target = dataPath + relPath + fileName;
+ if (source != target) {
+ result.push_back({source, target, false});
+ }
}
// recurse into subdirectories
std::vector<DirectoryEntry*>::const_iterator current, end;
directoryEntry->getSubDirectories(current, end);
for (; current != end; ++current) {
- std::vector<std::pair<QString, QString>> subRes = fileMapping(dataPath, base, *current);
+ int origin = (*current)->anyOrigin();
+ if (origin == 0) {
+ continue;
+ }
+
+ QString originPath
+ = QString::fromStdWString(base->getOriginByID(origin).getPath());
+ QString dirName = QString::fromStdWString((*current)->getName());
+ QString source = originPath + relPath + dirName;
+ QString target = dataPath + relPath + dirName;
+
+ result.push_back({source, target, true});
+ std::vector<Mapping> subRes
+ = fileMapping(dataPath, relPath + dirName + "\\", base, *current);
result.insert(result.end(), subRes.begin(), subRes.end());
}
return result;
}
-
diff --git a/src/organizercore.h b/src/organizercore.h
index 85f0e0c4..1de1dfe8 100644
--- a/src/organizercore.h
+++ b/src/organizercore.h
@@ -14,6 +14,7 @@
#include "modlistsortproxy.h"
#include "pluginlistsortproxy.h"
#include "executableslist.h"
+#include "usvfsconnector.h"
#include <directoryentry.h>
#include <imoinfo.h>
#include <iplugindiagnose.h>
@@ -157,7 +158,10 @@ public:
bool onFinishedRun(const std::function<void (const QString &, unsigned int)> &func);
void refreshModList(bool saveChanges = true);
- std::vector<std::pair<QString, QString> > fileMapping();
+ /**
+ * @brief return a descriptor of the mappings real file->virtual file
+ */
+ std::vector<Mapping> fileMapping();
public: // IPluginDiagnose interface
@@ -210,9 +214,10 @@ private:
bool testForSteam();
- std::vector<std::pair<QString, QString>> fileMapping(const QString &dataPath,
- const MOShared::DirectoryEntry *base,
- const MOShared::DirectoryEntry *directoryEntry);
+ std::vector<Mapping>
+ fileMapping(const QString &dataPath, const QString &relPath,
+ const MOShared::DirectoryEntry *base,
+ const MOShared::DirectoryEntry *directoryEntry);
private slots:
@@ -270,6 +275,7 @@ private:
bool m_ArchivesInit;
MOBase::DelayedFileWriter m_PluginListsWriter;
+ UsvfsConnector m_USVFS;
};
diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp
index bcf81cfd..270e2764 100644
--- a/src/selfupdater.cpp
+++ b/src/selfupdater.cpp
@@ -75,8 +75,6 @@ SelfUpdater::SelfUpdater(NexusInterface *nexusInterface)
throw MyException(InstallationManager::getErrorString(m_CurrentArchive->getLastError()));
}
- connect(m_Progress, SIGNAL(canceled()), this, SLOT(downloadCancel()));
-
VS_FIXEDFILEINFO version = GetFileVersion(ToWString(QApplication::applicationFilePath()));
m_MOVersion = VersionInfo(version.dwFileVersionMS >> 16,
@@ -135,6 +133,7 @@ void SelfUpdater::showProgress()
{
if (m_Progress == nullptr) {
m_Progress = new QProgressDialog(m_Parent, Qt::Dialog);
+ connect(m_Progress, SIGNAL(canceled()), this, SLOT(downloadCancel()));
}
m_Progress->setModal(true);
m_Progress->show();
diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp
index 54b6efff..e081c006 100644
--- a/src/shared/directoryentry.cpp
+++ b/src/shared/directoryentry.cpp
@@ -704,7 +704,7 @@ FilesOrigin &DirectoryEntry::getOriginByName(const std::wstring &name) const
return m_OriginConnection->getByName(name);
}
-
+/*
int DirectoryEntry::getOrigin(const std::wstring &path, bool &archive)
{
const DirectoryEntry *directory = nullptr;
@@ -718,7 +718,7 @@ int DirectoryEntry::getOrigin(const std::wstring &path, bool &archive)
return -1;
}
}
-}
+}*/
std::vector<FileEntry::Ptr> DirectoryEntry::getFiles() const
{
diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h
index 2d32450a..04b8782b 100644
--- a/src/shared/directoryentry.h
+++ b/src/shared/directoryentry.h
@@ -207,7 +207,8 @@ public:
DirectoryEntry(const std::wstring &name, DirectoryEntry *parent, int originID);
DirectoryEntry(const std::wstring &name, DirectoryEntry *parent, int originID,
- boost::shared_ptr<FileRegister> fileRegister, boost::shared_ptr<OriginConnection> originConnection);
+ boost::shared_ptr<FileRegister> fileRegister,
+ boost::shared_ptr<OriginConnection> originConnection);
~DirectoryEntry();
@@ -232,7 +233,9 @@ public:
FilesOrigin &getOriginByID(int ID) const;
FilesOrigin &getOriginByName(const std::wstring &name) const;
- int getOrigin(const std::wstring &path, bool &archive);
+ int anyOrigin() const;
+
+ //int getOrigin(const std::wstring &path, bool &archive);
std::vector<FileEntry::Ptr> getFiles() const;
@@ -316,8 +319,6 @@ private:
DirectoryEntry *getSubDirectoryRecursive(const std::wstring &path, bool create, int originID = -1);
- int anyOrigin() const;
-
void removeDirRecursive();
private:
diff --git a/src/spawn.cpp b/src/spawn.cpp
index c79714bb..ad6707e3 100644
--- a/src/spawn.cpp
+++ b/src/spawn.cpp
@@ -24,6 +24,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <gameinfo.h>
#include <report.h>
#include <inject.h>
+#include <usvfs.h>
#include <Shellapi.h>
#include <appconfig.h>
#include <windows_error.h>
@@ -37,7 +38,8 @@ using namespace MOShared;
static const int BUFSIZE = 4096;
-static bool spawn(LPCWSTR binary, LPCWSTR arguments, LPCWSTR currentDirectory, bool suspended,
+static bool spawn(LPCWSTR binary, LPCWSTR arguments, LPCWSTR currentDirectory,
+ bool suspended, bool hooked,
HANDLE stdOut, HANDLE stdErr,
HANDLE& processHandle, HANDLE& threadHandle)
{
@@ -85,15 +87,28 @@ static bool spawn(LPCWSTR binary, LPCWSTR arguments, LPCWSTR currentDirectory, b
}
PROCESS_INFORMATION pi;
- BOOL success = ::CreateProcess(nullptr,
- commandLine,
- nullptr, nullptr, // no special process or thread attributes
- inheritHandles, // inherit handles if we plan to use stdout or stderr reroute
- CREATE_BREAKAWAY_FROM_JOB | (suspended ? CREATE_SUSPENDED : 0), // create suspended so I have time to inject the DLL
- nullptr, // same environment as parent
- currentDirectory, // current directory
- &si, &pi // startup and process information
- );
+ BOOL success = FALSE;
+ if (hooked) {
+ success = ::CreateProcessHooked(nullptr,
+ commandLine,
+ nullptr, nullptr, // no special process or thread attributes
+ inheritHandles, // inherit handles if we plan to use stdout or stderr reroute
+ CREATE_BREAKAWAY_FROM_JOB,
+ nullptr, // same environment as parent
+ currentDirectory, // current directory
+ &si, &pi // startup and process information
+ );
+ } else {
+ success = ::CreateProcess(nullptr,
+ commandLine,
+ nullptr, nullptr, // no special process or thread attributes
+ inheritHandles, // inherit handles if we plan to use stdout or stderr reroute
+ CREATE_BREAKAWAY_FROM_JOB,
+ nullptr, // same environment as parent
+ currentDirectory, // current directory
+ &si, &pi // startup and process information
+ );
+ }
::SetEnvironmentVariable(TEXT("PATH"), oldPath.get());
@@ -136,8 +151,8 @@ HANDLE startBinary(const QFileInfo &binary,
std::wstring currentDirectoryName = ToWString(QDir::toNativeSeparators(currentDirectory.absolutePath()));
try {
- if (!spawn(binaryName.c_str(), ToWString(arguments).c_str(), currentDirectoryName.c_str(), true,
- stdOut, stdErr, processHandle, threadHandle)) {
+ if (!spawn(binaryName.c_str(), ToWString(arguments).c_str(), currentDirectoryName.c_str(),
+ true, hooked, stdOut, stdErr, processHandle, threadHandle)) {
reportError(QObject::tr("failed to spawn \"%1\"").arg(binary.fileName()));
return INVALID_HANDLE_VALUE;
}
@@ -165,7 +180,7 @@ HANDLE startBinary(const QFileInfo &binary,
return INVALID_HANDLE_VALUE;
}
}
-
+/*
if (hooked) {
try {
QFileInfo dllInfo(QApplication::applicationDirPath() + "/" + ToQString(AppConfig::hookDLLName()));
@@ -185,6 +200,7 @@ HANDLE startBinary(const QFileInfo &binary,
reportError("ready?");
#endif // DEBUG
}
+ */
if (::AssignProcessToJobObject(jobObject, processHandle) == 0) {
qWarning("failed to assign to job object: %lu", ::GetLastError());
@@ -194,10 +210,6 @@ HANDLE startBinary(const QFileInfo &binary,
::CloseHandle(processHandle);
}
- if (::ResumeThread(threadHandle) == (DWORD)-1) {
- reportError(QObject::tr("failed to run \"%1\"").arg(binary.fileName()));
- return INVALID_HANDLE_VALUE;
- }
::CloseHandle(threadHandle);
return jobObject;
}
diff --git a/src/splash.png b/src/splash.png
index 3eec8bed..4f1f1a3d 100644
--- a/src/splash.png
+++ b/src/splash.png
Binary files differ
diff --git a/src/usvfsconnector.cpp b/src/usvfsconnector.cpp
new file mode 100644
index 00000000..6e1e5b31
--- /dev/null
+++ b/src/usvfsconnector.cpp
@@ -0,0 +1,141 @@
+/*
+Copyright (C) 2015 Sebastian Herbord. All rights reserved.
+
+This file is part of Mod Organizer.
+
+Mod Organizer 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, either version 3 of the License, or
+(at your option) any later version.
+
+Mod Organizer 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 Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "usvfsconnector.h"
+#include <memory>
+#include <QTemporaryFile>
+#include <QProgressDialog>
+#include <QCoreApplication>
+
+
+static const char SHMID[] = "mod_organizer_instance";
+
+
+/*
+extern "C" DLLEXPORT BOOL WINAPI VirtualLinkFile(LPCWSTR source, LPCWSTR destination, BOOL failIfExists);
+extern "C" DLLEXPORT BOOL WINAPI VirtualLinkDirectoryStatic(LPCWSTR source, LPCWSTR destination, unsigned int flags);
+extern "C" DLLEXPORT BOOL WINAPI ConnectVFS(const usvfs::Parameters *parameters);
+extern "C" DLLEXPORT void WINAPI DisconnectVFS();
+extern "C" DLLEXPORT void WINAPI GetCurrentVFSName(char *buffer, size_t size);
+extern "C" DLLEXPORT BOOL WINAPI CreateProcessHooked(LPCWSTR lpApplicationName
+ , LPWSTR lpCommandLine
+ , LPSECURITY_ATTRIBUTES lpProcessAttributes
+ , LPSECURITY_ATTRIBUTES lpThreadAttributes
+ , BOOL bInheritHandles
+ , DWORD dwCreationFlags
+ , LPVOID lpEnvironment
+ , LPCWSTR lpCurrentDirectory
+ , LPSTARTUPINFOW lpStartupInfo
+ , LPPROCESS_INFORMATION lpProcessInformation
+ );
+extern "C" DLLEXPORT void __cdecl InitLogging(bool toLocal = false);
+extern "C" DLLEXPORT void __cdecl InitHooks(LPVOID userData, size_t userDataSize);
+*/
+
+
+LogWorker::LogWorker()
+ : m_Buffer(1024, '\0')
+ , m_QuitRequested(false)
+ , m_LogFile(new QTemporaryFile("usvfs-XXXXXX.log"))
+{
+ m_LogFile->open(QIODevice::WriteOnly);
+ qDebug("usvfs log messages are written to %s", qPrintable(m_LogFile->fileName()));
+}
+
+LogWorker::~LogWorker()
+{
+ delete m_LogFile;
+}
+
+void LogWorker::process()
+{
+ while (!m_QuitRequested) {
+ if (GetLogMessages(&m_Buffer[0], m_Buffer.size(), false)) {
+ m_LogFile->write(m_Buffer.c_str());
+ m_LogFile->write("\n");
+ m_LogFile->flush();
+
+ //emit outputLog(QString::fromStdString(m_Buffer));
+ } else {
+ QThread::sleep(1);
+ }
+ }
+ emit finished();
+}
+
+void LogWorker::exit()
+{
+ m_QuitRequested = true;
+
+}
+
+UsvfsConnector::UsvfsConnector()
+{
+ usvfs::Parameters params(SHMID, true, LogLevel::Debug);
+ InitLogging(false);
+ ConnectVFS(&params);
+
+ m_LogWorker.moveToThread(&m_WorkerThread);
+
+ connect(&m_WorkerThread, SIGNAL(started()), &m_LogWorker, SLOT(process()));
+ connect(&m_LogWorker, SIGNAL(finished()), &m_WorkerThread, SLOT(quit()));
+
+ m_WorkerThread.start(QThread::LowestPriority);
+}
+
+UsvfsConnector::~UsvfsConnector()
+{
+ DisconnectVFS();
+ m_LogWorker.exit();
+ m_WorkerThread.quit();
+ //m_WorkerThread.wait();
+}
+
+void UsvfsConnector::updateMapping(const MappingType &mapping)
+{
+ QProgressDialog progress;
+ progress.setLabelText(tr("Preparing vfs"));
+ progress.setMaximum(mapping.size());
+ progress.show();
+ int value = 0;
+ for (auto map : mapping) {
+ progress.setValue(value++);
+ if (value % 10 == 0) {
+ QCoreApplication::processEvents();
+ }
+ if (map.isDirectory) {
+ VirtualLinkDirectoryStatic(map.source.toStdWString().c_str()
+ , map.destination.toStdWString().c_str()
+ , 0);
+ } else {
+ VirtualLinkFile(map.source.toStdWString().c_str()
+ , map.destination.toStdWString().c_str()
+ , 0);
+ }
+ }
+/*
+ size_t dumpSize = 0;
+ CreateVFSDump(nullptr, &dumpSize);
+ std::unique_ptr<char[]> buffer(new char[dumpSize]);
+ CreateVFSDump(buffer.get(), &dumpSize);
+ qDebug(buffer.get());
+*/
+}
+
diff --git a/src/usvfsconnector.h b/src/usvfsconnector.h
new file mode 100644
index 00000000..464b932b
--- /dev/null
+++ b/src/usvfsconnector.h
@@ -0,0 +1,88 @@
+/*
+Copyright (C) 2015 Sebastian Herbord. All rights reserved.
+
+This file is part of Mod Organizer.
+
+Mod Organizer 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, either version 3 of the License, or
+(at your option) any later version.
+
+Mod Organizer 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 Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef USVFSCONNECTOR_H
+#define USVFSCONNECTOR_H
+
+
+#include <usvfs.h>
+#include <QString>
+#include <QThread>
+#include <QFile>
+#include <QDebug>
+
+
+struct Mapping {
+ QString source;
+ QString destination;
+ bool isDirectory;
+};
+
+typedef std::vector<Mapping> MappingType;
+
+
+class LogWorker : public QThread {
+
+ Q_OBJECT
+
+public:
+
+ LogWorker();
+ ~LogWorker();
+
+public slots:
+
+ void process();
+ void exit();
+
+signals:
+
+ void outputLog(const QString &message);
+ void finished();
+
+private:
+
+ std::string m_Buffer;
+ bool m_QuitRequested;
+ QFile *m_LogFile;
+
+};
+
+
+class UsvfsConnector : public QObject {
+
+ Q_OBJECT
+
+public:
+
+ UsvfsConnector();
+ ~UsvfsConnector();
+
+ void updateMapping(const MappingType &mapping);
+
+private:
+
+ LogWorker m_LogWorker;
+ QThread m_WorkerThread;
+
+};
+
+
+#endif // USVFSCONNECTOR_H
diff --git a/src/version.rc b/src/version.rc
index 50615bdc..d33afcbf 100644
--- a/src/version.rc
+++ b/src/version.rc
@@ -1,7 +1,7 @@
#include "Winver.h"
-#define VER_FILEVERSION 1,3,11,0
-#define VER_FILEVERSION_STR "1,3,11,0\0"
+#define VER_FILEVERSION 2,0,0
+#define VER_FILEVERSION_STR "2,0,0a1\0"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION