early-access version 4154

This commit is contained in:
pineappleEA 2024-02-20 03:21:02 +01:00
parent 742bf25252
commit 64bd48fad5
10 changed files with 114 additions and 40 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 4153. This is the source code for early-access 4154.
## Legal Notice ## Legal Notice

View file

@ -75,6 +75,9 @@ abstract class SettingsItem(
get() = NativeLibrary.isRunning() && !setting.global && get() = NativeLibrary.isRunning() && !setting.global &&
!NativeConfig.isPerGameConfigLoaded() !NativeConfig.isPerGameConfigLoaded()
val clearable: Boolean
get() = !setting.global && NativeConfig.isPerGameConfigLoaded()
companion object { companion object {
const val TYPE_HEADER = 0 const val TYPE_HEADER = 0
const val TYPE_SWITCH = 1 const val TYPE_SWITCH = 1

View file

@ -13,7 +13,6 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
@ -32,9 +31,7 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
binding.textSettingValue.text = dateFormatter.format(zonedTime) binding.textSettingValue.text = dateFormatter.format(zonedTime)
binding.buttonClear.setVisible( binding.buttonClear.setVisible(setting.clearable)
!setting.setting.global || NativeConfig.isPerGameConfigLoaded()
)
binding.buttonClear.setOnClickListener { binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition) adapter.onClearClick(setting, bindingAdapterPosition)
} }

View file

@ -10,7 +10,6 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
@ -48,9 +47,7 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
binding.textSettingValue.setVisible(false) binding.textSettingValue.setVisible(false)
} }
binding.buttonClear.setVisible( binding.buttonClear.setVisible(setting.clearable)
!setting.setting.global || NativeConfig.isPerGameConfigLoaded()
)
binding.buttonClear.setOnClickListener { binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition) adapter.onClearClick(setting, bindingAdapterPosition)
} }

View file

@ -9,7 +9,6 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
@ -28,9 +27,7 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
setting.units setting.units
) )
binding.buttonClear.setVisible( binding.buttonClear.setVisible(setting.clearable)
!setting.setting.global || NativeConfig.isPerGameConfigLoaded()
)
binding.buttonClear.setOnClickListener { binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition) adapter.onClearClick(setting, bindingAdapterPosition)
} }

View file

@ -9,7 +9,6 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) : class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) :
@ -29,9 +28,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition) adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition)
} }
binding.buttonClear.setVisible( binding.buttonClear.setVisible(setting.clearable)
!setting.setting.global || NativeConfig.isPerGameConfigLoaded()
)
binding.buttonClear.setOnClickListener { binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition) adapter.onClearClick(setting, bindingAdapterPosition)
} }

View file

