mirror of
https://github.com/PabloMK7/citra.git
synced 2025-09-10 04:40:05 +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