Skip to content

Commit 4da0bff

Browse files
Add instance manager to plugin API (#2335)
1 parent a394f02 commit 4da0bff

11 files changed

Lines changed: 206 additions & 37 deletions

src/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ mo2_add_filter(NAME src/application GROUPS
109109
multiprocess
110110
sanitychecks
111111
selfupdater
112+
systemtraymanager
112113
updatedialog
113114
)
114115

@@ -273,7 +274,9 @@ mo2_add_filter(NAME src/profiles GROUPS
273274

274275
mo2_add_filter(NAME src/proxies GROUPS
275276
downloadmanagerproxy
277+
executableslistproxy
276278
gamefeaturesproxy
279+
instancemanagerproxy
277280
modlistproxy
278281
organizerproxy
279282
pluginlistproxy

src/envshortcut.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ Shortcut::Shortcut() : m_iconIndex(0) {}
132132

133133
Shortcut::Shortcut(const Executable& exe) : Shortcut()
134134
{
135-
const auto i = *InstanceManager::singleton().currentInstance();
135+
const auto& i = *InstanceManager::singleton().currentInstance();
136136

137137
m_name = MOBase::sanitizeFileName(exe.title());
138138
m_target = QFileInfo(qApp->applicationFilePath()).absoluteFilePath();

src/instancemanager.cpp

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
3939
#include <QMessageBox>
4040
#include <QStandardPaths>
4141
#include <cstdint>
42+
#include <memory>
43+
#include <mutex>
4244

4345
using namespace MOBase;
4446

@@ -57,11 +59,25 @@ QString Instance::displayName() const
5759

5860
QString Instance::gameName() const
5961
{
62+
if (!m_iniValuesRead && m_gameName.isEmpty()) {
63+
std::scoped_lock lock(m_iniValuesMutex);
64+
if (!m_iniValuesRead) {
65+
readFromIni();
66+
}
67+
}
68+
6069
return m_gameName;
6170
}
6271

6372
QString Instance::gameDirectory() const
6473
{
74+
if (!m_iniValuesRead && m_gameDir.isEmpty()) {
75+
std::scoped_lock lock(m_iniValuesMutex);
76+
if (!m_iniValuesRead) {
77+
readFromIni();
78+
}
79+
}
80+
6581
return m_gameDir;
6682
}
6783

@@ -72,6 +88,13 @@ QString Instance::directory() const
7288

7389
QString Instance::baseDirectory() const
7490
{
91+
if (!m_iniValuesRead) {
92+
std::scoped_lock lock(m_iniValuesMutex);
93+
if (!m_iniValuesRead) {
94+
readFromIni();
95+
}
96+
}
97+
7598
return m_baseDir;
7699
}
77100

@@ -82,6 +105,13 @@ MOBase::IPluginGame* Instance::gamePlugin() const
82105

83106
QString Instance::profileName() const
84107
{
108+
if (!m_iniValuesRead) {
109+
std::scoped_lock lock(m_iniValuesMutex);
110+
if (!m_iniValuesRead) {
111+
readFromIni();
112+
}
113+
}
114+
85115
return m_profile;
86116
}
87117

@@ -110,12 +140,13 @@ bool Instance::isActive() const
110140
return false;
111141
}
112142

113-
bool Instance::readFromIni()
143+
bool Instance::readFromIni() const
114144
{
115145
Settings s(iniPath());
116146

117147
if (s.iniStatus() != QSettings::NoError) {
118148
log::error("can't read ini {}", iniPath());
149+
m_iniValuesRead = true;
119150
return false;
120151
}
121152

@@ -143,14 +174,18 @@ bool Instance::readFromIni()
143174
// figuring out profile from ini if it's missing
144175
getProfile(s);
145176

177+
m_iniValuesRead = true;
146178
return true;
147179
}
148180

149181
Instance::SetupResults Instance::setup(PluginContainer& plugins)
150182
{
151-
// read initial values from the ini
152-
if (!readFromIni()) {
153-
return SetupResults::BadIni;
183+
if (!m_iniValuesRead) {
184+
std::scoped_lock lock(m_iniValuesMutex);
185+
// read initial values from the ini
186+
if (!m_iniValuesRead && !readFromIni()) {
187+
return SetupResults::BadIni;
188+
}
154189
}
155190

156191
// getting game plugin
@@ -310,7 +345,7 @@ Instance::SetupResults Instance::getGamePlugin(PluginContainer& plugins)
310345
}
311346
}
312347

313-
void Instance::getProfile(const Settings& s)
348+
void Instance::getProfile(const Settings& s) const
314349
{
315350
if (!m_profile.isEmpty()) {
316351
// there's already a profile set up, probably an override
@@ -511,7 +546,7 @@ void InstanceManager::clearOverrides()
511546
m_overrideProfileName = {};
512547
}
513548

514-
std::unique_ptr<Instance> InstanceManager::currentInstance() const
549+
std::shared_ptr<Instance> InstanceManager::currentInstance() const
515550
{
516551
const QString profile = m_overrideProfileName ? *m_overrideProfileName : "";
517552

@@ -520,20 +555,20 @@ std::unique_ptr<Instance> InstanceManager::currentInstance() const
520555

521556
if (!allowedToChangeInstance()) {
522557
// force portable instance
523-
return std::make_unique<Instance>(portablePath(), true, profile);
558+
return std::make_shared<Instance>(portablePath(), true, profile);
524559
}
525560

526561
if (name.isEmpty()) {
527562
if (portableInstanceExists()) {
528563
// use portable
529-
return std::make_unique<Instance>(portablePath(), true, profile);
564+
return std::make_shared<Instance>(portablePath(), true, profile);
530565
} else {
531566
// no instance set
532567
return {};
533568
}
534569
}
535570

536-
return std::make_unique<Instance>(instancePath(name), false, profile);
571+
return std::make_shared<Instance>(instancePath(name), false, profile);
537572
}
538573

539574
void InstanceManager::clearCurrentInstance()
@@ -583,6 +618,16 @@ std::vector<QString> InstanceManager::globalInstancePaths() const
583618
return list;
584619
}
585620

621+
std::shared_ptr<const Instance>
622+
InstanceManager::getGlobalInstance(const QString& instanceName) const
623+
{
624+
if (!instanceExists(instanceName)) {
625+
return nullptr;
626+
}
627+
628+
return std::make_shared<const Instance>(instancePath(instanceName), false, "");
629+
}
630+
586631
bool InstanceManager::hasAnyInstances() const
587632
{
588633
return portableInstanceExists() || !globalInstancePaths().empty();
@@ -696,7 +741,7 @@ bool InstanceManager::instanceExists(const QString& instanceName) const
696741
return root.exists(instanceName);
697742
}
698743

699-
std::unique_ptr<Instance> selectInstance()
744+
std::shared_ptr<Instance> selectInstance()
700745
{
701746
auto& m = InstanceManager::singleton();
702747

src/instancemanager.h

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
#ifndef MODORGANIZER_INSTANCEMANAGER_INCLUDED
22
#define MODORGANIZER_INSTANCEMANAGER_INCLUDED
33

4+
#include <QDir>
45
#include <QSettings>
56
#include <QString>
67

8+
#include <atomic>
9+
#include <memory>
10+
#include <mutex>
11+
12+
#include <uibase/iinstance.h>
13+
714
namespace MOBase
815
{
916
class IPluginGame;
@@ -26,7 +33,7 @@ class PluginContainer;
2633
// setGame() and setVariant() can be called before retrying setup(); this
2734
// happens on startup if that information is missing
2835
//
29-
class Instance
36+
class Instance : public MOBase::IInstance
3037
{
3138
public:
3239
// returned by setup()
@@ -92,18 +99,6 @@ class Instance
9299
//
93100
Instance(QString dir, bool portable, QString profileName = {});
94101

95-
// reads in values from the INI if they were not given yet:
96-
// - game name
97-
// - game directory
98-
// - game variant
99-
// - profile name
100-
//
101-
// note that setup() already calls this
102-
//
103-
// returns false if the ini couldn't be read from
104-
//
105-
bool readFromIni();
106-
107102
// finds the appropriate game plugin and sets it up so MO can use it; this
108103
// calls readFromIni() first
109104
//
@@ -192,17 +187,32 @@ class Instance
192187
private:
193188
QString m_dir;
194189
bool m_portable;
195-
QString m_gameName, m_gameDir, m_gameVariant, m_baseDir;
190+
mutable QString m_gameName, m_gameDir, m_gameVariant, m_baseDir;
196191
MOBase::IPluginGame* m_plugin;
197-
QString m_profile;
192+
mutable QString m_profile;
193+
194+
mutable std::mutex m_iniValuesMutex;
195+
mutable std::atomic<bool> m_iniValuesRead{false};
196+
197+
// reads in values from the INI if they were not given yet:
198+
// - game name
199+
// - game directory
200+
// - game variant
201+
// - profile name
202+
//
203+
// note that setup() already calls this
204+
//
205+
// returns false if the ini couldn't be read from
206+
//
207+
bool readFromIni() const;
198208

199209
// figures out the game plugin for this instance
200210
//
201211
SetupResults getGamePlugin(PluginContainer& plugins);
202212

203213
// figures out the profile name for this instance
204214
//
205-
void getProfile(const Settings& s);
215+
void getProfile(const Settings& s) const;
206216

207217
// updates the ini with the given values and the ones found by setup()
208218
//
@@ -259,7 +269,7 @@ class InstanceManager
259269
// instance name in the registry is empty or non-existent and there is no
260270
// portable instance set up
261271
//
262-
std::unique_ptr<Instance> currentInstance() const;
272+
std::shared_ptr<Instance> currentInstance() const;
263273

264274
// sets the instance name in the registry so the same instance is opened next
265275
// time MO runs
@@ -295,6 +305,10 @@ class InstanceManager
295305
//
296306
std::vector<QString> globalInstancePaths() const;
297307

308+
// returns the global Instance with the given name, or null if it doesn't exist
309+
//
310+
std::shared_ptr<const Instance> getGlobalInstance(const QString& instanceName) const;
311+
298312
// sanitizes the given instance name and either
299313
// 1) returns it if there is no instance with this name
300314
// 2) tries to add " (N)" at the end until it works
@@ -343,7 +357,7 @@ enum class SetupInstanceResults
343357
// instance manager dialog and returns the selected instance or empty if the
344358
// user cancelled
345359
//
346-
std::unique_ptr<Instance> selectInstance();
360+
std::shared_ptr<Instance> selectInstance();
347361

348362
// calls instance.setup() tries to handle problems by itself:
349363
//

src/instancemanagerdialog.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -257,11 +257,6 @@ void InstanceManagerDialog::updateInstances()
257257
m_instances.insert(m_instances.begin(),
258258
std::make_unique<Instance>(m.portablePath(), true));
259259
}
260-
261-
// read all inis, ignore errors
262-
for (auto&& i : m_instances) {
263-
i->readFromIni();
264-
}
265260
}
266261

267262
void InstanceManagerDialog::updateList()

src/instancemanagerproxy.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
Copyright (C) 2012 Sebastian Herbord. All rights reserved.
3+
4+
This file is part of Mod Organizer.
5+
6+
Mod Organizer is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
Mod Organizer is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include "instancemanagerproxy.h"
21+
22+
#include "instancemanager.h"
23+
24+
#include <memory>
25+
#include <vector>
26+
27+
#include <QDir>
28+
#include <QString>
29+
30+
#include <uibase/iinstance.h>
31+
32+
InstanceManagerProxy::InstanceManagerProxy(InstanceManager* instanceManager)
33+
: m_Proxied(instanceManager)
34+
{}
35+
36+
std::shared_ptr<MOBase::IInstance> InstanceManagerProxy::currentInstance() const
37+
{
38+
return m_Proxied->currentInstance();
39+
}
40+
41+
std::vector<QDir> InstanceManagerProxy::globalInstancePaths() const
42+
{
43+
const auto globalPaths = m_Proxied->globalInstancePaths();
44+
return std::vector<QDir>(globalPaths.begin(), globalPaths.end());
45+
}
46+
47+
std::shared_ptr<const MOBase::IInstance>
48+
InstanceManagerProxy::getGlobalInstance(const QString& instanceName) const
49+
{
50+
return m_Proxied->getGlobalInstance(instanceName);
51+
}

0 commit comments

Comments
 (0)