@@ -53,59 +53,26 @@ fs::path getPluginFolder()
5353 return fs::path (path).parent_path ();
5454}
5555
56- ProxyPython::ProxyPython ()
57- : m_MOInfo{nullptr }, m_RunnerLib{nullptr }, m_Runner{nullptr },
58- m_LoadFailure (FailureType::NONE)
59- {
60- }
56+ ProxyPython::ProxyPython () : m_RunnerLib{nullptr }, m_Runner{nullptr } {}
6157
62- bool ProxyPython::init (IOrganizer* moInfo )
58+ bool ProxyPython::initialize (QString& errorMessage )
6359{
64- m_MOInfo = moInfo;
65-
66- if (m_MOInfo && !m_MOInfo->isPluginEnabled (this )) {
67- return false ;
68- }
60+ errorMessage = " " ;
6961
7062 if (QCoreApplication::applicationDirPath ().contains (' ;' )) {
71- m_LoadFailure = FailureType::SEMICOLON;
63+ errorMessage = failureMessage ( FailureType::SEMICOLON) ;
7264 return true ;
7365 }
7466
7567 const auto pluginFolder = getPluginFolder ();
76-
7768 if (pluginFolder.empty ()) {
78- DWORD error = ::GetLastError ();
79- m_LoadFailure = FailureType::DLL_NOT_FOUND;
69+ DWORD error = ::GetLastError ();
70+ errorMessage = failureMessage ( FailureType::DLL_NOT_FOUND) ;
8071 log::error (" failed to resolve Python proxy directory ({}): {}" , error,
8172 qUtf8Printable (windowsErrorString (::GetLastError ())));
8273 return false ;
8374 }
8475
85- if (m_MOInfo && m_MOInfo->persistent (name (), " tryInit" , false ).toBool ()) {
86- m_LoadFailure = FailureType::INITIALIZATION;
87- if (QMessageBox::question (
88- parentWidget (), tr (" Python Initialization failed" ),
89- tr (" On a previous start the Python Plugin failed to initialize.\n "
90- " Do you want to try initializing python again (at the risk of "
91- " another crash)?\n "
92- " Suggestion: Select \" no\" , and click the warning sign for further "
93- " help.Afterwards you have to re-enable the python plugin." ),
94- QMessageBox::Yes | QMessageBox::No,
95- QMessageBox::No) == QMessageBox::No) {
96- // we force enabled here (note: this is a persistent settings since MO2 2.4
97- // or something), plugin
98- // usually should not handle enabled/disabled themselves but this is a base
99- // plugin so...
100- m_MOInfo->setPersistent (name (), " enabled" , false , true );
101- return true ;
102- }
103- }
104-
105- if (m_MOInfo) {
106- m_MOInfo->setPersistent (name (), " tryInit" , true );
107- }
108-
10976 // load the pythonrunner library, this is done in multiple steps:
11077 //
11178 // 1. we set the dlls/ subfolder (from the plugin) as the DLL directory so Windows
@@ -114,8 +81,8 @@ bool ProxyPython::init(IOrganizer* moInfo)
11481 //
11582 const auto dllPaths = pluginFolder / " dlls" ;
11683 if (SetDllDirectoryW (dllPaths.c_str ()) == 0 ) {
117- DWORD error = ::GetLastError ();
118- m_LoadFailure = FailureType::DLL_NOT_FOUND;
84+ DWORD error = ::GetLastError ();
85+ errorMessage = failureMessage ( FailureType::DLL_NOT_FOUND) ;
11986 log::error (" failed to add python DLL directory ({}): {}" , error,
12087 qUtf8Printable (windowsErrorString (::GetLastError ())));
12188 return false ;
@@ -129,21 +96,16 @@ bool ProxyPython::init(IOrganizer* moInfo)
12996
13097 if (m_Runner) {
13198 const auto libpath = pluginFolder / " libs" ;
132- const std::vector<fs::path> paths{
133- libpath / " pythoncore.zip" , libpath,
134- std::filesystem::path{IOrganizer::getPluginDataPath ().toStdWString ()}};
99+ const std::vector<fs::path> paths{libpath / " pythoncore.zip" , libpath};
135100 m_Runner->initialize (paths);
136101 }
137102
138- if (m_MOInfo) {
139- m_MOInfo->setPersistent (name (), " tryInit" , false );
140- }
141-
142103 // reset DLL directory
143104 SetDllDirectoryW (NULL );
144105
145106 if (!m_Runner || !m_Runner->isInitialized ()) {
146- m_LoadFailure = FailureType::INITIALIZATION;
107+ errorMessage = failureMessage (FailureType::INITIALIZATION);
108+ return false ;
147109 }
148110 else {
149111 m_Runner->addDllSearchPath (pluginFolder / " dlls" );
@@ -152,110 +114,57 @@ bool ProxyPython::init(IOrganizer* moInfo)
152114 return true ;
153115}
154116
155- QString ProxyPython::name () const
156- {
157- return " Python Proxy" ;
158- }
159-
160- QString ProxyPython::localizedName () const
161- {
162- return tr (" Python Proxy" );
163- }
164-
165- QString ProxyPython::author () const
166- {
167- return " AnyOldName3, Holt59, Silarn, Tannin" ;
168- }
169-
170- QString ProxyPython::description () const
171- {
172- return tr (" Proxy Plugin to allow plugins written in python to be loaded" );
173- }
174-
175- VersionInfo ProxyPython::version () const
176- {
177- return VersionInfo (3 , 0 , 0 , VersionInfo::RELEASE_FINAL);
178- }
179-
180- QList<PluginSetting> ProxyPython::settings () const
181- {
182- return {};
183- }
184-
185- QStringList ProxyPython::pluginList (const QDir& pluginPath) const
117+ QList<QList<QObject*>> ProxyPython::load (const PluginExtension& extension)
186118{
187- QDir dir (pluginPath);
188- dir.setFilter (dir.filter () | QDir::NoDotAndDotDot);
189- QDirIterator iter (dir);
190-
191- // Note: We put python script (.py) and directory names, not the __init__.py
192- // files in those since it is easier for the runner to import them.
193- QStringList result;
194- while (iter.hasNext ()) {
195- QString name = iter.next ();
196- QFileInfo info = iter.fileInfo ();
197-
198- if (info.isFile () && name.endsWith (" .py" )) {
199- result.append (name);
200- }
201- else if (info.isDir () && QDir (info.absoluteFilePath ()).exists (" __init__.py" )) {
202- result.append (name);
203- }
119+ if (!m_Runner) {
120+ return {};
204121 }
205122
206- return result;
207- }
208-
209- QList<QObject*> ProxyPython::load (const QString& identifier)
210- {
211- if (!m_Runner) {
123+ // currently, only handle __init__.py directly in the folder
124+ const auto pyIniFile = extension.directory () / " __init__.py" ;
125+ if (!exists (pyIniFile)) {
212126 return {};
213127 }
214- return m_Runner->load (identifier);
215- }
216128
217- void ProxyPython::unload (const QString& identifier)
218- {
219- if (m_Runner) {
220- return m_Runner->unload (identifier);
129+ m_ExtensionModules[&extension] = {pyIniFile};
130+
131+ QList<QList<QObject*>> plugins;
132+ for (auto && pythonModule : m_ExtensionModules[&extension]) {
133+ plugins.append (m_Runner->load (pythonModule));
221134 }
135+
136+ return plugins;
222137}
223138
224- std::vector< unsigned int > ProxyPython::activeProblems () const
139+ void ProxyPython::unload ( const PluginExtension& extension)
225140{
226- auto failure = m_LoadFailure;
227-
228- // don't know how this could happen but wth
229- if (m_Runner && !m_Runner->isInitialized ()) {
230- failure = FailureType::INITIALIZATION;
141+ if (!m_Runner) {
142+ return ;
231143 }
232144
233- if (failure != FailureType::NONE) {
234- return {static_cast <std::underlying_type_t <FailureType>>(failure)};
145+ if (auto it = m_ExtensionModules.find (&extension); it != m_ExtensionModules.end ()) {
146+ for (auto && pythonModule : it->second ) {
147+ m_Runner->unload (pythonModule);
148+ }
149+ m_ExtensionModules.erase (it);
235150 }
236-
237- return {};
238151}
239152
240- QString ProxyPython::shortDescription ( unsigned int key) const
153+ void ProxyPython::unloadAll ()
241154{
242- switch (static_cast <FailureType>(key)) {
243- case FailureType::SEMICOLON:
244- return tr (" ModOrganizer path contains a semicolon" );
245- case FailureType::DLL_NOT_FOUND:
246- return tr (" Python DLL not found" );
247- case FailureType::INVALID_DLL:
248- return tr (" Invalid Python DLL" );
249- case FailureType::INITIALIZATION:
250- return tr (" Initializing Python failed" );
251- default :
252- return tr (" invalid problem key %1" ).arg (key);
155+ if (m_Runner) {
156+ for (auto & [ext, modules] : m_ExtensionModules) {
157+ for (auto & pythonModule : modules) {
158+ m_Runner->unload (pythonModule);
159+ }
160+ }
253161 }
162+ m_ExtensionModules.clear ();
254163}
255164
256- QString ProxyPython::fullDescription ( unsigned int key) const
165+ QString ProxyPython::failureMessage (FailureType key)
257166{
258- switch (static_cast <FailureType>( key) ) {
167+ switch (key) {
259168 case FailureType::SEMICOLON:
260169 return tr (" The path to Mod Organizer (%1) contains a semicolon.<br>"
261170 " While this is legal on NTFS drives, many applications do not "
@@ -278,13 +187,6 @@ QString ProxyPython::fullDescription(unsigned int key) const
278187 return tr (" The initialization of the Python plugin DLL failed, unfortunately "
279188 " without any details." );
280189 default :
281- return tr (" invalid problem key %1 " ). arg (key );
190+ return tr (" no failure " );
282191 }
283192}
284-
285- bool ProxyPython::hasGuidedFix (unsigned int ) const
286- {
287- return false ;
288- }
289-
290- void ProxyPython::startGuidedFix (unsigned int ) const {}
0 commit comments