@ -28,6 +28,7 @@ import org.yuzu.yuzu_emu.features.input.NativeInput
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.input.model.NativeAnalog import org.yuzu.yuzu_emu.features.input.model.NativeAnalog
import org.yuzu.yuzu_emu.features.input.model.NativeButton import org.yuzu.yuzu_emu.features.input.model.NativeButton
import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.overlay.model.OverlayControl import org.yuzu.yuzu_emu.overlay.model.OverlayControl
@ -99,12 +100,10 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
} }
var shouldUpdateView = false var shouldUpdateView = false
val playerIndex = val playerIndex = when (NativeInput.getStyleIndex(0)) {
if (NativeInput.isHandheldOnly()) { NpadStyleIndex.Handheld -> 8
NativeInput.ConsoleDevice else -> 0
} else { }
NativeInput.Player1Device
}
for (button in overlayButtons) { for (button in overlayButtons) {
if (!button.updateStatus(event)) { if (!button.updateStatus(event)) {

View file

@ -1604,6 +1604,7 @@ void GMainWindow::ConnectMenuEvents() {
connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder); connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder);
connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents); connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents);
connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware); connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware);
connect_menu(ui->action_Install_Keys, &GMainWindow::OnInstallDecryptionKeys);
connect_menu(ui->action_About, &GMainWindow::OnAbout); connect_menu(ui->action_About, &GMainWindow::OnAbout);
} }
@ -1633,6 +1634,7 @@ void GMainWindow::UpdateMenuState() {
} }
ui->action_Install_Firmware->setEnabled(!emulation_running); ui->action_Install_Firmware->setEnabled(!emulation_running);
ui->action_Install_Keys->setEnabled(!emulation_running);
for (QAction* action : applet_actions) { for (QAction* action : applet_actions) {
action->setEnabled(is_firmware_available && !emulation_running); action->setEnabled(is_firmware_available && !emulation_running);
@ -4169,9 +4171,8 @@ void GMainWindow::OnInstallFirmware() {
return; return;
} }
QString firmware_source_location = const QString firmware_source_location = QFileDialog::getExistingDirectory(
QFileDialog::getExistingDirectory(this, tr("Select Dumped Firmware Source Location"), this, tr("Select Dumped Firmware Source Location"), {}, QFileDialog::ShowDirsOnly);
QString::fromStdString(""), QFileDialog::ShowDirsOnly);
if (firmware_source_location.isEmpty()) { if (firmware_source_location.isEmpty()) {
return; return;
} }
@ -4202,8 +4203,9 @@ void GMainWindow::OnInstallFirmware() {
std::vector<std::filesystem::path> out; std::vector<std::filesystem::path> out;
const Common::FS::DirEntryCallable callback = const Common::FS::DirEntryCallable callback =
[&out](const std::filesystem::directory_entry& entry) { [&out](const std::filesystem::directory_entry& entry) {
if (entry.path().has_extension() && entry.path().extension() == ".nca") if (entry.path().has_extension() && entry.path().extension() == ".nca") {
out.emplace_back(entry.path()); out.emplace_back(entry.path());
}
return true; return true;
}; };
@ -4235,7 +4237,6 @@ void GMainWindow::OnInstallFirmware() {
auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered");
bool success = true; bool success = true;
bool cancelled = false;
int i = 0; int i = 0;
for (const auto& firmware_src_path : out) { for (const auto& firmware_src_path : out) {
i++; i++;
@ -4250,24 +4251,22 @@ void GMainWindow::OnInstallFirmware() {
success = false; success = false;
} }
if (QtProgressCallback(100, 20 + (int)(((float)(i) / (float)out.size()) * 70.0))) { if (QtProgressCallback(
success = false; 100, 20 + static_cast<int>(((i) / static_cast<float>(out.size())) * 70.0))) {
cancelled = true; progress.close();
break; QMessageBox::warning(
this, tr("Firmware install failed"),
tr("Firmware installation cancelled, firmware may be in bad state, "
"restart yuzu or re-install firmware."));
return;
} }
} }
if (!success && !cancelled) { if (!success) {
progress.close(); progress.close();
QMessageBox::critical(this, tr("Firmware install failed"), QMessageBox::critical(this, tr("Firmware install failed"),
tr("One or more firmware files failed to copy into NAND.")); tr("One or more firmware files failed to copy into NAND."));
return; return;
} else if (cancelled) {
progress.close();
QMessageBox::warning(this, tr("Firmware install failed"),
tr("Firmware installation cancelled, firmware may be in bad state, "
"restart yuzu or re-install firmware."));
return;
} }
// Re-scan VFS for the newly placed firmware files. // Re-scan VFS for the newly placed firmware files.
@ -4295,6 +4294,84 @@ void GMainWindow::OnInstallFirmware() {
OnCheckFirmwareDecryption(); OnCheckFirmwareDecryption();
} }
void GMainWindow::OnInstallDecryptionKeys() {
// Don't do this while emulation is running.
if (emu_thread != nullptr && emu_thread->IsRunning()) {
return;
}
const QString key_source_location = QFileDialog::getOpenFileName(
this, tr("Select Dumped Keys Location"), {}, QStringLiteral("prod.keys (prod.keys)"), {},
QFileDialog::ReadOnly);
if (key_source_location.isEmpty()) {
return;
}
// Verify that it contains prod.keys, title.keys and optionally, key_retail.bin
LOG_INFO(Frontend, "Installing key files from {}", key_source_location.toStdString());
const std::filesystem::path prod_key_path = key_source_location.toStdString();
const std::filesystem::path key_source_path = prod_key_path.parent_path();
if (!Common::FS::IsDir(key_source_path)) {
return;
}
bool prod_keys_found = false;
std::vector<std::filesystem::path> source_key_files;
if (Common::FS::Exists(prod_key_path)) {
prod_keys_found = true;
source_key_files.emplace_back(prod_key_path);
}
if (Common::FS::Exists(key_source_path / "title.keys")) {
source_key_files.emplace_back(key_source_path / "title.keys");
}
if (Common::FS::Exists(key_source_path / "key_retail.bin")) {
source_key_files.emplace_back(key_source_path / "key_retail.bin");
}
// There should be at least prod.keys.
if (source_key_files.empty() || !prod_keys_found) {
QMessageBox::warning(this, tr("Decryption Keys install failed"),
tr("prod.keys is a required decryption key file."));
return;
}
const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
for (auto key_file : source_key_files) {
std::filesystem::path destination_key_file = yuzu_keys_dir / key_file.filename();
if (!std::filesystem::copy_file(key_file, destination_key_file,
std::filesystem::copy_options::overwrite_existing)) {
LOG_ERROR(Frontend, "Failed to copy file {} to {}", key_file.string(),
destination_key_file.string());
QMessageBox::critical(this, tr("Decryption Keys install failed"),
tr("One or more keys failed to copy."));
return;
}
}
// Reinitialize the key manager, re-read the vfs (for update/dlc files),
// and re-populate the game list in the UI if the user has already added
// game folders.
Core::Crypto::KeyManager::Instance().ReloadKeys();
system->GetFileSystemController().CreateFactories(*vfs);
game_list->PopulateAsync(UISettings::values.game_dirs);
if (ContentManager::AreKeysPresent()) {
QMessageBox::information(this, tr("Decryption Keys install succeeded"),
tr("Decryption Keys were successfully installed"));
} else {
QMessageBox::critical(
this, tr("Decryption Keys install failed"),
tr("Decryption Keys failed to initialize. Check that your dumping tools are "
"up to date and re-dump keys."));
}
OnCheckFirmwareDecryption();
}
void GMainWindow::OnAbout() { void GMainWindow::OnAbout() {
AboutDialog aboutDialog(this); AboutDialog aboutDialog(this);
aboutDialog.exec(); aboutDialog.exec();

View file

@ -381,6 +381,7 @@ private slots:
void OnOpenYuzuFolder(); void OnOpenYuzuFolder();
void OnVerifyInstalledContents(); void OnVerifyInstalledContents();
void OnInstallFirmware(); void OnInstallFirmware();
void OnInstallDecryptionKeys();
void OnAbout(); void OnAbout();
void OnToggleFilterBar(); void OnToggleFilterBar();
void OnToggleStatusBar(); void OnToggleStatusBar();

View file

@ -165,8 +165,9 @@
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="action_Configure_Tas"/> <addaction name="action_Configure_Tas"/>
</widget> </widget>
<addaction name="action_Verify_installed_contents"/> <addaction name="action_Install_Keys"/>
<addaction name="action_Install_Firmware"/> <addaction name="action_Install_Firmware"/>
<addaction name="action_Verify_installed_contents"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="menu_cabinet_applet"/> <addaction name="menu_cabinet_applet"/>
<addaction name="action_Load_Album"/> <addaction name="action_Load_Album"/>
@ -469,6 +470,11 @@
<string>Install Firmware</string> <string>Install Firmware</string>
</property> </property>
</action> </action>
<action name="action_Install_Keys">
<property name="text">
<string>Install Decryption Keys</string>
</property>
</action>
</widget> </widget>
<resources> <resources>
<include location="yuzu.qrc"/> <include location="yuzu.qrc"/>