summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2025-02-22 14:08:41 -0500
committerGitHub <noreply@github.com>2025-02-22 14:08:41 -0500
commitaabde7148453d81173787335c12ee8de17f575aa (patch)
treecf933d2cea9ddcfedc1f4cc3a38d7d6ac02cf541
parentddb0e1e309d176ea1ba9e8dc33cb76e47ff6681e (diff)
parent7a37d015b7dc187d304b6f52a223daa8a58a55eb (diff)
Merge pull request #13348 from jordan-woyak/movie-SerializedWiimoteState
Core/Movie: Make DTM Wii Remote data use SerializedWiimoteState.
-rw-r--r--Source/Core/Core/DolphinAnalytics.cpp3
-rw-r--r--Source/Core/Core/DolphinAnalytics.h5
-rw-r--r--Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp18
-rw-r--r--Source/Core/Core/HW/WiimoteEmu/Extension/Extension.cpp9
-rw-r--r--Source/Core/Core/HW/WiimoteEmu/Extension/Extension.h7
-rw-r--r--Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp131
-rw-r--r--Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h3
-rw-r--r--Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp13
-rw-r--r--Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp5
-rw-r--r--Source/Core/Core/Movie.cpp237
-rw-r--r--Source/Core/Core/Movie.h9
11 files changed, 183 insertions, 257 deletions
diff --git a/Source/Core/Core/DolphinAnalytics.cpp b/Source/Core/Core/DolphinAnalytics.cpp
index 5f54420013..ebd855f2c4 100644
--- a/Source/Core/Core/DolphinAnalytics.cpp
+++ b/Source/Core/Core/DolphinAnalytics.cpp
@@ -137,8 +137,7 @@ void DolphinAnalytics::ReportGameStart()
}
// Keep in sync with enum class GameQuirk definition.
-constexpr std::array<const char*, 34> GAME_QUIRKS_NAMES{
- "directly-reads-wiimote-input",
+constexpr std::array GAME_QUIRKS_NAMES{
"uses-DVDLowStopLaser",
"uses-DVDLowOffset",
"uses-DVDLowReadDiskBca",
diff --git a/Source/Core/Core/DolphinAnalytics.h b/Source/Core/Core/DolphinAnalytics.h
index 83a5a45822..8fc23161a8 100644
--- a/Source/Core/Core/DolphinAnalytics.h
+++ b/Source/Core/Core/DolphinAnalytics.h
@@ -4,7 +4,6 @@
#pragma once
#include <array>
-#include <memory>
#include <mutex>
#include <string>
#include <string_view>
@@ -21,10 +20,6 @@
enum class GameQuirk
{
- // The Wii remote hardware makes it possible to bypass normal data reporting and directly
- // "read" extension or IR data. This would break our current TAS/NetPlay implementation.
- DIRECTLY_READS_WIIMOTE_INPUT = 0,
-
// Several Wii DI commands that are rarely/never used and not implemented by Dolphin
USES_DVD_LOW_STOP_LASER,
USES_DVD_LOW_OFFSET,
diff --git a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp
index 9d354a4b8e..7c3202cc0b 100644
--- a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp
+++ b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp
@@ -4,22 +4,19 @@
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
#include <cmath>
-#include <fstream>
#include <iterator>
#include "Common/BitUtils.h"
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
#include "Common/EnumUtils.h"
-#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Common/Swap.h"
+
#include "Core/Core.h"
-#include "Core/DolphinAnalytics.h"
#include "Core/HW/Wiimote.h"
#include "Core/HW/WiimoteCommon/WiimoteHid.h"
-#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
namespace WiimoteEmu
{
@@ -490,19 +487,6 @@ bool Wiimote::ProcessReadDataRequest()
break;
}
- // It is possible to bypass data reporting and directly read extension input.
- // While I am not aware of any games that actually do this,
- // our NetPlay and TAS methods are completely unprepared for it.
- const bool is_reading_ext = EncryptedExtension::I2C_ADDR == m_read_request.slave_address &&
- m_read_request.address < EncryptedExtension::CONTROLLER_DATA_BYTES;
- const bool is_reading_ir =
- CameraLogic::I2C_ADDR == m_read_request.slave_address &&
- m_read_request.address < CameraLogic::REPORT_DATA_OFFSET + CameraLogic::CAMERA_DATA_BYTES &&
- m_read_request.address + m_read_request.size > CameraLogic::REPORT_DATA_OFFSET;
-
- if (is_reading_ext || is_reading_ir)
- DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::DIRECTLY_READS_WIIMOTE_INPUT);
-
// Top byte of address is ignored on the bus, but it IS maintained in the read-reply.
auto const bytes_read = m_i2c_bus.BusRead(
m_read_request.slave_address, (u8)m_read_request.address, bytes_to_read, reply.data);
diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Extension.cpp b/Source/Core/Core/HW/WiimoteEmu/Extension/Extension.cpp
index fd2b185872..d733385dbb 100644
--- a/Source/Core/Core/HW/WiimoteEmu/Extension/Extension.cpp
+++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Extension.cpp
@@ -3,19 +3,14 @@
#include "Core/HW/WiimoteEmu/Extension/Extension.h"
-#include <algorithm>
-#include <array>
#include <cstring>
#include "Common/CommonTypes.h"
-#include "Common/Inline.h"
#include "Core/HW/Wiimote.h"
#include "Core/HW/WiimoteEmu/Extension/DesiredExtensionState.h"
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
-#include "Common/Logging/Log.h"
-
namespace WiimoteEmu
{
Extension::Extension(const char* name) : Extension(name, name)
@@ -91,11 +86,9 @@ int EncryptedExtension::BusRead(u8 slave_addr, u8 addr, int count, u8* data_out)
if (I2C_ADDR != slave_addr)
return 0;
- if (0x00 == addr)
+ if (offsetof(Register, controller_data) == addr)
{
// This is where real hardware would update controller data
- // We do it in Update() for TAS determinism
- // TAS code fails to sync data reads and such..
}
auto const result = RawRead(&m_reg, addr, count, data_out);
diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Extension.h b/Source/Core/Core/HW/WiimoteEmu/Extension/Extension.h
index 4a055c597d..d836e49a46 100644
--- a/Source/Core/Core/HW/WiimoteEmu/Extension/Extension.h
+++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Extension.h
@@ -3,8 +3,6 @@
#pragma once
-#include "Core/HW/WiimoteEmu/Extension/Extension.h"
-
#include <array>
#include <string>
@@ -69,10 +67,6 @@ public:
using Extension::Extension;
- // TODO: This is public for TAS reasons.
- // TODO: TAS handles encryption poorly.
- EncryptionKey ext_key;
-
static constexpr int CALIBRATION_CHECKSUM_BYTES = 2;
#pragma pack(push, 1)
@@ -103,6 +97,7 @@ public:
static_assert(0x100 == sizeof(Register));
protected:
+ EncryptionKey ext_key;
Register m_reg = {};
void Reset() override;
diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp
index a93ad379e8..f8115afdf8 100644
--- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp
+++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp
@@ -17,13 +17,10 @@
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "Common/MathUtil.h"
-#include "Common/MsgHandler.h"
#include "Core/Config/MainSettings.h"
#include "Core/Core.h"
#include "Core/HW/Wiimote.h"
-#include "Core/Movie.h"
-#include "Core/System.h"
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
#include "Core/HW/WiimoteCommon/WiimoteHid.h"
@@ -39,8 +36,6 @@
#include "Core/HW/WiimoteEmu/Extension/Turntable.h"
#include "Core/HW/WiimoteEmu/Extension/UDrawTablet.h"
-#include "InputCommon/ControllerEmu/Control/Input.h"
-#include "InputCommon/ControllerEmu/Control/Output.h"
#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
@@ -589,9 +584,6 @@ void Wiimote::Update(const WiimoteEmu::DesiredWiimoteState& target_state)
void Wiimote::SendDataReport(const DesiredWiimoteState& target_state)
{
- auto& movie = Core::System::GetInstance().GetMovie();
- movie.SetPolledDevice();
-
if (InputReportID::ReportDisabled == m_reporting_mode)
{
// The wiimote is in this disabled after an extension change.
@@ -607,79 +599,67 @@ void Wiimote::SendDataReport(const DesiredWiimoteState& target_state)
DataReportBuilder rpt_builder(m_reporting_mode);
- if (movie.IsPlayingInput() && movie.PlayWiimote(m_bt_device_index, rpt_builder,
- m_active_extension, GetExtensionEncryptionKey()))
+ // Core buttons:
+ if (rpt_builder.HasCore())
{
- // Update buttons in status struct from movie:
- rpt_builder.GetCoreData(&m_status.buttons);
+ rpt_builder.SetCoreData(m_status.buttons);
}
- else
+
+ // Acceleration:
+ if (rpt_builder.HasAccel())
{
- // Core buttons:
- if (rpt_builder.HasCore())
- {
- rpt_builder.SetCoreData(m_status.buttons);
- }
+ rpt_builder.SetAccelData(target_state.acceleration);
+ }
+
+ // IR Camera:
+ if (rpt_builder.HasIR())
+ {
+ // Note: Camera logic currently contains no changing state so we can just update it here.
+ // If that changes this should be moved to Wiimote::Update();
+ m_camera_logic.Update(target_state.camera_points);
+
+ // The real wiimote reads camera data from the i2c bus starting at offset 0x37:
+ const u8 camera_data_offset =
+ CameraLogic::REPORT_DATA_OFFSET + rpt_builder.GetIRDataFormatOffset();
+
+ u8* ir_data = rpt_builder.GetIRDataPtr();
+ const u8 ir_size = rpt_builder.GetIRDataSize();
- // Acceleration:
- if (rpt_builder.HasAccel())
+ if (ir_size != m_i2c_bus.BusRead(CameraLogic::I2C_ADDR, camera_data_offset, ir_size, ir_data))
{
- rpt_builder.SetAccelData(target_state.acceleration);
+ // This happens when IR reporting is enabled but the camera hardware is disabled.
+ // It commonly occurs when changing IR sensitivity.
+ std::fill_n(ir_data, ir_size, u8(0xff));
}
+ }
+
+ // Extension port:
+ if (rpt_builder.HasExt())
+ {
+ // Prepare extension input first as motion-plus may read from it.
+ // This currently happens in Wiimote::Update();
+ // TODO: Separate extension input data preparation from Update.
+ // GetActiveExtension()->PrepareInput();
- // IR Camera:
- if (rpt_builder.HasIR())
+ if (m_is_motion_plus_attached)
{
- // Note: Camera logic currently contains no changing state so we can just update it here.
- // If that changes this should be moved to Wiimote::Update();
- m_camera_logic.Update(target_state.camera_points);
-
- // The real wiimote reads camera data from the i2c bus starting at offset 0x37:
- const u8 camera_data_offset =
- CameraLogic::REPORT_DATA_OFFSET + rpt_builder.GetIRDataFormatOffset();
-
- u8* ir_data = rpt_builder.GetIRDataPtr();
- const u8 ir_size = rpt_builder.GetIRDataSize();
-
- if (ir_size != m_i2c_bus.BusRead(CameraLogic::I2C_ADDR, camera_data_offset, ir_size, ir_data))
- {
- // This happens when IR reporting is enabled but the camera hardware is disabled.
- // It commonly occurs when changing IR sensitivity.
- std::fill_n(ir_data, ir_size, u8(0xff));
- }
+ // TODO: Make input preparation triggered by bus read.
+ m_motion_plus.PrepareInput(target_state.motion_plus.has_value() ?
+ target_state.motion_plus.value() :
+ MotionPlus::GetDefaultGyroscopeData());
}
- // Extension port:
- if (rpt_builder.HasExt())
+ u8* ext_data = rpt_builder.GetExtDataPtr();
+ const u8 ext_size = rpt_builder.GetExtDataSize();
+
+ if (ext_size != m_i2c_bus.BusRead(ExtensionPort::REPORT_I2C_SLAVE,
+ ExtensionPort::REPORT_I2C_ADDR, ext_size, ext_data))
{
- // Prepare extension input first as motion-plus may read from it.
- // This currently happens in Wiimote::Update();
- // TODO: Separate extension input data preparation from Update.
- // GetActiveExtension()->PrepareInput();
-
- if (m_is_motion_plus_attached)
- {
- // TODO: Make input preparation triggered by bus read.
- m_motion_plus.PrepareInput(target_state.motion_plus.has_value() ?
- target_state.motion_plus.value() :
- MotionPlus::GetDefaultGyroscopeData());
- }
-
- u8* ext_data = rpt_builder.GetExtDataPtr();
- const u8 ext_size = rpt_builder.GetExtDataSize();
-
- if (ext_size != m_i2c_bus.BusRead(ExtensionPort::REPORT_I2C_SLAVE,
- ExtensionPort::REPORT_I2C_ADDR, ext_size, ext_data))
- {
- // Real wiimote seems to fill with 0xff on failed bus read
- std::fill_n(ext_data, ext_size, u8(0xff));
- }
+ // Real wiimote seems to fill with 0xff on failed bus read
+ std::fill_n(ext_data, ext_size, u8(0xff));
}
}
- movie.CheckWiimoteStatus(m_bt_device_index, rpt_builder, m_active_extension,
- GetExtensionEncryptionKey());
-
// Send the report:
InterruptDataInputCallback(rpt_builder.GetDataPtr(), rpt_builder.GetDataSize());
@@ -741,10 +721,11 @@ void Wiimote::LoadDefaults(const ControllerInterface& ciface)
// B
m_buttons->SetControlExpression(1, "`Click 1`");
#endif
- m_buttons->SetControlExpression(2, "`1`"); // 1
- m_buttons->SetControlExpression(3, "`2`"); // 2
- m_buttons->SetControlExpression(4, "Q"); // -
- m_buttons->SetControlExpression(5, "E"); // +
+ // 1 2 - +
+ m_buttons->SetControlExpression(2, "`1`");
+ m_buttons->SetControlExpression(3, "`2`");
+ m_buttons->SetControlExpression(4, "Q");
+ m_buttons->SetControlExpression(5, "E");
#ifdef _WIN32
m_buttons->SetControlExpression(6, "RETURN"); // Home
@@ -822,14 +803,6 @@ Extension* Wiimote::GetActiveExtension() const
return static_cast<Extension*>(m_attachments->GetAttachmentList()[m_active_extension].get());
}
-EncryptionKey Wiimote::GetExtensionEncryptionKey() const
-{
- if (ExtensionNumber::NONE == GetActiveExtensionNumber())
- return {};
-
- return static_cast<EncryptedExtension*>(GetActiveExtension())->ext_key;
-}
-
bool Wiimote::IsSideways() const
{
const bool sideways_modifier_toggle = m_hotkeys->GetSettingsModifier()[0];
diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h
index e50a6efbc9..be5fdfdc6e 100644
--- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h
+++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h
@@ -246,9 +246,6 @@ private:
Extension* GetActiveExtension() const;
Extension* GetNoneExtension() const;
- // TODO: Kill this nonsensical function used for TAS:
- EncryptionKey GetExtensionEncryptionKey() const;
-
struct ReadRequest
{
WiimoteCommon::AddressSpace space;
diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp
index 5c66d48cb2..a63ca59ba9 100644
--- a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp
+++ b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp
@@ -11,8 +11,6 @@
#include "Common/Assert.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
-#include "Common/NandPaths.h"
-#include "Common/StringUtil.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/Debugger/Debugger_SymbolMap.h"
@@ -22,6 +20,7 @@
#include "Core/HW/WiimoteEmu/DesiredWiimoteState.h"
#include "Core/IOS/Device.h"
#include "Core/IOS/IOS.h"
+#include "Core/Movie.h"
#include "Core/NetPlayClient.h"
#include "Core/NetPlayProto.h"
#include "Core/SysConf.h"
@@ -390,6 +389,16 @@ void BluetoothEmuDevice::Update()
}
}
+ auto& movie = Core::System::GetInstance().GetMovie();
+ for (int i = 0; i != MAX_WIIMOTES; ++i)
+ {
+ if (next_call[i] == WiimoteDevice::NextUpdateInputCall::None)
+ continue;
+
+ movie.PlayWiimote(i, &wiimote_states[i]);
+ movie.CheckWiimoteStatus(i, wiimote_states[i]);
+ }
+
for (size_t i = 0; i < m_wiimotes.size(); ++i)
m_wiimotes[i]->UpdateInput(next_call[i], wiimote_states[i]);
diff --git a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp
index a48be51173..8b556da6d7 100644
--- a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp
+++ b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp
@@ -292,9 +292,8 @@ void WiimoteDevice::SetSource(WiimoteCommon::HIDWiimote* hid_source)
if (m_hid_source)
{
- m_hid_source->SetInterruptCallback(std::bind(&WiimoteDevice::InterruptDataInputCallback, this,
- std::placeholders::_1, std::placeholders::_2,
- std::placeholders::_3));
+ m_hid_source->SetInterruptCallback(
+ std::bind_front(&WiimoteDevice::InterruptDataInputCallback, this));
Activate(true);
}
}
diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp
index 5b11ddf72a..d4264d52d3 100644
--- a/Source/Core/Core/Movie.cpp
+++ b/Source/Core/Core/Movie.cpp
@@ -12,7 +12,6 @@
#include <mbedtls/config.h>
#include <mbedtls/md.h>
#include <mutex>
-#include <sstream>
#include <thread>
#include <utility>
#include <variant>
@@ -32,13 +31,13 @@
#include "Common/NandPaths.h"
#include "Common/StringUtil.h"
#include "Common/Timer.h"
+#include "Common/VariantUtil.h"
#include "Common/Version.h"
#include "Core/AchievementManager.h"
#include "Core/Boot/Boot.h"
#include "Core/Config/AchievementSettings.h"
#include "Core/Config/MainSettings.h"
-#include "Core/Config/SYSCONFSettings.h"
#include "Core/Config/WiimoteSettings.h"
#include "Core/ConfigLoaders/MovieConfigLoader.h"
#include "Core/ConfigManager.h"
@@ -54,14 +53,10 @@
#include "Core/HW/SI/SI.h"
#include "Core/HW/SI/SI_Device.h"
#include "Core/HW/Wiimote.h"
-#include "Core/HW/WiimoteCommon/DataReport.h"
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
-
-#include "Core/HW/WiimoteEmu/Encryption.h"
#include "Core/HW/WiimoteEmu/Extension/Classic.h"
#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
#include "Core/HW/WiimoteEmu/ExtensionPort.h"
-
#include "Core/IOS/USB/Bluetooth/BTEmu.h"
#include "Core/IOS/USB/Bluetooth/WiimoteDevice.h"
#include "Core/NetPlayProto.h"
@@ -69,16 +64,11 @@
#include "Core/System.h"
#include "Core/WiiUtils.h"
-#include "DiscIO/Enums.h"
-
#include "InputCommon/GCPadStatus.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h"
-// The chunk to allocate movie data in multiples of.
-#define DTM_BASE_LENGTH (1024)
-
namespace Movie
{
using namespace WiimoteCommon;
@@ -554,7 +544,7 @@ bool MovieManager::BeginRecordingInput(const ControllerTypeArray& controllers,
if (!Core::IsRunning(m_system))
{
// This will also reset the Wiimotes for GameCube games, but that shouldn't do anything
- Wiimote::ResetAllWiimotes();
+ ::Wiimote::ResetAllWiimotes();
}
m_play_mode = PlayMode::Recording;
@@ -673,16 +663,13 @@ static std::string GenerateInputDisplayString(ControllerState padState, int cont
}
// NOTE: CPU Thread
-static std::string GenerateWiiInputDisplayString(int remoteID, const DataReportBuilder& rpt,
- ExtensionNumber ext, const EncryptionKey& key)
+static std::string GenerateWiiInputDisplayString(int index, const DesiredWiimoteState& state)
{
- std::string display_str = fmt::format("R{}:", remoteID + 1);
+ std::string display_str = fmt::format("R{}:", index + 1);
- if (rpt.HasCore())
+ const auto& buttons = state.buttons;
+ if (buttons.hex & WiimoteCommon::ButtonData::BUTTON_MASK)
{
- ButtonData buttons;
- rpt.GetCoreData(&buttons);
-
if (buttons.left)
display_str += " LEFT";
if (buttons.right)
@@ -707,94 +694,83 @@ static std::string GenerateWiiInputDisplayString(int remoteID, const DataReportB
display_str += " HOME";
}
- if (rpt.HasAccel())
+ if (state.acceleration != state.DEFAULT_ACCELERATION)
{
- AccelData accel_data;
- rpt.GetAccelData(&accel_data);
-
- // FYI: This will only print partial data for interleaved reports.
-
+ const AccelData& accel_data = state.acceleration;
display_str +=
fmt::format(" ACC:{},{},{}", accel_data.value.x, accel_data.value.y, accel_data.value.z);
}
- if (rpt.HasIR())
- {
- const u8* const ir_data = rpt.GetIRDataPtr();
-
- // TODO: This does not handle the different IR formats.
-
- const u16 x = ir_data[0] | ((ir_data[2] >> 4 & 0x3) << 8);
- const u16 y = ir_data[1] | ((ir_data[2] >> 6 & 0x3) << 8);
- display_str += fmt::format(" IR:{},{}", x, y);
- }
-
- // Nunchuk
- if (rpt.HasExt() && ext == ExtensionNumber::NUNCHUK)
+ if (state.camera_points != state.DEFAULT_CAMERA)
{
- const u8* const extData = rpt.GetExtDataPtr();
-
- Nunchuk::DataFormat nunchuk;
- memcpy(&nunchuk, extData, sizeof(nunchuk));
- key.Decrypt((u8*)&nunchuk, 0, sizeof(nunchuk));
- nunchuk.bt.hex = nunchuk.bt.hex ^ 0x3;
-
- const std::string accel = fmt::format(" N-ACC:{},{},{}", nunchuk.GetAccelX(),
- nunchuk.GetAccelY(), nunchuk.GetAccelZ());
-
- if (nunchuk.bt.c)
- display_str += " C";
- if (nunchuk.bt.z)
- display_str += " Z";
- display_str += accel;
- display_str += Analog2DToString(nunchuk.jx, nunchuk.jy, " ANA");
+ display_str += " IR:";
+ for (auto& point : state.camera_points)
+ {
+ if (point.size == 0xff)
+ display_str += "_,";
+ else
+ display_str += fmt::format("{},{},", point.position.x, point.position.y);
+ }
+ display_str.pop_back();
}
- // Classic controller
- if (rpt.HasExt() && ext == ExtensionNumber::CLASSIC)
+ if (state.extension.data.index() != ExtensionNumber::NONE)
{
- const u8* const extData = rpt.GetExtDataPtr();
-
- Classic::DataFormat cc;
- memcpy(&cc, extData, sizeof(cc));
- key.Decrypt((u8*)&cc, 0, sizeof(cc));
- cc.bt.hex = cc.bt.hex ^ 0xFFFF;
-
- if (cc.bt.dpad_left)
- display_str += " LEFT";
- if (cc.bt.dpad_right)
- display_str += " RIGHT";
- if (cc.bt.dpad_down)
- display_str += " DOWN";
- if (cc.bt.dpad_up)
- display_str += " UP";
- if (cc.bt.a)
- display_str += " A";
- if (cc.bt.b)
- display_str += " B";
- if (cc.bt.x)
- display_str += " X";
- if (cc.bt.y)
- display_str += " Y";
- if (cc.bt.zl)
- display_str += " ZL";
- if (cc.bt.zr)
- display_str += " ZR";
- if (cc.bt.plus)
- display_str += " +";
- if (cc.bt.minus)
- display_str += " -";
- if (cc.bt.home)
- display_str += " HOME";
-
- display_str += Analog1DToString(cc.GetLeftTrigger().value, " L", 31);
- display_str += Analog1DToString(cc.GetRightTrigger().value, " R", 31);
-
- const auto left_stick = cc.GetLeftStick().value;
- display_str += Analog2DToString(left_stick.x, left_stick.y, " ANA", 63);
-
- const auto right_stick = cc.GetRightStick().value;
- display_str += Analog2DToString(right_stick.x, right_stick.y, " R-ANA", 31);
+ const auto ext_visitor = overloaded{
+ [&](const Nunchuk::DataFormat& nunchuk) {
+ const auto bt = nunchuk.GetButtons();
+ if (bt & Nunchuk::BUTTON_C)
+ display_str += " C";
+ if (bt & Nunchuk::BUTTON_Z)
+ display_str += " Z";
+ display_str += fmt::format(" N-ACC:{},{},{}", nunchuk.GetAccelX(), nunchuk.GetAccelY(),
+ nunchuk.GetAccelZ());
+ display_str += Analog2DToString(nunchuk.jx, nunchuk.jy, " ANA");
+ },
+ [&](const Classic::DataFormat& cc) {
+ const auto bt = cc.GetButtons();
+ constexpr std::pair<u16, const char*> named_buttons[] = {
+ {Classic::PAD_LEFT, "LEFT"}, {Classic::PAD_RIGHT, "RIGHT"},
+ {Classic::PAD_DOWN, "DOWN"}, {Classic::PAD_UP, "UP"},
+ {Classic::BUTTON_A, "A"}, {Classic::BUTTON_B, "B"},
+ {Classic::BUTTON_X, "X"}, {Classic::BUTTON_Y, "Y"},
+ {Classic::BUTTON_ZL, "ZL"}, {Classic::BUTTON_ZR, "ZR"},
+ {Classic::BUTTON_PLUS, "+"}, {Classic::BUTTON_MINUS, "-"},
+ {Classic::BUTTON_HOME, "HOME"},
+ };
+ for (auto& [value, name] : named_buttons)
+ {
+ if (bt & value)
+ {
+ display_str += ' ';
+ display_str += name;
+ }
+ }
+ constexpr auto trigger_max = (1 << Classic::TRIGGER_BITS) - 1;
+ display_str += Analog1DToString(cc.GetLeftTrigger().value, " L", trigger_max);
+ display_str += Analog1DToString(cc.GetRightTrigger().value, " R", trigger_max);
+
+ constexpr auto lstick_max = (1 << Classic::LEFT_STICK_BITS) - 1;
+ const auto left_stick = cc.GetLeftStick().value;
+ display_str += Analog2DToString(left_stick.x, left_stick.y, " ANA", lstick_max);
+
+ constexpr auto rstick_max = (1 << Classic::RIGHT_STICK_BITS) - 1;
+ const auto right_stick = cc.GetRightStick().value;
+ display_str += Analog2DToString(right_stick.x, right_stick.y, " R-ANA", rstick_max);
+ },
+ [&](const Guitar::DataFormat&) { display_str += " Guitar"; },
+ [&](const Drums::DesiredState&) { display_str += " Drums"; },
+ [&](const Turntable::DataFormat&) { display_str += " Turntable"; },
+ [&](const UDrawTablet::DataFormat&) { display_str += " UDraw"; },
+ [&](const DrawsomeTablet::DataFormat&) { display_str += " Drawsome"; },
+ [&](const TaTaCon::DataFormat&) { display_str += " TaTaCon"; },
+ [&](const Shinkansen::DesiredState&) { display_str += " Shinkansen"; },
+ [](const auto& arg) {
+ static_assert(std::is_same_v<std::monostate, std::decay_t<decltype(arg)>>,
+ "unimplemented extension");
+ },
+ };
+ std::visit(ext_visitor, state.extension.data);
}
return display_str;
@@ -857,29 +833,32 @@ void MovieManager::RecordInput(const GCPadStatus* PadStatus, int controllerID)
}
// NOTE: CPU Thread
-void MovieManager::CheckWiimoteStatus(int wiimote, const DataReportBuilder& rpt,
- ExtensionNumber ext, const EncryptionKey& key)
+void MovieManager::CheckWiimoteStatus(int wiimote, const DesiredWiimoteState& desired_state)
{
+ SetPolledDevice();
+
{
- std::string display_str = GenerateWiiInputDisplayString(wiimote, rpt, ext, key);
+ std::string display_str = GenerateWiiInputDisplayString(wiimote, desired_state);
std::lock_guard guard(m_input_display_lock);
m_input_display[wiimote + 4] = std::move(display_str);
}
if (IsRecordingInput())
- RecordWiimote(wiimote, rpt.GetDataPtr(), rpt.GetDataSize());
+ RecordWiimote(wiimote, SerializeDesiredState(desired_state));
}
-void MovieManager::RecordWiimote(int wiimote, const u8* data, u8 size)
+void MovieManager::RecordWiimote(int wiimote, const SerializedWiimoteState& serialized_state)
{
if (!IsRecordingInput() || !IsUsingWiimote(wiimote))
return;
InputUpdate();
+
+ const u8 size = serialized_state.length;
m_temp_input.resize(m_current_byte + size + 1);
m_temp_input[m_current_byte++] = size;
- memcpy(&m_temp_input[m_current_byte], data, size);
+ std::copy_n(serialized_state.data.data(), size, m_temp_input.data() + m_current_byte);
m_current_byte += size;
}
@@ -955,7 +934,7 @@ bool MovieManager::PlayInput(const std::string& movie_path,
m_play_mode = PlayMode::Playing;
// Wiimotes cause desync issues if they're not reset before launching the game
- Wiimote::ResetAllWiimotes();
+ ::Wiimote::ResetAllWiimotes();
Core::UpdateWantDeterminism(m_system);
@@ -1275,50 +1254,54 @@ void MovieManager::PlayController(GCPadStatus* PadStatus, int controllerID)
}
// NOTE: CPU Thread
-bool MovieManager::PlayWiimote(int wiimote, WiimoteCommon::DataReportBuilder& rpt,
- ExtensionNumber ext, const EncryptionKey& key)
+bool MovieManager::PlayWiimote(int wiimote, DesiredWiimoteState* desired_state)
{
if (!IsPlayingInput() || !IsUsingWiimote(wiimote) || m_temp_input.empty())
return false;
- if (m_current_byte > m_temp_input.size())
+ if (m_current_byte + sizeof(u8) > m_temp_input.size())
{
- PanicAlertFmtT("Premature movie end in PlayWiimote. {0} > {1}", m_current_byte,
+ PanicAlertFmtT("Premature movie end in PlayWiimote. {0} + 1 > {1}", m_current_byte,
m_temp_input.size());
EndPlayInput(!m_read_only);
return false;
}
- const u8 size = rpt.GetDataSize();
- const u8 sizeInMovie = m_temp_input[m_current_byte];
+ SerializedWiimoteState serialized;
+ serialized.length = m_temp_input[m_current_byte];
- if (size != sizeInMovie)
+ if (serialized.length > serialized.data.size())
{
- PanicAlertFmtT(
- "Fatal desync. Aborting playback. (Error in PlayWiimote: {0} != {1}, byte {2}.){3}",
- sizeInMovie, size, m_current_byte,
- (m_controllers == ControllerTypeArray{}) ?
- " Try re-creating the recording with all GameCube controllers "
- "disabled (in Configure > GameCube > Device Settings)." :
- "");
+ PanicAlertFmtT("Invalid serialized length:{0} in PlayWiimote. byte:{1}", int(serialized.length),
+ m_current_byte);
EndPlayInput(!m_read_only);
return false;
}
- m_current_byte++;
-
- if (m_current_byte + size > m_temp_input.size())
+ ++m_current_byte;
+ if (m_current_byte + serialized.length > m_temp_input.size())
{
- PanicAlertFmtT("Premature movie end in PlayWiimote. {0} + {1} > {2}", m_current_byte, size,
- m_temp_input.size());
+ PanicAlertFmtT("Premature movie end in PlayWiimote. {0} + {1} > {2}", m_current_byte,
+ int(serialized.length), m_temp_input.size());
EndPlayInput(!m_read_only);
return false;
}
- memcpy(rpt.GetDataPtr(), &m_temp_input[m_current_byte], size);
- m_current_byte += size;
+ std::copy_n(m_temp_input.data() + m_current_byte, serialized.length, serialized.data.data());
+ if (!WiimoteEmu::DeserializeDesiredState(desired_state, serialized))
+ {
+ PanicAlertFmtT("Aborting playback. Error in DeserializeDesiredState. byte:{0}{1}",
+ m_current_byte,
+ (m_controllers == ControllerTypeArray{}) ?
+ " Try re-creating the recording with all GameCube controllers "
+ "disabled (in Configure > GameCube > Device Settings)." :
+ "");
+ EndPlayInput(!m_read_only);
+ return false;
+ }
- m_current_input_count++;
+ m_current_byte += serialized.length;
+ ++m_current_input_count;
CheckInputEnd();
return true;
diff --git a/Source/Core/Core/Movie.h b/Source/Core/Core/Movie.h
index 314123cf51..ea709e1d74 100644
--- a/Source/Core/Core/Movie.h
+++ b/Source/Core/Core/Movie.h
@@ -12,6 +12,7 @@
#include <vector>
#include "Common/CommonTypes.h"
+#include "Core/HW/WiimoteEmu/DesiredWiimoteState.h"
struct BootParameters;
@@ -206,21 +207,19 @@ public:
bool BeginRecordingInput(const ControllerTypeArray& controllers,
const WiimoteEnabledArray& wiimotes);
void RecordInput(const GCPadStatus* PadStatus, int controllerID);
- void RecordWiimote(int wiimote, const u8* data, u8 size);
+ void RecordWiimote(int wiimote, const WiimoteEmu::SerializedWiimoteState& serialized_state);
bool PlayInput(const std::string& movie_path, std::optional<std::string>* savestate_path);
void LoadInput(const std::string& movie_path);
void ReadHeader();
void PlayController(GCPadStatus* PadStatus, int controllerID);
- bool PlayWiimote(int wiimote, WiimoteCommon::DataReportBuilder& rpt,
- WiimoteEmu::ExtensionNumber ext, const WiimoteEmu::EncryptionKey& key);
+ bool PlayWiimote(int wiimote, WiimoteEmu::DesiredWiimoteState* desired_state);
void EndPlayInput(bool cont);
void SaveRecording(const std::string& filename);
void DoState(PointerWrap& p);
void Shutdown();
void CheckPadStatus(const GCPadStatus* PadStatus, int controllerID);
- void CheckWiimoteStatus(int wiimote, const WiimoteCommon::DataReportBuilder& rpt,
- WiimoteEmu::ExtensionNumber ext, const WiimoteEmu::EncryptionKey& key);
+ void CheckWiimoteStatus(int wiimote, const WiimoteEmu::DesiredWiimoteState& desired_state);
std::string GetInputDisplay();
std::string GetRTCDisplay() const;