mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 06:40:42 -07:00
MDX: Fixed Ring Buffer Traversal Direction (P4IO Timing Fix) (#441)
## Description of change In the real `libacio2.dll` implementation, `ac_io_mdxf_get_control_status_buffer` returns the ring buffer entry at `(head - index) mod size` but this function was using `(head + index) mod size` instead. Basically, `index` is supposed to indicate how many entries back, not forward. This was causing the polling history of each player to be returned backwards. A few other things were updated to bring the function's behavior closer to the real implementation: 1. Number of ring buffer entries per player were increased to 16 (this is the size of them in the real implementation) 2. `ac_io_mdxf_get_control_status_buffer` now returns the current head of the ring buffer (instead of a success/failure boolean), which is what `arkmdxp4.dll` expects. ## Testing I played a few songs to make sure nothing was broken. I also attached a debugger and verified the ring buffer entries are *actually* now being returned in reverse chronological order as intended.
This commit is contained in:
@@ -11,14 +11,14 @@
|
||||
const size_t STATUS_BUFFER_SIZE = 32;
|
||||
|
||||
// static stuff
|
||||
static uint8_t COUNTER_P1 = 0;
|
||||
static uint8_t COUNTER_P2 = 0;
|
||||
static uint8_t HEAD_P1 = 0;
|
||||
static uint8_t HEAD_P2 = 0;
|
||||
|
||||
// buffers
|
||||
#pragma pack(push, 1)
|
||||
static struct {
|
||||
uint8_t STATUS_BUFFER_P1[7][STATUS_BUFFER_SIZE] {};
|
||||
uint8_t STATUS_BUFFER_P2[7][STATUS_BUFFER_SIZE] {};
|
||||
uint8_t STATUS_BUFFER_P1[16][STATUS_BUFFER_SIZE] {};
|
||||
uint8_t STATUS_BUFFER_P2[16][STATUS_BUFFER_SIZE] {};
|
||||
} BUFFERS {};
|
||||
#pragma pack(pop)
|
||||
|
||||
@@ -41,30 +41,50 @@ static uint64_t arkGetTickTime64() {
|
||||
* Implementations
|
||||
*/
|
||||
|
||||
static bool __cdecl ac_io_mdxf_get_control_status_buffer(int node, void *buffer, uint8_t a3, uint8_t a4) {
|
||||
static uint64_t __cdecl ac_io_mdxf_get_control_status_buffer(int node, void *out, uint8_t index, uint8_t head_in) {
|
||||
|
||||
// Default error value (matches original mask behavior)
|
||||
auto error_ret = static_cast<uint64_t>(node - 0x11) & 0xFFFFFFFFFFFFFF00;
|
||||
|
||||
// Dance Dance Revolution
|
||||
if (avs::game::is_model("MDX")) {
|
||||
|
||||
// copy buffer
|
||||
// Select player-specific state
|
||||
uint8_t head;
|
||||
uint8_t (*buffer)[STATUS_BUFFER_SIZE];
|
||||
size_t size;
|
||||
|
||||
if (node == 17 || node == 25) {
|
||||
// get buffer index
|
||||
auto i = (COUNTER_P1 + a3) % std::size(BUFFERS.STATUS_BUFFER_P1);
|
||||
memcpy(buffer, BUFFERS.STATUS_BUFFER_P1[i], STATUS_BUFFER_SIZE);
|
||||
head = HEAD_P1;
|
||||
buffer = BUFFERS.STATUS_BUFFER_P1;
|
||||
size = std::size(BUFFERS.STATUS_BUFFER_P1);
|
||||
} else if (node == 18 || node == 26) {
|
||||
// get buffer index
|
||||
auto i = (COUNTER_P2 + a3) % std::size(BUFFERS.STATUS_BUFFER_P2);
|
||||
memcpy(buffer, BUFFERS.STATUS_BUFFER_P2[i], STATUS_BUFFER_SIZE);
|
||||
head = HEAD_P2;
|
||||
buffer = BUFFERS.STATUS_BUFFER_P2;
|
||||
size = std::size(BUFFERS.STATUS_BUFFER_P2);
|
||||
} else {
|
||||
|
||||
// fill with zeros on unknown node
|
||||
memset(buffer, 0, STATUS_BUFFER_SIZE);
|
||||
return false;
|
||||
}
|
||||
memset(out, 0, STATUS_BUFFER_SIZE);
|
||||
return error_ret;
|
||||
}
|
||||
|
||||
// return success
|
||||
return true;
|
||||
if (head_in != 0xFF) {
|
||||
head = head_in;
|
||||
}
|
||||
|
||||
// Compute ring index: walk backwards from head as index increases
|
||||
// Assumes ring buffer size is a power of two
|
||||
const size_t mask = size - 1;
|
||||
const size_t offset = static_cast<size_t>(index) & mask;
|
||||
const size_t i = (static_cast<size_t>(head) - offset + size) & mask;
|
||||
|
||||
// Copy the chosen entry
|
||||
memcpy(out, buffer[i], STATUS_BUFFER_SIZE);
|
||||
|
||||
// Return the head value actually used
|
||||
return static_cast<uint64_t>(head);
|
||||
}
|
||||
|
||||
return error_ret;
|
||||
}
|
||||
|
||||
static bool __cdecl ac_io_mdxf_set_output_level(unsigned int a1, unsigned int a2, uint8_t value) {
|
||||
@@ -119,14 +139,14 @@ static bool __cdecl ac_io_mdxf_update_control_status_buffer(int node) {
|
||||
case 17:
|
||||
case 25:
|
||||
// increase counter
|
||||
COUNTER_P1 = (COUNTER_P1 + 1) % std::size(BUFFERS.STATUS_BUFFER_P1);
|
||||
buffer = BUFFERS.STATUS_BUFFER_P1[COUNTER_P1];
|
||||
HEAD_P1 = (HEAD_P1 + 1) % std::size(BUFFERS.STATUS_BUFFER_P1);
|
||||
buffer = BUFFERS.STATUS_BUFFER_P1[HEAD_P1];
|
||||
break;
|
||||
case 18:
|
||||
case 26:
|
||||
// increase counter
|
||||
COUNTER_P2 = (COUNTER_P2 + 1) % std::size(BUFFERS.STATUS_BUFFER_P2);
|
||||
buffer = BUFFERS.STATUS_BUFFER_P2[COUNTER_P2];
|
||||
HEAD_P2 = (HEAD_P2 + 1) % std::size(BUFFERS.STATUS_BUFFER_P2);
|
||||
buffer = BUFFERS.STATUS_BUFFER_P2[HEAD_P2];
|
||||
break;
|
||||
default:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user