mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Add Artic Base support (#105)
* Add Artic Base support * Add Android support
This commit is contained in:
		
							parent
							
								
									572d3ab71c
								
							
						
					
					
						commit
						24c6ec5e6a
					
				
					 83 changed files with 5592 additions and 516 deletions
				
			
		|  | @ -636,6 +636,8 @@ void Config::ReadPathValues() { | |||
|                 UISettings::values.game_dirs.append(game_dir); | ||||
|             } | ||||
|         } | ||||
|         UISettings::values.last_artic_base_addr = | ||||
|             ReadSetting(QStringLiteral("last_artic_base_addr"), QString{}).toString(); | ||||
|         UISettings::values.recent_files = ReadSetting(QStringLiteral("recentFiles")).toStringList(); | ||||
|         UISettings::values.language = ReadSetting(QStringLiteral("language"), QString{}).toString(); | ||||
|     } | ||||
|  | @ -1135,6 +1137,8 @@ void Config::SavePathValues() { | |||
|             WriteSetting(QStringLiteral("expanded"), game_dir.expanded, true); | ||||
|         } | ||||
|         qt_config->endArray(); | ||||
|         WriteSetting(QStringLiteral("last_artic_base_addr"), | ||||
|                      UISettings::values.last_artic_base_addr, QString{}); | ||||
|         WriteSetting(QStringLiteral("recentFiles"), UISettings::values.recent_files); | ||||
|         WriteSetting(QStringLiteral("language"), UISettings::values.language, QString{}); | ||||
|     } | ||||
|  |  | |||
|  | @ -381,6 +381,10 @@ void GMainWindow::InitializeWidgets() { | |||
|     progress_bar->hide(); | ||||
|     statusBar()->addPermanentWidget(progress_bar); | ||||
| 
 | ||||
|     artic_traffic_label = new QLabel(); | ||||
|     artic_traffic_label->setToolTip( | ||||
|         tr("Current Artic Base traffic speed. Higher values indicate bigger transfer loads.")); | ||||
| 
 | ||||
|     emu_speed_label = new QLabel(); | ||||
|     emu_speed_label->setToolTip(tr("Current emulation speed. Values higher or lower than 100% " | ||||
|                                    "indicate emulation is running faster or slower than a 3DS.")); | ||||
|  | @ -392,7 +396,8 @@ void GMainWindow::InitializeWidgets() { | |||
|         tr("Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For " | ||||
|            "full-speed emulation this should be at most 16.67 ms.")); | ||||
| 
 | ||||
|     for (auto& label : {emu_speed_label, game_fps_label, emu_frametime_label}) { | ||||
|     for (auto& label : | ||||
|          {artic_traffic_label, emu_speed_label, game_fps_label, emu_frametime_label}) { | ||||
|         label->setVisible(false); | ||||
|         label->setFrameStyle(QFrame::NoFrame); | ||||
|         label->setContentsMargins(4, 0, 4, 0); | ||||
|  | @ -866,6 +871,7 @@ void GMainWindow::ConnectMenuEvents() { | |||
|     // File
 | ||||
|     connect_menu(ui->action_Load_File, &GMainWindow::OnMenuLoadFile); | ||||
|     connect_menu(ui->action_Install_CIA, &GMainWindow::OnMenuInstallCIA); | ||||
|     connect_menu(ui->action_Connect_Artic, &GMainWindow::OnMenuConnectArticBase); | ||||
|     for (u32 region = 0; region < Core::NUM_SYSTEM_TITLE_REGIONS; region++) { | ||||
|         connect_menu(ui->menu_Boot_Home_Menu->actions().at(region), | ||||
|                      [this, region] { OnMenuBootHomeMenu(region); }); | ||||
|  | @ -1203,6 +1209,11 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
|                                   tr("GBA Virtual Console ROMs are not supported by Citra.")); | ||||
|             break; | ||||
| 
 | ||||
|         case Core::System::ResultStatus::ErrorArticDisconnected: | ||||
|             QMessageBox::critical( | ||||
|                 this, tr("Artic Base Server"), | ||||
|                 tr("An error has occurred whilst communicating with the Artic Base Server.")); | ||||
|             break; | ||||
|         default: | ||||
|             QMessageBox::critical( | ||||
|                 this, tr("Error while loading ROM!"), | ||||
|  | @ -1223,7 +1234,9 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| } | ||||
| 
 | ||||
| void GMainWindow::BootGame(const QString& filename) { | ||||
|     if (filename.endsWith(QStringLiteral(".cia"))) { | ||||
|     const bool is_artic = filename.startsWith(QString::fromStdString("articbase://")); | ||||
| 
 | ||||
|     if (!is_artic && filename.endsWith(QStringLiteral(".cia"))) { | ||||
|         const auto answer = QMessageBox::question( | ||||
|             this, tr("CIA must be installed before usage"), | ||||
|             tr("Before using this CIA, you must install it. Do you want to install it now?"), | ||||
|  | @ -1235,8 +1248,12 @@ void GMainWindow::BootGame(const QString& filename) { | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     show_artic_label = is_artic; | ||||
| 
 | ||||
|     LOG_INFO(Frontend, "Citra starting..."); | ||||
|     StoreRecentFile(filename); // Put the filename on top of the list
 | ||||
|     if (!is_artic) { | ||||
|         StoreRecentFile(filename); // Put the filename on top of the list
 | ||||
|     } | ||||
| 
 | ||||
|     if (movie_record_on_start) { | ||||
|         movie.PrepareForRecording(); | ||||
|  | @ -1246,16 +1263,26 @@ void GMainWindow::BootGame(const QString& filename) { | |||
|     } | ||||
| 
 | ||||
|     const std::string path = filename.toStdString(); | ||||
|     const auto loader = Loader::GetLoader(path); | ||||
|     auto loader = Loader::GetLoader(path); | ||||
| 
 | ||||
|     u64 title_id{0}; | ||||
|     loader->ReadProgramId(title_id); | ||||
|     Loader::ResultStatus res = loader->ReadProgramId(title_id); | ||||
| 
 | ||||
|     if (Loader::ResultStatus::Success == res) { | ||||
|         // Load per game settings
 | ||||
|         const std::string name{is_artic ? "" : FileUtil::GetFilename(filename.toStdString())}; | ||||
|         const std::string config_file_name = | ||||
|             title_id == 0 ? name : fmt::format("{:016X}", title_id); | ||||
|         LOG_INFO(Frontend, "Loading per game config file for title {}", config_file_name); | ||||
|         Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig); | ||||
|     } | ||||
| 
 | ||||
|     // Artic Base Server cannot accept a client multiple times, so multiple loaders are not
 | ||||
|     // possible. Instead register the app loader early and do not create it again on system load.
 | ||||
|     if (!loader->SupportsMultipleInstancesForSameFile()) { | ||||
|         system.RegisterAppLoaderEarly(loader); | ||||
|     } | ||||
| 
 | ||||
|     // Load per game settings
 | ||||
|     const std::string name{FileUtil::GetFilename(filename.toStdString())}; | ||||
|     const std::string config_file_name = title_id == 0 ? name : fmt::format("{:016X}", title_id); | ||||
|     LOG_INFO(Frontend, "Loading per game config file for title {}", config_file_name); | ||||
|     Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig); | ||||
|     system.ApplySettings(); | ||||
| 
 | ||||
|     Settings::LogSettings(); | ||||
|  | @ -1265,8 +1292,11 @@ void GMainWindow::BootGame(const QString& filename) { | |||
|     game_list->SaveInterfaceLayout(); | ||||
|     config->Save(); | ||||
| 
 | ||||
|     if (!LoadROM(filename)) | ||||
|     if (!LoadROM(filename)) { | ||||
|         render_window->ReleaseRenderTarget(); | ||||
|         secondary_window->ReleaseRenderTarget(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // Set everything up
 | ||||
|     if (movie_record_on_start) { | ||||
|  | @ -1420,6 +1450,8 @@ void GMainWindow::ShutdownGame() { | |||
|     // Disable status bar updates
 | ||||
|     status_bar_update_timer.stop(); | ||||
|     message_label_used_for_movie = false; | ||||
|     show_artic_label = false; | ||||
|     artic_traffic_label->setVisible(false); | ||||
|     emu_speed_label->setVisible(false); | ||||
|     game_fps_label->setVisible(false); | ||||
|     emu_frametime_label->setVisible(false); | ||||
|  | @ -1759,6 +1791,17 @@ void GMainWindow::OnMenuInstallCIA() { | |||
|     InstallCIA(filepaths); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::OnMenuConnectArticBase() { | ||||
|     bool ok = false; | ||||
|     auto res = QInputDialog::getText(this, tr("Connect to Artic Base"), | ||||
|                                      tr("Enter Artic Base server address:"), QLineEdit::Normal, | ||||
|                                      UISettings::values.last_artic_base_addr, &ok); | ||||
|     if (ok) { | ||||
|         UISettings::values.last_artic_base_addr = res; | ||||
|         BootGame(QString::fromStdString("articbase://").append(res)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::OnMenuBootHomeMenu(u32 region) { | ||||
|     BootGame(QString::fromStdString(Core::GetHomeMenuNcchPath(region))); | ||||
| } | ||||
|  | @ -2575,6 +2618,51 @@ void GMainWindow::UpdateStatusBar() { | |||
| 
 | ||||
|     auto results = system.GetAndResetPerfStats(); | ||||
| 
 | ||||
|     if (show_artic_label) { | ||||
|         const bool do_mb = results.artic_transmitted >= (1000.0 * 1000.0); | ||||
|         const double value = do_mb ? (results.artic_transmitted / (1000.0 * 1000.0)) | ||||
|                                    : (results.artic_transmitted / 1000.0); | ||||
|         static const std::array<std::pair<Core::PerfStats::PerfArticEventBits, QString>, 4> | ||||
|             perf_events = { | ||||
|                 std::make_pair(Core::PerfStats::PerfArticEventBits::ARTIC_SHARED_EXT_DATA, | ||||
|                                tr("(Accessing SharedExtData)")), | ||||
|                 std::make_pair(Core::PerfStats::PerfArticEventBits::ARTIC_BOSS_EXT_DATA, | ||||
|                                tr("(Accessing BossExtData)")), | ||||
|                 std::make_pair(Core::PerfStats::PerfArticEventBits::ARTIC_EXT_DATA, | ||||
|                                tr("(Accessing ExtData)")), | ||||
|                 std::make_pair(Core::PerfStats::PerfArticEventBits::ARTIC_SAVE_DATA, | ||||
|                                tr("(Accessing SaveData)")), | ||||
|             }; | ||||
| 
 | ||||
|         const QString unit = do_mb ? tr("MB/s") : tr("KB/s"); | ||||
|         QString event{}; | ||||
|         for (auto p : perf_events) { | ||||
|             if (results.artic_events.Get(p.first)) { | ||||
|                 event = QString::fromStdString(" ") + p.second; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         static const std::array label_color = {QStringLiteral("#ffffff"), QStringLiteral("#eed202"), | ||||
|                                                QStringLiteral("#ff3333")}; | ||||
| 
 | ||||
|         int style_index; | ||||
| 
 | ||||
|         if (value > 200.0) { | ||||
|             style_index = 2; | ||||
|         } else if (value > 125.0) { | ||||
|             style_index = 1; | ||||
|         } else { | ||||
|             style_index = 0; | ||||
|         } | ||||
|         const QString style_sheet = | ||||
|             QStringLiteral("QLabel { color: %0; }").arg(label_color[style_index]); | ||||
| 
 | ||||
|         artic_traffic_label->setText( | ||||
|             tr("Artic Base Traffic: %1 %2%3").arg(value, 0, 'f', 0).arg(unit).arg(event)); | ||||
|         artic_traffic_label->setStyleSheet(style_sheet); | ||||
|     } | ||||
| 
 | ||||
|     if (Settings::values.frame_limit.GetValue() == 0) { | ||||
|         emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0)); | ||||
|     } else { | ||||
|  | @ -2585,6 +2673,9 @@ void GMainWindow::UpdateStatusBar() { | |||
|     game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0)); | ||||
|     emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2)); | ||||
| 
 | ||||
|     if (show_artic_label) { | ||||
|         artic_traffic_label->setVisible(true); | ||||
|     } | ||||
|     emu_speed_label->setVisible(true); | ||||
|     game_fps_label->setVisible(true); | ||||
|     emu_frametime_label->setVisible(true); | ||||
|  | @ -2736,6 +2827,7 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det | |||
| 
 | ||||
|     QString title, message; | ||||
|     QMessageBox::Icon error_severity_icon; | ||||
|     bool can_continue = true; | ||||
|     if (result == Core::System::ResultStatus::ErrorSystemFiles) { | ||||
|         const QString common_message = | ||||
|             tr("%1 is missing. Please <a " | ||||
|  | @ -2756,6 +2848,11 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det | |||
|         title = tr("Save/load Error"); | ||||
|         message = QString::fromStdString(details); | ||||
|         error_severity_icon = QMessageBox::Icon::Warning; | ||||
|     } else if (result == Core::System::ResultStatus::ErrorArticDisconnected) { | ||||
|         title = tr("Artic Base Server"); | ||||
|         message = tr("A communication error has occurred. The game will quit."); | ||||
|         error_severity_icon = QMessageBox::Icon::Critical; | ||||
|         can_continue = false; | ||||
|     } else { | ||||
|         title = tr("Fatal Error"); | ||||
|         message = | ||||
|  | @ -2772,12 +2869,14 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det | |||
|     message_box.setText(message); | ||||
|     message_box.setIcon(error_severity_icon); | ||||
|     if (error_severity_icon == QMessageBox::Icon::Critical) { | ||||
|         message_box.addButton(tr("Continue"), QMessageBox::RejectRole); | ||||
|         if (can_continue) { | ||||
|             message_box.addButton(tr("Continue"), QMessageBox::RejectRole); | ||||
|         } | ||||
|         QPushButton* abort_button = message_box.addButton(tr("Quit Game"), QMessageBox::AcceptRole); | ||||
|         if (result != Core::System::ResultStatus::ShutdownRequested) | ||||
|             message_box.exec(); | ||||
| 
 | ||||
|         if (result == Core::System::ResultStatus::ShutdownRequested || | ||||
|         if (!can_continue || result == Core::System::ResultStatus::ShutdownRequested || | ||||
|             message_box.clickedButton() == abort_button) { | ||||
|             if (emu_thread) { | ||||
|                 ShutdownGame(); | ||||
|  |  | |||
|  | @ -216,6 +216,7 @@ private slots: | |||
|     void OnConfigurePerGame(); | ||||
|     void OnMenuLoadFile(); | ||||
|     void OnMenuInstallCIA(); | ||||
|     void OnMenuConnectArticBase(); | ||||
|     void OnMenuBootHomeMenu(u32 region); | ||||
|     void OnUpdateProgress(std::size_t written, std::size_t total); | ||||
|     void OnCIAInstallReport(Service::AM::InstallStatus status, QString filepath); | ||||
|  | @ -302,6 +303,8 @@ private: | |||
|     // Status bar elements
 | ||||
|     QProgressBar* progress_bar = nullptr; | ||||
|     QLabel* message_label = nullptr; | ||||
|     bool show_artic_label = false; | ||||
|     QLabel* artic_traffic_label = nullptr; | ||||
|     QLabel* emu_speed_label = nullptr; | ||||
|     QLabel* game_fps_label = nullptr; | ||||
|     QLabel* emu_frametime_label = nullptr; | ||||
|  |  | |||
|  | @ -78,6 +78,7 @@ | |||
|     </widget> | ||||
|     <addaction name="action_Load_File"/> | ||||
|     <addaction name="action_Install_CIA"/> | ||||
|     <addaction name="action_Connect_Artic"/> | ||||
|     <addaction name="menu_Boot_Home_Menu"/> | ||||
|     <addaction name="separator"/> | ||||
|     <addaction name="menu_recent_files"/> | ||||
|  | @ -222,6 +223,11 @@ | |||
|     <string>Install CIA...</string> | ||||
|    </property> | ||||
|   </action> | ||||
|   <action name="action_Connect_Artic"> | ||||
|     <property name="text"> | ||||
|       <string>Connect to Artic Base...</string> | ||||
|     </property> | ||||
|   </action> | ||||
|   <action name="action_Boot_Home_Menu_JPN"> | ||||
|    <property name="text"> | ||||
|     <string>JPN</string> | ||||
|  |  | |||
|  | @ -116,6 +116,7 @@ struct Values { | |||
|     bool game_dir_deprecated_deepscan; | ||||
|     QVector<UISettings::GameDir> game_dirs; | ||||
|     QStringList recent_files; | ||||
|     QString last_artic_base_addr; | ||||
|     QString language; | ||||
| 
 | ||||
|     QString theme; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue