From 73cee9a43dc49597b1bd9e5f14926b45909dcc9d Mon Sep 17 00:00:00 2001 From: Joshua de Reeper Date: Sun, 3 Nov 2024 17:11:40 +0000 Subject: [PATCH] sys_usbd: Better Dimensions Move Handling --- rpcs3/Emu/Io/Dimensions.cpp | 80 +++++++++++++++++++++-------- rpcs3/Emu/Io/Dimensions.h | 4 +- rpcs3/rpcs3qt/dimensions_dialog.cpp | 5 ++ 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/rpcs3/Emu/Io/Dimensions.cpp b/rpcs3/Emu/Io/Dimensions.cpp index ccaac30adf..40216e9ba4 100644 --- a/rpcs3/Emu/Io/Dimensions.cpp +++ b/rpcs3/Emu/Io/Dimensions.cpp @@ -259,9 +259,9 @@ dimensions_figure& dimensions_toypad::get_figure_by_index(u8 index) void dimensions_toypad::random_uid(u8* uid_buffer) { uid_buffer[0] = 0x04; - uid_buffer[6] = 0x80; + uid_buffer[7] = 0x80; - for (u8 i = 1; i < 6; i++) + for (u8 i = 1; i < 7; i++) { u8 random = rand() % 255; uid_buffer[i] = random; @@ -384,10 +384,10 @@ u32 dimensions_toypad::load_figure(const std::array& buf, fs::f std::memcpy(figure.data.data(), buf.data(), buf.size()); // When a figure is added to the toypad, respond to the game with the pad they were added to, their index, // the direction (0x00 in byte 6 for added) and their UID - std::array figure_change_response = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x00}; - std::memcpy(&figure_change_response[6], buf.data(), 7); + std::array figure_change_response = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x00, + buf[0], buf[1], buf[2], buf[4], buf[5], buf[6], buf[7]}; figure_change_response[13] = generate_checksum(figure_change_response, 13); - m_figure_added_removed_responses.push(figure_change_response); + m_figure_added_removed_responses.push(std::move(figure_change_response)); if (lock) { @@ -396,7 +396,7 @@ u32 dimensions_toypad::load_figure(const std::array& buf, fs::f return id; } -bool dimensions_toypad::remove_figure(u8 pad, u8 index, bool save, bool lock) +bool dimensions_toypad::remove_figure(u8 pad, u8 index, bool full_remove, bool lock) { dimensions_figure& figure = get_figure_by_index(index); if (figure.index == 255) @@ -411,17 +411,20 @@ bool dimensions_toypad::remove_figure(u8 pad, u8 index, bool save, bool lock) // When a figure is removed from the toypad, respond to the game with the pad they were removed from, their index, // the direction (0x01 in byte 6 for removed) and their UID - std::array figure_change_response = {0x56, 0x0b, pad, 0x00, figure.index, 0x01}; - std::memcpy(&figure_change_response[6], figure.data.data(), 7); - if (save) + if (full_remove) { + std::array figure_change_response = {0x56, 0x0b, pad, 0x00, figure.index, 0x01, + figure.data[0], figure.data[1], figure.data[2], + figure.data[4], figure.data[5], figure.data[6], figure.data[7]}; + figure_change_response[13] = generate_checksum(figure_change_response, 13); + m_figure_added_removed_responses.push(std::move(figure_change_response)); figure.save(); figure.dim_file.close(); } + figure.index = 255; figure.pad = 255; - figure_change_response[13] = generate_checksum(figure_change_response, 13); - m_figure_added_removed_responses.push(figure_change_response); + figure.id = 0; if (lock) { @@ -430,23 +433,56 @@ bool dimensions_toypad::remove_figure(u8 pad, u8 index, bool save, bool lock) return true; } -bool dimensions_toypad::move_figure(u8 pad, u8 index, u8 old_pad, u8 old_index) +bool dimensions_toypad::temp_remove(u8 index) { std::lock_guard lock(m_dimensions_mutex); + const dimensions_figure& figure = get_figure_by_index(index); + if (figure.index == 255) + return false; + + // Send a response to the game that the figure has been "Picked up" from existing slot, + // until either the movement is cancelled, or user chooses a space to move to + std::array figure_change_response = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x01, + figure.data[0], figure.data[1], figure.data[2], + figure.data[4], figure.data[5], figure.data[6], figure.data[7]}; + + figure_change_response[13] = generate_checksum(figure_change_response, 13); + m_figure_added_removed_responses.push(std::move(figure_change_response)); + + return true; +} + +bool dimensions_toypad::cancel_remove(u8 index) +{ + std::lock_guard lock(m_dimensions_mutex); + + dimensions_figure& figure = get_figure_by_index(index); + if (figure.index == 255) + return false; + + // Cancel the previous movement of the figure + std::array figure_change_response = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x00, + figure.data[0], figure.data[1], figure.data[2], + figure.data[4], figure.data[5], figure.data[6], figure.data[7]}; + + figure_change_response[13] = generate_checksum(figure_change_response, 13); + m_figure_added_removed_responses.push(std::move(figure_change_response)); + + return true; +} + +bool dimensions_toypad::move_figure(u8 pad, u8 index, u8 old_pad, u8 old_index) +{ if (old_index == index) { // Don't bother removing and loading again, just send response to the game - const dimensions_figure& figure = get_figure_by_index(old_index); - std::array figure_remove_response = {0x56, 0x0b, pad, 0x00, figure.index, 0x01}; - figure_remove_response[13] = generate_checksum(figure_remove_response, 13); - std::array figure_add_response = {0x56, 0x0b, pad, 0x00, figure.index, 0x00}; - figure_add_response[13] = generate_checksum(figure_add_response, 13); - m_figure_added_removed_responses.push(std::move(figure_remove_response)); - m_figure_added_removed_responses.push(std::move(figure_add_response)); + cancel_remove(index); return true; } + std::lock_guard lock(m_dimensions_mutex); + // When moving figures between spaces on the toypad, remove any figure from the space they are moving to, // then remove them from their current space, then load them to the space they are moving to remove_figure(pad, index, true, false); @@ -465,14 +501,16 @@ bool dimensions_toypad::move_figure(u8 pad, u8 index, u8 old_pad, u8 old_index) bool dimensions_toypad::create_blank_character(std::array& buf, u16 id) { random_uid(buf.data()); - buf[7] = id & 0xFF; - std::array uid = {buf[0], buf[1], buf[2], buf[4], buf[5], buf[6], buf[7]}; + buf[3] = id & 0xFF; // Only characters are created with their ID encrypted and stored in pages 36 and 37, // as well as a password stored in page 43. Blank tags have their information populated // by the game when it calls the write_block command. if (id != 0) { + // LEGO Dimensions figures use NTAG213 tag types, and the UID for these is stored in + // bytes 0, 1, 2, 4, 5, 6 and 7 (out of 180 bytes) + std::array uid = {buf[0], buf[1], buf[2], buf[4], buf[5], buf[6], buf[7]}; const std::array figure_key = generate_figure_key(buf); std::array value_to_encrypt = {}; diff --git a/rpcs3/Emu/Io/Dimensions.h b/rpcs3/Emu/Io/Dimensions.h index d532be0c77..db1c6577c3 100644 --- a/rpcs3/Emu/Io/Dimensions.h +++ b/rpcs3/Emu/Io/Dimensions.h @@ -30,7 +30,9 @@ public: void get_model(const u8* buf, u8 sequence, std::array& reply_buf); std::optional> pop_added_removed_response(); - bool remove_figure(u8 pad, u8 index, bool save, bool lock); + bool remove_figure(u8 pad, u8 index, bool full_remove, bool lock); + bool temp_remove(u8 index); + bool cancel_remove(u8 index); u32 load_figure(const std::array& buf, fs::file in_file, u8 pad, u8 index, bool lock); bool move_figure(u8 pad, u8 index, u8 old_pad, u8 old_index); static bool create_blank_character(std::array& buf, u16 id); diff --git a/rpcs3/rpcs3qt/dimensions_dialog.cpp b/rpcs3/rpcs3qt/dimensions_dialog.cpp index 0d26d35def..596d94ae25 100644 --- a/rpcs3/rpcs3qt/dimensions_dialog.cpp +++ b/rpcs3/rpcs3qt/dimensions_dialog.cpp @@ -724,6 +724,7 @@ void dimensions_dialog::move_figure(u8 pad, u8 index) { ensure(index < figure_slots.size()); minifig_move_dialog move_dlg(this, index); + g_dimensionstoypad.temp_remove(index); if (move_dlg.exec() == Accepted) { g_dimensionstoypad.move_figure(move_dlg.get_new_pad(), move_dlg.get_new_index(), pad, index); @@ -735,6 +736,10 @@ void dimensions_dialog::move_figure(u8 pad, u8 index) m_edit_figures[index]->setText(tr("None")); } } + else + { + g_dimensionstoypad.cancel_remove(index); + } } void dimensions_dialog::load_figure_path(u8 pad, u8 index, const QString& path)