Valid block/num checks, rename variables, remove translatable strings

Capitalize Skylander in tr strings

Lint and validation method fixes

Proper Attach and Change Interface method

Re-jig code to exit early and read easier
This commit is contained in:
Joshua de Reeper 2023-01-22 09:56:08 +13:00
parent 18fd0d7dcd
commit c76d2c16eb
3 changed files with 359 additions and 311 deletions

View File

@ -66,6 +66,12 @@ bool SkylanderUSB::Attach()
bool SkylanderUSB::AttachAndChangeInterface(const u8 interface) bool SkylanderUSB::AttachAndChangeInterface(const u8 interface)
{ {
if (!Attach())
return false;
if (interface != m_active_interface)
return ChangeInterface(interface) == 0;
return true; return true;
} }
@ -109,26 +115,48 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
m_vid, m_pid, m_active_interface, cmd->request_type, cmd->request, cmd->value, m_vid, m_pid, m_active_interface, cmd->request_type, cmd->request, cmd->value,
cmd->index, cmd->length); cmd->index, cmd->length);
// If not HID Host to Device type, return invalid
if (cmd->request_type != 0x21)
return IPC_EINVAL;
// Data to be sent back via the control transfer immediately
std::array<u8, 64> control_response = {};
s32 expected_count = 0;
u64 expected_time_us = 100;
// Non 0x09 Requests are handled here - no portal data is requested
if (cmd->request != 0x09)
{
switch (cmd->request)
{
// Get Interface
case 0x0A:
expected_count = 8;
break;
// Set Interface
case 0x0B:
expected_count = 8;
break;
default:
ERROR_LOG_FMT(IOS_USB, "Unhandled Request {}", cmd->request);
break;
}
}
else
{
// Skylander Portal Requests
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
u8* buf = memory.GetPointerForRange(cmd->data_address, cmd->length); u8* buf = memory.GetPointerForRange(cmd->data_address, cmd->length);
if ((cmd->length == 0 || buf == nullptr) && cmd->request == 0x09) if (cmd->length == 0 || buf == nullptr)
{ {
ERROR_LOG_FMT(IOS_USB, "Skylander command invalid"); ERROR_LOG_FMT(IOS_USB, "Skylander command invalid");
return IPC_EINVAL; return IPC_EINVAL;
} }
std::array<u8, 64> result = {}; // Data to be queued to be sent back via the Interrupt Transfer (if needed)
std::array<u8, 64> data = {}; std::array<u8, 64> interrupt_response = {};
s32 expected_count = 0;
u64 expected_time_us = 100; // The first byte of the Control Request is always a char for Skylanders
// Control transfers are instantaneous
u8 request_type = cmd->request_type;
if (request_type == 0x21)
{
// HID host to device type
switch (cmd->request)
{
case 0x09:
switch (buf[0]) switch (buf[0])
{ {
case 'A': case 'A':
@ -150,11 +178,11 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
// Wii U Wireless: 41 01 f4 00 41 00 ed 00 41 01 f4 00 41 00 eb 00 41 01 f3 00 41 00 ed 00 // Wii U Wireless: 41 01 f4 00 41 00 ed 00 41 01 f4 00 41 00 eb 00 41 01 f3 00 41 00 ed 00
if (cmd->length == 2) if (cmd->length == 2)
{ {
data = {buf[0], buf[1]}; control_response = {buf[0], buf[1]};
result = {0x41, buf[1], 0xFF, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, interrupt_response = {0x41, buf[1], 0xFF, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
m_queries.push(result); m_queries.push(interrupt_response);
expected_count = 10; expected_count = 10;
system.GetSkylanderPortal().Activate(); system.GetSkylanderPortal().Activate();
} }
@ -176,7 +204,7 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
if (cmd->length == 4) if (cmd->length == 4)
{ {
system.GetSkylanderPortal().SetLEDs(0x01, buf[1], buf[2], buf[3]); system.GetSkylanderPortal().SetLEDs(0x01, buf[1], buf[2], buf[3]);
data = {0x43, buf[1], buf[2], buf[3]}; control_response = {0x43, buf[1], buf[2], buf[3]};
expected_count = 12; expected_count = 12;
} }
break; break;
@ -197,14 +225,13 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
// are 0x00, 0x01 and 0x07. Custom commands show that the higher this value the longer the // are 0x00, 0x01 and 0x07. Custom commands show that the higher this value the longer the
// duration. // duration.
// Empty J response is send after the fade is completed. Immeditately sending it is fine // Empty J response is sent after the fade is completed.
// as long as we don't show the fade happening
if (cmd->length == 7) if (cmd->length == 7)
{ {
data = {buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]}; control_response = {buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]};
expected_count = 15; expected_count = 15;
result = {buf[0]}; interrupt_response = {buf[0]};
m_queries.push(result); m_queries.push(interrupt_response);
system.GetSkylanderPortal().SetLEDs(buf[1], buf[2], buf[3], buf[4]); system.GetSkylanderPortal().SetLEDs(buf[1], buf[2], buf[3], buf[4]);
} }
break; break;
@ -224,7 +251,7 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
// increasing or decreasing the values results in a brighter or dimmer light // increasing or decreasing the values results in a brighter or dimmer light
if (cmd->length == 5) if (cmd->length == 5)
{ {
data = {buf[0], buf[1], buf[2], buf[3], buf[4]}; control_response = {buf[0], buf[1], buf[2], buf[3], buf[4]};
expected_count = 13; expected_count = 13;
u8 side = buf[1]; u8 side = buf[1];
@ -242,10 +269,10 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
// Respond with version obtained from Trap Team wired portal // Respond with version obtained from Trap Team wired portal
if (cmd->length == 2) if (cmd->length == 2)
{ {
data = {buf[0], buf[1]}; control_response = {buf[0], buf[1]};
expected_count = 10; expected_count = 10;
result = {buf[0], buf[1], 0x00, 0x19}; interrupt_response = {buf[0], buf[1], 0x00, 0x19};
m_queries.push(result); m_queries.push(interrupt_response);
} }
break; break;
} }
@ -267,14 +294,13 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
// character indexes, these may not be sequential. // character indexes, these may not be sequential.
case 'Q': case 'Q':
{ {
// Queries a block
if (cmd->length == 3) if (cmd->length == 3)
{ {
const u8 sky_num = buf[1] & 0xF; const u8 sky_num = buf[1] & 0xF;
const u8 block = buf[2]; const u8 block = buf[2];
system.GetSkylanderPortal().QueryBlock(sky_num, block, result.data()); system.GetSkylanderPortal().QueryBlock(sky_num, block, interrupt_response.data());
m_queries.push(result); m_queries.push(interrupt_response);
data = {buf[0], buf[1], buf[2]}; control_response = {buf[0], buf[1], buf[2]};
expected_count = 11; expected_count = 11;
} }
break; break;
@ -291,11 +317,11 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
// type. // type.
if (cmd->length == 2) if (cmd->length == 2)
{ {
data = {0x52, 0x00}; control_response = {0x52, 0x00};
result = {0x52, 0x02, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, interrupt_response = {0x52, 0x02, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
m_queries.push(result); m_queries.push(interrupt_response);
expected_count = 10; expected_count = 10;
} }
break; break;
@ -333,7 +359,8 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
{ {
if (cmd->length == 1) if (cmd->length == 1)
{ {
data = {buf[0]}; // The Status interrupt responses are automatically handled via the GetStatus method
control_response = {buf[0]};
expected_count = 9; expected_count = 9;
} }
break; break;
@ -342,7 +369,7 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
{ {
if (cmd->length == 4) if (cmd->length == 4)
{ {
data = {buf[0], buf[1], buf[2], buf[3]}; control_response = {buf[0], buf[1], buf[2], buf[3]};
expected_count = 12; expected_count = 12;
} }
break; break;
@ -372,9 +399,9 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
{ {
const u8 sky_num = buf[1] & 0xF; const u8 sky_num = buf[1] & 0xF;
const u8 block = buf[2]; const u8 block = buf[2];
system.GetSkylanderPortal().WriteBlock(sky_num, block, &buf[3], result.data()); system.GetSkylanderPortal().WriteBlock(sky_num, block, &buf[3], interrupt_response.data());
m_queries.push(result); m_queries.push(interrupt_response);
data = {buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], control_response = {buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13],
buf[14], buf[15], buf[16], buf[17], buf[18]}; buf[14], buf[15], buf[16], buf[17], buf[18]};
expected_count = 27; expected_count = 27;
@ -385,21 +412,12 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
ERROR_LOG_FMT(IOS_USB, "Unhandled Skylander Portal Query: {}", buf[0]); ERROR_LOG_FMT(IOS_USB, "Unhandled Skylander Portal Query: {}", buf[0]);
break; break;
} }
break;
case 0x0A:
expected_count = 8;
break;
case 0x0B:
expected_count = 8;
break;
default:
ERROR_LOG_FMT(IOS_USB, "Unhandled Request {}", cmd->request);
break;
}
} }
if (expected_count == 0) if (expected_count == 0)
return IPC_EINVAL; return IPC_EINVAL;
ScheduleTransfer(std::move(cmd), data, expected_count, expected_time_us);
ScheduleTransfer(std::move(cmd), control_response, expected_count, expected_time_us);
return 0; return 0;
} }
@ -427,26 +445,26 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<IntrMessage> cmd)
ERROR_LOG_FMT(IOS_USB, "Skylander command invalid"); ERROR_LOG_FMT(IOS_USB, "Skylander command invalid");
return IPC_EINVAL; return IPC_EINVAL;
} }
std::array<u8, 64> result = {}; std::array<u8, 64> interrupt_response = {};
s32 expected_count; s32 expected_count;
u64 expected_time_us; u64 expected_time_us;
// Audio requests are 64 bytes long, are the only Interrupt requests longer than 32 bytes, // Audio requests are 64 bytes long, are the only Interrupt requests longer than 32 bytes,
// echo the request as the response and respond after 1ms // echo the request as the response and respond after 1ms
if (cmd->length > 32 && cmd->length <= 64) if (cmd->length > 32 && cmd->length <= 64)
{ {
std::array<u8, 64> audio_result = {}; std::array<u8, 64> audio_interrupt_response = {};
u8* audio_buf = audio_result.data(); u8* audio_buf = audio_interrupt_response.data();
memcpy(audio_buf, buf, cmd->length); memcpy(audio_buf, buf, cmd->length);
expected_time_us = 1000; expected_time_us = 1000;
expected_count = cmd->length; expected_count = cmd->length;
ScheduleTransfer(std::move(cmd), audio_result, expected_count, expected_time_us); ScheduleTransfer(std::move(cmd), audio_interrupt_response, expected_count, expected_time_us);
return 0; return 0;
} }
// If some data was requested from the Control Message, then the Interrupt message needs to // If some data was requested from the Control Message, then the Interrupt message needs to
// respond with that data. Check if the queries queue is empty // respond with that data. Check if the queries queue is empty
if (!m_queries.empty()) if (!m_queries.empty())
{ {
result = m_queries.front(); interrupt_response = m_queries.front();
m_queries.pop(); m_queries.pop();
// This needs to happen after ~22 milliseconds // This needs to happen after ~22 milliseconds
expected_time_us = 22000; expected_time_us = 22000;
@ -454,11 +472,11 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr<IntrMessage> cmd)
// If there is no relevant data to respond with, respond with the currentstatus of the Portal // If there is no relevant data to respond with, respond with the currentstatus of the Portal
else else
{ {
result = system.GetSkylanderPortal().GetStatus(); interrupt_response = system.GetSkylanderPortal().GetStatus();
expected_time_us = 2000; expected_time_us = 2000;
} }
expected_count = 32; expected_count = 32;
ScheduleTransfer(std::move(cmd), result, expected_count, expected_time_us); ScheduleTransfer(std::move(cmd), interrupt_response, expected_count, expected_time_us);
return 0; return 0;
} }
@ -616,18 +634,21 @@ std::array<u8, 64> SkylanderPortal::GetStatus()
status |= s.status; status |= s.status;
} }
std::array<u8, 64> result = {0x53, 0x00, 0x00, 0x00, 0x00, m_interrupt_counter++, std::array<u8, 64> interrupt_response = {0x53, 0x00, 0x00, 0x00, 0x00, m_interrupt_counter++,
active, 0x00, 0x00, 0x00, 0x00, 0x00, active, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00}; 0x00, 0x00};
memcpy(&result[1], &status, sizeof(status)); memcpy(&interrupt_response[1], &status, sizeof(status));
return result; return interrupt_response;
} }
void SkylanderPortal::QueryBlock(u8 sky_num, u8 block, u8* reply_buf) void SkylanderPortal::QueryBlock(u8 sky_num, u8 block, u8* reply_buf)
{ {
if (!IsSkylanderNumberValid(sky_num) || !IsBlockNumberValid(block))
return;
std::lock_guard lock(sky_mutex); std::lock_guard lock(sky_mutex);
const auto& skylander = skylanders[sky_num]; const auto& skylander = skylanders[sky_num];
@ -647,6 +668,9 @@ void SkylanderPortal::QueryBlock(u8 sky_num, u8 block, u8* reply_buf)
void SkylanderPortal::WriteBlock(u8 sky_num, u8 block, const u8* to_write_buf, u8* reply_buf) void SkylanderPortal::WriteBlock(u8 sky_num, u8 block, const u8* to_write_buf, u8* reply_buf)
{ {
if (!IsSkylanderNumberValid(sky_num) || !IsBlockNumberValid(block))
return;
std::lock_guard lock(sky_mutex); std::lock_guard lock(sky_mutex);
auto& skylander = skylanders[sky_num]; auto& skylander = skylanders[sky_num];
@ -738,6 +762,9 @@ bool SkylanderPortal::CreateSkylander(const std::string& file_path, u16 sky_id,
bool SkylanderPortal::RemoveSkylander(u8 sky_num) bool SkylanderPortal::RemoveSkylander(u8 sky_num)
{ {
if (!IsSkylanderNumberValid(sky_num))
return false;
DEBUG_LOG_FMT(IOS_USB, "Cleared Skylander from slot {}", sky_num); DEBUG_LOG_FMT(IOS_USB, "Cleared Skylander from slot {}", sky_num);
std::lock_guard lock(sky_mutex); std::lock_guard lock(sky_mutex);
auto& skylander = skylanders[sky_num]; auto& skylander = skylanders[sky_num];
@ -801,4 +828,14 @@ u8 SkylanderPortal::LoadSkylander(u8* buf, File::IOFile in_file)
return found_slot; return found_slot;
} }
bool SkylanderPortal::IsSkylanderNumberValid(u8 sky_num)
{
return sky_num < MAX_SKYLANDERS;
}
bool SkylanderPortal::IsBlockNumberValid(u8 block)
{
return block < 64;
}
} // namespace IOS::HLE::USB } // namespace IOS::HLE::USB

View File

@ -107,6 +107,10 @@ protected:
SkylanderLEDColor m_color_trap = {}; SkylanderLEDColor m_color_trap = {};
std::array<Skylander, MAX_SKYLANDERS> skylanders; std::array<Skylander, MAX_SKYLANDERS> skylanders;
private:
static bool IsSkylanderNumberValid(u8 sky_num);
static bool IsBlockNumberValid(u8 block);
}; };
} // namespace IOS::HLE::USB } // namespace IOS::HLE::USB

View File

@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
// DolphinQt code copied and modified for Dolphin from the RPCS3 Qt utility for Creating, Loading // DolphinQt code copied and modified for Dolphin from the RPCS3 Qt utility for Creating, Loading
// and Clearing skylanders // and Clearing Skylanders
#include "DolphinQt/SkylanderPortal/SkylanderPortalWindow.h" #include "DolphinQt/SkylanderPortal/SkylanderPortalWindow.h"
@ -11,7 +11,6 @@
#include <QCompleter> #include <QCompleter>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QEvent> #include <QEvent>
#include <QFileDialog>
#include <QGroupBox> #include <QGroupBox>
#include <QKeyEvent> #include <QKeyEvent>
#include <QKeySequence> #include <QKeySequence>
@ -522,7 +521,7 @@ const std::map<const std::pair<const u16, const u16>, const char*> list_skylande
SkylanderPortalWindow::SkylanderPortalWindow(QWidget* parent) : QWidget(parent) SkylanderPortalWindow::SkylanderPortalWindow(QWidget* parent) : QWidget(parent)
{ {
setWindowTitle(tr("Skylanders Manager")); setWindowTitle(tr("Skylanders Manager"));
setObjectName(tr("skylanders_manager")); setObjectName(QString::fromStdString("skylanders_manager"));
setMinimumSize(QSize(700, 200)); setMinimumSize(QSize(700, 200));
CreateMainWindow(); CreateMainWindow();
@ -611,7 +610,7 @@ void SkylanderPortalWindow::OnEmulationStateChanged(Core::State state)
CreateSkylanderDialog::CreateSkylanderDialog(QWidget* parent) : QDialog(parent) CreateSkylanderDialog::CreateSkylanderDialog(QWidget* parent) : QDialog(parent)
{ {
setWindowTitle(tr("Skylander Creator")); setWindowTitle(tr("Skylander Creator"));
setObjectName(tr("skylanders_creator")); setObjectName(QString::fromStdString("skylanders_creator"));
setMinimumSize(QSize(500, 150)); setMinimumSize(QSize(500, 150));
auto* layout = new QVBoxLayout; auto* layout = new QVBoxLayout;
@ -620,8 +619,8 @@ CreateSkylanderDialog::CreateSkylanderDialog(QWidget* parent) : QDialog(parent)
for (const auto& entry : list_skylanders) for (const auto& entry : list_skylanders)
{ {
const uint qvar = (entry.first.first << 16) | entry.first.second; const uint qvar = (entry.first.first << 16) | entry.first.second;
combo_skylist->addItem(tr(entry.second), QVariant(qvar)); combo_skylist->addItem(QString::fromStdString(entry.second), QVariant(qvar));
filterlist << tr(entry.second); filterlist << QString::fromStdString(entry.second);
} }
combo_skylist->addItem(tr("--Unknown--"), QVariant(0xFFFFFFFF)); combo_skylist->addItem(tr("--Unknown--"), QVariant(0xFFFFFFFF));
combo_skylist->setEditable(true); combo_skylist->setEditable(true);
@ -645,7 +644,8 @@ CreateSkylanderDialog::CreateSkylanderDialog(QWidget* parent) : QDialog(parent)
auto* label_var = new QLabel(tr("Variant:")); auto* label_var = new QLabel(tr("Variant:"));
auto* edit_id = new QLineEdit(tr("0")); auto* edit_id = new QLineEdit(tr("0"));
auto* edit_var = new QLineEdit(tr("0")); auto* edit_var = new QLineEdit(tr("0"));
auto* rxv = new QRegularExpressionValidator(QRegularExpression(tr("\\d*")), this); auto* rxv =
new QRegularExpressionValidator(QRegularExpression(QString::fromStdString("\\d*")), this);
edit_id->setValidator(rxv); edit_id->setValidator(rxv);
edit_var->setValidator(rxv); edit_var->setValidator(rxv);
hbox_idvar->addWidget(label_id); hbox_idvar->addWidget(label_id);
@ -693,8 +693,7 @@ CreateSkylanderDialog::CreateSkylanderDialog(QWidget* parent) : QDialog(parent)
const auto found_sky = list_skylanders.find(std::make_pair(sky_id, sky_var)); const auto found_sky = list_skylanders.find(std::make_pair(sky_id, sky_var));
if (found_sky != list_skylanders.end()) if (found_sky != list_skylanders.end())
{ {
std::string name = std::string(found_sky->second) + ".sky"; predef_name += QString::fromStdString(std::string(found_sky->second) + ".sky");
predef_name += tr(name.c_str());
} }
else else
{ {
@ -702,7 +701,7 @@ CreateSkylanderDialog::CreateSkylanderDialog(QWidget* parent) : QDialog(parent)
predef_name += str.arg(sky_id, sky_var); predef_name += str.arg(sky_id, sky_var);
} }
m_file_path = QFileDialog::getSaveFileName(this, tr("Create Skylander File"), predef_name, m_file_path = DolphinFileDialog::getSaveFileName(this, tr("Create Skylander File"), predef_name,
tr("Skylander Object (*.sky);;")); tr("Skylander Object (*.sky);;"));
if (m_file_path.isEmpty()) if (m_file_path.isEmpty())
{ {
@ -713,12 +712,12 @@ CreateSkylanderDialog::CreateSkylanderDialog(QWidget* parent) : QDialog(parent)
if (!system.GetSkylanderPortal().CreateSkylander(m_file_path.toStdString(), sky_id, sky_var)) if (!system.GetSkylanderPortal().CreateSkylander(m_file_path.toStdString(), sky_id, sky_var))
{ {
QMessageBox::warning(this, tr("Failed to create skylander file!"), QMessageBox::warning(this, tr("Failed to create Skylander file!"),
tr("Failed to create skylander file:\n%1").arg(m_file_path), tr("Failed to create Skylander file:\n%1").arg(m_file_path),
QMessageBox::Ok); QMessageBox::Ok);
return; return;
} }
s_last_skylander_path = QFileInfo(m_file_path).absolutePath() + tr("/"); s_last_skylander_path = QFileInfo(m_file_path).absolutePath() + QString::fromStdString("/");
accept(); accept();
}); });
@ -753,13 +752,14 @@ void SkylanderPortalWindow::CreateSkylander(u8 slot)
void SkylanderPortalWindow::LoadSkylander(u8 slot) void SkylanderPortalWindow::LoadSkylander(u8 slot)
{ {
const QString file_path = DolphinFileDialog::getOpenFileName( const QString file_path =
this, tr("Select Skylander File"), s_last_skylander_path, tr("Skylander (*.sky);;")); DolphinFileDialog::getOpenFileName(this, tr("Select Skylander File"), s_last_skylander_path,
QString::fromStdString("Skylander (*.sky);;"));
if (file_path.isEmpty()) if (file_path.isEmpty())
{ {
return; return;
} }
s_last_skylander_path = QFileInfo(file_path).absolutePath() + tr("/"); s_last_skylander_path = QFileInfo(file_path).absolutePath() + QString::fromStdString("/");
LoadSkylanderPath(slot, file_path); LoadSkylanderPath(slot, file_path);
} }
@ -770,8 +770,8 @@ void SkylanderPortalWindow::LoadSkylanderPath(u8 slot, const QString& path)
if (!sky_file) if (!sky_file)
{ {
QMessageBox::warning( QMessageBox::warning(
this, tr("Failed to open the skylander file!"), this, tr("Failed to open the Skylander file!"),
tr("Failed to open the skylander file(%1)!\nFile may already be in use on the portal.") tr("Failed to open the Skylander file(%1)!\nFile may already be in use on the portal.")
.arg(path), .arg(path),
QMessageBox::Ok); QMessageBox::Ok);
return; return;
@ -780,8 +780,8 @@ void SkylanderPortalWindow::LoadSkylanderPath(u8 slot, const QString& path)
if (!sky_file.ReadBytes(file_data.data(), file_data.size())) if (!sky_file.ReadBytes(file_data.data(), file_data.size()))
{ {
QMessageBox::warning( QMessageBox::warning(
this, tr("Failed to read the skylander file!"), this, tr("Failed to read the Skylander file!"),
tr("Failed to read the skylander file(%1)!\nFile was too small.").arg(path), tr("Failed to read the Skylander file(%1)!\nFile was too small.").arg(path),
QMessageBox::Ok); QMessageBox::Ok);
return; return;
} }
@ -804,8 +804,8 @@ void SkylanderPortalWindow::LoadSkylanderPath(u8 slot, const QString& path)
u8 portal_slot = system.GetSkylanderPortal().LoadSkylander(file_data.data(), std::move(sky_file)); u8 portal_slot = system.GetSkylanderPortal().LoadSkylander(file_data.data(), std::move(sky_file));
if (portal_slot == 0xFF) if (portal_slot == 0xFF)
{ {
QMessageBox::warning(this, tr("Failed to load the skylander file!"), QMessageBox::warning(this, tr("Failed to load the Skylander file!"),
tr("Failed to load the skylander file(%1)!\n").arg(path), QMessageBox::Ok); tr("Failed to load the Skylander file(%1)!\n").arg(path), QMessageBox::Ok);
return; return;
} }
m_sky_slots[slot] = {portal_slot, sky_id, sky_var}; m_sky_slots[slot] = {portal_slot, sky_id, sky_var};
@ -817,6 +817,13 @@ void SkylanderPortalWindow::ClearSkylander(u8 slot)
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
if (auto slot_infos = m_sky_slots[slot]) if (auto slot_infos = m_sky_slots[slot])
{ {
if (!system.GetSkylanderPortal().RemoveSkylander(slot_infos->portal_slot))
{
QMessageBox::warning(this, tr("Failed to clear Skylander!"),
tr("Failed to clear the Skylander from slot(%1)!\n").arg(slot),
QMessageBox::Ok);
return;
}
system.GetSkylanderPortal().RemoveSkylander(slot_infos->portal_slot); system.GetSkylanderPortal().RemoveSkylander(slot_infos->portal_slot);
m_sky_slots[slot].reset(); m_sky_slots[slot].reset();
UpdateEdits(); UpdateEdits();
@ -833,7 +840,7 @@ void SkylanderPortalWindow::UpdateEdits()
auto found_sky = list_skylanders.find(std::make_pair(sd->sky_id, sd->sky_var)); auto found_sky = list_skylanders.find(std::make_pair(sd->sky_id, sd->sky_var));
if (found_sky != list_skylanders.end()) if (found_sky != list_skylanders.end())
{ {
display_string = tr(found_sky->second); display_string = QString::fromStdString(found_sky->second);
} }
else else
{ {