NOISSUE Allow joining servers from the servers page
This commit is contained in:
		| @@ -147,7 +147,8 @@ public: | |||||||
|     virtual shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) = 0; |     virtual shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) = 0; | ||||||
|  |  | ||||||
|     /// returns a valid launcher (task container) |     /// returns a valid launcher (task container) | ||||||
|     virtual shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) = 0; |     virtual shared_qobject_ptr<LaunchTask> createLaunchTask( | ||||||
|  |             AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) = 0; | ||||||
|  |  | ||||||
|     /// returns the current launch task (if any) |     /// returns the current launch task (if any) | ||||||
|     shared_qobject_ptr<LaunchTask> getLaunchTask(); |     shared_qobject_ptr<LaunchTask> getLaunchTask(); | ||||||
|   | |||||||
| @@ -238,6 +238,7 @@ set(MINECRAFT_SOURCES | |||||||
|     minecraft/launch/ExtractNatives.h |     minecraft/launch/ExtractNatives.h | ||||||
|     minecraft/launch/LauncherPartLaunch.cpp |     minecraft/launch/LauncherPartLaunch.cpp | ||||||
|     minecraft/launch/LauncherPartLaunch.h |     minecraft/launch/LauncherPartLaunch.h | ||||||
|  |     minecraft/launch/MinecraftServerTarget.cpp | ||||||
|     minecraft/launch/MinecraftServerTarget.h |     minecraft/launch/MinecraftServerTarget.h | ||||||
|     minecraft/launch/PrintInstanceInfo.cpp |     minecraft/launch/PrintInstanceInfo.cpp | ||||||
|     minecraft/launch/PrintInstanceInfo.h |     minecraft/launch/PrintInstanceInfo.h | ||||||
|   | |||||||
| @@ -27,7 +27,7 @@ public: | |||||||
|     { |     { | ||||||
|         return instanceRoot(); |         return instanceRoot(); | ||||||
|     }; |     }; | ||||||
|     shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr) override |     shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr, MinecraftServerTargetPtr) override | ||||||
|     { |     { | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -822,7 +822,7 @@ shared_qobject_ptr<Task> MinecraftInstance::createUpdateTask(Net::Mode mode) | |||||||
|     return nullptr; |     return nullptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session) | shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) | ||||||
| { | { | ||||||
|     // FIXME: get rid of shared_from_this ... |     // FIXME: get rid of shared_from_this ... | ||||||
|     auto process = LaunchTask::create(std::dynamic_pointer_cast<MinecraftInstance>(shared_from_this())); |     auto process = LaunchTask::create(std::dynamic_pointer_cast<MinecraftInstance>(shared_from_this())); | ||||||
| @@ -854,66 +854,19 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt | |||||||
|         process->appendStep(new CreateGameFolders(pptr)); |         process->appendStep(new CreateGameFolders(pptr)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     MinecraftServerTargetPtr serverToJoin = std::make_shared<MinecraftServerTarget>(); |     if (!serverToJoin && m_settings->get("JoinServerOnLaunch").toBool()) | ||||||
|  |  | ||||||
|     if (m_settings->get("JoinServerOnLaunch").toBool()) |  | ||||||
|     { |     { | ||||||
|         QString fullAddress = m_settings->get("JoinServerOnLaunchAddress").toString(); |         QString fullAddress = m_settings->get("JoinServerOnLaunchAddress").toString(); | ||||||
|         QStringList split = fullAddress.split(":"); |         serverToJoin.reset(new MinecraftServerTarget(MinecraftServerTarget::parse(fullAddress))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|         // The logic below replicates the exact logic minecraft uses for parsing server addresses. |     if(serverToJoin && serverToJoin->port == 25565) | ||||||
|         // While the conversion is not lossless and eats errors, it ensures the same behavior |     { | ||||||
|         // within Minecraft and MultiMC when entering server addresses. |         // Resolve server address to join on launch | ||||||
|         if (fullAddress.startsWith("[")) |         auto *step = new LookupServerAddress(pptr); | ||||||
|         { |         step->setLookupAddress(serverToJoin->address); | ||||||
|             int bracket = fullAddress.indexOf("]"); |         step->setOutputAddressPtr(serverToJoin); | ||||||
|             if (bracket > 0) |         process->appendStep(step); | ||||||
|             { |  | ||||||
|                 QString ipv6 = fullAddress.mid(1, bracket - 1); |  | ||||||
|                 QString port = fullAddress.mid(bracket + 1).trimmed(); |  | ||||||
|  |  | ||||||
|                 if (port.startsWith(":") && !ipv6.isEmpty()) |  | ||||||
|                 { |  | ||||||
|                     port = port.mid(1); |  | ||||||
|                     split = QStringList({ ipv6, port }); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     split = QStringList({ipv6}); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (split.size() > 2) |  | ||||||
|         { |  | ||||||
|             split = QStringList({fullAddress}); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         QString realAddress = split[0]; |  | ||||||
|  |  | ||||||
|         quint16 realPort = 25565; |  | ||||||
|         if (split.size() > 1) |  | ||||||
|         { |  | ||||||
|             bool ok; |  | ||||||
|             realPort = split[1].toUInt(&ok); |  | ||||||
|  |  | ||||||
|             if (!ok) |  | ||||||
|             { |  | ||||||
|                 realPort = 25565; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         serverToJoin->port = realPort; |  | ||||||
|         serverToJoin->address = realAddress; |  | ||||||
|  |  | ||||||
|         if(realPort == 25565) |  | ||||||
|         { |  | ||||||
|             // Resolve server address to join on launch |  | ||||||
|             auto *step = new LookupServerAddress(pptr); |  | ||||||
|             step->setLookupAddress(realAddress); |  | ||||||
|             step->setOutputAddressPtr(serverToJoin); |  | ||||||
|             process->appendStep(step); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // run pre-launch command if that's needed |     // run pre-launch command if that's needed | ||||||
|   | |||||||
| @@ -77,7 +77,7 @@ public: | |||||||
|  |  | ||||||
|     //////  Launch stuff ////// |     //////  Launch stuff ////// | ||||||
|     shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) override; |     shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) override; | ||||||
|     shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) override; |     shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) override; | ||||||
|     QStringList extraArguments() const override; |     QStringList extraArguments() const override; | ||||||
|     QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override; |     QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override; | ||||||
|     QList<Mod> getJarMods() const; |     QList<Mod> getJarMods() const; | ||||||
|   | |||||||
							
								
								
									
										66
									
								
								api/logic/minecraft/launch/MinecraftServerTarget.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								api/logic/minecraft/launch/MinecraftServerTarget.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | /* Copyright 2013-2021 MultiMC Contributors | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "MinecraftServerTarget.h" | ||||||
|  |  | ||||||
|  | #include <QStringList> | ||||||
|  |  | ||||||
|  | MinecraftServerTarget MinecraftServerTarget::parse(const QString &fullAddress) { | ||||||
|  |     QStringList split = fullAddress.split(":"); | ||||||
|  |  | ||||||
|  |     // The logic below replicates the exact logic minecraft uses for parsing server addresses. | ||||||
|  |     // While the conversion is not lossless and eats errors, it ensures the same behavior | ||||||
|  |     // within Minecraft and MultiMC when entering server addresses. | ||||||
|  |     if (fullAddress.startsWith("[")) | ||||||
|  |     { | ||||||
|  |         int bracket = fullAddress.indexOf("]"); | ||||||
|  |         if (bracket > 0) | ||||||
|  |         { | ||||||
|  |             QString ipv6 = fullAddress.mid(1, bracket - 1); | ||||||
|  |             QString port = fullAddress.mid(bracket + 1).trimmed(); | ||||||
|  |  | ||||||
|  |             if (port.startsWith(":") && !ipv6.isEmpty()) | ||||||
|  |             { | ||||||
|  |                 port = port.mid(1); | ||||||
|  |                 split = QStringList({ ipv6, port }); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 split = QStringList({ipv6}); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (split.size() > 2) | ||||||
|  |     { | ||||||
|  |         split = QStringList({fullAddress}); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     QString realAddress = split[0]; | ||||||
|  |  | ||||||
|  |     quint16 realPort = 25565; | ||||||
|  |     if (split.size() > 1) | ||||||
|  |     { | ||||||
|  |         bool ok; | ||||||
|  |         realPort = split[1].toUInt(&ok); | ||||||
|  |  | ||||||
|  |         if (!ok) | ||||||
|  |         { | ||||||
|  |             realPort = 25565; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return MinecraftServerTarget { realAddress, realPort }; | ||||||
|  | } | ||||||
| @@ -17,9 +17,14 @@ | |||||||
|  |  | ||||||
| #include <memory> | #include <memory> | ||||||
|  |  | ||||||
|  | #include <QString> | ||||||
|  | #include <multimc_logic_export.h> | ||||||
|  |  | ||||||
| struct MinecraftServerTarget { | struct MinecraftServerTarget { | ||||||
|     QString address; |     QString address; | ||||||
|     quint16 port; |     quint16 port; | ||||||
|  |  | ||||||
|  |     static MULTIMC_LOGIC_EXPORT MinecraftServerTarget parse(const QString &fullAddress); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| typedef std::shared_ptr<MinecraftServerTarget> MinecraftServerTargetPtr; | typedef std::shared_ptr<MinecraftServerTarget> MinecraftServerTargetPtr; | ||||||
|   | |||||||
| @@ -111,7 +111,8 @@ public: | |||||||
|     { |     { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) override |     shared_qobject_ptr<LaunchTask> createLaunchTask( | ||||||
|  |             AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) override | ||||||
|     { |     { | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -46,7 +46,7 @@ public: | |||||||
|             values.append(new TexturePackPage(onesix.get())); |             values.append(new TexturePackPage(onesix.get())); | ||||||
|             values.append(new NotesPage(onesix.get())); |             values.append(new NotesPage(onesix.get())); | ||||||
|             values.append(new WorldListPage(onesix.get(), onesix->worldList())); |             values.append(new WorldListPage(onesix.get(), onesix->worldList())); | ||||||
|             values.append(new ServersPage(onesix.get())); |             values.append(new ServersPage(onesix)); | ||||||
|             // values.append(new GameOptionsPage(onesix.get())); |             // values.append(new GameOptionsPage(onesix.get())); | ||||||
|             values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots"))); |             values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots"))); | ||||||
|             values.append(new InstanceSettingsPage(onesix.get())); |             values.append(new InstanceSettingsPage(onesix.get())); | ||||||
|   | |||||||
| @@ -197,7 +197,7 @@ void LaunchController::launchInstance() | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     m_launcher = m_instance->createLaunchTask(m_session); |     m_launcher = m_instance->createLaunchTask(m_session, m_serverToJoin); | ||||||
|     if (!m_launcher) |     if (!m_launcher) | ||||||
|     { |     { | ||||||
|         emitFailed(tr("Couldn't instantiate a launcher.")); |         emitFailed(tr("Couldn't instantiate a launcher.")); | ||||||
|   | |||||||
| @@ -3,6 +3,8 @@ | |||||||
| #include <BaseInstance.h> | #include <BaseInstance.h> | ||||||
| #include <tools/BaseProfiler.h> | #include <tools/BaseProfiler.h> | ||||||
|  |  | ||||||
|  | #include "minecraft/launch/MinecraftServerTarget.h" | ||||||
|  |  | ||||||
| class InstanceWindow; | class InstanceWindow; | ||||||
| class LaunchController: public Task | class LaunchController: public Task | ||||||
| { | { | ||||||
| @@ -33,6 +35,10 @@ public: | |||||||
|     { |     { | ||||||
|         m_parentWidget = widget; |         m_parentWidget = widget; | ||||||
|     } |     } | ||||||
|  |     void setServerToJoin(MinecraftServerTargetPtr serverToJoin) | ||||||
|  |     { | ||||||
|  |         m_serverToJoin = std::move(serverToJoin); | ||||||
|  |     } | ||||||
|     QString id() |     QString id() | ||||||
|     { |     { | ||||||
|         return m_instance->id(); |         return m_instance->id(); | ||||||
| @@ -58,4 +64,5 @@ private: | |||||||
|     InstanceWindow *m_console = nullptr; |     InstanceWindow *m_console = nullptr; | ||||||
|     AuthSessionPtr m_session; |     AuthSessionPtr m_session; | ||||||
|     shared_qobject_ptr<LaunchTask> m_launcher; |     shared_qobject_ptr<LaunchTask> m_launcher; | ||||||
|  |     MinecraftServerTargetPtr m_serverToJoin; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -1014,8 +1014,12 @@ bool MultiMC::openJsonEditor(const QString &filename) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| bool MultiMC::launch(InstancePtr instance, bool online, BaseProfilerFactory *profiler) | bool MultiMC::launch( | ||||||
| { |         InstancePtr instance, | ||||||
|  |         bool online, | ||||||
|  |         BaseProfilerFactory *profiler, | ||||||
|  |         MinecraftServerTargetPtr serverToJoin | ||||||
|  | ) { | ||||||
|     if(m_updateRunning) |     if(m_updateRunning) | ||||||
|     { |     { | ||||||
|         qDebug() << "Cannot launch instances while an update is running. Please try again when updates are completed."; |         qDebug() << "Cannot launch instances while an update is running. Please try again when updates are completed."; | ||||||
| @@ -1036,6 +1040,7 @@ bool MultiMC::launch(InstancePtr instance, bool online, BaseProfilerFactory *pro | |||||||
|         controller->setInstance(instance); |         controller->setInstance(instance); | ||||||
|         controller->setOnline(online); |         controller->setOnline(online); | ||||||
|         controller->setProfiler(profiler); |         controller->setProfiler(profiler); | ||||||
|  |         controller->setServerToJoin(serverToJoin); | ||||||
|         if(window) |         if(window) | ||||||
|         { |         { | ||||||
|             controller->setParentWidget(window); |             controller->setParentWidget(window); | ||||||
|   | |||||||
| @@ -11,6 +11,8 @@ | |||||||
|  |  | ||||||
| #include <BaseInstance.h> | #include <BaseInstance.h> | ||||||
|  |  | ||||||
|  | #include "minecraft/launch/MinecraftServerTarget.h" | ||||||
|  |  | ||||||
| class LaunchController; | class LaunchController; | ||||||
| class LocalPeer; | class LocalPeer; | ||||||
| class InstanceWindow; | class InstanceWindow; | ||||||
| @@ -150,7 +152,12 @@ signals: | |||||||
|     void globalSettingsClosed(); |     void globalSettingsClosed(); | ||||||
|  |  | ||||||
| public slots: | public slots: | ||||||
|     bool launch(InstancePtr instance, bool online = true, BaseProfilerFactory *profiler = nullptr); |     bool launch( | ||||||
|  |             InstancePtr instance, | ||||||
|  |             bool online = true, | ||||||
|  |             BaseProfilerFactory *profiler = nullptr, | ||||||
|  |             MinecraftServerTargetPtr serverToJoin = nullptr | ||||||
|  |     ); | ||||||
|     bool kill(InstancePtr instance); |     bool kill(InstancePtr instance); | ||||||
|  |  | ||||||
| private slots: | private slots: | ||||||
|   | |||||||
| @@ -39,7 +39,7 @@ | |||||||
|       <enum>QTabWidget::Rounded</enum> |       <enum>QTabWidget::Rounded</enum> | ||||||
|      </property> |      </property> | ||||||
|      <property name="currentIndex"> |      <property name="currentIndex"> | ||||||
|       <number>4</number> |       <number>0</number> | ||||||
|      </property> |      </property> | ||||||
|      <widget class="QWidget" name="minecraftTab"> |      <widget class="QWidget" name="minecraftTab"> | ||||||
|       <attribute name="title"> |       <attribute name="title"> | ||||||
|   | |||||||
| @@ -556,7 +556,7 @@ private: | |||||||
|     QTimer m_saveTimer; |     QTimer m_saveTimer; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| ServersPage::ServersPage(MinecraftInstance * inst, QWidget* parent) | ServersPage::ServersPage(InstancePtr inst, QWidget* parent) | ||||||
|     : QMainWindow(parent), ui(new Ui::ServersPage) |     : QMainWindow(parent), ui(new Ui::ServersPage) | ||||||
| { | { | ||||||
|     ui->setupUi(this); |     ui->setupUi(this); | ||||||
| @@ -579,7 +579,7 @@ ServersPage::ServersPage(MinecraftInstance * inst, QWidget* parent) | |||||||
|  |  | ||||||
|     auto selectionModel = ui->serversView->selectionModel(); |     auto selectionModel = ui->serversView->selectionModel(); | ||||||
|     connect(selectionModel, &QItemSelectionModel::currentChanged, this, &ServersPage::currentChanged); |     connect(selectionModel, &QItemSelectionModel::currentChanged, this, &ServersPage::currentChanged); | ||||||
|     connect(m_inst, &MinecraftInstance::runningStatusChanged, this, &ServersPage::on_RunningState_changed); |     connect(m_inst.get(), &MinecraftInstance::runningStatusChanged, this, &ServersPage::on_RunningState_changed); | ||||||
|     connect(ui->nameLine, &QLineEdit::textEdited, this, &ServersPage::nameEdited); |     connect(ui->nameLine, &QLineEdit::textEdited, this, &ServersPage::nameEdited); | ||||||
|     connect(ui->addressLine, &QLineEdit::textEdited, this, &ServersPage::addressEdited); |     connect(ui->addressLine, &QLineEdit::textEdited, this, &ServersPage::addressEdited); | ||||||
|     connect(ui->resourceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(resourceIndexChanged(int))); |     connect(ui->resourceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(resourceIndexChanged(int))); | ||||||
| @@ -695,6 +695,7 @@ void ServersPage::updateState() | |||||||
|     ui->actionMove_Down->setEnabled(serverEditEnabled); |     ui->actionMove_Down->setEnabled(serverEditEnabled); | ||||||
|     ui->actionMove_Up->setEnabled(serverEditEnabled); |     ui->actionMove_Up->setEnabled(serverEditEnabled); | ||||||
|     ui->actionRemove->setEnabled(serverEditEnabled); |     ui->actionRemove->setEnabled(serverEditEnabled); | ||||||
|  |     ui->actionJoin->setEnabled(serverEditEnabled); | ||||||
|  |  | ||||||
|     if(server) |     if(server) | ||||||
|     { |     { | ||||||
| @@ -758,4 +759,10 @@ void ServersPage::on_actionMove_Down_triggered() | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void ServersPage::on_actionJoin_triggered() | ||||||
|  | { | ||||||
|  |     const auto &address = m_model->at(currentServer)->m_address; | ||||||
|  |     MMC->launch(m_inst, true, nullptr, std::make_shared<MinecraftServerTarget>(MinecraftServerTarget::parse(address))); | ||||||
|  | } | ||||||
|  |  | ||||||
| #include "ServersPage.moc" | #include "ServersPage.moc" | ||||||
|   | |||||||
| @@ -35,7 +35,7 @@ class ServersPage : public QMainWindow, public BasePage | |||||||
|     Q_OBJECT |     Q_OBJECT | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     explicit ServersPage(MinecraftInstance *inst, QWidget *parent = 0); |     explicit ServersPage(InstancePtr inst, QWidget *parent = 0); | ||||||
|     virtual ~ServersPage(); |     virtual ~ServersPage(); | ||||||
|  |  | ||||||
|     void openedImpl() override; |     void openedImpl() override; | ||||||
| @@ -74,6 +74,7 @@ private slots: | |||||||
|     void on_actionRemove_triggered(); |     void on_actionRemove_triggered(); | ||||||
|     void on_actionMove_Up_triggered(); |     void on_actionMove_Up_triggered(); | ||||||
|     void on_actionMove_Down_triggered(); |     void on_actionMove_Down_triggered(); | ||||||
|  |     void on_actionJoin_triggered(); | ||||||
|  |  | ||||||
|     void on_RunningState_changed(bool running); |     void on_RunningState_changed(bool running); | ||||||
|  |  | ||||||
| @@ -88,6 +89,6 @@ private: // data | |||||||
|     bool m_locked = true; |     bool m_locked = true; | ||||||
|     Ui::ServersPage *ui = nullptr; |     Ui::ServersPage *ui = nullptr; | ||||||
|     ServersModel * m_model = nullptr; |     ServersModel * m_model = nullptr; | ||||||
|     MinecraftInstance * m_inst = nullptr; |     InstancePtr m_inst = nullptr; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -148,6 +148,7 @@ | |||||||
|    <addaction name="actionRemove"/> |    <addaction name="actionRemove"/> | ||||||
|    <addaction name="actionMove_Up"/> |    <addaction name="actionMove_Up"/> | ||||||
|    <addaction name="actionMove_Down"/> |    <addaction name="actionMove_Down"/> | ||||||
|  |    <addaction name="actionJoin"/> | ||||||
|   </widget> |   </widget> | ||||||
|   <action name="actionAdd"> |   <action name="actionAdd"> | ||||||
|    <property name="text"> |    <property name="text"> | ||||||
| @@ -169,6 +170,11 @@ | |||||||
|     <string>Move Down</string> |     <string>Move Down</string> | ||||||
|    </property> |    </property> | ||||||
|   </action> |   </action> | ||||||
|  |   <action name="actionJoin"> | ||||||
|  |    <property name="text"> | ||||||
|  |     <string>Join</string> | ||||||
|  |    </property> | ||||||
|  |   </action> | ||||||
|  </widget> |  </widget> | ||||||
|  <customwidgets> |  <customwidgets> | ||||||
|   <customwidget> |   <customwidget> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Janrupf
					Janrupf