mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-22 09:09:18 +01:00
nsyshid: Skylander emulation fixes and code cleanup (#1244)
This commit is contained in:
parent
93b58ae6f7
commit
aefbb918be
@ -1,5 +1,7 @@
|
|||||||
#include "Skylander.h"
|
#include "Skylander.h"
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#include "nsyshid.h"
|
#include "nsyshid.h"
|
||||||
#include "Backend.h"
|
#include "Backend.h"
|
||||||
|
|
||||||
@ -9,8 +11,8 @@ namespace nsyshid
|
|||||||
{
|
{
|
||||||
SkylanderUSB g_skyportal;
|
SkylanderUSB g_skyportal;
|
||||||
|
|
||||||
const std::map<const std::pair<const uint16, const uint16>, const std::string>
|
const std::map<const std::pair<const uint16, const uint16>, const char*>
|
||||||
listSkylanders = {
|
s_listSkylanders = {
|
||||||
{{0, 0x0000}, "Whirlwind"},
|
{{0, 0x0000}, "Whirlwind"},
|
||||||
{{0, 0x1801}, "Series 2 Whirlwind"},
|
{{0, 0x1801}, "Series 2 Whirlwind"},
|
||||||
{{0, 0x1C02}, "Polar Whirlwind"},
|
{{0, 0x1C02}, "Polar Whirlwind"},
|
||||||
@ -845,6 +847,49 @@ namespace nsyshid
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SkylanderUSB::CreateSkylander(fs::path pathName, uint16 skyId, uint16 skyVar)
|
||||||
|
{
|
||||||
|
FileStream* skyFile(FileStream::createFile2(pathName));
|
||||||
|
if (!skyFile)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<uint8, BLOCK_COUNT * BLOCK_SIZE> data{};
|
||||||
|
|
||||||
|
uint32 first_block = 0x690F0F0F;
|
||||||
|
uint32 other_blocks = 0x69080F7F;
|
||||||
|
memcpy(&data[0x36], &first_block, sizeof(first_block));
|
||||||
|
for (size_t index = 1; index < 0x10; index++)
|
||||||
|
{
|
||||||
|
memcpy(&data[(index * 0x40) + 0x36], &other_blocks, sizeof(other_blocks));
|
||||||
|
}
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 mt(rd());
|
||||||
|
std::uniform_int_distribution<int> dist(0, 255);
|
||||||
|
data[0] = dist(mt);
|
||||||
|
data[1] = dist(mt);
|
||||||
|
data[2] = dist(mt);
|
||||||
|
data[3] = dist(mt);
|
||||||
|
data[4] = data[0] ^ data[1] ^ data[2] ^ data[3];
|
||||||
|
data[5] = 0x81;
|
||||||
|
data[6] = 0x01;
|
||||||
|
data[7] = 0x0F;
|
||||||
|
|
||||||
|
memcpy(&data[0x10], &skyId, sizeof(skyId));
|
||||||
|
memcpy(&data[0x1C], &skyVar, sizeof(skyVar));
|
||||||
|
|
||||||
|
uint16 crc = nsyshid::g_skyportal.SkylanderCRC16(0xFFFF, data.data(), 0x1E);
|
||||||
|
|
||||||
|
memcpy(&data[0x1E], &crc, sizeof(crc));
|
||||||
|
|
||||||
|
skyFile->writeData(data.data(), data.size());
|
||||||
|
|
||||||
|
delete skyFile;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void SkylanderUSB::QueryBlock(uint8 skyNum, uint8 block, uint8* replyBuf)
|
void SkylanderUSB::QueryBlock(uint8 skyNum, uint8 block, uint8* replyBuf)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(m_skyMutex);
|
std::lock_guard lock(m_skyMutex);
|
||||||
@ -865,7 +910,7 @@ namespace nsyshid
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SkylanderUSB::WriteBlock(uint8 skyNum, uint8 block,
|
void SkylanderUSB::WriteBlock(uint8 skyNum, uint8 block,
|
||||||
const uint8* toWriteBuf, uint8* replyBuf)
|
const uint8* toWriteBuf, uint8* replyBuf)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(m_skyMutex);
|
std::lock_guard lock(m_skyMutex);
|
||||||
|
|
||||||
@ -919,21 +964,39 @@ namespace nsyshid
|
|||||||
status |= s.status;
|
status |= s.status;
|
||||||
}
|
}
|
||||||
interruptResponse = {0x53, 0x00, 0x00, 0x00, 0x00, m_interruptCounter++,
|
interruptResponse = {0x53, 0x00, 0x00, 0x00, 0x00, m_interruptCounter++,
|
||||||
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(&interruptResponse[1], &status, sizeof(status));
|
memcpy(&interruptResponse[1], &status, sizeof(status));
|
||||||
}
|
}
|
||||||
return interruptResponse;
|
return interruptResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string SkylanderUSB::FindSkylander(uint16 skyId, uint16 skyVar)
|
||||||
|
{
|
||||||
|
for (const auto& it : GetListSkylanders())
|
||||||
|
{
|
||||||
|
if(it.first.first == skyId && it.first.second == skyVar)
|
||||||
|
{
|
||||||
|
return it.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt::format("Unknown ({} {})", skyId, skyVar);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<const std::pair<const uint16, const uint16>, const char*> SkylanderUSB::GetListSkylanders()
|
||||||
|
{
|
||||||
|
return s_listSkylanders;
|
||||||
|
}
|
||||||
|
|
||||||
void SkylanderUSB::Skylander::Save()
|
void SkylanderUSB::Skylander::Save()
|
||||||
{
|
{
|
||||||
if (!skyFile)
|
if (!skyFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
skyFile->SetPosition(0);
|
||||||
skyFile->writeData(data.data(), data.size());
|
skyFile->writeData(data.data(), data.size());
|
||||||
}
|
}
|
||||||
} // namespace nsyshid
|
} // namespace nsyshid
|
@ -1,3 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include "nsyshid.h"
|
#include "nsyshid.h"
|
||||||
@ -36,7 +38,10 @@ namespace nsyshid
|
|||||||
bool m_IsOpened;
|
bool m_IsOpened;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const std::map<const std::pair<const uint16, const uint16>, const std::string> listSkylanders;
|
constexpr uint16 BLOCK_COUNT = 0x40;
|
||||||
|
constexpr uint16 BLOCK_SIZE = 0x10;
|
||||||
|
constexpr uint16 FIGURE_SIZE = BLOCK_COUNT * BLOCK_SIZE;
|
||||||
|
constexpr uint8 MAX_SKYLANDERS = 16;
|
||||||
|
|
||||||
class SkylanderUSB {
|
class SkylanderUSB {
|
||||||
public:
|
public:
|
||||||
@ -45,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, 0x40 * 0x10> data{};
|
std::array<uint8, BLOCK_COUNT * BLOCK_SIZE> data{};
|
||||||
uint32 lastId = 0;
|
uint32 lastId = 0;
|
||||||
void Save();
|
void Save();
|
||||||
|
|
||||||
@ -74,16 +79,19 @@ namespace nsyshid
|
|||||||
std::array<uint8, 64> GetStatus();
|
std::array<uint8, 64> GetStatus();
|
||||||
void QueryBlock(uint8 skyNum, uint8 block, uint8* replyBuf);
|
void QueryBlock(uint8 skyNum, uint8 block, uint8* replyBuf);
|
||||||
void WriteBlock(uint8 skyNum, uint8 block, const uint8* toWriteBuf,
|
void WriteBlock(uint8 skyNum, uint8 block, const uint8* toWriteBuf,
|
||||||
uint8* replyBuf);
|
uint8* replyBuf);
|
||||||
|
|
||||||
uint8 LoadSkylander(uint8* buf, std::unique_ptr<FileStream> file);
|
uint8 LoadSkylander(uint8* buf, std::unique_ptr<FileStream> file);
|
||||||
bool RemoveSkylander(uint8 skyNum);
|
bool RemoveSkylander(uint8 skyNum);
|
||||||
|
bool CreateSkylander(fs::path pathName, uint16 skyId, uint16 skyVar);
|
||||||
uint16 SkylanderCRC16(uint16 initValue, const uint8* buffer, uint32 size);
|
uint16 SkylanderCRC16(uint16 initValue, const uint8* buffer, uint32 size);
|
||||||
|
static std::map<const std::pair<const uint16, const uint16>, const char*> GetListSkylanders();
|
||||||
|
std::string FindSkylander(uint16 skyId, uint16 skyVar);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::mutex m_skyMutex;
|
std::mutex m_skyMutex;
|
||||||
std::mutex m_queryMutex;
|
std::mutex m_queryMutex;
|
||||||
std::array<Skylander, 16> m_skylanders;
|
std::array<Skylander, MAX_SKYLANDERS> m_skylanders;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::queue<std::array<uint8, 64>> m_queries;
|
std::queue<std::array<uint8, 64>> m_queries;
|
||||||
@ -92,7 +100,6 @@ namespace nsyshid
|
|||||||
SkylanderLEDColor m_colorRight = {};
|
SkylanderLEDColor m_colorRight = {};
|
||||||
SkylanderLEDColor m_colorLeft = {};
|
SkylanderLEDColor m_colorLeft = {};
|
||||||
SkylanderLEDColor m_colorTrap = {};
|
SkylanderLEDColor m_colorTrap = {};
|
||||||
|
|
||||||
};
|
};
|
||||||
extern SkylanderUSB g_skyportal;
|
extern SkylanderUSB g_skyportal;
|
||||||
} // namespace nsyshid
|
} // namespace nsyshid
|
@ -1,7 +1,6 @@
|
|||||||
#include "gui/EmulatedUSBDevices/EmulatedUSBDeviceFrame.h"
|
#include "gui/EmulatedUSBDevices/EmulatedUSBDeviceFrame.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <random>
|
|
||||||
|
|
||||||
#include "config/CemuConfig.h"
|
#include "config/CemuConfig.h"
|
||||||
#include "gui/helpers/wxHelpers.h"
|
#include "gui/helpers/wxHelpers.h"
|
||||||
@ -9,7 +8,6 @@
|
|||||||
#include "util/helpers/helpers.h"
|
#include "util/helpers/helpers.h"
|
||||||
|
|
||||||
#include "Cafe/OS/libs/nsyshid/nsyshid.h"
|
#include "Cafe/OS/libs/nsyshid/nsyshid.h"
|
||||||
#include "Cafe/OS/libs/nsyshid/Skylander.h"
|
|
||||||
|
|
||||||
#include "Common/FileStream.h"
|
#include "Common/FileStream.h"
|
||||||
|
|
||||||
@ -75,7 +73,7 @@ wxPanel* EmulatedUSBDeviceFrame::AddSkylanderPage(wxNotebook* notebook)
|
|||||||
});
|
});
|
||||||
row->Add(m_emulatePortal, 1, wxEXPAND | wxALL, 2);
|
row->Add(m_emulatePortal, 1, wxEXPAND | wxALL, 2);
|
||||||
boxSizer->Add(row, 1, wxEXPAND | wxALL, 2);
|
boxSizer->Add(row, 1, wxEXPAND | wxALL, 2);
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < nsyshid::MAX_SKYLANDERS; i++)
|
||||||
{
|
{
|
||||||
boxSizer->Add(AddSkylanderRow(i, box), 1, wxEXPAND | wxALL, 2);
|
boxSizer->Add(AddSkylanderRow(i, box), 1, wxEXPAND | wxALL, 2);
|
||||||
}
|
}
|
||||||
@ -153,7 +151,7 @@ void EmulatedUSBDeviceFrame::LoadSkylanderPath(uint8 slot, wxString path)
|
|||||||
uint16 skyVar = uint16(fileData[0x1D]) << 8 | uint16(fileData[0x1C]);
|
uint16 skyVar = uint16(fileData[0x1D]) << 8 | uint16(fileData[0x1C]);
|
||||||
|
|
||||||
uint8 portalSlot = nsyshid::g_skyportal.LoadSkylander(fileData.data(),
|
uint8 portalSlot = nsyshid::g_skyportal.LoadSkylander(fileData.data(),
|
||||||
std::move(skyFile));
|
std::move(skyFile));
|
||||||
m_skySlots[slot] = std::tuple(portalSlot, skyId, skyVar);
|
m_skySlots[slot] = std::tuple(portalSlot, skyId, skyVar);
|
||||||
UpdateSkylanderEdits();
|
UpdateSkylanderEdits();
|
||||||
}
|
}
|
||||||
@ -189,11 +187,11 @@ CreateSkylanderDialog::CreateSkylanderDialog(wxWindow* parent, uint8 slot)
|
|||||||
auto* comboBox = new wxComboBox(this, wxID_ANY);
|
auto* comboBox = new wxComboBox(this, wxID_ANY);
|
||||||
comboBox->Append("---Select---", reinterpret_cast<void*>(0xFFFFFFFF));
|
comboBox->Append("---Select---", reinterpret_cast<void*>(0xFFFFFFFF));
|
||||||
wxArrayString filterlist;
|
wxArrayString filterlist;
|
||||||
for (auto it = nsyshid::listSkylanders.begin(); it != nsyshid::listSkylanders.end(); it++)
|
for (const auto& it : nsyshid::g_skyportal.GetListSkylanders())
|
||||||
{
|
{
|
||||||
const uint32 variant = uint32(uint32(it->first.first) << 16) | uint32(it->first.second);
|
const uint32 variant = uint32(uint32(it.first.first) << 16) | uint32(it.first.second);
|
||||||
comboBox->Append(it->second, reinterpret_cast<void*>(variant));
|
comboBox->Append(it.second, reinterpret_cast<void*>(variant));
|
||||||
filterlist.Add(it->second);
|
filterlist.Add(it.second);
|
||||||
}
|
}
|
||||||
comboBox->SetSelection(0);
|
comboBox->SetSelection(0);
|
||||||
bool enabled = comboBox->AutoComplete(filterlist);
|
bool enabled = comboBox->AutoComplete(filterlist);
|
||||||
@ -233,16 +231,7 @@ CreateSkylanderDialog::CreateSkylanderDialog(wxWindow* parent, uint8 slot)
|
|||||||
}
|
}
|
||||||
uint16 skyId = longSkyId & 0xFFFF;
|
uint16 skyId = longSkyId & 0xFFFF;
|
||||||
uint16 skyVar = longSkyVar & 0xFFFF;
|
uint16 skyVar = longSkyVar & 0xFFFF;
|
||||||
const auto foundSky = nsyshid::listSkylanders.find(std::make_pair(skyId, skyVar));
|
wxString predefName = nsyshid::g_skyportal.FindSkylander(skyId, skyVar) + ".sky";
|
||||||
wxString predefName;
|
|
||||||
if (foundSky != nsyshid::listSkylanders.end())
|
|
||||||
{
|
|
||||||
predefName = foundSky->second + ".sky";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
predefName = wxString::Format(_("Unknown(%i %i).sky"), skyId, skyVar);
|
|
||||||
}
|
|
||||||
wxFileDialog
|
wxFileDialog
|
||||||
saveFileDialog(this, _("Create Skylander file"), "", predefName,
|
saveFileDialog(this, _("Create Skylander file"), "", predefName,
|
||||||
"SKY files (*.sky)|*.sky", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
"SKY files (*.sky)|*.sky", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
||||||
@ -252,45 +241,14 @@ CreateSkylanderDialog::CreateSkylanderDialog(wxWindow* parent, uint8 slot)
|
|||||||
|
|
||||||
m_filePath = saveFileDialog.GetPath();
|
m_filePath = saveFileDialog.GetPath();
|
||||||
|
|
||||||
wxFileOutputStream output_stream(saveFileDialog.GetPath());
|
if(!nsyshid::g_skyportal.CreateSkylander(_utf8ToPath(m_filePath.utf8_string()), skyId, skyVar))
|
||||||
if (!output_stream.IsOk())
|
|
||||||
{
|
{
|
||||||
wxMessageDialog saveError(this, "Error Creating Skylander File");
|
wxMessageDialog errorMessage(this, "Failed to create file");
|
||||||
|
errorMessage.ShowModal();
|
||||||
|
this->EndModal(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<uint8, 0x40 * 0x10> data{};
|
|
||||||
|
|
||||||
uint32 first_block = 0x690F0F0F;
|
|
||||||
uint32 other_blocks = 0x69080F7F;
|
|
||||||
memcpy(&data[0x36], &first_block, sizeof(first_block));
|
|
||||||
for (size_t index = 1; index < 0x10; index++)
|
|
||||||
{
|
|
||||||
memcpy(&data[(index * 0x40) + 0x36], &other_blocks, sizeof(other_blocks));
|
|
||||||
}
|
|
||||||
std::random_device rd;
|
|
||||||
std::mt19937 mt(rd());
|
|
||||||
std::uniform_int_distribution<int> dist(0, 255);
|
|
||||||
data[0] = dist(mt);
|
|
||||||
data[1] = dist(mt);
|
|
||||||
data[2] = dist(mt);
|
|
||||||
data[3] = dist(mt);
|
|
||||||
data[4] = data[0] ^ data[1] ^ data[2] ^ data[3];
|
|
||||||
data[5] = 0x81;
|
|
||||||
data[6] = 0x01;
|
|
||||||
data[7] = 0x0F;
|
|
||||||
|
|
||||||
memcpy(&data[0x10], &skyId, sizeof(skyId));
|
|
||||||
memcpy(&data[0x1C], &skyVar, sizeof(skyVar));
|
|
||||||
|
|
||||||
uint16 crc = nsyshid::g_skyportal.SkylanderCRC16(0xFFFF, data.data(), 0x1E);
|
|
||||||
|
|
||||||
memcpy(&data[0x1E], &crc, sizeof(crc));
|
|
||||||
|
|
||||||
output_stream.SeekO(0);
|
|
||||||
output_stream.WriteAll(data.data(), data.size());
|
|
||||||
output_stream.Close();
|
|
||||||
|
|
||||||
this->EndModal(1);
|
this->EndModal(1);
|
||||||
});
|
});
|
||||||
auto* cancelButton = new wxButton(this, wxID_ANY, _("Cancel"));
|
auto* cancelButton = new wxButton(this, wxID_ANY, _("Cancel"));
|
||||||
@ -328,21 +286,13 @@ wxString CreateSkylanderDialog::GetFilePath() const
|
|||||||
|
|
||||||
void EmulatedUSBDeviceFrame::UpdateSkylanderEdits()
|
void EmulatedUSBDeviceFrame::UpdateSkylanderEdits()
|
||||||
{
|
{
|
||||||
for (auto i = 0; i < 16; i++)
|
for (auto i = 0; i < nsyshid::MAX_SKYLANDERS; i++)
|
||||||
{
|
{
|
||||||
std::string displayString;
|
std::string displayString;
|
||||||
if (auto sd = m_skySlots[i])
|
if (auto sd = m_skySlots[i])
|
||||||
{
|
{
|
||||||
auto [portalSlot, skyId, skyVar] = sd.value();
|
auto [portalSlot, skyId, skyVar] = sd.value();
|
||||||
auto foundSky = nsyshid::listSkylanders.find(std::make_pair(skyId, skyVar));
|
displayString = nsyshid::g_skyportal.FindSkylander(skyId, skyVar);
|
||||||
if (foundSky != nsyshid::listSkylanders.end())
|
|
||||||
{
|
|
||||||
displayString = foundSky->second;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
displayString = fmt::format("Unknown (Id:{} Var:{})", skyId, skyVar);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#include <wx/dialog.h>
|
#include <wx/dialog.h>
|
||||||
#include <wx/frame.h>
|
#include <wx/frame.h>
|
||||||
|
|
||||||
|
#include "Cafe/OS/libs/nsyshid/Skylander.h"
|
||||||
|
|
||||||
class wxBoxSizer;
|
class wxBoxSizer;
|
||||||
class wxCheckBox;
|
class wxCheckBox;
|
||||||
class wxFlexGridSizer;
|
class wxFlexGridSizer;
|
||||||
@ -21,8 +23,8 @@ class EmulatedUSBDeviceFrame : public wxFrame {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
wxCheckBox* m_emulatePortal;
|
wxCheckBox* m_emulatePortal;
|
||||||
std::array<wxTextCtrl*, 16> m_skylanderSlots;
|
std::array<wxTextCtrl*, nsyshid::MAX_SKYLANDERS> m_skylanderSlots;
|
||||||
std::array<std::optional<std::tuple<uint8, uint16, uint16>>, 16> m_skySlots;
|
std::array<std::optional<std::tuple<uint8, uint16, uint16>>, nsyshid::MAX_SKYLANDERS> m_skySlots;
|
||||||
|
|
||||||
wxPanel* AddSkylanderPage(wxNotebook* notebook);
|
wxPanel* AddSkylanderPage(wxNotebook* notebook);
|
||||||
wxBoxSizer* AddSkylanderRow(uint8 row_number, wxStaticBox* box);
|
wxBoxSizer* AddSkylanderRow(uint8 row_number, wxStaticBox* box);
|
||||||
|
Loading…
Reference in New Issue
Block a user