mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-25 12:12:50 +01:00
sys_usbd: Emulate Disney Infinity Base
This commit is contained in:
parent
911cd678ff
commit
8e15afb2c4
@ -395,6 +395,7 @@ target_sources(rpcs3_emu PRIVATE
|
|||||||
Io/PadHandler.cpp
|
Io/PadHandler.cpp
|
||||||
Io/usb_device.cpp
|
Io/usb_device.cpp
|
||||||
Io/usb_vfs.cpp
|
Io/usb_vfs.cpp
|
||||||
|
Io/Infinity.cpp
|
||||||
Io/Skylander.cpp
|
Io/Skylander.cpp
|
||||||
Io/GHLtar.cpp
|
Io/GHLtar.cpp
|
||||||
Io/Buzz.cpp
|
Io/Buzz.cpp
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "Emu/Io/usb_device.h"
|
#include "Emu/Io/usb_device.h"
|
||||||
#include "Emu/Io/usb_vfs.h"
|
#include "Emu/Io/usb_vfs.h"
|
||||||
#include "Emu/Io/Skylander.h"
|
#include "Emu/Io/Skylander.h"
|
||||||
|
#include "Emu/Io/Infinity.h"
|
||||||
#include "Emu/Io/GHLtar.h"
|
#include "Emu/Io/GHLtar.h"
|
||||||
#include "Emu/Io/Buzz.h"
|
#include "Emu/Io/Buzz.h"
|
||||||
#include "Emu/Io/Turntable.h"
|
#include "Emu/Io/Turntable.h"
|
||||||
@ -179,6 +180,7 @@ usb_handler_thread::usb_handler_thread()
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool found_skylander = false;
|
bool found_skylander = false;
|
||||||
|
bool found_infinity = false;
|
||||||
bool found_usio = false;
|
bool found_usio = false;
|
||||||
bool found_h050 = false;
|
bool found_h050 = false;
|
||||||
|
|
||||||
@ -210,8 +212,12 @@ usb_handler_thread::usb_handler_thread()
|
|||||||
found_skylander = true;
|
found_skylander = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (check_device(0x0E6F, 0x0129, 0x0129, "Disney Infinity Base"))
|
||||||
|
{
|
||||||
|
found_infinity = true;
|
||||||
|
}
|
||||||
|
|
||||||
check_device(0x0E6F, 0x0241, 0x0241, "Lego Dimensions Portal");
|
check_device(0x0E6F, 0x0241, 0x0241, "Lego Dimensions Portal");
|
||||||
check_device(0x0E6F, 0x0129, 0x0129, "Disney Infinity Portal");
|
|
||||||
check_device(0x0E6F, 0x200A, 0x200A, "Kamen Rider Summonride Portal");
|
check_device(0x0E6F, 0x200A, 0x200A, "Kamen Rider Summonride Portal");
|
||||||
|
|
||||||
// Cameras
|
// Cameras
|
||||||
@ -297,6 +303,12 @@ usb_handler_thread::usb_handler_thread()
|
|||||||
usb_devices.push_back(std::make_shared<usb_device_skylander>(get_new_location()));
|
usb_devices.push_back(std::make_shared<usb_device_skylander>(get_new_location()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!found_infinity)
|
||||||
|
{
|
||||||
|
sys_usbd.notice("Adding emulated infinity base");
|
||||||
|
usb_devices.push_back(std::make_shared<usb_device_infinity>(get_new_location()));
|
||||||
|
}
|
||||||
|
|
||||||
if (!found_usio && !found_h050) // Only one of these two IO boards should be present at the same time; otherwise, an exception will be thrown by the game.
|
if (!found_usio && !found_h050) // Only one of these two IO boards should be present at the same time; otherwise, an exception will be thrown by the game.
|
||||||
{
|
{
|
||||||
sys_usbd.notice("Adding emulated v406 usio");
|
sys_usbd.notice("Adding emulated v406 usio");
|
||||||
|
457
rpcs3/Emu/Io/Infinity.cpp
Normal file
457
rpcs3/Emu/Io/Infinity.cpp
Normal file
@ -0,0 +1,457 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
#include "Infinity.h"
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
|
|
||||||
|
#include "Crypto/aes.h"
|
||||||
|
#include "Crypto/sha1.h"
|
||||||
|
#include "util/asm.hpp"
|
||||||
|
|
||||||
|
LOG_CHANNEL(infinity_log, "infinity");
|
||||||
|
|
||||||
|
infinity_base g_infinitybase;
|
||||||
|
|
||||||
|
static constexpr std::array<u8, 32> SHA1_CONSTANT = {
|
||||||
|
0xAF, 0x62, 0xD2, 0xEC, 0x04, 0x91, 0x96, 0x8C, 0xC5, 0x2A, 0x1A, 0x71, 0x65, 0xF8, 0x65, 0xFE,
|
||||||
|
0x28, 0x63, 0x29, 0x20, 0x44, 0x69, 0x73, 0x6e, 0x65, 0x79, 0x20, 0x32, 0x30, 0x31, 0x33};
|
||||||
|
|
||||||
|
void infinity_figure::save()
|
||||||
|
{
|
||||||
|
if (!inf_file)
|
||||||
|
{
|
||||||
|
infinity_log.error("Tried to save infinity figure to file but no infinity figure is active!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inf_file.seek(0, fs::seek_set);
|
||||||
|
inf_file.write(data.data(), 0x14 * 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 infinity_base::generate_checksum(const std::array<u8, 32>& data, int num_of_bytes) const
|
||||||
|
{
|
||||||
|
int checksum = 0;
|
||||||
|
for (int i = 0; i < num_of_bytes; i++)
|
||||||
|
{
|
||||||
|
checksum += data[i];
|
||||||
|
}
|
||||||
|
return (checksum & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void infinity_base::get_blank_response(u8 sequence, std::array<u8, 32>& reply_buf)
|
||||||
|
{
|
||||||
|
reply_buf[0] = 0xaa;
|
||||||
|
reply_buf[1] = 0x01;
|
||||||
|
reply_buf[2] = sequence;
|
||||||
|
reply_buf[3] = generate_checksum(reply_buf, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void infinity_base::descramble_and_seed(u8* buf, u8 sequence, std::array<u8, 32>& reply_buf)
|
||||||
|
{
|
||||||
|
u64 value = u64(buf[4]) << 56 | u64(buf[5]) << 48 | u64(buf[6]) << 40 | u64(buf[7]) << 32 |
|
||||||
|
u64(buf[8]) << 24 | u64(buf[9]) << 16 | u64(buf[10]) << 8 | u64(buf[11]);
|
||||||
|
u32 seed = descramble(value);
|
||||||
|
generate_seed(seed);
|
||||||
|
get_blank_response(sequence, reply_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void infinity_base::get_next_and_scramble(u8 sequence, std::array<u8, 32>& reply_buf)
|
||||||
|
{
|
||||||
|
const u32 next_random = get_next();
|
||||||
|
const u64 scrambled_next_random = scramble(next_random, 0);
|
||||||
|
reply_buf = {0xAA, 0x09, sequence};
|
||||||
|
reply_buf[3] = u8((scrambled_next_random >> 56) & 0xFF);
|
||||||
|
reply_buf[4] = u8((scrambled_next_random >> 48) & 0xFF);
|
||||||
|
reply_buf[5] = u8((scrambled_next_random >> 40) & 0xFF);
|
||||||
|
reply_buf[6] = u8((scrambled_next_random >> 32) & 0xFF);
|
||||||
|
reply_buf[7] = u8((scrambled_next_random >> 24) & 0xFF);
|
||||||
|
reply_buf[8] = u8((scrambled_next_random >> 16) & 0xFF);
|
||||||
|
reply_buf[9] = u8((scrambled_next_random >> 8) & 0xFF);
|
||||||
|
reply_buf[10] = u8(scrambled_next_random & 0xFF);
|
||||||
|
reply_buf[11] = generate_checksum(reply_buf, 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 infinity_base::descramble(u64 num_to_descramble)
|
||||||
|
{
|
||||||
|
u64 mask = 0x8E55AA1B3999E8AA;
|
||||||
|
u32 ret = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
if (mask & 0x8000000000000000)
|
||||||
|
{
|
||||||
|
ret = (ret << 1) | (num_to_descramble & 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
num_to_descramble >>= 1;
|
||||||
|
mask <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 infinity_base::scramble(u32 num_to_scramble, u32 garbage)
|
||||||
|
{
|
||||||
|
u64 mask = 0x8E55AA1B3999E8AA;
|
||||||
|
u64 ret = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
ret <<= 1;
|
||||||
|
|
||||||
|
if ((mask & 1) != 0)
|
||||||
|
{
|
||||||
|
ret |= (num_to_scramble & 1);
|
||||||
|
num_to_scramble >>= 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret |= (garbage & 1);
|
||||||
|
garbage >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void infinity_base::generate_seed(u32 seed)
|
||||||
|
{
|
||||||
|
random_a = 0xF1EA5EED;
|
||||||
|
random_b = seed;
|
||||||
|
random_c = seed;
|
||||||
|
random_d = seed;
|
||||||
|
|
||||||
|
for (int i = 0; i < 23; i++)
|
||||||
|
{
|
||||||
|
get_next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 infinity_base::get_next()
|
||||||
|
{
|
||||||
|
u32 a = random_a;
|
||||||
|
u32 b = random_b;
|
||||||
|
u32 c = random_c;
|
||||||
|
u32 ret = std::rotl(random_b, 27);
|
||||||
|
|
||||||
|
const u32 temp = (a + ((ret ^ 0xFFFFFFFF) + 1));
|
||||||
|
b ^= std::rotl(c, 17);
|
||||||
|
a = random_d;
|
||||||
|
c += a;
|
||||||
|
ret = b + temp;
|
||||||
|
a += temp;
|
||||||
|
|
||||||
|
random_c = a;
|
||||||
|
random_a = b;
|
||||||
|
random_b = c;
|
||||||
|
random_d = ret;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void infinity_base::get_present_figures(u8 sequence, std::array<u8, 32>& reply_buf)
|
||||||
|
{
|
||||||
|
int x = 3;
|
||||||
|
for (u8 i = 0; i < figures.size(); i++)
|
||||||
|
{
|
||||||
|
u8 slot = i == 0 ? 0x10 : (i < 4) ? 0x20 :
|
||||||
|
0x30;
|
||||||
|
if (figures[i].present)
|
||||||
|
{
|
||||||
|
reply_buf[x] = slot + figures[i].order_added;
|
||||||
|
reply_buf[x + 1] = 0x09;
|
||||||
|
x += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reply_buf[0] = 0xaa;
|
||||||
|
reply_buf[1] = x - 2;
|
||||||
|
reply_buf[2] = sequence;
|
||||||
|
reply_buf[x] = generate_checksum(reply_buf, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
infinity_figure& infinity_base::get_figure_by_order(u8 order_added)
|
||||||
|
{
|
||||||
|
for (u8 i = 0; i < figures.size(); i++)
|
||||||
|
{
|
||||||
|
if (figures[i].order_added == order_added)
|
||||||
|
{
|
||||||
|
return figures[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return figures[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 infinity_base::derive_figure_position(u8 position)
|
||||||
|
{
|
||||||
|
while (position > 2)
|
||||||
|
position -= 2;
|
||||||
|
|
||||||
|
position++;
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void infinity_base::query_block(u8 fig_num, u8 block, std::array<u8, 32>& reply_buf, u8 sequence)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(infinity_mutex);
|
||||||
|
|
||||||
|
infinity_figure& figure = get_figure_by_order(fig_num);
|
||||||
|
|
||||||
|
reply_buf[0] = 0xaa;
|
||||||
|
reply_buf[1] = 0x12;
|
||||||
|
reply_buf[2] = sequence;
|
||||||
|
reply_buf[3] = 0x00;
|
||||||
|
const u8 file_block = (block == 0) ? 1 : (block * 4);
|
||||||
|
if (figure.present && file_block < 20)
|
||||||
|
{
|
||||||
|
memcpy(&reply_buf[4], figure.data.data() + (16 * file_block), 16);
|
||||||
|
}
|
||||||
|
reply_buf[20] = generate_checksum(reply_buf, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
void infinity_base::write_block(u8 fig_num, u8 block, const u8* to_write_buf,
|
||||||
|
std::array<u8, 32>& reply_buf, u8 sequence)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(infinity_mutex);
|
||||||
|
|
||||||
|
infinity_figure& figure = get_figure_by_order(fig_num);
|
||||||
|
|
||||||
|
reply_buf[0] = 0xaa;
|
||||||
|
reply_buf[1] = 0x02;
|
||||||
|
reply_buf[2] = sequence;
|
||||||
|
reply_buf[3] = 0x00;
|
||||||
|
const u8 file_block = (block == 0) ? 1 : (block * 4);
|
||||||
|
if (figure.present && file_block < 20)
|
||||||
|
{
|
||||||
|
memcpy(figure.data.data() + (file_block * 16), to_write_buf, 16);
|
||||||
|
figure.save();
|
||||||
|
}
|
||||||
|
reply_buf[4] = generate_checksum(reply_buf, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void infinity_base::get_figure_identifier(u8 fig_num, u8 sequence, std::array<u8, 32>& reply_buf)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(infinity_mutex);
|
||||||
|
|
||||||
|
infinity_figure& figure = get_figure_by_order(fig_num);
|
||||||
|
|
||||||
|
reply_buf[0] = 0xaa;
|
||||||
|
reply_buf[1] = 0x09;
|
||||||
|
reply_buf[2] = sequence;
|
||||||
|
reply_buf[3] = 0x00;
|
||||||
|
|
||||||
|
if (figure.present)
|
||||||
|
{
|
||||||
|
memcpy(&reply_buf[4], figure.data.data(), 7);
|
||||||
|
}
|
||||||
|
reply_buf[11] = generate_checksum(reply_buf, 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool infinity_base::has_figure_been_added_removed() const
|
||||||
|
{
|
||||||
|
return !m_figure_added_removed_responses.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<u8, 32> infinity_base::pop_added_removed_response()
|
||||||
|
{
|
||||||
|
std::array<u8, 32> response = m_figure_added_removed_responses.front();
|
||||||
|
m_figure_added_removed_responses.pop();
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool infinity_base::remove_figure(u8 position)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(infinity_mutex);
|
||||||
|
infinity_figure& figure = figures[position];
|
||||||
|
|
||||||
|
if (figure.present)
|
||||||
|
{
|
||||||
|
figure.present = false;
|
||||||
|
|
||||||
|
position = derive_figure_position(position);
|
||||||
|
|
||||||
|
std::array<u8, 32> figure_change_response = {0xab, 0x04, position, 0x09, figure.order_added,
|
||||||
|
0x01};
|
||||||
|
figure_change_response[6] = generate_checksum(figure_change_response, 6);
|
||||||
|
m_figure_added_removed_responses.push(figure_change_response);
|
||||||
|
|
||||||
|
figure.save();
|
||||||
|
figure.inf_file.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 infinity_base::load_figure(const std::array<u8, 0x14 * 0x10>& buf, fs::file in_file, u8 position)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(infinity_mutex);
|
||||||
|
u8 order_added;
|
||||||
|
|
||||||
|
std::vector<u8> sha1_calc = {SHA1_CONSTANT.begin(), SHA1_CONSTANT.end() - 1};
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
sha1_calc.push_back(buf[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sha1_context ctx;
|
||||||
|
u8 output[20];
|
||||||
|
|
||||||
|
sha1_starts(&ctx);
|
||||||
|
sha1_update(&ctx, sha1_calc.data(), sha1_calc.size());
|
||||||
|
sha1_finish(&ctx, output);
|
||||||
|
|
||||||
|
std::array<u8, 16> key{};
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < 4; x++)
|
||||||
|
{
|
||||||
|
key[x + (i * 4)] = output[(3 - x) + (i * 4)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aes_context aes;
|
||||||
|
aes_setkey_dec(&aes, key.data(), 128);
|
||||||
|
std::array<u8, 16> infinity_decrypted_block{};
|
||||||
|
aes_crypt_ecb(&aes, AES_DECRYPT, &buf[16], infinity_decrypted_block.data());
|
||||||
|
|
||||||
|
u32 number = u32(infinity_decrypted_block[1]) << 16 | u32(infinity_decrypted_block[2]) << 8 |
|
||||||
|
u32(infinity_decrypted_block[3]);
|
||||||
|
|
||||||
|
infinity_figure& figure = figures[position];
|
||||||
|
|
||||||
|
figure.inf_file = std::move(in_file);
|
||||||
|
memcpy(figure.data.data(), buf.data(), figure.data.size());
|
||||||
|
figure.present = true;
|
||||||
|
if (figure.order_added == 255)
|
||||||
|
{
|
||||||
|
figure.order_added = m_figure_order;
|
||||||
|
m_figure_order++;
|
||||||
|
}
|
||||||
|
order_added = figure.order_added;
|
||||||
|
|
||||||
|
position = derive_figure_position(position);
|
||||||
|
|
||||||
|
std::array<u8, 32> figure_change_response = {0xab, 0x04, position, 0x09, order_added, 0x00};
|
||||||
|
figure_change_response[6] = generate_checksum(figure_change_response, 6);
|
||||||
|
m_figure_added_removed_responses.push(figure_change_response);
|
||||||
|
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_device_infinity::usb_device_infinity(const std::array<u8, 7>& location)
|
||||||
|
: usb_device_emulated(location)
|
||||||
|
{
|
||||||
|
device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x200, 0x0, 0x0, 0x0, 0x20, 0x0E6F, 0x0129, 0x200, 0x1, 0x2, 0x3, 0x1});
|
||||||
|
auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, UsbDeviceConfiguration{0x29, 0x1, 0x1, 0x0, 0x80, 0xFA}));
|
||||||
|
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, UsbDeviceInterface{0x0, 0x0, 0x2, 0x3, 0x0, 0x0, 0x0}));
|
||||||
|
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, UsbDeviceHID{0x0111, 0x00, 0x01, 0x22, 0x001d}));
|
||||||
|
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x81, 0x3, 0x20, 0x1}));
|
||||||
|
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x1, 0x3, 0x20, 0x1}));
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_device_infinity::~usb_device_infinity()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_device_infinity::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer)
|
||||||
|
{
|
||||||
|
usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_device_infinity::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer)
|
||||||
|
{
|
||||||
|
ensure(buf_size == 0x20);
|
||||||
|
|
||||||
|
transfer->fake = true;
|
||||||
|
transfer->expected_count = buf_size;
|
||||||
|
transfer->expected_result = HC_CC_NOERR;
|
||||||
|
|
||||||
|
if (endpoint == 0x81)
|
||||||
|
{
|
||||||
|
// Respond after FF command
|
||||||
|
transfer->expected_time = get_timestamp() + 1000;
|
||||||
|
if (g_infinitybase.has_figure_been_added_removed())
|
||||||
|
{
|
||||||
|
memcpy(buf, g_infinitybase.pop_added_removed_response().data(), 0x20);
|
||||||
|
}
|
||||||
|
else if (!m_queries.empty())
|
||||||
|
{
|
||||||
|
memcpy(buf, m_queries.front().data(), 0x20);
|
||||||
|
m_queries.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (endpoint == 0x01)
|
||||||
|
{
|
||||||
|
const u8 command = buf[2];
|
||||||
|
const u8 sequence = buf[3];
|
||||||
|
|
||||||
|
transfer->expected_time = get_timestamp() + 500;
|
||||||
|
std::array<u8, 32> q_result{};
|
||||||
|
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case 0x80:
|
||||||
|
{
|
||||||
|
q_result = {0xaa, 0x15, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x03, 0x02, 0x09, 0x09, 0x43,
|
||||||
|
0x20, 0x32, 0x62, 0x36, 0x36, 0x4b, 0x34, 0x99, 0x67, 0x31, 0x93, 0x8c};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x81:
|
||||||
|
{
|
||||||
|
// Initiate Challenge
|
||||||
|
g_infinitybase.descramble_and_seed(buf, sequence, q_result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x83:
|
||||||
|
{
|
||||||
|
// Challenge Response
|
||||||
|
g_infinitybase.get_next_and_scramble(sequence, q_result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x90:
|
||||||
|
case 0x92:
|
||||||
|
case 0x93:
|
||||||
|
case 0x95:
|
||||||
|
case 0x96:
|
||||||
|
{
|
||||||
|
// Color commands
|
||||||
|
g_infinitybase.get_blank_response(sequence, q_result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0xA1:
|
||||||
|
{
|
||||||
|
// Get Present Figures
|
||||||
|
g_infinitybase.get_present_figures(sequence, q_result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0xA2:
|
||||||
|
{
|
||||||
|
// Read Block from Figure
|
||||||
|
g_infinitybase.query_block(buf[4], buf[5], q_result, sequence);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0xA3:
|
||||||
|
{
|
||||||
|
// Write block to figure
|
||||||
|
g_infinitybase.write_block(buf[4], buf[5], &buf[7], q_result, sequence);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0xB4:
|
||||||
|
{
|
||||||
|
// Get figure ID
|
||||||
|
g_infinitybase.get_figure_identifier(buf[4], sequence, q_result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0xB5:
|
||||||
|
{
|
||||||
|
// Get status?
|
||||||
|
g_infinitybase.get_blank_response(sequence, q_result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
infinity_log.error("Unhandled Query Type: 0x%02X", command);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_queries.push(q_result);
|
||||||
|
}
|
||||||
|
}
|
68
rpcs3/Emu/Io/Infinity.h
Normal file
68
rpcs3/Emu/Io/Infinity.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Emu/Io/usb_device.h"
|
||||||
|
#include "Utilities/mutex.h"
|
||||||
|
#include <array>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
struct infinity_figure
|
||||||
|
{
|
||||||
|
fs::file inf_file;
|
||||||
|
std::array<u8, 0x14 * 0x10> data{};
|
||||||
|
bool present = false;
|
||||||
|
u8 order_added = 255;
|
||||||
|
void save();
|
||||||
|
};
|
||||||
|
|
||||||
|
class infinity_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void get_blank_response(u8 sequence, std::array<u8, 32>& reply_buf);
|
||||||
|
void descramble_and_seed(u8* buf, u8 sequence, std::array<u8, 32>& reply_buf);
|
||||||
|
void get_next_and_scramble(u8 sequence, std::array<u8, 32>& reply_buf);
|
||||||
|
void get_present_figures(u8 sequence, std::array<u8, 32>& reply_buf);
|
||||||
|
void query_block(u8 fig_num, u8 block, std::array<u8, 32>& reply_buf, u8 sequence);
|
||||||
|
void write_block(u8 fig_num, u8 block, const u8* to_write_buf, std::array<u8, 32>& reply_buf, u8 sequence);
|
||||||
|
void get_figure_identifier(u8 fig_num, u8 sequence, std::array<u8, 32>& reply_buf);
|
||||||
|
bool has_figure_been_added_removed() const;
|
||||||
|
std::array<u8, 32> pop_added_removed_response();
|
||||||
|
|
||||||
|
bool remove_figure(u8 position);
|
||||||
|
u32 load_figure(const std::array<u8, 0x14 * 0x10>& buf, fs::file in_file, u8 position);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
shared_mutex infinity_mutex;
|
||||||
|
std::array<infinity_figure, 7> figures;
|
||||||
|
|
||||||
|
private:
|
||||||
|
u8 generate_checksum(const std::array<u8, 32>& data, int num_of_bytes) const;
|
||||||
|
u32 descramble(u64 num_to_descramble);
|
||||||
|
u64 scramble(u32 num_to_scramble, u32 garbage);
|
||||||
|
void generate_seed(u32 seed);
|
||||||
|
u32 get_next();
|
||||||
|
infinity_figure& get_figure_by_order(u8 order_added);
|
||||||
|
u8 derive_figure_position(u8 position);
|
||||||
|
|
||||||
|
u32 random_a;
|
||||||
|
u32 random_b;
|
||||||
|
u32 random_c;
|
||||||
|
u32 random_d;
|
||||||
|
|
||||||
|
u8 m_figure_order = 0;
|
||||||
|
std::queue<std::array<u8, 32>> m_figure_added_removed_responses;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern infinity_base g_infinitybase;
|
||||||
|
|
||||||
|
class usb_device_infinity : public usb_device_emulated
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
usb_device_infinity(const std::array<u8, 7>& location);
|
||||||
|
~usb_device_infinity();
|
||||||
|
|
||||||
|
void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) override;
|
||||||
|
void interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::queue<std::array<u8, 32>> m_queries;
|
||||||
|
};
|
@ -380,6 +380,7 @@
|
|||||||
<ClCompile Include="Emu\Cell\SPUDisAsm.cpp" />
|
<ClCompile Include="Emu\Cell\SPUDisAsm.cpp" />
|
||||||
<ClCompile Include="Emu\Cell\SPUInterpreter.cpp" />
|
<ClCompile Include="Emu\Cell\SPUInterpreter.cpp" />
|
||||||
<ClCompile Include="Emu\IdManager.cpp" />
|
<ClCompile Include="Emu\IdManager.cpp" />
|
||||||
|
<ClCompile Include="Emu\Io\Infinity.cpp" />
|
||||||
<ClCompile Include="Emu\Io\Skylander.cpp" />
|
<ClCompile Include="Emu\Io\Skylander.cpp" />
|
||||||
<ClCompile Include="Emu\Io\usb_device.cpp" />
|
<ClCompile Include="Emu\Io\usb_device.cpp" />
|
||||||
<ClCompile Include="Emu\Io\usb_vfs.cpp" />
|
<ClCompile Include="Emu\Io\usb_vfs.cpp" />
|
||||||
@ -666,6 +667,7 @@
|
|||||||
<ClInclude Include="Emu\Cell\PPUAnalyser.h" />
|
<ClInclude Include="Emu\Cell\PPUAnalyser.h" />
|
||||||
<ClInclude Include="Emu\Cell\PPUTranslator.h" />
|
<ClInclude Include="Emu\Cell\PPUTranslator.h" />
|
||||||
<ClInclude Include="Emu\CPU\CPUTranslator.h" />
|
<ClInclude Include="Emu\CPU\CPUTranslator.h" />
|
||||||
|
<ClInclude Include="Emu\Io\Infinity.h" />
|
||||||
<ClInclude Include="Emu\Io\Skylander.h" />
|
<ClInclude Include="Emu\Io\Skylander.h" />
|
||||||
<ClInclude Include="Emu\Io\usb_device.h" />
|
<ClInclude Include="Emu\Io\usb_device.h" />
|
||||||
<ClInclude Include="Emu\Io\usb_vfs.h" />
|
<ClInclude Include="Emu\Io\usb_vfs.h" />
|
||||||
|
@ -834,6 +834,9 @@
|
|||||||
<ClCompile Include="Emu\Cell\lv2\sys_config.cpp">
|
<ClCompile Include="Emu\Cell\lv2\sys_config.cpp">
|
||||||
<Filter>Emu\Cell\lv2</Filter>
|
<Filter>Emu\Cell\lv2</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Emu\Io\Infinity.cpp">
|
||||||
|
<Filter>Emu\Io</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="Emu\Io\Skylander.cpp">
|
<ClCompile Include="Emu\Io\Skylander.cpp">
|
||||||
<Filter>Emu\Io</Filter>
|
<Filter>Emu\Io</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -1884,6 +1887,9 @@
|
|||||||
<ClInclude Include="Emu\Io\Keyboard.h">
|
<ClInclude Include="Emu\Io\Keyboard.h">
|
||||||
<Filter>Emu\Io</Filter>
|
<Filter>Emu\Io</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\Io\Infinity.h">
|
||||||
|
<Filter>Emu\Io</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="Emu\Io\Skylander.h">
|
<ClInclude Include="Emu\Io\Skylander.h">
|
||||||
<Filter>Emu\Io</Filter>
|
<Filter>Emu\Io</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -273,6 +273,9 @@
|
|||||||
<ClCompile Include="QTGeneratedFiles\Debug\moc_headless_application.cpp">
|
<ClCompile Include="QTGeneratedFiles\Debug\moc_headless_application.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="QTGeneratedFiles\Debug\moc_infinity_dialog.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="QTGeneratedFiles\Debug\moc_input_dialog.cpp">
|
<ClCompile Include="QTGeneratedFiles\Debug\moc_input_dialog.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -528,6 +531,9 @@
|
|||||||
<ClCompile Include="QTGeneratedFiles\Release\moc_headless_application.cpp">
|
<ClCompile Include="QTGeneratedFiles\Release\moc_headless_application.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="QTGeneratedFiles\Release\moc_infinity_dialog.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="QTGeneratedFiles\Release\moc_input_dialog.cpp">
|
<ClCompile Include="QTGeneratedFiles\Release\moc_input_dialog.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -711,6 +717,7 @@
|
|||||||
<ClCompile Include="rpcs3qt\game_list_grid_item.cpp" />
|
<ClCompile Include="rpcs3qt\game_list_grid_item.cpp" />
|
||||||
<ClCompile Include="rpcs3qt\game_list_table.cpp" />
|
<ClCompile Include="rpcs3qt\game_list_table.cpp" />
|
||||||
<ClCompile Include="rpcs3qt\gui_application.cpp" />
|
<ClCompile Include="rpcs3qt\gui_application.cpp" />
|
||||||
|
<ClCompile Include="rpcs3qt\infinity_dialog.cpp" />
|
||||||
<ClCompile Include="rpcs3qt\input_dialog.cpp" />
|
<ClCompile Include="rpcs3qt\input_dialog.cpp" />
|
||||||
<ClCompile Include="rpcs3qt\ipc_settings_dialog.cpp" />
|
<ClCompile Include="rpcs3qt\ipc_settings_dialog.cpp" />
|
||||||
<ClCompile Include="rpcs3qt\localized.cpp" />
|
<ClCompile Include="rpcs3qt\localized.cpp" />
|
||||||
@ -1425,6 +1432,16 @@
|
|||||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"</Command>
|
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"</Command>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
<CustomBuild Include="rpcs3qt\infinity_dialog.h">
|
||||||
|
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||||
|
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing %(Identity)...</Message>
|
||||||
|
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||||
|
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"</Command>
|
||||||
|
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||||
|
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Moc%27ing %(Identity)...</Message>
|
||||||
|
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||||
|
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"</Command>
|
||||||
|
</CustomBuild>
|
||||||
<CustomBuild Include="rpcs3qt\update_manager.h">
|
<CustomBuild Include="rpcs3qt\update_manager.h">
|
||||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing %(Identity)...</Message>
|
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing %(Identity)...</Message>
|
||||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||||
|
@ -101,6 +101,9 @@
|
|||||||
<Filter Include="Io\DS3">
|
<Filter Include="Io\DS3">
|
||||||
<UniqueIdentifier>{66e6027b-d3dd-4894-814c-cc4444a4c7df}</UniqueIdentifier>
|
<UniqueIdentifier>{66e6027b-d3dd-4894-814c-cc4444a4c7df}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="Gui\infinity">
|
||||||
|
<UniqueIdentifier>{f5fcca0d-918b-46ba-bb91-2f2f9d9ddbba}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
<Filter Include="Gui\skylanders">
|
<Filter Include="Gui\skylanders">
|
||||||
<UniqueIdentifier>{c25f8f80-cc74-4760-8488-a291b3026b1d}</UniqueIdentifier>
|
<UniqueIdentifier>{c25f8f80-cc74-4760-8488-a291b3026b1d}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
@ -546,6 +549,9 @@
|
|||||||
<ClCompile Include="headless_application.cpp">
|
<ClCompile Include="headless_application.cpp">
|
||||||
<Filter>rpcs3</Filter>
|
<Filter>rpcs3</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="rpcs3qt\infinity_dialog.cpp">
|
||||||
|
<Filter>Gui\infinity</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="rpcs3qt\skylander_dialog.cpp">
|
<ClCompile Include="rpcs3qt\skylander_dialog.cpp">
|
||||||
<Filter>Gui\skylanders</Filter>
|
<Filter>Gui\skylanders</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -648,6 +654,12 @@
|
|||||||
<ClCompile Include="QTGeneratedFiles\Release\moc_screenshot_preview.cpp">
|
<ClCompile Include="QTGeneratedFiles\Release\moc_screenshot_preview.cpp">
|
||||||
<Filter>Generated Files\Release</Filter>
|
<Filter>Generated Files\Release</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="QTGeneratedFiles\Debug\moc_infinity_dialog.cpp">
|
||||||
|
<Filter>Generated Files\Debug</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="QTGeneratedFiles\Release\moc_infinity_dialog.cpp">
|
||||||
|
<Filter>Generated Files\Release</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="QTGeneratedFiles\Debug\moc_skylander_dialog.cpp">
|
<ClCompile Include="QTGeneratedFiles\Debug\moc_skylander_dialog.cpp">
|
||||||
<Filter>Generated Files\Debug</Filter>
|
<Filter>Generated Files\Debug</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -1357,6 +1369,9 @@
|
|||||||
<CustomBuild Include="rpcs3qt\screenshot_preview.h">
|
<CustomBuild Include="rpcs3qt\screenshot_preview.h">
|
||||||
<Filter>Gui\screenshot manager</Filter>
|
<Filter>Gui\screenshot manager</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
<CustomBuild Include="rpcs3qt\infinity_dialog.h">
|
||||||
|
<Filter>Gui\infinity</Filter>
|
||||||
|
</CustomBuild>
|
||||||
<CustomBuild Include="rpcs3qt\skylander_dialog.h">
|
<CustomBuild Include="rpcs3qt\skylander_dialog.h">
|
||||||
<Filter>Gui\skylanders</Filter>
|
<Filter>Gui\skylanders</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
@ -38,6 +38,7 @@ set(SRC_FILES
|
|||||||
gl_gs_frame.cpp
|
gl_gs_frame.cpp
|
||||||
gs_frame.cpp
|
gs_frame.cpp
|
||||||
gui_settings.cpp
|
gui_settings.cpp
|
||||||
|
infinity_dialog.cpp
|
||||||
input_dialog.cpp
|
input_dialog.cpp
|
||||||
instruction_editor_dialog.cpp
|
instruction_editor_dialog.cpp
|
||||||
ipc_settings_dialog.cpp
|
ipc_settings_dialog.cpp
|
||||||
|
832
rpcs3/rpcs3qt/infinity_dialog.cpp
Normal file
832
rpcs3/rpcs3qt/infinity_dialog.cpp
Normal file
@ -0,0 +1,832 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
#include "Utilities/File.h"
|
||||||
|
#include "Crypto/md5.h"
|
||||||
|
#include "Crypto/aes.h"
|
||||||
|
#include "Crypto/sha1.h"
|
||||||
|
#include "infinity_dialog.h"
|
||||||
|
#include "Emu/Io/Infinity.h"
|
||||||
|
|
||||||
|
#include "util/asm.hpp"
|
||||||
|
|
||||||
|
#include <locale>
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QCompleter>
|
||||||
|
|
||||||
|
infinity_dialog* infinity_dialog::inst = nullptr;
|
||||||
|
std::array<std::optional<u32>, 7> infinity_dialog::figure_slots = {};
|
||||||
|
static QString s_last_figure_path;
|
||||||
|
|
||||||
|
LOG_CHANNEL(infinity_log, "infinity");
|
||||||
|
|
||||||
|
static constexpr std::array<u8, 16> BLANK_BLOCK = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
static constexpr std::array<u8, 32> SHA1_CONSTANT = {
|
||||||
|
0xAF, 0x62, 0xD2, 0xEC, 0x04, 0x91, 0x96, 0x8C, 0xC5, 0x2A, 0x1A, 0x71, 0x65, 0xF8, 0x65, 0xFE,
|
||||||
|
0x28, 0x63, 0x29, 0x20, 0x44, 0x69, 0x73, 0x6e, 0x65, 0x79, 0x20, 0x32, 0x30, 0x31, 0x33};
|
||||||
|
|
||||||
|
const std::map<const u32, const std::pair<const u8, const std::string>> list_figures = {
|
||||||
|
{0x0F4241, {1, "Mr. Incredible"}},
|
||||||
|
{0x0F4242, {1, "Sulley"}},
|
||||||
|
{0x0F4243, {1, "Jack Sparrow"}},
|
||||||
|
{0x0F4244, {1, "Lone Ranger"}},
|
||||||
|
{0x0F4245, {1, "Tonto"}},
|
||||||
|
{0x0F4246, {1, "Lightning McQueen"}},
|
||||||
|
{0x0F4247, {1, "Holley Shiftwell"}},
|
||||||
|
{0x0F4248, {1, "Buzz Lightyear"}},
|
||||||
|
{0x0F4249, {1, "Jessie"}},
|
||||||
|
{0x0F424A, {1, "Mike"}},
|
||||||
|
{0x0F424B, {1, "Mrs. Incredible"}},
|
||||||
|
{0x0F424C, {1, "Hector Barbossa"}},
|
||||||
|
{0x0F424D, {1, "Davy Jones"}},
|
||||||
|
{0x0F424E, {1, "Randy"}},
|
||||||
|
{0x0F424F, {1, "Syndrome"}},
|
||||||
|
{0x0F4250, {1, "Woody"}},
|
||||||
|
{0x0F4251, {1, "Mater"}},
|
||||||
|
{0x0F4252, {1, "Dash"}},
|
||||||
|
{0x0F4253, {1, "Violet"}},
|
||||||
|
{0x0F4254, {1, "Francesco Bernoulli"}},
|
||||||
|
{0x0F4255, {1, "Sorcerer's Apprentice Mickey"}},
|
||||||
|
{0x0F4256, {1, "Jack Skellington"}},
|
||||||
|
{0x0F4257, {1, "Rapunzel"}},
|
||||||
|
{0x0F4258, {1, "Anna"}},
|
||||||
|
{0x0F4259, {1, "Elsa"}},
|
||||||
|
{0x0F425A, {1, "Phineas"}},
|
||||||
|
{0x0F425B, {1, "Agent P"}},
|
||||||
|
{0x0F425C, {1, "Wreck-It Ralph"}},
|
||||||
|
{0x0F425D, {1, "Vanellope"}},
|
||||||
|
{0x0F425E, {1, "Mr. Incredible (Crystal)"}},
|
||||||
|
{0x0F425F, {1, "Jack Sparrow (Crystal)"}},
|
||||||
|
{0x0F4260, {1, "Sulley (Crystal)"}},
|
||||||
|
{0x0F4261, {1, "Lightning McQueen (Crystal)"}},
|
||||||
|
{0x0F4262, {1, "Lone Ranger (Crystal)"}},
|
||||||
|
{0x0F4263, {1, "Buzz Lightyear (Crystal)"}},
|
||||||
|
{0x0F4264, {1, "Agent P (Crystal)"}},
|
||||||
|
{0x0F4265, {1, "Sorcerer's Apprentice Mickey (Crystal)"}},
|
||||||
|
{0x0F4266, {1, "Buzz Lightyear (Glowing)"}},
|
||||||
|
{0x0F42A4, {2, "Captain America"}},
|
||||||
|
{0x0F42A5, {2, "Hulk"}},
|
||||||
|
{0x0F42A6, {2, "Iron Man"}},
|
||||||
|
{0x0F42A7, {2, "Thor"}},
|
||||||
|
{0x0F42A8, {2, "Groot"}},
|
||||||
|
{0x0F42A9, {2, "Rocket Raccoon"}},
|
||||||
|
{0x0F42AA, {2, "Star-Lord"}},
|
||||||
|
{0x0F42AB, {2, "Spider-Man"}},
|
||||||
|
{0x0F42AC, {2, "Nick Fury"}},
|
||||||
|
{0x0F42AD, {2, "Black Widow"}},
|
||||||
|
{0x0F42AE, {2, "Hawkeye"}},
|
||||||
|
{0x0F42AF, {2, "Drax"}},
|
||||||
|
{0x0F42B0, {2, "Gamora"}},
|
||||||
|
{0x0F42B1, {2, "Iron Fist"}},
|
||||||
|
{0x0F42B2, {2, "Nova"}},
|
||||||
|
{0x0F42B3, {2, "Venom"}},
|
||||||
|
{0x0F42B4, {2, "Donald Duck"}},
|
||||||
|
{0x0F42B5, {2, "Aladdin"}},
|
||||||
|
{0x0F42B6, {2, "Stitch"}},
|
||||||
|
{0x0F42B7, {2, "Merida"}},
|
||||||
|
{0x0F42B8, {2, "Tinker Bell"}},
|
||||||
|
{0x0F42B9, {2, "Maleficent"}},
|
||||||
|
{0x0F42BA, {2, "Hiro"}},
|
||||||
|
{0x0F42BB, {2, "Baymax"}},
|
||||||
|
{0x0F42BC, {2, "Loki"}},
|
||||||
|
{0x0F42BD, {2, "Ronan"}},
|
||||||
|
{0x0F42BE, {2, "Green Goblin"}},
|
||||||
|
{0x0F42BF, {2, "Falcon"}},
|
||||||
|
{0x0F42C0, {2, "Yondu"}},
|
||||||
|
{0x0F42C1, {2, "Jasmine"}},
|
||||||
|
{0x0F42C6, {2, "Black Suit Spider-Man"}},
|
||||||
|
{0x0F42D6, {3, "Sam Flynn"}},
|
||||||
|
{0x0F42D7, {3, "Quorra"}},
|
||||||
|
{0x0F4308, {3, "Anakin Skywalker"}},
|
||||||
|
{0x0F4309, {3, "Obi-Wan Kenobi"}},
|
||||||
|
{0x0F430A, {3, "Yoda"}},
|
||||||
|
{0x0F430B, {3, "Ahsoka Tano"}},
|
||||||
|
{0x0F430C, {3, "Darth Maul"}},
|
||||||
|
{0x0F430E, {3, "Luke Skywalker"}},
|
||||||
|
{0x0F430F, {3, "Han Solo"}},
|
||||||
|
{0x0F4310, {3, "Princess Leia"}},
|
||||||
|
{0x0F4311, {3, "Chewbacca"}},
|
||||||
|
{0x0F4312, {3, "Darth Vader"}},
|
||||||
|
{0x0F4313, {3, "Boba Fett"}},
|
||||||
|
{0x0F4314, {3, "Ezra Bridger"}},
|
||||||
|
{0x0F4315, {3, "Kanan Jarrus"}},
|
||||||
|
{0x0F4316, {3, "Sabine Wren"}},
|
||||||
|
{0x0F4317, {3, "Zeb Orrelios"}},
|
||||||
|
{0x0F4318, {3, "Joy"}},
|
||||||
|
{0x0F4319, {3, "Anger"}},
|
||||||
|
{0x0F431A, {3, "Fear"}},
|
||||||
|
{0x0F431B, {3, "Sadness"}},
|
||||||
|
{0x0F431C, {3, "Disgust"}},
|
||||||
|
{0x0F431D, {3, "Mickey Mouse"}},
|
||||||
|
{0x0F431E, {3, "Minnie Mouse"}},
|
||||||
|
{0x0F431F, {3, "Mulan"}},
|
||||||
|
{0x0F4320, {3, "Olaf"}},
|
||||||
|
{0x0F4321, {3, "Vision"}},
|
||||||
|
{0x0F4322, {3, "Ultron"}},
|
||||||
|
{0x0F4323, {3, "Ant-Man"}},
|
||||||
|
{0x0F4325, {3, "Captain America - The First Avenger"}},
|
||||||
|
{0x0F4326, {3, "Finn"}},
|
||||||
|
{0x0F4327, {3, "Kylo Ren"}},
|
||||||
|
{0x0F4328, {3, "Poe Dameron"}},
|
||||||
|
{0x0F4329, {3, "Rey"}},
|
||||||
|
{0x0F432B, {3, "Spot"}},
|
||||||
|
{0x0F432C, {3, "Nick Wilde"}},
|
||||||
|
{0x0F432D, {3, "Judy Hopps"}},
|
||||||
|
{0x0F432E, {3, "Hulkbuster"}},
|
||||||
|
{0x0F432F, {3, "Anakin Skywalker (Light FX)"}},
|
||||||
|
{0x0F4330, {3, "Obi-Wan Kenobi (Light FX)"}},
|
||||||
|
{0x0F4331, {3, "Yoda (Light FX)"}},
|
||||||
|
{0x0F4332, {3, "Luke Skywalker (Light FX)"}},
|
||||||
|
{0x0F4333, {3, "Darth Vader (Light FX)"}},
|
||||||
|
{0x0F4334, {3, "Kanan Jarrus (Light FX)"}},
|
||||||
|
{0x0F4335, {3, "Kylo Ren (Light FX)"}},
|
||||||
|
{0x0F4336, {3, "Black Panther"}},
|
||||||
|
{0x0F436C, {3, "Nemo"}},
|
||||||
|
{0x0F436D, {3, "Dory"}},
|
||||||
|
{0x0F436E, {3, "Baloo"}},
|
||||||
|
{0x0F436F, {3, "Alice"}},
|
||||||
|
{0x0F4370, {3, "Mad Hatter"}},
|
||||||
|
{0x0F4371, {3, "Time"}},
|
||||||
|
{0x0F4372, {3, "Peter Pan"}},
|
||||||
|
{0x1E8481, {1, "Starter Play Set"}},
|
||||||
|
{0x1E8482, {1, "Lone Ranger Play Set"}},
|
||||||
|
{0x1E8483, {1, "Cars Play Set"}},
|
||||||
|
{0x1E8484, {1, "Toy Story in Space Play Set"}},
|
||||||
|
{0x1E84E4, {2, "Marvel's The Avengers Play Set"}},
|
||||||
|
{0x1E84E5, {2, "Marvel's Spider-Man Play Set"}},
|
||||||
|
{0x1E84E6, {2, "Marvel's Guardians of the Galaxy Play Set"}},
|
||||||
|
{0x1E84E7, {2, "Assault on Asgard"}},
|
||||||
|
{0x1E84E8, {2, "Escape from the Kyln"}},
|
||||||
|
{0x1E84E9, {2, "Stitch's Tropical Rescue"}},
|
||||||
|
{0x1E84EA, {2, "Brave Forest Siege"}},
|
||||||
|
{0x1E8548, {3, "Inside Out Play Set"}},
|
||||||
|
{0x1E8549, {3, "Star Wars: Twilight of the Republic Play Set"}},
|
||||||
|
{0x1E854A, {3, "Star Wars: Rise Against the Empire Play Set"}},
|
||||||
|
{0x1E854B, {3, "Star Wars: The Force Awakens Play Set"}},
|
||||||
|
{0x1E854C, {3, "Marvel Battlegrounds Play Set"}},
|
||||||
|
{0x1E854D, {3, "Toy Box Speedway"}},
|
||||||
|
{0x1E854E, {3, "Toy Box Takeover"}},
|
||||||
|
{0x1E85AC, {3, "Finding Dory Play Set"}},
|
||||||
|
{0x2DC6C3, {1, "Bolt's Super Strength"}},
|
||||||
|
{0x2DC6C4, {1, "Ralph's Power of Destruction"}},
|
||||||
|
{0x2DC6C5, {1, "Chernabog's Power"}},
|
||||||
|
{0x2DC6C6, {1, "C.H.R.O.M.E. Damage Increaser"}},
|
||||||
|
{0x2DC6C7, {1, "Dr. Doofenshmirtz's Damage-Inator!"}},
|
||||||
|
{0x2DC6C8, {1, "Electro-Charge"}},
|
||||||
|
{0x2DC6C9, {1, "Fix-It Felix's Repair Power"}},
|
||||||
|
{0x2DC6CA, {1, "Rapunzel's Healing"}},
|
||||||
|
{0x2DC6CB, {1, "C.H.R.O.M.E. Armor Shield"}},
|
||||||
|
{0x2DC6CC, {1, "Star Command Shield"}},
|
||||||
|
{0x2DC6CD, {1, "Violet's Force Field"}},
|
||||||
|
{0x2DC6CE, {1, "Pieces of Eight"}},
|
||||||
|
{0x2DC6CF, {1, "Scrooge McDuck's Lucky Dime"}},
|
||||||
|
{0x2DC6D0, {1, "User Control"}},
|
||||||
|
{0x2DC6D1, {1, "Sorcerer Mickey's Hat"}},
|
||||||
|
{0x2DC6FE, {1, "Emperor Zurg's Wrath"}},
|
||||||
|
{0x2DC6FF, {1, "Merlin's Summon"}},
|
||||||
|
{0x2DC765, {2, "Enchanted Rose"}},
|
||||||
|
{0x2DC766, {2, "Mulan's Training Uniform"}},
|
||||||
|
{0x2DC767, {2, "Flubber"}},
|
||||||
|
{0x2DC768, {2, "S.H.I.E.L.D. Helicarrier Strike"}},
|
||||||
|
{0x2DC769, {2, "Zeus' Thunderbolts"}},
|
||||||
|
{0x2DC76A, {2, "King Louie's Monkeys"}},
|
||||||
|
{0x2DC76B, {2, "Infinity Gauntlet"}},
|
||||||
|
{0x2DC76D, {2, "Sorcerer Supreme"}},
|
||||||
|
{0x2DC76E, {2, "Maleficent's Spell Cast"}},
|
||||||
|
{0x2DC76F, {2, "Chernabog's Spirit Cyclone"}},
|
||||||
|
{0x2DC770, {2, "Marvel Team-Up: Capt. Marvel"}},
|
||||||
|
{0x2DC771, {2, "Marvel Team-Up: Iron Patriot"}},
|
||||||
|
{0x2DC772, {2, "Marvel Team-Up: Ant-Man"}},
|
||||||
|
{0x2DC773, {2, "Marvel Team-Up: White Tiger"}},
|
||||||
|
{0x2DC774, {2, "Marvel Team-Up: Yondu"}},
|
||||||
|
{0x2DC775, {2, "Marvel Team-Up: Winter Soldier"}},
|
||||||
|
{0x2DC776, {2, "Stark Arc Reactor"}},
|
||||||
|
{0x2DC777, {2, "Gamma Rays"}},
|
||||||
|
{0x2DC778, {2, "Alien Symbiote"}},
|
||||||
|
{0x2DC779, {2, "All for One"}},
|
||||||
|
{0x2DC77A, {2, "Sandy Claws Surprise"}},
|
||||||
|
{0x2DC77B, {2, "Glory Days"}},
|
||||||
|
{0x2DC77C, {2, "Cursed Pirate Gold"}},
|
||||||
|
{0x2DC77D, {2, "Sentinel of Liberty"}},
|
||||||
|
{0x2DC77E, {2, "The Immortal Iron Fist"}},
|
||||||
|
{0x2DC77F, {2, "Space Armor"}},
|
||||||
|
{0x2DC780, {2, "Rags to Riches"}},
|
||||||
|
{0x2DC781, {2, "Ultimate Falcon"}},
|
||||||
|
{0x2DC788, {3, "Tomorrowland Time Bomb"}},
|
||||||
|
{0x2DC78E, {3, "Galactic Team-Up: Mace Windu"}},
|
||||||
|
{0x2DC791, {3, "Luke's Rebel Alliance Flight Suit Costume"}},
|
||||||
|
{0x2DC798, {3, "Finn's Stormtrooper Costume"}},
|
||||||
|
{0x2DC799, {3, "Poe's Resistance Jacket"}},
|
||||||
|
{0x2DC79A, {3, "Resistance Tactical Strike"}},
|
||||||
|
{0x2DC79E, {3, "Officer Nick Wilde"}},
|
||||||
|
{0x2DC79F, {3, "Meter Maid Judy"}},
|
||||||
|
{0x2DC7A2, {3, "Darkhawk's Blast"}},
|
||||||
|
{0x2DC7A3, {3, "Cosmic Cube Blast"}},
|
||||||
|
{0x2DC7A4, {3, "Princess Leia's Boushh Disguise"}},
|
||||||
|
{0x2DC7A6, {3, "Nova Corps Strike"}},
|
||||||
|
{0x2DC7A7, {3, "King Mickey"}},
|
||||||
|
{0x3D0912, {1, "Mickey's Car"}},
|
||||||
|
{0x3D0913, {1, "Cinderella's Coach"}},
|
||||||
|
{0x3D0914, {1, "Electric Mayhem Bus"}},
|
||||||
|
{0x3D0915, {1, "Cruella De Vil's Car"}},
|
||||||
|
{0x3D0916, {1, "Pizza Planet Delivery Truck"}},
|
||||||
|
{0x3D0917, {1, "Mike's New Car"}},
|
||||||
|
{0x3D0919, {1, "Parking Lot Tram"}},
|
||||||
|
{0x3D091A, {1, "Captain Hook's Ship"}},
|
||||||
|
{0x3D091B, {1, "Dumbo"}},
|
||||||
|
{0x3D091C, {1, "Calico Helicopter"}},
|
||||||
|
{0x3D091D, {1, "Maximus"}},
|
||||||
|
{0x3D091E, {1, "Angus"}},
|
||||||
|
{0x3D091F, {1, "Abu the Elephant"}},
|
||||||
|
{0x3D0920, {1, "Headless Horseman's Horse"}},
|
||||||
|
{0x3D0921, {1, "Phillipe"}},
|
||||||
|
{0x3D0922, {1, "Khan"}},
|
||||||
|
{0x3D0923, {1, "Tantor"}},
|
||||||
|
{0x3D0924, {1, "Dragon Firework Cannon"}},
|
||||||
|
{0x3D0925, {1, "Stitch's Blaster"}},
|
||||||
|
{0x3D0926, {1, "Toy Story Mania Blaster"}},
|
||||||
|
{0x3D0927, {1, "Flamingo Croquet Mallet"}},
|
||||||
|
{0x3D0928, {1, "Carl Fredricksen's Cane"}},
|
||||||
|
{0x3D0929, {1, "Hangin' Ten Stitch With Surfboard"}},
|
||||||
|
{0x3D092A, {1, "Condorman Glider"}},
|
||||||
|
{0x3D092B, {1, "WALL-E's Fire Extinguisher"}},
|
||||||
|
{0x3D092C, {1, "On the Grid"}},
|
||||||
|
{0x3D092D, {1, "WALL-E's Collection"}},
|
||||||
|
{0x3D092E, {1, "King Candy's Dessert Toppings"}},
|
||||||
|
{0x3D0930, {1, "Victor's Experiments"}},
|
||||||
|
{0x3D0931, {1, "Jack's Scary Decorations"}},
|
||||||
|
{0x3D0933, {1, "Frozen Flourish"}},
|
||||||
|
{0x3D0934, {1, "Rapunzel's Kingdom"}},
|
||||||
|
{0x3D0935, {1, "TRON Interface"}},
|
||||||
|
{0x3D0936, {1, "Buy N Large Atmosphere"}},
|
||||||
|
{0x3D0937, {1, "Sugar Rush Sky"}},
|
||||||
|
{0x3D0939, {1, "New Holland Skyline"}},
|
||||||
|
{0x3D093A, {1, "Halloween Town Sky"}},
|
||||||
|
{0x3D093C, {1, "Chill in the Air"}},
|
||||||
|
{0x3D093D, {1, "Rapunzel's Birthday Sky"}},
|
||||||
|
{0x3D0940, {1, "Astro Blasters Space Cruiser"}},
|
||||||
|
{0x3D0941, {1, "Marlin's Reef"}},
|
||||||
|
{0x3D0942, {1, "Nemo's Seascape"}},
|
||||||
|
{0x3D0943, {1, "Alice's Wonderland"}},
|
||||||
|
{0x3D0944, {1, "Tulgey Wood"}},
|
||||||
|
{0x3D0945, {1, "Tri-State Area Terrain"}},
|
||||||
|
{0x3D0946, {1, "Danville Sky"}},
|
||||||
|
{0x3D0965, {2, "Stark Tech"}},
|
||||||
|
{0x3D0966, {2, "Spider-Streets"}},
|
||||||
|
{0x3D0967, {2, "World War Hulk"}},
|
||||||
|
{0x3D0968, {2, "Gravity Falls Forest"}},
|
||||||
|
{0x3D0969, {2, "Neverland"}},
|
||||||
|
{0x3D096A, {2, "Simba's Pridelands"}},
|
||||||
|
{0x3D096C, {2, "Calhoun's Command"}},
|
||||||
|
{0x3D096D, {2, "Star-Lord's Galaxy"}},
|
||||||
|
{0x3D096E, {2, "Dinosaur World"}},
|
||||||
|
{0x3D096F, {2, "Groot's Roots"}},
|
||||||
|
{0x3D0970, {2, "Mulan's Countryside"}},
|
||||||
|
{0x3D0971, {2, "The Sands of Agrabah"}},
|
||||||
|
{0x3D0974, {2, "A Small World"}},
|
||||||
|
{0x3D0975, {2, "View from the Suit"}},
|
||||||
|
{0x3D0976, {2, "Spider-Sky"}},
|
||||||
|
{0x3D0977, {2, "World War Hulk Sky"}},
|
||||||
|
{0x3D0978, {2, "Gravity Falls Sky"}},
|
||||||
|
{0x3D0979, {2, "Second Star to the Right"}},
|
||||||
|
{0x3D097A, {2, "The King's Domain"}},
|
||||||
|
{0x3D097C, {2, "CyBug Swarm"}},
|
||||||
|
{0x3D097D, {2, "The Rip"}},
|
||||||
|
{0x3D097E, {2, "Forgotten Skies"}},
|
||||||
|
{0x3D097F, {2, "Groot's View"}},
|
||||||
|
{0x3D0980, {2, "The Middle Kingdom"}},
|
||||||
|
{0x3D0984, {2, "Skies of the World"}},
|
||||||
|
{0x3D0985, {2, "S.H.I.E.L.D. Containment Truck"}},
|
||||||
|
{0x3D0986, {2, "Main Street Electrical Parade Float"}},
|
||||||
|
{0x3D0987, {2, "Mr. Toad's Motorcar"}},
|
||||||
|
{0x3D0988, {2, "Le Maximum"}},
|
||||||
|
{0x3D0989, {2, "Alice in Wonderland's Caterpillar"}},
|
||||||
|
{0x3D098A, {2, "Eglantine's Motorcycle"}},
|
||||||
|
{0x3D098B, {2, "Medusa's Swamp Mobile"}},
|
||||||
|
{0x3D098C, {2, "Hydra Motorcycle"}},
|
||||||
|
{0x3D098D, {2, "Darkwing Duck's Ratcatcher"}},
|
||||||
|
{0x3D098F, {2, "The USS Swinetrek"}},
|
||||||
|
{0x3D0991, {2, "Spider-Copter"}},
|
||||||
|
{0x3D0992, {2, "Aerial Area Rug"}},
|
||||||
|
{0x3D0993, {2, "Jack-O-Lantern's Glider"}},
|
||||||
|
{0x3D0994, {2, "Spider-Buggy"}},
|
||||||
|
{0x3D0995, {2, "Jack Skellington's Reindeer"}},
|
||||||
|
{0x3D0996, {2, "Fantasyland Carousel Horse"}},
|
||||||
|
{0x3D0997, {2, "Odin's Horse"}},
|
||||||
|
{0x3D0998, {2, "Gus the Mule"}},
|
||||||
|
{0x3D099A, {2, "Darkwing Duck's Grappling Gun"}},
|
||||||
|
{0x3D099C, {2, "Ghost Rider's Chain Whip"}},
|
||||||
|
{0x3D099D, {2, "Lew Zealand's Boomerang Fish"}},
|
||||||
|
{0x3D099E, {2, "Sergeant Calhoun's Blaster"}},
|
||||||
|
{0x3D09A0, {2, "Falcon's Wings"}},
|
||||||
|
{0x3D09A1, {2, "Mabel's Kittens for Fists"}},
|
||||||
|
{0x3D09A2, {2, "Jim Hawkins' Solar Board"}},
|
||||||
|
{0x3D09A3, {2, "Black Panther's Vibranium Knives"}},
|
||||||
|
{0x3D09A4, {2, "Cloak of Levitation"}},
|
||||||
|
{0x3D09A5, {2, "Aladdin's Magic Carpet"}},
|
||||||
|
{0x3D09A6, {2, "Honey Lemon's Ice Capsules"}},
|
||||||
|
{0x3D09A7, {2, "Jasmine's Palace View"}},
|
||||||
|
{0x3D09C1, {2, "Lola"}},
|
||||||
|
{0x3D09C2, {2, "Spider-Cycle"}},
|
||||||
|
{0x3D09C3, {2, "The Avenjet"}},
|
||||||
|
{0x3D09C4, {2, "Spider-Glider"}},
|
||||||
|
{0x3D09C5, {2, "Light Cycle"}},
|
||||||
|
{0x3D09C6, {2, "Light Jet"}},
|
||||||
|
{0x3D09C9, {3, "Retro Ray Gun"}},
|
||||||
|
{0x3D09CA, {3, "Tomorrowland Futurescape"}},
|
||||||
|
{0x3D09CB, {3, "Tomorrowland Stratosphere"}},
|
||||||
|
{0x3D09CC, {3, "Skies Over Felucia"}},
|
||||||
|
{0x3D09CD, {3, "Forests of Felucia"}},
|
||||||
|
{0x3D09CF, {3, "General Grievous' Wheel Bike"}},
|
||||||
|
{0x3D09D2, {3, "Slave I Flyer"}},
|
||||||
|
{0x3D09D3, {3, "Y-Wing Fighter"}},
|
||||||
|
{0x3D09D4, {3, "Arlo"}},
|
||||||
|
{0x3D09D5, {3, "Nash"}},
|
||||||
|
{0x3D09D6, {3, "Butch"}},
|
||||||
|
{0x3D09D7, {3, "Ramsey"}},
|
||||||
|
{0x3D09DC, {3, "Stars Over Sahara Square"}},
|
||||||
|
{0x3D09DD, {3, "Sahara Square Sands"}},
|
||||||
|
{0x3D09E0, {3, "Ghost Rider's Motorcycle"}},
|
||||||
|
{0x3D09E5, {3, "Quad Jumper"}}};
|
||||||
|
|
||||||
|
u32 infinity_crc32(u16 init_value, const u8* buffer, u32 size)
|
||||||
|
{
|
||||||
|
const std::array<u32, 256> CRC32_TABLE = {
|
||||||
|
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535,
|
||||||
|
0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd,
|
||||||
|
0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d,
|
||||||
|
0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
|
||||||
|
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
|
||||||
|
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||||
|
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac,
|
||||||
|
0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||||
|
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
|
||||||
|
0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
|
||||||
|
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb,
|
||||||
|
0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||||
|
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea,
|
||||||
|
0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce,
|
||||||
|
0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
|
||||||
|
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||||
|
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409,
|
||||||
|
0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||||
|
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739,
|
||||||
|
0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
||||||
|
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268,
|
||||||
|
0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0,
|
||||||
|
0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8,
|
||||||
|
0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||||
|
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
|
||||||
|
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703,
|
||||||
|
0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
|
||||||
|
0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
|
||||||
|
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae,
|
||||||
|
0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||||
|
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6,
|
||||||
|
0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||||
|
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d,
|
||||||
|
0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5,
|
||||||
|
0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
|
||||||
|
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||||
|
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
|
||||||
|
u32 crc = init_value;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
u8 index = u8(crc & 0xFF) ^ buffer[i];
|
||||||
|
crc = ((crc >> 8) ^ CRC32_TABLE[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure_creator_dialog::figure_creator_dialog(QWidget* parent, u8 slot)
|
||||||
|
: QDialog(parent)
|
||||||
|
{
|
||||||
|
setWindowTitle(tr("Figure Creator"));
|
||||||
|
setObjectName("figure_creator");
|
||||||
|
setMinimumSize(QSize(500, 150));
|
||||||
|
|
||||||
|
QVBoxLayout* vbox_panel = new QVBoxLayout();
|
||||||
|
|
||||||
|
QComboBox* combo_figlist = new QComboBox();
|
||||||
|
QStringList filterlist;
|
||||||
|
u32 first_entry = 0;
|
||||||
|
|
||||||
|
for (const auto& entry : list_figures)
|
||||||
|
{
|
||||||
|
const auto figure = entry.first;
|
||||||
|
// Only display entry if it is a piece appropriate for the slot
|
||||||
|
if ((slot == 0 &&
|
||||||
|
((figure > 0x1E8480 && figure < 0x2DC6BF) || (figure > 0x3D0900 && figure < 0x4C4B3F))) ||
|
||||||
|
((slot == 1 || slot == 2) && figure < 0x1E847F) ||
|
||||||
|
((slot == 3 || slot == 4 || slot == 5 || slot == 6) &&
|
||||||
|
(figure > 0x2DC6C0 && figure < 0x3D08FF)))
|
||||||
|
{
|
||||||
|
const u32 qnum = (figure << 8) | entry.second.first;
|
||||||
|
combo_figlist->addItem(QString::fromStdString(entry.second.second), QVariant(qnum));
|
||||||
|
filterlist << entry.second.second.c_str();
|
||||||
|
if (first_entry == 0)
|
||||||
|
{
|
||||||
|
first_entry = figure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
combo_figlist->addItem(tr("--Unknown--"), QVariant(0xFFFFFFFF));
|
||||||
|
combo_figlist->setEditable(true);
|
||||||
|
combo_figlist->setInsertPolicy(QComboBox::NoInsert);
|
||||||
|
|
||||||
|
QCompleter* co_compl = new QCompleter(filterlist, this);
|
||||||
|
co_compl->setCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
co_compl->setCompletionMode(QCompleter::PopupCompletion);
|
||||||
|
co_compl->setFilterMode(Qt::MatchContains);
|
||||||
|
combo_figlist->setCompleter(co_compl);
|
||||||
|
|
||||||
|
vbox_panel->addWidget(combo_figlist);
|
||||||
|
|
||||||
|
QFrame* line = new QFrame();
|
||||||
|
line->setFrameShape(QFrame::HLine);
|
||||||
|
line->setFrameShadow(QFrame::Sunken);
|
||||||
|
vbox_panel->addWidget(line);
|
||||||
|
|
||||||
|
QHBoxLayout* hbox_number = new QHBoxLayout();
|
||||||
|
QLabel* label_number = new QLabel(tr("Figure Number:"));
|
||||||
|
QLineEdit* edit_number = new QLineEdit(QString::fromStdString(std::to_string(first_entry)));
|
||||||
|
QLabel* label_series = new QLabel(tr("Series:"));
|
||||||
|
QLineEdit* edit_series = new QLineEdit("1");
|
||||||
|
QRegularExpressionValidator* rxv = new QRegularExpressionValidator(QRegularExpression("\\d*"), this);
|
||||||
|
QIntValidator* valid_series = new QIntValidator(1, 3, this);
|
||||||
|
edit_number->setValidator(rxv);
|
||||||
|
edit_series->setValidator(valid_series);
|
||||||
|
hbox_number->addWidget(label_number);
|
||||||
|
hbox_number->addWidget(edit_number);
|
||||||
|
hbox_number->addWidget(label_series);
|
||||||
|
hbox_number->addWidget(edit_series);
|
||||||
|
vbox_panel->addLayout(hbox_number);
|
||||||
|
|
||||||
|
QHBoxLayout* hbox_buttons = new QHBoxLayout();
|
||||||
|
QPushButton* btn_create = new QPushButton(tr("Create"), this);
|
||||||
|
QPushButton* btn_cancel = new QPushButton(tr("Cancel"), this);
|
||||||
|
hbox_buttons->addStretch();
|
||||||
|
hbox_buttons->addWidget(btn_create);
|
||||||
|
hbox_buttons->addWidget(btn_cancel);
|
||||||
|
vbox_panel->addLayout(hbox_buttons);
|
||||||
|
|
||||||
|
setLayout(vbox_panel);
|
||||||
|
|
||||||
|
connect(combo_figlist, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](int index)
|
||||||
|
{
|
||||||
|
const u32 fig_info = combo_figlist->itemData(index).toUInt();
|
||||||
|
if (fig_info != 0xFFFFFFFF)
|
||||||
|
{
|
||||||
|
const u32 fig_num = fig_info >> 8;
|
||||||
|
const u8 series = fig_info & 0xFF;
|
||||||
|
|
||||||
|
edit_number->setText(QString::number(fig_num));
|
||||||
|
edit_series->setText(QString::number(series));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(btn_create, &QAbstractButton::clicked, this, [=, this]()
|
||||||
|
{
|
||||||
|
bool ok_num = false, ok_series = false;
|
||||||
|
const u32 fig_num = edit_number->text().toULong(&ok_num);
|
||||||
|
if (!ok_num)
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Error converting value"), tr("Figure number entered is invalid!"), QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const u8 series = edit_series->text().toUShort(&ok_series);
|
||||||
|
if (!ok_series || series > 3 || series < 1)
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Error converting value"), tr("Series number entered is invalid!"), QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto found_figure = list_figures.find(fig_num);
|
||||||
|
if (found_figure != list_figures.end())
|
||||||
|
{
|
||||||
|
s_last_figure_path += QString::fromStdString(found_figure->second.second + ".bin");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_last_figure_path += QString("Unknown(%1 %2).bin").arg(fig_num).arg(series);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_file_path = QFileDialog::getSaveFileName(this, tr("Create Figure File"), s_last_figure_path, tr("Infinity Figure (*.bin);;"));
|
||||||
|
if (m_file_path.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!create_blank_figure(fig_num, series))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Failed to create figure file!"), tr("Failed to create figure file:\n%1").arg(m_file_path), QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_last_figure_path = QFileInfo(m_file_path).absolutePath() + "/";
|
||||||
|
accept();
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(btn_cancel, &QAbstractButton::clicked, this, &QDialog::reject);
|
||||||
|
|
||||||
|
connect(co_compl, QOverload<const QString&>::of(&QCompleter::activated), [=](const QString& text)
|
||||||
|
{
|
||||||
|
combo_figlist->setCurrentIndex(combo_figlist->findText(text));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool figure_creator_dialog::create_blank_figure(u32 character, u8 series)
|
||||||
|
{
|
||||||
|
infinity_log.trace("File path: %s Character: %d Series: %d", m_file_path.toStdString(), character, series);
|
||||||
|
fs::file inf_file(m_file_path.toStdString(), fs::read + fs::write + fs::create);
|
||||||
|
if (!inf_file)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Create a 320 byte file with standard NFC read/write permissions
|
||||||
|
std::array<u8, 0x14 * 0x10> file_data{};
|
||||||
|
u32 first_block = 0x17878E;
|
||||||
|
u32 other_blocks = 0x778788;
|
||||||
|
for (u8 i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
file_data[0x36 + i] = u8((first_block >> (2 - i) * 8) & 0xFF);
|
||||||
|
}
|
||||||
|
for (u32 index = 1; index < 5; index++)
|
||||||
|
{
|
||||||
|
for (u8 i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
file_data[((index * 0x40) + 0x36) + i] = u8((other_blocks >> (2 - i) * 8) & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Create the vector to calculate the SHA1 hash with
|
||||||
|
std::vector<u8> sha1_calc = {SHA1_CONSTANT.begin(), SHA1_CONSTANT.end() - 1};
|
||||||
|
// Generate random UID, used for AES encrypt/decrypt
|
||||||
|
std::array<u8, 16> uid_data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x44, 0x00, 0xC2};
|
||||||
|
for (u8 i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
u8 random = rand() % 255;
|
||||||
|
sha1_calc.push_back(random);
|
||||||
|
uid_data[i] = random;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<u8, 16> figure_data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, series, 0xD1, 0x1F};
|
||||||
|
|
||||||
|
// Figure Number, input by end user
|
||||||
|
figure_data[1] = u8((character >> 16) & 0xFF);
|
||||||
|
figure_data[2] = u8((character >> 8) & 0xFF);
|
||||||
|
figure_data[3] = u8(character & 0xFF);
|
||||||
|
|
||||||
|
// Manufacture date, formatted as YY/MM/DD. Set to release date of figure's series
|
||||||
|
if (series == 1)
|
||||||
|
{
|
||||||
|
figure_data[4] = 0x0D;
|
||||||
|
figure_data[5] = 0x08;
|
||||||
|
figure_data[6] = 0x12;
|
||||||
|
}
|
||||||
|
else if (series == 2)
|
||||||
|
{
|
||||||
|
figure_data[4] = 0x0E;
|
||||||
|
figure_data[5] = 0x09;
|
||||||
|
figure_data[6] = 0x12;
|
||||||
|
}
|
||||||
|
else if (series == 3)
|
||||||
|
{
|
||||||
|
figure_data[4] = 0x0F;
|
||||||
|
figure_data[5] = 0x08;
|
||||||
|
figure_data[6] = 0x1C;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 checksum = infinity_crc32(0, figure_data.data(), 12);
|
||||||
|
for (s8 i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
figure_data[12 + i] = u8((checksum >> (3 - i) * 8) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (figure_data[1] == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sha1_context ctx;
|
||||||
|
u8 output[20];
|
||||||
|
|
||||||
|
sha1_starts(&ctx);
|
||||||
|
sha1_update(&ctx, sha1_calc.data(), sha1_calc.size());
|
||||||
|
sha1_finish(&ctx, output);
|
||||||
|
|
||||||
|
u8 key[0x10];
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < 4; x++)
|
||||||
|
{
|
||||||
|
key[x + (i * 4)] = output[(3 - x) + (i * 4)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create AES Encrypt context based on AES key, use this to encrypt the character data and 4 blank
|
||||||
|
// blocks
|
||||||
|
aes_context aes;
|
||||||
|
aes_setkey_enc(&aes, key, 128);
|
||||||
|
std::array<u8, 16> encrypted_block{};
|
||||||
|
std::array<u8, 16> encrypted_blank{};
|
||||||
|
aes_crypt_ecb(&aes, AES_ENCRYPT, figure_data.data(), encrypted_block.data());
|
||||||
|
aes_crypt_ecb(&aes, AES_ENCRYPT, BLANK_BLOCK.data(), encrypted_blank.data());
|
||||||
|
|
||||||
|
// Copy encrypted data and UID data to the Figure File
|
||||||
|
memcpy(&file_data[0], uid_data.data(), uid_data.size());
|
||||||
|
memcpy(&file_data[16], encrypted_block.data(), encrypted_block.size());
|
||||||
|
memcpy(&file_data[16 * 0x04], encrypted_blank.data(), encrypted_blank.size());
|
||||||
|
memcpy(&file_data[16 * 0x08], encrypted_blank.data(), encrypted_blank.size());
|
||||||
|
memcpy(&file_data[16 * 0x0C], encrypted_blank.data(), encrypted_blank.size());
|
||||||
|
memcpy(&file_data[16 * 0x0D], encrypted_blank.data(), encrypted_blank.size());
|
||||||
|
|
||||||
|
inf_file.write(file_data.data(), file_data.size());
|
||||||
|
inf_file.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString figure_creator_dialog::get_file_path() const
|
||||||
|
{
|
||||||
|
return m_file_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
infinity_dialog::infinity_dialog(QWidget* parent)
|
||||||
|
: QDialog(parent)
|
||||||
|
{
|
||||||
|
setWindowTitle(tr("Infinity Manager"));
|
||||||
|
setObjectName("infinity_manager");
|
||||||
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
setMinimumSize(QSize(700, 200));
|
||||||
|
|
||||||
|
QVBoxLayout* vbox_panel = new QVBoxLayout();
|
||||||
|
|
||||||
|
auto add_line = [](QVBoxLayout* vbox)
|
||||||
|
{
|
||||||
|
QFrame* line = new QFrame();
|
||||||
|
line->setFrameShape(QFrame::HLine);
|
||||||
|
line->setFrameShadow(QFrame::Sunken);
|
||||||
|
vbox->addWidget(line);
|
||||||
|
};
|
||||||
|
|
||||||
|
QGroupBox* group_figures = new QGroupBox(tr("Active Infinity Figures:"));
|
||||||
|
QVBoxLayout* vbox_group = new QVBoxLayout();
|
||||||
|
|
||||||
|
add_figure_slot(vbox_group, QString(tr("Play Set/Power Disc")), 0);
|
||||||
|
add_line(vbox_group);
|
||||||
|
add_figure_slot(vbox_group, QString(tr("Player One")), 1);
|
||||||
|
add_line(vbox_group);
|
||||||
|
add_figure_slot(vbox_group, QString(tr("Player One Ability One")), 3);
|
||||||
|
add_line(vbox_group);
|
||||||
|
add_figure_slot(vbox_group, QString(tr("Player One Ability Two")), 5);
|
||||||
|
add_line(vbox_group);
|
||||||
|
add_figure_slot(vbox_group, QString(tr("Player Two")), 2);
|
||||||
|
add_line(vbox_group);
|
||||||
|
add_figure_slot(vbox_group, QString(tr("Player Two Ability One")), 4);
|
||||||
|
add_line(vbox_group);
|
||||||
|
add_figure_slot(vbox_group, QString(tr("Player Two Ability Two")), 6);
|
||||||
|
|
||||||
|
group_figures->setLayout(vbox_group);
|
||||||
|
vbox_panel->addWidget(group_figures);
|
||||||
|
setLayout(vbox_panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
infinity_dialog::~infinity_dialog()
|
||||||
|
{
|
||||||
|
inst = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
infinity_dialog* infinity_dialog::get_dlg(QWidget* parent)
|
||||||
|
{
|
||||||
|
if (inst == nullptr)
|
||||||
|
inst = new infinity_dialog(parent);
|
||||||
|
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void infinity_dialog::add_figure_slot(QVBoxLayout* vbox_group, QString name, u8 slot)
|
||||||
|
{
|
||||||
|
ensure(slot < figure_slots.size());
|
||||||
|
|
||||||
|
QHBoxLayout* hbox_infinity = new QHBoxLayout();
|
||||||
|
|
||||||
|
QLabel* label_figname = new QLabel(name);
|
||||||
|
|
||||||
|
QPushButton* clear_btn = new QPushButton(tr("Clear"));
|
||||||
|
QPushButton* create_btn = new QPushButton(tr("Create"));
|
||||||
|
QPushButton* load_btn = new QPushButton(tr("Load"));
|
||||||
|
|
||||||
|
m_edit_figures[slot] = new QLineEdit();
|
||||||
|
m_edit_figures[slot]->setEnabled(false);
|
||||||
|
if (figure_slots[slot])
|
||||||
|
{
|
||||||
|
const auto found_figure = list_figures.find(figure_slots[slot].value());
|
||||||
|
if (found_figure != list_figures.end())
|
||||||
|
{
|
||||||
|
m_edit_figures[slot]->setText(QString::fromStdString(found_figure->second.second));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_edit_figures[slot]->setText(tr("Unknown Figure"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_edit_figures[slot]->setText(tr("None"));
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(clear_btn, &QAbstractButton::clicked, this, [this, slot]
|
||||||
|
{
|
||||||
|
clear_figure(slot);
|
||||||
|
});
|
||||||
|
connect(create_btn, &QAbstractButton::clicked, this, [this, slot]
|
||||||
|
{
|
||||||
|
create_figure(slot);
|
||||||
|
});
|
||||||
|
connect(load_btn, &QAbstractButton::clicked, this, [this, slot]
|
||||||
|
{
|
||||||
|
load_figure(slot);
|
||||||
|
});
|
||||||
|
|
||||||
|
hbox_infinity->addWidget(label_figname);
|
||||||
|
hbox_infinity->addWidget(m_edit_figures[slot]);
|
||||||
|
hbox_infinity->addWidget(clear_btn);
|
||||||
|
hbox_infinity->addWidget(create_btn);
|
||||||
|
hbox_infinity->addWidget(load_btn);
|
||||||
|
|
||||||
|
vbox_group->addLayout(hbox_infinity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void infinity_dialog::clear_figure(u8 slot)
|
||||||
|
{
|
||||||
|
ensure(slot < figure_slots.size());
|
||||||
|
|
||||||
|
if (figure_slots[slot])
|
||||||
|
{
|
||||||
|
g_infinitybase.remove_figure(slot);
|
||||||
|
figure_slots[slot] = 0;
|
||||||
|
m_edit_figures[slot]->setText(tr("None"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void infinity_dialog::create_figure(u8 slot)
|
||||||
|
{
|
||||||
|
ensure(slot < figure_slots.size());
|
||||||
|
figure_creator_dialog create_dlg(this, slot);
|
||||||
|
if (create_dlg.exec() == Accepted)
|
||||||
|
{
|
||||||
|
load_figure_path(slot, create_dlg.get_file_path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void infinity_dialog::load_figure(u8 slot)
|
||||||
|
{
|
||||||
|
ensure(slot < figure_slots.size());
|
||||||
|
const QString file_path = QFileDialog::getOpenFileName(this, tr("Select Infinity File"), s_last_figure_path, tr("Infinity Figure (*.bin);;"));
|
||||||
|
if (file_path.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_last_figure_path = QFileInfo(file_path).absolutePath() + "/";
|
||||||
|
|
||||||
|
load_figure_path(slot, file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void infinity_dialog::load_figure_path(u8 slot, const QString& path)
|
||||||
|
{
|
||||||
|
fs::file inf_file(path.toStdString(), fs::read + fs::write + fs::lock);
|
||||||
|
if (!inf_file)
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Failed to open the figure file!"), tr("Failed to open the figure file(%1)!\nFile may already be in use on the base.").arg(path), QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<u8, 0x14 * 0x10> data;
|
||||||
|
if (inf_file.read(data.data(), data.size()) != data.size())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Failed to read the figure file!"), tr("Failed to read the figure file(%1)!\nFile was too small.").arg(path), QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_figure(slot);
|
||||||
|
|
||||||
|
const u32 fignum = g_infinitybase.load_figure(data, std::move(inf_file), slot);
|
||||||
|
auto name = list_figures.find(fignum);
|
||||||
|
if (name != list_figures.end())
|
||||||
|
{
|
||||||
|
m_edit_figures[slot]->setText(QString::fromStdString(name->second.second));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_edit_figures[slot]->setText(tr("Unknown Figure"));
|
||||||
|
}
|
||||||
|
figure_slots[slot] = fignum;
|
||||||
|
}
|
50
rpcs3/rpcs3qt/infinity_dialog.h
Normal file
50
rpcs3/rpcs3qt/infinity_dialog.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include "util/types.hpp"
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
class figure_creator_dialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit figure_creator_dialog(QWidget* parent, u8 slot);
|
||||||
|
QString get_file_path() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QString m_file_path;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool create_blank_figure(u32 character, u8 series);
|
||||||
|
};
|
||||||
|
|
||||||
|
class infinity_dialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit infinity_dialog(QWidget* parent);
|
||||||
|
~infinity_dialog();
|
||||||
|
static infinity_dialog* get_dlg(QWidget* parent);
|
||||||
|
|
||||||
|
infinity_dialog(infinity_dialog const&) = delete;
|
||||||
|
void operator=(infinity_dialog const&) = delete;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void clear_figure(u8 slot);
|
||||||
|
void create_figure(u8 slot);
|
||||||
|
void load_figure(u8 slot);
|
||||||
|
void load_figure_path(u8 slot, const QString& path);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::array<QLineEdit*, 7> m_edit_figures{};
|
||||||
|
static std::array<std::optional<u32>, 7> figure_slots;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void add_figure_slot(QVBoxLayout* vbox_group, QString name, u8 slot);
|
||||||
|
static infinity_dialog* inst;
|
||||||
|
};
|
@ -20,6 +20,7 @@
|
|||||||
#include "pad_settings_dialog.h"
|
#include "pad_settings_dialog.h"
|
||||||
#include "progress_dialog.h"
|
#include "progress_dialog.h"
|
||||||
#include "skylander_dialog.h"
|
#include "skylander_dialog.h"
|
||||||
|
#include "infinity_dialog.h"
|
||||||
#include "cheat_manager.h"
|
#include "cheat_manager.h"
|
||||||
#include "patch_manager_dialog.h"
|
#include "patch_manager_dialog.h"
|
||||||
#include "patch_creator_dialog.h"
|
#include "patch_creator_dialog.h"
|
||||||
@ -2415,6 +2416,12 @@ void main_window::CreateConnects()
|
|||||||
sky_diag->show();
|
sky_diag->show();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(ui->actionManage_Infinity_Base, &QAction::triggered, this, [this]
|
||||||
|
{
|
||||||
|
infinity_dialog* inf_dlg = infinity_dialog::get_dlg(this);
|
||||||
|
inf_dlg->show();
|
||||||
|
});
|
||||||
|
|
||||||
connect(ui->actionManage_Cheats, &QAction::triggered, this, [this]
|
connect(ui->actionManage_Cheats, &QAction::triggered, this, [this]
|
||||||
{
|
{
|
||||||
cheat_manager_dialog* cheat_manager = cheat_manager_dialog::get_dlg(this);
|
cheat_manager_dialog* cheat_manager = cheat_manager_dialog::get_dlg(this);
|
||||||
|
@ -260,6 +260,7 @@
|
|||||||
<addaction name="actionManage_RAP_Licenses"/>
|
<addaction name="actionManage_RAP_Licenses"/>
|
||||||
<addaction name="actionManage_Trophy_Data"/>
|
<addaction name="actionManage_Trophy_Data"/>
|
||||||
<addaction name="actionManage_Skylanders_Portal"/>
|
<addaction name="actionManage_Skylanders_Portal"/>
|
||||||
|
<addaction name="actionManage_Infinity_Base"/>
|
||||||
<addaction name="actionManage_Cheats"/>
|
<addaction name="actionManage_Cheats"/>
|
||||||
<addaction name="actionManage_Game_Patches"/>
|
<addaction name="actionManage_Game_Patches"/>
|
||||||
<addaction name="actionManage_Screenshots"/>
|
<addaction name="actionManage_Screenshots"/>
|
||||||
@ -1104,6 +1105,11 @@
|
|||||||
<string>Skylanders Portal</string>
|
<string>Skylanders Portal</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionManage_Infinity_Base">
|
||||||
|
<property name="text">
|
||||||
|
<string>Infinity Base</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
<action name="actionManage_Cheats">
|
<action name="actionManage_Cheats">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Cheats</string>
|
<string>Cheats</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user