Merge branch 'master' of https://github.com/GPUCode/citra into vulkan-2
This commit is contained in:
@ -12,6 +12,7 @@ import android.view.InputDevice;
|
|||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.SubMenu;
|
import android.view.SubMenu;
|
||||||
@ -19,11 +20,13 @@ import android.view.View;
|
|||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.appcompat.widget.PopupMenu;
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
|
||||||
@ -74,6 +77,7 @@ public final class EmulationActivity extends AppCompatActivity {
|
|||||||
public static final int MENU_ACTION_JOYSTICK_REL_CENTER = 15;
|
public static final int MENU_ACTION_JOYSTICK_REL_CENTER = 15;
|
||||||
public static final int MENU_ACTION_DPAD_SLIDE_ENABLE = 16;
|
public static final int MENU_ACTION_DPAD_SLIDE_ENABLE = 16;
|
||||||
public static final int MENU_ACTION_OPEN_CHEATS = 17;
|
public static final int MENU_ACTION_OPEN_CHEATS = 17;
|
||||||
|
public static final int MENU_ACTION_CLOSE_GAME = 18;
|
||||||
|
|
||||||
public static final int REQUEST_SELECT_AMIIBO = 2;
|
public static final int REQUEST_SELECT_AMIIBO = 2;
|
||||||
private static final int EMULATION_RUNNING_NOTIFICATION = 0x1000;
|
private static final int EMULATION_RUNNING_NOTIFICATION = 0x1000;
|
||||||
@ -114,6 +118,8 @@ public final class EmulationActivity extends AppCompatActivity {
|
|||||||
EmulationActivity.MENU_ACTION_DPAD_SLIDE_ENABLE);
|
EmulationActivity.MENU_ACTION_DPAD_SLIDE_ENABLE);
|
||||||
buttonsActionsMap
|
buttonsActionsMap
|
||||||
.append(R.id.menu_emulation_open_cheats, EmulationActivity.MENU_ACTION_OPEN_CHEATS);
|
.append(R.id.menu_emulation_open_cheats, EmulationActivity.MENU_ACTION_OPEN_CHEATS);
|
||||||
|
buttonsActionsMap
|
||||||
|
.append(R.id.menu_emulation_close_game, EmulationActivity.MENU_ACTION_CLOSE_GAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
private View mDecorView;
|
private View mDecorView;
|
||||||
@ -223,21 +229,12 @@ public final class EmulationActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
NativeLibrary.PauseEmulation();
|
View anchor = findViewById(R.id.menu_anchor);
|
||||||
new AlertDialog.Builder(this)
|
PopupMenu popupMenu = new PopupMenu(this, anchor);
|
||||||
.setTitle(R.string.emulation_close_game)
|
onCreateOptionsMenu(popupMenu.getMenu(), popupMenu.getMenuInflater());
|
||||||
.setMessage(R.string.emulation_close_game_message)
|
updateSavestateMenuOptions(popupMenu.getMenu());
|
||||||
.setPositiveButton(android.R.string.yes, (dialogInterface, i) ->
|
popupMenu.setOnMenuItemClickListener(this::onOptionsItemSelected);
|
||||||
{
|
popupMenu.show();
|
||||||
mEmulationFragment.stopEmulation();
|
|
||||||
finish();
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.cancel, (dialogInterface, i) ->
|
|
||||||
NativeLibrary.UnPauseEmulation())
|
|
||||||
.setOnCancelListener(dialogInterface ->
|
|
||||||
NativeLibrary.UnPauseEmulation())
|
|
||||||
.create()
|
|
||||||
.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -271,6 +268,10 @@ public final class EmulationActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onEmulationStarted() {
|
||||||
|
Toast.makeText(this, getString(R.string.emulation_menu_help), Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
private void enableFullscreenImmersive() {
|
private void enableFullscreenImmersive() {
|
||||||
// It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar.
|
// It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar.
|
||||||
mDecorView.setSystemUiVisibility(
|
mDecorView.setSystemUiVisibility(
|
||||||
@ -285,7 +286,12 @@ public final class EmulationActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
// Inflate the menu; this adds items to the action bar if it is present.
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||||
getMenuInflater().inflate(R.menu.menu_emulation, menu);
|
onCreateOptionsMenu(menu, getMenuInflater());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
|
inflater.inflate(R.menu.menu_emulation, menu);
|
||||||
|
|
||||||
int layoutOptionMenuItem = R.id.menu_screen_layout_landscape;
|
int layoutOptionMenuItem = R.id.menu_screen_layout_landscape;
|
||||||
switch (EmulationMenuSettings.getLandscapeScreenLayout()) {
|
switch (EmulationMenuSettings.getLandscapeScreenLayout()) {
|
||||||
@ -306,8 +312,6 @@ public final class EmulationActivity extends AppCompatActivity {
|
|||||||
menu.findItem(R.id.menu_emulation_show_fps).setChecked(EmulationMenuSettings.getShowFps());
|
menu.findItem(R.id.menu_emulation_show_fps).setChecked(EmulationMenuSettings.getShowFps());
|
||||||
menu.findItem(R.id.menu_emulation_swap_screens).setChecked(EmulationMenuSettings.getSwapScreens());
|
menu.findItem(R.id.menu_emulation_swap_screens).setChecked(EmulationMenuSettings.getSwapScreens());
|
||||||
menu.findItem(R.id.menu_emulation_show_overlay).setChecked(EmulationMenuSettings.getShowOverlay());
|
menu.findItem(R.id.menu_emulation_show_overlay).setChecked(EmulationMenuSettings.getShowOverlay());
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisplaySavestateWarning() {
|
private void DisplaySavestateWarning() {
|
||||||
@ -333,12 +337,16 @@ public final class EmulationActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||||
super.onPrepareOptionsMenu(menu);
|
super.onPrepareOptionsMenu(menu);
|
||||||
|
updateSavestateMenuOptions(menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSavestateMenuOptions(Menu menu) {
|
||||||
final NativeLibrary.SavestateInfo[] savestates = NativeLibrary.GetSavestateInfo();
|
final NativeLibrary.SavestateInfo[] savestates = NativeLibrary.GetSavestateInfo();
|
||||||
if (savestates == null) {
|
if (savestates == null) {
|
||||||
menu.findItem(R.id.menu_emulation_save_state).setVisible(false);
|
menu.findItem(R.id.menu_emulation_save_state).setVisible(false);
|
||||||
menu.findItem(R.id.menu_emulation_load_state).setVisible(false);
|
menu.findItem(R.id.menu_emulation_load_state).setVisible(false);
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
menu.findItem(R.id.menu_emulation_save_state).setVisible(true);
|
menu.findItem(R.id.menu_emulation_save_state).setVisible(true);
|
||||||
menu.findItem(R.id.menu_emulation_load_state).setVisible(true);
|
menu.findItem(R.id.menu_emulation_load_state).setVisible(true);
|
||||||
@ -367,7 +375,6 @@ public final class EmulationActivity extends AppCompatActivity {
|
|||||||
saveStateMenu.getItem(info.slot - 1).setTitle(text);
|
saveStateMenu.getItem(info.slot - 1).setTitle(text);
|
||||||
loadStateMenu.getItem(info.slot - 1).setTitle(text).setEnabled(true);
|
loadStateMenu.getItem(info.slot - 1).setTitle(text).setEnabled(true);
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("WrongConstant")
|
@SuppressWarnings("WrongConstant")
|
||||||
@ -480,6 +487,24 @@ public final class EmulationActivity extends AppCompatActivity {
|
|||||||
case MENU_ACTION_OPEN_CHEATS:
|
case MENU_ACTION_OPEN_CHEATS:
|
||||||
CheatsActivity.launch(this);
|
CheatsActivity.launch(this);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MENU_ACTION_CLOSE_GAME:
|
||||||
|
NativeLibrary.PauseEmulation();
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle(R.string.emulation_close_game)
|
||||||
|
.setMessage(R.string.emulation_close_game_message)
|
||||||
|
.setPositiveButton(android.R.string.yes, (dialogInterface, i) ->
|
||||||
|
{
|
||||||
|
mEmulationFragment.stopEmulation();
|
||||||
|
finish();
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.cancel, (dialogInterface, i) ->
|
||||||
|
NativeLibrary.UnPauseEmulation())
|
||||||
|
.setOnCancelListener(dialogInterface ->
|
||||||
|
NativeLibrary.UnPauseEmulation())
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -133,6 +133,8 @@ public class DiskShaderCacheProgress {
|
|||||||
case Complete:
|
case Complete:
|
||||||
// Workaround for when dialog is dismissed when the app is in the background
|
// Workaround for when dialog is dismissed when the app is in the background
|
||||||
fragment.dismissAllowingStateLoss();
|
fragment.dismissAllowingStateLoss();
|
||||||
|
|
||||||
|
emulationActivity.runOnUiThread(emulationActivity::onEmulationStarted);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,10 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:transitionName="image_game_icon" />
|
android:transitionName="image_game_icon" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/menu_anchor"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_gravity="top|end" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
@ -115,4 +115,9 @@
|
|||||||
app:showAsAction="never"
|
app:showAsAction="never"
|
||||||
android:title="@string/emulation_open_settings" />
|
android:title="@string/emulation_open_settings" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_emulation_close_game"
|
||||||
|
app:showAsAction="never"
|
||||||
|
android:title="@string/emulation_close_game" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -164,6 +164,7 @@
|
|||||||
<string name="loader_error_invalid_format">Invalid ROM format</string>
|
<string name="loader_error_invalid_format">Invalid ROM format</string>
|
||||||
|
|
||||||
<!-- Emulation Menu -->
|
<!-- Emulation Menu -->
|
||||||
|
<string name="emulation_menu_help">Press Back to access the menu.</string>
|
||||||
<string name="emulation_save_state">Save State</string>
|
<string name="emulation_save_state">Save State</string>
|
||||||
<string name="emulation_load_state">Load State</string>
|
<string name="emulation_load_state">Load State</string>
|
||||||
<string name="emulation_empty_state_slot">Slot %1$d</string>
|
<string name="emulation_empty_state_slot">Slot %1$d</string>
|
||||||
|
@ -17,7 +17,6 @@ CheatDialog::CheatDialog(QWidget* parent)
|
|||||||
: QDialog(parent), ui(std::make_unique<Ui::CheatDialog>()) {
|
: QDialog(parent), ui(std::make_unique<Ui::CheatDialog>()) {
|
||||||
// Setup gui control settings
|
// Setup gui control settings
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
|
||||||
ui->tableCheats->setColumnWidth(0, 30);
|
ui->tableCheats->setColumnWidth(0, 30);
|
||||||
ui->tableCheats->setColumnWidth(2, 85);
|
ui->tableCheats->setColumnWidth(2, 85);
|
||||||
ui->tableCheats->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
|
ui->tableCheats->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
|
||||||
|
@ -20,8 +20,6 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, bool
|
|||||||
|
|
||||||
PopulateSelectionList();
|
PopulateSelectionList();
|
||||||
|
|
||||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
|
||||||
|
|
||||||
connect(ui->uiTab, &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged);
|
connect(ui->uiTab, &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged);
|
||||||
connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
|
connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
|
||||||
&ConfigureDialog::UpdateVisibleTabs);
|
&ConfigureDialog::UpdateVisibleTabs);
|
||||||
|
@ -41,8 +41,6 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const QString
|
|||||||
|
|
||||||
setFocusPolicy(Qt::ClickFocus);
|
setFocusPolicy(Qt::ClickFocus);
|
||||||
setWindowTitle(tr("Properties"));
|
setWindowTitle(tr("Properties"));
|
||||||
// remove Help question mark button from the title bar
|
|
||||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
|
||||||
|
|
||||||
scene = new QGraphicsScene;
|
scene = new QGraphicsScene;
|
||||||
ui->icon_view->setScene(scene);
|
ui->icon_view->setScene(scene);
|
||||||
|
@ -50,9 +50,8 @@ MicroProfileDialog::MicroProfileDialog(QWidget* parent) : QWidget(parent, Qt::Di
|
|||||||
setObjectName(QStringLiteral("MicroProfile"));
|
setObjectName(QStringLiteral("MicroProfile"));
|
||||||
setWindowTitle(tr("MicroProfile"));
|
setWindowTitle(tr("MicroProfile"));
|
||||||
resize(1000, 600);
|
resize(1000, 600);
|
||||||
// Remove the "?" button from the titlebar and enable the maximize button
|
// Enable the maximize button
|
||||||
setWindowFlags((windowFlags() & ~Qt::WindowContextHelpButtonHint) |
|
setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint);
|
||||||
Qt::WindowMaximizeButtonHint);
|
|
||||||
|
|
||||||
#if MICROPROFILE_ENABLED
|
#if MICROPROFILE_ENABLED
|
||||||
|
|
||||||
|
@ -1019,6 +1019,11 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
|||||||
"titles</a>."));
|
"titles</a>."));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Core::System::ResultStatus::ErrorLoader_ErrorGbaTitle:
|
||||||
|
QMessageBox::critical(this, tr("Unsupported ROM"),
|
||||||
|
tr("GBA Virtual Console ROMs are not supported by Citra."));
|
||||||
|
break;
|
||||||
|
|
||||||
case Core::System::ResultStatus::ErrorVideoCore:
|
case Core::System::ResultStatus::ErrorVideoCore:
|
||||||
QMessageBox::critical(
|
QMessageBox::critical(
|
||||||
this, tr("Video Core Error"),
|
this, tr("Video Core Error"),
|
||||||
@ -2659,6 +2664,10 @@ int main(int argc, char* argv[]) {
|
|||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + "..";
|
std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + "..";
|
||||||
chdir(bin_path.c_str());
|
chdir(bin_path.c_str());
|
||||||
|
#endif
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
// Disables the "?" button on all dialogs. Disabled by default on Qt6.
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton);
|
||||||
#endif
|
#endif
|
||||||
QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
|
QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
|
||||||
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
SequenceDialog::SequenceDialog(QWidget* parent) : QDialog(parent) {
|
SequenceDialog::SequenceDialog(QWidget* parent) : QDialog(parent) {
|
||||||
setWindowTitle(tr("Enter a hotkey"));
|
setWindowTitle(tr("Enter a hotkey"));
|
||||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
|
||||||
|
|
||||||
key_sequence = new QKeySequenceEdit;
|
key_sequence = new QKeySequenceEdit;
|
||||||
|
|
||||||
|
@ -20,6 +20,10 @@
|
|||||||
#else
|
#else
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define EMU_DATA_DIR "Citra"
|
#define EMU_DATA_DIR "Citra"
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#define MACOS_EMU_DATA_DIR "Library" DIR_SEP "Application Support" DIR_SEP "Citra"
|
||||||
|
// For compatibility with XDG paths.
|
||||||
|
#define EMU_DATA_DIR "citra-emu"
|
||||||
#elif ANDROID
|
#elif ANDROID
|
||||||
// On Android internal storage is mounted as "/sdcard"
|
// On Android internal storage is mounted as "/sdcard"
|
||||||
#define SDCARD_DIR "sdcard"
|
#define SDCARD_DIR "sdcard"
|
||||||
|
@ -709,13 +709,26 @@ void SetUserPath(const std::string& path) {
|
|||||||
g_paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
|
g_paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
|
||||||
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
|
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
|
||||||
} else {
|
} else {
|
||||||
std::string data_dir = GetUserDirectory("XDG_DATA_HOME");
|
std::string data_dir = GetUserDirectory("XDG_DATA_HOME") + DIR_SEP EMU_DATA_DIR DIR_SEP;
|
||||||
std::string config_dir = GetUserDirectory("XDG_CONFIG_HOME");
|
std::string config_dir =
|
||||||
std::string cache_dir = GetUserDirectory("XDG_CACHE_HOME");
|
GetUserDirectory("XDG_CONFIG_HOME") + DIR_SEP EMU_DATA_DIR DIR_SEP;
|
||||||
|
std::string cache_dir =
|
||||||
|
GetUserDirectory("XDG_CACHE_HOME") + DIR_SEP EMU_DATA_DIR DIR_SEP;
|
||||||
|
|
||||||
user_path = data_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
|
#if defined(__APPLE__)
|
||||||
g_paths.emplace(UserPath::ConfigDir, config_dir + DIR_SEP EMU_DATA_DIR DIR_SEP);
|
// If XDG directories don't already exist from a previous setup, use standard macOS
|
||||||
g_paths.emplace(UserPath::CacheDir, cache_dir + DIR_SEP EMU_DATA_DIR DIR_SEP);
|
// paths.
|
||||||
|
if (!FileUtil::Exists(data_dir) && !FileUtil::Exists(config_dir) &&
|
||||||
|
!FileUtil::Exists(cache_dir)) {
|
||||||
|
data_dir = GetHomeDirectory() + DIR_SEP MACOS_EMU_DATA_DIR DIR_SEP;
|
||||||
|
config_dir = data_dir + CONFIG_DIR DIR_SEP;
|
||||||
|
cache_dir = data_dir + CACHE_DIR DIR_SEP;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
user_path = data_dir;
|
||||||
|
g_paths.emplace(UserPath::ConfigDir, config_dir);
|
||||||
|
g_paths.emplace(UserPath::CacheDir, cache_dir);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -268,6 +268,8 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
|
|||||||
return ResultStatus::ErrorLoader_ErrorEncrypted;
|
return ResultStatus::ErrorLoader_ErrorEncrypted;
|
||||||
case Loader::ResultStatus::ErrorInvalidFormat:
|
case Loader::ResultStatus::ErrorInvalidFormat:
|
||||||
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
|
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
|
||||||
|
case Loader::ResultStatus::ErrorGbaTitle:
|
||||||
|
return ResultStatus::ErrorLoader_ErrorGbaTitle;
|
||||||
default:
|
default:
|
||||||
return ResultStatus::ErrorSystemMode;
|
return ResultStatus::ErrorSystemMode;
|
||||||
}
|
}
|
||||||
@ -292,7 +294,6 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
|
|||||||
telemetry_session->AddInitialInfo(*app_loader);
|
telemetry_session->AddInitialInfo(*app_loader);
|
||||||
std::shared_ptr<Kernel::Process> process;
|
std::shared_ptr<Kernel::Process> process;
|
||||||
const Loader::ResultStatus load_result{app_loader->Load(process)};
|
const Loader::ResultStatus load_result{app_loader->Load(process)};
|
||||||
kernel->SetCurrentProcess(process);
|
|
||||||
if (Loader::ResultStatus::Success != load_result) {
|
if (Loader::ResultStatus::Success != load_result) {
|
||||||
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
|
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
|
||||||
System::Shutdown();
|
System::Shutdown();
|
||||||
@ -302,10 +303,13 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
|
|||||||
return ResultStatus::ErrorLoader_ErrorEncrypted;
|
return ResultStatus::ErrorLoader_ErrorEncrypted;
|
||||||
case Loader::ResultStatus::ErrorInvalidFormat:
|
case Loader::ResultStatus::ErrorInvalidFormat:
|
||||||
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
|
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
|
||||||
|
case Loader::ResultStatus::ErrorGbaTitle:
|
||||||
|
return ResultStatus::ErrorLoader_ErrorGbaTitle;
|
||||||
default:
|
default:
|
||||||
return ResultStatus::ErrorLoader;
|
return ResultStatus::ErrorLoader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
kernel->SetCurrentProcess(process);
|
||||||
cheat_engine = std::make_unique<Cheats::CheatEngine>(*this);
|
cheat_engine = std::make_unique<Cheats::CheatEngine>(*this);
|
||||||
title_id = 0;
|
title_id = 0;
|
||||||
if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
|
if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
|
||||||
@ -537,7 +541,8 @@ void System::Shutdown(bool is_deserializing) {
|
|||||||
perf_results.emulation_speed * 100.0);
|
perf_results.emulation_speed * 100.0);
|
||||||
telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps);
|
telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps);
|
||||||
telemetry_session->AddField(performance, "Shutdown_Frametime", perf_results.frametime * 1000.0);
|
telemetry_session->AddField(performance, "Shutdown_Frametime", perf_results.frametime * 1000.0);
|
||||||
telemetry_session->AddField(performance, "Mean_Frametime_MS", perf_stats->GetMeanFrametime());
|
telemetry_session->AddField(performance, "Mean_Frametime_MS",
|
||||||
|
perf_stats ? perf_stats->GetMeanFrametime() : 0);
|
||||||
|
|
||||||
// Shutdown emulation session
|
// Shutdown emulation session
|
||||||
VideoCore::Shutdown();
|
VideoCore::Shutdown();
|
||||||
|
@ -82,10 +82,12 @@ public:
|
|||||||
ErrorSystemMode, ///< Error determining the system mode
|
ErrorSystemMode, ///< Error determining the system mode
|
||||||
ErrorLoader, ///< Error loading the specified application
|
ErrorLoader, ///< Error loading the specified application
|
||||||
ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption
|
ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption
|
||||||
ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an
|
ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an
|
||||||
/// invalid format
|
/// invalid format
|
||||||
ErrorSystemFiles, ///< Error in finding system files
|
ErrorLoader_ErrorGbaTitle, ///< Error loading the specified application as it is GBA Virtual
|
||||||
ErrorVideoCore, ///< Error in the video core
|
///< Console
|
||||||
|
ErrorSystemFiles, ///< Error in finding system files
|
||||||
|
ErrorVideoCore, ///< Error in the video core
|
||||||
ErrorVideoCore_ErrorGenericDrivers, ///< Error in the video core due to the user having
|
ErrorVideoCore_ErrorGenericDrivers, ///< Error in the video core due to the user having
|
||||||
/// generic drivers installed
|
/// generic drivers installed
|
||||||
ErrorSavestate, ///< Error saving or loading
|
ErrorSavestate, ///< Error saving or loading
|
||||||
|
@ -26,7 +26,8 @@
|
|||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
|
|
||||||
static std::string ReadTextInfo(FileUtil::IOFile& file, std::size_t offset, std::size_t max_size) {
|
static std::string ReadTextInfo(FileUtil::IOFile& file, std::size_t offset, std::size_t max_size) {
|
||||||
if (max_size > 0x400) { // Limit read string size to 0x400 bytes, just in case
|
if (offset == 0 || max_size == 0 ||
|
||||||
|
max_size > 0x400) { // Limit read string size to 0x400 bytes, just in case
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
std::vector<char> char_data(max_size);
|
std::vector<char> char_data(max_size);
|
||||||
|
@ -75,6 +75,7 @@ enum class ResultStatus {
|
|||||||
ErrorAlreadyLoaded,
|
ErrorAlreadyLoaded,
|
||||||
ErrorMemoryAllocationFailed,
|
ErrorMemoryAllocationFailed,
|
||||||
ErrorEncrypted,
|
ErrorEncrypted,
|
||||||
|
ErrorGbaTitle,
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr u32 MakeMagic(char a, char b, char c, char d) {
|
constexpr u32 MakeMagic(char a, char b, char c, char d) {
|
||||||
|
@ -85,6 +85,11 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process)
|
|||||||
u64_le program_id;
|
u64_le program_id;
|
||||||
if (ResultStatus::Success == ReadCode(code) &&
|
if (ResultStatus::Success == ReadCode(code) &&
|
||||||
ResultStatus::Success == ReadProgramId(program_id)) {
|
ResultStatus::Success == ReadProgramId(program_id)) {
|
||||||
|
if (IsGbaVirtualConsole(code)) {
|
||||||
|
LOG_ERROR(Loader, "Encountered unsupported GBA Virtual Console code section.");
|
||||||
|
return ResultStatus::ErrorGbaTitle;
|
||||||
|
}
|
||||||
|
|
||||||
std::string process_name = Common::StringFromFixedZeroTerminatedBuffer(
|
std::string process_name = Common::StringFromFixedZeroTerminatedBuffer(
|
||||||
(const char*)overlay_ncch->exheader_header.codeset_info.name, 8);
|
(const char*)overlay_ncch->exheader_header.codeset_info.name, 8);
|
||||||
|
|
||||||
@ -177,6 +182,12 @@ void AppLoader_NCCH::ParseRegionLockoutInfo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AppLoader_NCCH::IsGbaVirtualConsole(const std::vector<u8>& code) {
|
||||||
|
const u32* gbaVcHeader = reinterpret_cast<const u32*>(code.data() + code.size() - 0x10);
|
||||||
|
return code.size() >= 0x10 && gbaVcHeader[0] == MakeMagic('.', 'C', 'A', 'A') &&
|
||||||
|
gbaVcHeader[1] == 1;
|
||||||
|
}
|
||||||
|
|
||||||
ResultStatus AppLoader_NCCH::Load(std::shared_ptr<Kernel::Process>& process) {
|
ResultStatus AppLoader_NCCH::Load(std::shared_ptr<Kernel::Process>& process) {
|
||||||
u64_le ncch_program_id;
|
u64_le ncch_program_id;
|
||||||
|
|
||||||
|
@ -78,6 +78,9 @@ private:
|
|||||||
/// Reads the region lockout info in the SMDH and send it to CFG service
|
/// Reads the region lockout info in the SMDH and send it to CFG service
|
||||||
void ParseRegionLockoutInfo();
|
void ParseRegionLockoutInfo();
|
||||||
|
|
||||||
|
/// Detects whether the NCCH contains GBA Virtual Console.
|
||||||
|
bool IsGbaVirtualConsole(const std::vector<u8>& code);
|
||||||
|
|
||||||
FileSys::NCCHContainer base_ncch;
|
FileSys::NCCHContainer base_ncch;
|
||||||
FileSys::NCCHContainer update_ncch;
|
FileSys::NCCHContainer update_ncch;
|
||||||
FileSys::NCCHContainer* overlay_ncch;
|
FileSys::NCCHContainer* overlay_ncch;
|
||||||
|
Reference in New Issue
Block a user