210 lines
5.9 KiB
C++
210 lines
5.9 KiB
C++
#include "mdxf.h"
|
|
|
|
#include "avs/game.h"
|
|
#include "games/ddr/io.h"
|
|
#include "launcher/launcher.h"
|
|
#include "rawinput/rawinput.h"
|
|
#include "util/logging.h"
|
|
#include "util/utils.h"
|
|
|
|
// constants
|
|
const size_t STATUS_BUFFER_SIZE = 32;
|
|
|
|
// static stuff
|
|
static uint8_t COUNTER = 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] {};
|
|
} BUFFERS {};
|
|
#pragma pack(pop)
|
|
|
|
static bool STATUS_BUFFER_FREEZE = false;
|
|
|
|
typedef uint64_t (__cdecl *ARK_GET_TICK_TIME64_T)();
|
|
|
|
static uint64_t arkGetTickTime64() {
|
|
static ARK_GET_TICK_TIME64_T getTickTime64 =
|
|
(ARK_GET_TICK_TIME64_T)GetProcAddress(avs::game::DLL_INSTANCE, "arkGetTickTime64");
|
|
if (getTickTime64 == nullptr) {
|
|
// this works on 32-bit versions of avs, but not on 64.
|
|
// it's better than nothing though.
|
|
return timeGetTime();
|
|
}
|
|
return getTickTime64();
|
|
}
|
|
|
|
/*
|
|
* Implementations
|
|
*/
|
|
|
|
static bool __cdecl ac_io_mdxf_get_control_status_buffer(int node, void *buffer, uint8_t a3, uint8_t a4) {
|
|
|
|
// Dance Dance Revolution
|
|
if (avs::game::is_model("MDX")) {
|
|
|
|
// get buffer index
|
|
auto i = (COUNTER + a3) % std::size(BUFFERS.STATUS_BUFFER_P1);
|
|
|
|
// copy buffer
|
|
if (node == 17 || node == 25) {
|
|
memcpy(buffer, BUFFERS.STATUS_BUFFER_P1[i], STATUS_BUFFER_SIZE);
|
|
} else if (node == 18 || node == 26) {
|
|
memcpy(buffer, BUFFERS.STATUS_BUFFER_P2[i], STATUS_BUFFER_SIZE);
|
|
} else {
|
|
|
|
// fill with zeros on unknown node
|
|
memset(buffer, 0, STATUS_BUFFER_SIZE);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// return success
|
|
return true;
|
|
}
|
|
|
|
static bool __cdecl ac_io_mdxf_set_output_level(unsigned int a1, unsigned int a2, uint8_t value) {
|
|
if (avs::game::is_model("MDX")) {
|
|
static const struct {
|
|
int a2[4];
|
|
} mapping[] = {
|
|
{
|
|
// a1 == 17
|
|
{
|
|
games::ddr::Lights::GOLD_P1_STAGE_UP_RIGHT,
|
|
games::ddr::Lights::GOLD_P1_STAGE_DOWN_LEFT,
|
|
games::ddr::Lights::GOLD_P1_STAGE_UP_LEFT,
|
|
games::ddr::Lights::GOLD_P1_STAGE_DOWN_RIGHT
|
|
}
|
|
},
|
|
{
|
|
// a1 == 18
|
|
{
|
|
games::ddr::Lights::GOLD_P2_STAGE_UP_RIGHT,
|
|
games::ddr::Lights::GOLD_P2_STAGE_DOWN_LEFT,
|
|
games::ddr::Lights::GOLD_P2_STAGE_UP_LEFT,
|
|
games::ddr::Lights::GOLD_P2_STAGE_DOWN_RIGHT
|
|
}
|
|
}
|
|
};
|
|
if ((a1 == 17 || a1 == 18) && (a2 < 4)) {
|
|
// get light from mapping
|
|
const auto light = mapping[a1 - 17].a2[a2];
|
|
|
|
// get lights
|
|
auto &lights = games::ddr::get_lights();
|
|
|
|
// write lights
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[light], value / 128.f);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool __cdecl ac_io_mdxf_update_control_status_buffer(int node) {
|
|
|
|
// increase counter
|
|
COUNTER = (COUNTER + 1) % std::size(BUFFERS.STATUS_BUFFER_P1);
|
|
|
|
// check freeze
|
|
if (STATUS_BUFFER_FREEZE) {
|
|
return true;
|
|
}
|
|
|
|
// clear buffer
|
|
uint8_t *buffer = nullptr;
|
|
switch (node) {
|
|
case 17:
|
|
case 25:
|
|
buffer = BUFFERS.STATUS_BUFFER_P1[COUNTER];
|
|
break;
|
|
case 18:
|
|
case 26:
|
|
buffer = BUFFERS.STATUS_BUFFER_P2[COUNTER];
|
|
break;
|
|
default:
|
|
|
|
// return failure on unknown node
|
|
return false;
|
|
}
|
|
memset(buffer, 0, STATUS_BUFFER_SIZE);
|
|
|
|
// Dance Dance Revolution
|
|
if (avs::game::is_model("MDX")) {
|
|
|
|
// Sensor Map (LDUR):
|
|
// FOOT DOWN = bit 32-35 = byte 4, bit 0-3
|
|
// FOOT UP = bit 36-39 = byte 4, bit 4-7
|
|
// FOOT RIGHT = bit 40-43 = byte 5, bit 0-3
|
|
// FOOT LEFT = bit 44-47 = byte 5, bit 4-7
|
|
static const size_t buttons_p1[] = {
|
|
games::ddr::Buttons::P1_PANEL_UP,
|
|
games::ddr::Buttons::P1_PANEL_DOWN,
|
|
games::ddr::Buttons::P1_PANEL_LEFT,
|
|
games::ddr::Buttons::P1_PANEL_RIGHT,
|
|
};
|
|
static const size_t buttons_p2[] = {
|
|
games::ddr::Buttons::P2_PANEL_UP,
|
|
games::ddr::Buttons::P2_PANEL_DOWN,
|
|
games::ddr::Buttons::P2_PANEL_LEFT,
|
|
games::ddr::Buttons::P2_PANEL_RIGHT,
|
|
};
|
|
|
|
// decide on button map
|
|
const size_t *button_map = nullptr;
|
|
switch (node) {
|
|
case 17:
|
|
case 25:
|
|
button_map = &buttons_p1[0];
|
|
break;
|
|
case 18:
|
|
case 26:
|
|
button_map = &buttons_p2[0];
|
|
break;
|
|
}
|
|
|
|
*(uint64_t*)&buffer[0x18] = arkGetTickTime64();
|
|
|
|
// get buttons
|
|
auto &buttons = games::ddr::get_buttons();
|
|
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(button_map[0]))) {
|
|
buffer[4] |= 0xF0;
|
|
}
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(button_map[1]))) {
|
|
buffer[4] |= 0x0F;
|
|
}
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(button_map[2]))) {
|
|
buffer[5] |= 0xF0;
|
|
}
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(button_map[3]))) {
|
|
buffer[5] |= 0x0F;
|
|
}
|
|
}
|
|
|
|
// return success
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Module stuff
|
|
*/
|
|
|
|
acio::MDXFModule::MDXFModule(HMODULE module, acio::HookMode hookMode) : ACIOModule("MDXF", module, hookMode) {
|
|
this->status_buffer = (uint8_t*) &BUFFERS;
|
|
this->status_buffer_size = sizeof(BUFFERS);
|
|
this->status_buffer_freeze = &STATUS_BUFFER_FREEZE;
|
|
}
|
|
|
|
void acio::MDXFModule::attach() {
|
|
ACIOModule::attach();
|
|
|
|
// hooks
|
|
ACIO_MODULE_HOOK(ac_io_mdxf_get_control_status_buffer);
|
|
ACIO_MODULE_HOOK(ac_io_mdxf_set_output_level);
|
|
ACIO_MODULE_HOOK(ac_io_mdxf_update_control_status_buffer);
|
|
}
|