mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-25 18:46:55 +01:00
nsyshid: Emulate Infinity Base (#1246)
This commit is contained in:
parent
64232ffdbd
commit
a1c1a608d7
@ -463,6 +463,8 @@ add_library(CemuCafe
|
|||||||
OS/libs/nsyshid/BackendLibusb.h
|
OS/libs/nsyshid/BackendLibusb.h
|
||||||
OS/libs/nsyshid/BackendWindowsHID.cpp
|
OS/libs/nsyshid/BackendWindowsHID.cpp
|
||||||
OS/libs/nsyshid/BackendWindowsHID.h
|
OS/libs/nsyshid/BackendWindowsHID.h
|
||||||
|
OS/libs/nsyshid/Infinity.cpp
|
||||||
|
OS/libs/nsyshid/Infinity.h
|
||||||
OS/libs/nsyshid/Skylander.cpp
|
OS/libs/nsyshid/Skylander.cpp
|
||||||
OS/libs/nsyshid/Skylander.h
|
OS/libs/nsyshid/Skylander.h
|
||||||
OS/libs/nsyskbd/nsyskbd.cpp
|
OS/libs/nsyskbd/nsyskbd.cpp
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "BackendEmulated.h"
|
#include "BackendEmulated.h"
|
||||||
|
#include "Infinity.h"
|
||||||
#include "Skylander.h"
|
#include "Skylander.h"
|
||||||
#include "config/CemuConfig.h"
|
#include "config/CemuConfig.h"
|
||||||
|
|
||||||
@ -25,5 +26,12 @@ namespace nsyshid::backend::emulated
|
|||||||
auto device = std::make_shared<SkylanderPortalDevice>();
|
auto device = std::make_shared<SkylanderPortalDevice>();
|
||||||
AttachDevice(device);
|
AttachDevice(device);
|
||||||
}
|
}
|
||||||
|
if (GetConfig().emulated_usb_devices.emulate_infinity_base && !FindDeviceById(0x0E6F, 0x0129))
|
||||||
|
{
|
||||||
|
cemuLog_logDebug(LogType::Force, "Attaching Emulated Base");
|
||||||
|
// Add Infinity Base
|
||||||
|
auto device = std::make_shared<InfinityBaseDevice>();
|
||||||
|
AttachDevice(device);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace nsyshid::backend::emulated
|
} // namespace nsyshid::backend::emulated
|
1102
src/Cafe/OS/libs/nsyshid/Infinity.cpp
Normal file
1102
src/Cafe/OS/libs/nsyshid/Infinity.cpp
Normal file
File diff suppressed because it is too large
Load Diff
105
src/Cafe/OS/libs/nsyshid/Infinity.h
Normal file
105
src/Cafe/OS/libs/nsyshid/Infinity.h
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include "nsyshid.h"
|
||||||
|
#include "Backend.h"
|
||||||
|
|
||||||
|
#include "Common/FileStream.h"
|
||||||
|
|
||||||
|
namespace nsyshid
|
||||||
|
{
|
||||||
|
class InfinityBaseDevice final : public Device {
|
||||||
|
public:
|
||||||
|
InfinityBaseDevice();
|
||||||
|
~InfinityBaseDevice() = default;
|
||||||
|
|
||||||
|
bool Open() override;
|
||||||
|
|
||||||
|
void Close() override;
|
||||||
|
|
||||||
|
bool IsOpened() override;
|
||||||
|
|
||||||
|
ReadResult Read(ReadMessage* message) override;
|
||||||
|
|
||||||
|
WriteResult Write(WriteMessage* message) override;
|
||||||
|
|
||||||
|
bool GetDescriptor(uint8 descType,
|
||||||
|
uint8 descIndex,
|
||||||
|
uint8 lang,
|
||||||
|
uint8* output,
|
||||||
|
uint32 outputMaxLength) override;
|
||||||
|
|
||||||
|
bool SetProtocol(uint8 ifIndex, uint8 protocol) override;
|
||||||
|
|
||||||
|
bool SetReport(ReportMessage* message) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_IsOpened;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint16 INF_BLOCK_COUNT = 0x14;
|
||||||
|
constexpr uint16 INF_BLOCK_SIZE = 0x10;
|
||||||
|
constexpr uint16 INF_FIGURE_SIZE = INF_BLOCK_COUNT * INF_BLOCK_SIZE;
|
||||||
|
constexpr uint8 MAX_FIGURES = 9;
|
||||||
|
class InfinityUSB {
|
||||||
|
public:
|
||||||
|
struct InfinityFigure final
|
||||||
|
{
|
||||||
|
std::unique_ptr<FileStream> infFile;
|
||||||
|
std::array<uint8, INF_FIGURE_SIZE> data{};
|
||||||
|
bool present = false;
|
||||||
|
uint8 orderAdded = 255;
|
||||||
|
void Save();
|
||||||
|
};
|
||||||
|
|
||||||
|
void SendCommand(uint8* buf, sint32 originalLength);
|
||||||
|
std::array<uint8, 32> GetStatus();
|
||||||
|
|
||||||
|
void GetBlankResponse(uint8 sequence, std::array<uint8, 32>& replyBuf);
|
||||||
|
void DescrambleAndSeed(uint8* buf, uint8 sequence,
|
||||||
|
std::array<uint8, 32>& replyBuf);
|
||||||
|
void GetNextAndScramble(uint8 sequence, std::array<uint8, 32>& replyBuf);
|
||||||
|
void GetPresentFigures(uint8 sequence, std::array<uint8, 32>& replyBuf);
|
||||||
|
void QueryBlock(uint8 figNum, uint8 block, std::array<uint8, 32>& replyBuf,
|
||||||
|
uint8 sequence);
|
||||||
|
void WriteBlock(uint8 figNum, uint8 block, const uint8* toWriteBuf,
|
||||||
|
std::array<uint8, 32>& replyBuf, uint8 sequence);
|
||||||
|
void GetFigureIdentifier(uint8 figNum, uint8 sequence,
|
||||||
|
std::array<uint8, 32>& replyBuf);
|
||||||
|
|
||||||
|
bool RemoveFigure(uint8 position);
|
||||||
|
uint32 LoadFigure(const std::array<uint8, INF_FIGURE_SIZE>& buf,
|
||||||
|
std::unique_ptr<FileStream>, uint8 position);
|
||||||
|
bool CreateFigure(fs::path pathName, uint32 figureNum, uint8 series);
|
||||||
|
static std::map<const uint32, const std::pair<const uint8, const char*>> GetFigureList();
|
||||||
|
std::pair<uint8, std::string> FindFigure(uint32 figNum);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::shared_mutex m_infinityMutex;
|
||||||
|
std::array<InfinityFigure, 9> m_figures;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 GenerateChecksum(const std::array<uint8, 32>& data,
|
||||||
|
int numOfBytes) const;
|
||||||
|
uint32 Descramble(uint64 numToDescramble);
|
||||||
|
uint64 Scramble(uint32 numToScramble, uint32 garbage);
|
||||||
|
void GenerateSeed(uint32 seed);
|
||||||
|
uint32 GetNext();
|
||||||
|
InfinityFigure& GetFigureByOrder(uint8 orderAdded);
|
||||||
|
uint8 DeriveFigurePosition(uint8 position);
|
||||||
|
std::array<uint8, 16> GenerateInfinityFigureKey(const std::vector<uint8>& sha1Data);
|
||||||
|
std::array<uint8, 16> GenerateBlankFigureData(uint32 figureNum, uint8 series);
|
||||||
|
|
||||||
|
uint32 m_randomA;
|
||||||
|
uint32 m_randomB;
|
||||||
|
uint32 m_randomC;
|
||||||
|
uint32 m_randomD;
|
||||||
|
|
||||||
|
uint8 m_figureOrder = 0;
|
||||||
|
std::queue<std::array<uint8, 32>> m_figureAddedRemovedResponses;
|
||||||
|
std::queue<std::array<uint8, 32>> m_queries;
|
||||||
|
};
|
||||||
|
extern InfinityUSB g_infinitybase;
|
||||||
|
|
||||||
|
} // namespace nsyshid
|
@ -855,7 +855,7 @@ namespace nsyshid
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<uint8, BLOCK_COUNT * BLOCK_SIZE> data{};
|
std::array<uint8, SKY_FIGURE_SIZE> data{};
|
||||||
|
|
||||||
uint32 first_block = 0x690F0F0F;
|
uint32 first_block = 0x690F0F0F;
|
||||||
uint32 other_blocks = 0x69080F7F;
|
uint32 other_blocks = 0x69080F7F;
|
||||||
|
@ -38,9 +38,9 @@ namespace nsyshid
|
|||||||
bool m_IsOpened;
|
bool m_IsOpened;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr uint16 BLOCK_COUNT = 0x40;
|
constexpr uint16 SKY_BLOCK_COUNT = 0x40;
|
||||||
constexpr uint16 BLOCK_SIZE = 0x10;
|
constexpr uint16 SKY_BLOCK_SIZE = 0x10;
|
||||||
constexpr uint16 FIGURE_SIZE = BLOCK_COUNT * BLOCK_SIZE;
|
constexpr uint16 SKY_FIGURE_SIZE = SKY_BLOCK_COUNT * SKY_BLOCK_SIZE;
|
||||||
constexpr uint8 MAX_SKYLANDERS = 16;
|
constexpr uint8 MAX_SKYLANDERS = 16;
|
||||||
|
|
||||||
class SkylanderUSB {
|
class SkylanderUSB {
|
||||||
@ -50,7 +50,7 @@ namespace nsyshid
|
|||||||
std::unique_ptr<FileStream> skyFile;
|
std::unique_ptr<FileStream> skyFile;
|
||||||
uint8 status = 0;
|
uint8 status = 0;
|
||||||
std::queue<uint8> queuedStatus;
|
std::queue<uint8> queuedStatus;
|
||||||
std::array<uint8, BLOCK_COUNT * BLOCK_SIZE> data{};
|
std::array<uint8, SKY_BLOCK_SIZE> data{};
|
||||||
uint32 lastId = 0;
|
uint32 lastId = 0;
|
||||||
void Save();
|
void Save();
|
||||||
|
|
||||||
|
@ -344,6 +344,7 @@ void CemuConfig::Load(XMLConfigParser& parser)
|
|||||||
// emulatedusbdevices
|
// emulatedusbdevices
|
||||||
auto usbdevices = parser.get("EmulatedUsbDevices");
|
auto usbdevices = parser.get("EmulatedUsbDevices");
|
||||||
emulated_usb_devices.emulate_skylander_portal = usbdevices.get("EmulateSkylanderPortal", emulated_usb_devices.emulate_skylander_portal);
|
emulated_usb_devices.emulate_skylander_portal = usbdevices.get("EmulateSkylanderPortal", emulated_usb_devices.emulate_skylander_portal);
|
||||||
|
emulated_usb_devices.emulate_infinity_base = usbdevices.get("EmulateInfinityBase", emulated_usb_devices.emulate_infinity_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CemuConfig::Save(XMLConfigParser& parser)
|
void CemuConfig::Save(XMLConfigParser& parser)
|
||||||
@ -541,6 +542,7 @@ void CemuConfig::Save(XMLConfigParser& parser)
|
|||||||
// emulated usb devices
|
// emulated usb devices
|
||||||
auto usbdevices = config.set("EmulatedUsbDevices");
|
auto usbdevices = config.set("EmulatedUsbDevices");
|
||||||
usbdevices.set("EmulateSkylanderPortal", emulated_usb_devices.emulate_skylander_portal.GetValue());
|
usbdevices.set("EmulateSkylanderPortal", emulated_usb_devices.emulate_skylander_portal.GetValue());
|
||||||
|
usbdevices.set("EmulateInfinityBase", emulated_usb_devices.emulate_infinity_base.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
GameEntry* CemuConfig::GetGameEntryByTitleId(uint64 titleId)
|
GameEntry* CemuConfig::GetGameEntryByTitleId(uint64 titleId)
|
||||||
|
@ -519,6 +519,7 @@ struct CemuConfig
|
|||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
ConfigValue<bool> emulate_skylander_portal{false};
|
ConfigValue<bool> emulate_skylander_portal{false};
|
||||||
|
ConfigValue<bool> emulate_infinity_base{true};
|
||||||
}emulated_usb_devices{};
|
}emulated_usb_devices{};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -43,6 +43,7 @@ EmulatedUSBDeviceFrame::EmulatedUSBDeviceFrame(wxWindow* parent)
|
|||||||
auto* notebook = new wxNotebook(this, wxID_ANY);
|
auto* notebook = new wxNotebook(this, wxID_ANY);
|
||||||
|
|
||||||
notebook->AddPage(AddSkylanderPage(notebook), _("Skylanders Portal"));
|
notebook->AddPage(AddSkylanderPage(notebook), _("Skylanders Portal"));
|
||||||
|
notebook->AddPage(AddInfinityPage(notebook), _("Infinity Base"));
|
||||||
|
|
||||||
sizer->Add(notebook, 1, wxEXPAND | wxALL, 2);
|
sizer->Add(notebook, 1, wxEXPAND | wxALL, 2);
|
||||||
|
|
||||||
@ -83,32 +84,98 @@ wxPanel* EmulatedUSBDeviceFrame::AddSkylanderPage(wxNotebook* notebook)
|
|||||||
return panel;
|
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)
|
wxStaticBox* box)
|
||||||
{
|
{
|
||||||
auto* row = new wxBoxSizer(wxHORIZONTAL);
|
auto* row = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
|
||||||
row->Add(new wxStaticText(box, wxID_ANY,
|
row->Add(new wxStaticText(box, wxID_ANY,
|
||||||
fmt::format("{} {}", _("Skylander").ToStdString(),
|
fmt::format("{} {}", _("Skylander").ToStdString(),
|
||||||
(row_number + 1))),
|
(rowNumber + 1))),
|
||||||
1, wxEXPAND | wxALL, 2);
|
1, wxEXPAND | wxALL, 2);
|
||||||
m_skylanderSlots[row_number] =
|
m_skylanderSlots[rowNumber] =
|
||||||
new wxTextCtrl(box, wxID_ANY, _("None"), wxDefaultPosition, wxDefaultSize,
|
new wxTextCtrl(box, wxID_ANY, _("None"), wxDefaultPosition, wxDefaultSize,
|
||||||
wxTE_READONLY);
|
wxTE_READONLY);
|
||||||
m_skylanderSlots[row_number]->SetMinSize(wxSize(150, -1));
|
m_skylanderSlots[rowNumber]->SetMinSize(wxSize(150, -1));
|
||||||
m_skylanderSlots[row_number]->Disable();
|
m_skylanderSlots[rowNumber]->Disable();
|
||||||
row->Add(m_skylanderSlots[row_number], 1, wxEXPAND | wxALL, 2);
|
row->Add(m_skylanderSlots[rowNumber], 1, wxEXPAND | wxALL, 2);
|
||||||
auto* loadButton = new wxButton(box, wxID_ANY, _("Load"));
|
auto* loadButton = new wxButton(box, wxID_ANY, _("Load"));
|
||||||
loadButton->Bind(wxEVT_BUTTON, [row_number, this](wxCommandEvent&) {
|
loadButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {
|
||||||
LoadSkylander(row_number);
|
LoadSkylander(rowNumber);
|
||||||
});
|
});
|
||||||
auto* createButton = new wxButton(box, wxID_ANY, _("Create"));
|
auto* createButton = new wxButton(box, wxID_ANY, _("Create"));
|
||||||
createButton->Bind(wxEVT_BUTTON, [row_number, this](wxCommandEvent&) {
|
createButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {
|
||||||
CreateSkylander(row_number);
|
CreateSkylander(rowNumber);
|
||||||
});
|
});
|
||||||
auto* clearButton = new wxButton(box, wxID_ANY, _("Clear"));
|
auto* clearButton = new wxButton(box, wxID_ANY, _("Clear"));
|
||||||
clearButton->Bind(wxEVT_BUTTON, [row_number, this](wxCommandEvent&) {
|
clearButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {
|
||||||
ClearSkylander(row_number);
|
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(loadButton, 1, wxEXPAND | wxALL, 2);
|
||||||
row->Add(createButton, 1, wxEXPAND | wxALL, 2);
|
row->Add(createButton, 1, wxEXPAND | wxALL, 2);
|
||||||
@ -138,7 +205,7 @@ void EmulatedUSBDeviceFrame::LoadSkylanderPath(uint8 slot, wxString path)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<uint8, 0x40 * 0x10> fileData;
|
std::array<uint8, nsyshid::SKY_FIGURE_SIZE> fileData;
|
||||||
if (skyFile->readData(fileData.data(), fileData.size()) != fileData.size())
|
if (skyFile->readData(fileData.data(), fileData.size()) != fileData.size())
|
||||||
{
|
{
|
||||||
wxMessageDialog open_error(this, "Failed to read file! File was too small");
|
wxMessageDialog open_error(this, "Failed to read file! File was too small");
|
||||||
@ -218,15 +285,15 @@ CreateSkylanderDialog::CreateSkylanderDialog(wxWindow* parent, uint8 slot)
|
|||||||
long longSkyId;
|
long longSkyId;
|
||||||
if (!editId->GetValue().ToLong(&longSkyId) || longSkyId > 0xFFFF)
|
if (!editId->GetValue().ToLong(&longSkyId) || longSkyId > 0xFFFF)
|
||||||
{
|
{
|
||||||
wxMessageDialog id_error(this, "Error Converting ID!", "ID Entered is Invalid");
|
wxMessageDialog idError(this, "Error Converting ID!", "ID Entered is Invalid");
|
||||||
id_error.ShowModal();
|
idError.ShowModal();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long longSkyVar;
|
long longSkyVar;
|
||||||
if (!editVar->GetValue().ToLong(&longSkyVar) || longSkyVar > 0xFFFF)
|
if (!editVar->GetValue().ToLong(&longSkyVar) || longSkyVar > 0xFFFF)
|
||||||
{
|
{
|
||||||
wxMessageDialog id_error(this, "Error Converting Variant!", "Variant Entered is Invalid");
|
wxMessageDialog idError(this, "Error Converting Variant!", "Variant Entered is Invalid");
|
||||||
id_error.ShowModal();
|
idError.ShowModal();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint16 skyId = longSkyId & 0xFFFF;
|
uint16 skyId = longSkyId & 0xFFFF;
|
||||||
@ -284,6 +351,157 @@ wxString CreateSkylanderDialog::GetFilePath() const
|
|||||||
return m_filePath;
|
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()
|
void EmulatedUSBDeviceFrame::UpdateSkylanderEdits()
|
||||||
{
|
{
|
||||||
for (auto i = 0; i < nsyshid::MAX_SKYLANDERS; i++)
|
for (auto i = 0; i < nsyshid::MAX_SKYLANDERS; i++)
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <wx/dialog.h>
|
#include <wx/dialog.h>
|
||||||
#include <wx/frame.h>
|
#include <wx/frame.h>
|
||||||
|
|
||||||
|
#include "Cafe/OS/libs/nsyshid/Infinity.h"
|
||||||
#include "Cafe/OS/libs/nsyshid/Skylander.h"
|
#include "Cafe/OS/libs/nsyshid/Skylander.h"
|
||||||
|
|
||||||
class wxBoxSizer;
|
class wxBoxSizer;
|
||||||
@ -23,15 +24,23 @@ class EmulatedUSBDeviceFrame : public wxFrame {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
wxCheckBox* m_emulatePortal;
|
wxCheckBox* m_emulatePortal;
|
||||||
|
wxCheckBox* m_emulateBase;
|
||||||
std::array<wxTextCtrl*, nsyshid::MAX_SKYLANDERS> m_skylanderSlots;
|
std::array<wxTextCtrl*, nsyshid::MAX_SKYLANDERS> m_skylanderSlots;
|
||||||
|
std::array<wxTextCtrl*, nsyshid::MAX_FIGURES> m_infinitySlots;
|
||||||
std::array<std::optional<std::tuple<uint8, uint16, uint16>>, nsyshid::MAX_SKYLANDERS> m_skySlots;
|
std::array<std::optional<std::tuple<uint8, uint16, uint16>>, nsyshid::MAX_SKYLANDERS> m_skySlots;
|
||||||
|
|
||||||
wxPanel* AddSkylanderPage(wxNotebook* notebook);
|
wxPanel* AddSkylanderPage(wxNotebook* notebook);
|
||||||
|
wxPanel* AddInfinityPage(wxNotebook* notebook);
|
||||||
wxBoxSizer* AddSkylanderRow(uint8 row_number, wxStaticBox* box);
|
wxBoxSizer* AddSkylanderRow(uint8 row_number, wxStaticBox* box);
|
||||||
|
wxBoxSizer* AddInfinityRow(wxString name, uint8 row_number, wxStaticBox* box);
|
||||||
void LoadSkylander(uint8 slot);
|
void LoadSkylander(uint8 slot);
|
||||||
void LoadSkylanderPath(uint8 slot, wxString path);
|
void LoadSkylanderPath(uint8 slot, wxString path);
|
||||||
void CreateSkylander(uint8 slot);
|
void CreateSkylander(uint8 slot);
|
||||||
void ClearSkylander(uint8 slot);
|
void ClearSkylander(uint8 slot);
|
||||||
|
void LoadFigure(uint8 slot);
|
||||||
|
void LoadFigurePath(uint8 slot, wxString path);
|
||||||
|
void CreateFigure(uint8 slot);
|
||||||
|
void ClearFigure(uint8 slot);
|
||||||
void UpdateSkylanderEdits();
|
void UpdateSkylanderEdits();
|
||||||
};
|
};
|
||||||
class CreateSkylanderDialog : public wxDialog {
|
class CreateSkylanderDialog : public wxDialog {
|
||||||
@ -42,3 +51,12 @@ class CreateSkylanderDialog : public wxDialog {
|
|||||||
protected:
|
protected:
|
||||||
wxString m_filePath;
|
wxString m_filePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CreateInfinityFigureDialog : public wxDialog {
|
||||||
|
public:
|
||||||
|
explicit CreateInfinityFigureDialog(wxWindow* parent, uint8 slot);
|
||||||
|
wxString GetFilePath() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
wxString m_filePath;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user