nsyshid: Emulate Infinity Base (#1246)

This commit is contained in:
Joshua de Reeper 2024-07-23 02:18:48 +01:00 committed by GitHub
parent 64232ffdbd
commit a1c1a608d7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 1478 additions and 22 deletions

View file

@ -43,6 +43,7 @@ EmulatedUSBDeviceFrame::EmulatedUSBDeviceFrame(wxWindow* parent)
auto* notebook = new wxNotebook(this, wxID_ANY);
notebook->AddPage(AddSkylanderPage(notebook), _("Skylanders Portal"));
notebook->AddPage(AddInfinityPage(notebook), _("Infinity Base"));
sizer->Add(notebook, 1, wxEXPAND | wxALL, 2);
@ -83,32 +84,98 @@ wxPanel* EmulatedUSBDeviceFrame::AddSkylanderPage(wxNotebook* notebook)
return panel;
}
wxBoxSizer* EmulatedUSBDeviceFrame::AddSkylanderRow(uint8 row_number,
wxPanel* EmulatedUSBDeviceFrame::AddInfinityPage(wxNotebook* notebook)
{
auto* panel = new wxPanel(notebook);
auto* panelSizer = new wxBoxSizer(wxBOTH);
auto* box = new wxStaticBox(panel, wxID_ANY, _("Infinity Manager"));
auto* boxSizer = new wxStaticBoxSizer(box, wxBOTH);
auto* row = new wxBoxSizer(wxHORIZONTAL);
m_emulateBase =
new wxCheckBox(box, wxID_ANY, _("Emulate Infinity Base"));
m_emulateBase->SetValue(
GetConfig().emulated_usb_devices.emulate_infinity_base);
m_emulateBase->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {
GetConfig().emulated_usb_devices.emulate_infinity_base =
m_emulateBase->IsChecked();
g_config.Save();
});
row->Add(m_emulateBase, 1, wxEXPAND | wxALL, 2);
boxSizer->Add(row, 1, wxEXPAND | wxALL, 2);
boxSizer->Add(AddInfinityRow("Play Set/Power Disc", 0, box), 1, wxEXPAND | wxALL, 2);
boxSizer->Add(AddInfinityRow("Power Disc Two", 1, box), 1, wxEXPAND | wxALL, 2);
boxSizer->Add(AddInfinityRow("Power Disc Three", 2, box), 1, wxEXPAND | wxALL, 2);
boxSizer->Add(AddInfinityRow("Player One", 3, box), 1, wxEXPAND | wxALL, 2);
boxSizer->Add(AddInfinityRow("Player One Ability One", 4, box), 1, wxEXPAND | wxALL, 2);
boxSizer->Add(AddInfinityRow("Player One Ability Two", 5, box), 1, wxEXPAND | wxALL, 2);
boxSizer->Add(AddInfinityRow("Player Two", 6, box), 1, wxEXPAND | wxALL, 2);
boxSizer->Add(AddInfinityRow("Player Two Ability One", 7, box), 1, wxEXPAND | wxALL, 2);
boxSizer->Add(AddInfinityRow("Player Two Ability Two", 8, box), 1, wxEXPAND | wxALL, 2);
panelSizer->Add(boxSizer, 1, wxEXPAND | wxALL, 2);
panel->SetSizerAndFit(panelSizer);
return panel;
}
wxBoxSizer* EmulatedUSBDeviceFrame::AddSkylanderRow(uint8 rowNumber,
wxStaticBox* box)
{
auto* row = new wxBoxSizer(wxHORIZONTAL);
row->Add(new wxStaticText(box, wxID_ANY,
fmt::format("{} {}", _("Skylander").ToStdString(),
(row_number + 1))),
(rowNumber + 1))),
1, wxEXPAND | wxALL, 2);
m_skylanderSlots[row_number] =
m_skylanderSlots[rowNumber] =
new wxTextCtrl(box, wxID_ANY, _("None"), wxDefaultPosition, wxDefaultSize,
wxTE_READONLY);
m_skylanderSlots[row_number]->SetMinSize(wxSize(150, -1));
m_skylanderSlots[row_number]->Disable();
row->Add(m_skylanderSlots[row_number], 1, wxEXPAND | wxALL, 2);
m_skylanderSlots[rowNumber]->SetMinSize(wxSize(150, -1));
m_skylanderSlots[rowNumber]->Disable();
row->Add(m_skylanderSlots[rowNumber], 1, wxEXPAND | wxALL, 2);
auto* loadButton = new wxButton(box, wxID_ANY, _("Load"));
loadButton->Bind(wxEVT_BUTTON, [row_number, this](wxCommandEvent&) {
LoadSkylander(row_number);
loadButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {
LoadSkylander(rowNumber);
});
auto* createButton = new wxButton(box, wxID_ANY, _("Create"));
createButton->Bind(wxEVT_BUTTON, [row_number, this](wxCommandEvent&) {
CreateSkylander(row_number);
createButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {
CreateSkylander(rowNumber);
});
auto* clearButton = new wxButton(box, wxID_ANY, _("Clear"));
clearButton->Bind(wxEVT_BUTTON, [row_number, this](wxCommandEvent&) {
ClearSkylander(row_number);
clearButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {
ClearSkylander(rowNumber);
});
row->Add(loadButton, 1, wxEXPAND | wxALL, 2);
row->Add(createButton, 1, wxEXPAND | wxALL, 2);
row->Add(clearButton, 1, wxEXPAND | wxALL, 2);
return row;
}
wxBoxSizer* EmulatedUSBDeviceFrame::AddInfinityRow(wxString name, uint8 rowNumber, wxStaticBox* box)
{
auto* row = new wxBoxSizer(wxHORIZONTAL);
row->Add(new wxStaticText(box, wxID_ANY, name), 1, wxEXPAND | wxALL, 2);
m_infinitySlots[rowNumber] =
new wxTextCtrl(box, wxID_ANY, _("None"), wxDefaultPosition, wxDefaultSize,
wxTE_READONLY);
m_infinitySlots[rowNumber]->SetMinSize(wxSize(150, -1));
m_infinitySlots[rowNumber]->Disable();
row->Add(m_infinitySlots[rowNumber], 1, wxALL | wxEXPAND, 5);
auto* loadButton = new wxButton(box, wxID_ANY, _("Load"));
loadButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {
LoadFigure(rowNumber);
});
auto* createButton = new wxButton(box, wxID_ANY, _("Create"));
createButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {
CreateFigure(rowNumber);
});
auto* clearButton = new wxButton(box, wxID_ANY, _("Clear"));
clearButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {
ClearFigure(rowNumber);
});
row->Add(loadButton, 1, wxEXPAND | wxALL, 2);
row->Add(createButton, 1, wxEXPAND | wxALL, 2);
@ -138,7 +205,7 @@ void EmulatedUSBDeviceFrame::LoadSkylanderPath(uint8 slot, wxString path)
return;
}
std::array<uint8, 0x40 * 0x10> fileData;
std::array<uint8, nsyshid::SKY_FIGURE_SIZE> fileData;
if (skyFile->readData(fileData.data(), fileData.size()) != fileData.size())
{
wxMessageDialog open_error(this, "Failed to read file! File was too small");
@ -218,15 +285,15 @@ CreateSkylanderDialog::CreateSkylanderDialog(wxWindow* parent, uint8 slot)
long longSkyId;
if (!editId->GetValue().ToLong(&longSkyId) || longSkyId > 0xFFFF)
{
wxMessageDialog id_error(this, "Error Converting ID!", "ID Entered is Invalid");
id_error.ShowModal();
wxMessageDialog idError(this, "Error Converting ID!", "ID Entered is Invalid");
idError.ShowModal();
return;
}
long longSkyVar;
if (!editVar->GetValue().ToLong(&longSkyVar) || longSkyVar > 0xFFFF)
{
wxMessageDialog id_error(this, "Error Converting Variant!", "Variant Entered is Invalid");
id_error.ShowModal();
wxMessageDialog idError(this, "Error Converting Variant!", "Variant Entered is Invalid");
idError.ShowModal();
return;
}
uint16 skyId = longSkyId & 0xFFFF;
@ -284,6 +351,157 @@ wxString CreateSkylanderDialog::GetFilePath() const
return m_filePath;
}
CreateInfinityFigureDialog::CreateInfinityFigureDialog(wxWindow* parent, uint8 slot)
: wxDialog(parent, wxID_ANY, _("Infinity Figure Creator"), wxDefaultPosition, wxSize(500, 150))
{
auto* sizer = new wxBoxSizer(wxVERTICAL);
auto* comboRow = new wxBoxSizer(wxHORIZONTAL);
auto* comboBox = new wxComboBox(this, wxID_ANY);
comboBox->Append("---Select---", reinterpret_cast<void*>(0xFFFFFF));
wxArrayString filterlist;
for (const auto& it : nsyshid::g_infinitybase.GetFigureList())
{
const uint32 figure = it.first;
if ((slot == 0 &&
((figure > 0x1E8480 && figure < 0x2DC6BF) || (figure > 0x3D0900 && figure < 0x4C4B3F))) ||
((slot == 1 || slot == 2) && (figure > 0x3D0900 && figure < 0x4C4B3F)) ||
((slot == 3 || slot == 6) && figure < 0x1E847F) ||
((slot == 4 || slot == 5 || slot == 7 || slot == 8) &&
(figure > 0x2DC6C0 && figure < 0x3D08FF)))
{
comboBox->Append(it.second.second, reinterpret_cast<void*>(figure));
filterlist.Add(it.second.second);
}
}
comboBox->SetSelection(0);
bool enabled = comboBox->AutoComplete(filterlist);
comboRow->Add(comboBox, 1, wxEXPAND | wxALL, 2);
auto* figNumRow = new wxBoxSizer(wxHORIZONTAL);
wxIntegerValidator<uint32> validator;
auto* labelFigNum = new wxStaticText(this, wxID_ANY, "Figure Number:");
auto* editFigNum = new wxTextCtrl(this, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0, validator);
figNumRow->Add(labelFigNum, 1, wxALL, 5);
figNumRow->Add(editFigNum, 1, wxALL, 5);
auto* buttonRow = new wxBoxSizer(wxHORIZONTAL);
auto* createButton = new wxButton(this, wxID_ANY, _("Create"));
createButton->Bind(wxEVT_BUTTON, [editFigNum, this](wxCommandEvent&) {
long longFigNum;
if (!editFigNum->GetValue().ToLong(&longFigNum))
{
wxMessageDialog idError(this, "Error Converting Figure Number!", "Number Entered is Invalid");
idError.ShowModal();
this->EndModal(0);;
}
uint32 figNum = longFigNum & 0xFFFFFFFF;
auto figure = nsyshid::g_infinitybase.FindFigure(figNum);
wxString predefName = figure.second + ".bin";
wxFileDialog
saveFileDialog(this, _("Create Infinity Figure file"), "", predefName,
"BIN files (*.bin)|*.bin", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if (saveFileDialog.ShowModal() == wxID_CANCEL)
this->EndModal(0);;
m_filePath = saveFileDialog.GetPath();
nsyshid::g_infinitybase.CreateFigure(_utf8ToPath(m_filePath.utf8_string()), figNum, figure.first);
this->EndModal(1);
});
auto* cancelButton = new wxButton(this, wxID_ANY, _("Cancel"));
cancelButton->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
this->EndModal(0);
});
comboBox->Bind(wxEVT_COMBOBOX, [comboBox, editFigNum, this](wxCommandEvent&) {
const uint64 fig_info = reinterpret_cast<uint64>(comboBox->GetClientData(comboBox->GetSelection()));
if (fig_info != 0xFFFFFF)
{
const uint32 figNum = fig_info & 0xFFFFFFFF;
editFigNum->SetValue(wxString::Format(wxT("%i"), figNum));
}
});
buttonRow->Add(createButton, 1, wxALL, 5);
buttonRow->Add(cancelButton, 1, wxALL, 5);
sizer->Add(comboRow, 1, wxEXPAND | wxALL, 2);
sizer->Add(figNumRow, 1, wxEXPAND | wxALL, 2);
sizer->Add(buttonRow, 1, wxEXPAND | wxALL, 2);
this->SetSizer(sizer);
this->Centre(wxBOTH);
}
wxString CreateInfinityFigureDialog::GetFilePath() const
{
return m_filePath;
}
void EmulatedUSBDeviceFrame::LoadFigure(uint8 slot)
{
wxFileDialog openFileDialog(this, _("Open Infinity Figure dump"), "", "",
"BIN files (*.bin)|*.bin",
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if (openFileDialog.ShowModal() != wxID_OK || openFileDialog.GetPath().empty())
{
wxMessageDialog errorMessage(this, "File Okay Error");
errorMessage.ShowModal();
return;
}
LoadFigurePath(slot, openFileDialog.GetPath());
}
void EmulatedUSBDeviceFrame::LoadFigurePath(uint8 slot, wxString path)
{
std::unique_ptr<FileStream> infFile(FileStream::openFile2(_utf8ToPath(path.utf8_string()), true));
if (!infFile)
{
wxMessageDialog errorMessage(this, "File Open Error");
errorMessage.ShowModal();
return;
}
std::array<uint8, nsyshid::INF_FIGURE_SIZE> fileData;
if (infFile->readData(fileData.data(), fileData.size()) != fileData.size())
{
wxMessageDialog open_error(this, "Failed to read file! File was too small");
open_error.ShowModal();
return;
}
ClearFigure(slot);
uint32 number = nsyshid::g_infinitybase.LoadFigure(fileData, std::move(infFile), slot);
m_infinitySlots[slot]->ChangeValue(nsyshid::g_infinitybase.FindFigure(number).second);
}
void EmulatedUSBDeviceFrame::CreateFigure(uint8 slot)
{
cemuLog_log(LogType::Force, "Create Figure: {}", slot);
CreateInfinityFigureDialog create_dlg(this, slot);
create_dlg.ShowModal();
if (create_dlg.GetReturnCode() == 1)
{
LoadFigurePath(slot, create_dlg.GetFilePath());
}
}
void EmulatedUSBDeviceFrame::ClearFigure(uint8 slot)
{
m_infinitySlots[slot]->ChangeValue("None");
nsyshid::g_infinitybase.RemoveFigure(slot);
}
void EmulatedUSBDeviceFrame::UpdateSkylanderEdits()
{
for (auto i = 0; i < nsyshid::MAX_SKYLANDERS; i++)