chore: CRLF to LF

This commit is contained in:
smpn2
2022-12-16 23:18:35 +09:00
parent b7a60638a4
commit 6c914266d9
725 changed files with 131020 additions and 131020 deletions
+37 -37
View File
@@ -1,37 +1,37 @@
#include "bbc.h"
#include "avs/game.h"
#include "hooks/graphics/graphics.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/sigscan.h"
namespace games::bbc {
BBCGame::BBCGame() : Game("Bishi Bashi Channel") {
}
void BBCGame::attach() {
Game::attach();
// window patch
if (GRAPHICS_WINDOWED) {
unsigned char pattern[] = {
0x48, 0x8D, 0x54, 0x24, 0x40, 0x41, 0x8D, 0x4E, 0x20, 0x41, 0x0F, 0xB6, 0xE8
};
unsigned char replace[] = {
0x48, 0x8D, 0x54, 0x24, 0x40, 0x41, 0x8D, 0x4E, 0x20, 0x31, 0xED, 0x90, 0x90
};
std::string mask = "XXXXXXXXXXXXX";
if (!replace_pattern(
avs::game::DLL_INSTANCE,
pattern,
mask.c_str(),
0,
0,
replace,
mask.c_str()))
log_warning("bbc", "windowed mode failed");
}
}
}
#include "bbc.h"
#include "avs/game.h"
#include "hooks/graphics/graphics.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/sigscan.h"
namespace games::bbc {
BBCGame::BBCGame() : Game("Bishi Bashi Channel") {
}
void BBCGame::attach() {
Game::attach();
// window patch
if (GRAPHICS_WINDOWED) {
unsigned char pattern[] = {
0x48, 0x8D, 0x54, 0x24, 0x40, 0x41, 0x8D, 0x4E, 0x20, 0x41, 0x0F, 0xB6, 0xE8
};
unsigned char replace[] = {
0x48, 0x8D, 0x54, 0x24, 0x40, 0x41, 0x8D, 0x4E, 0x20, 0x31, 0xED, 0x90, 0x90
};
std::string mask = "XXXXXXXXXXXXX";
if (!replace_pattern(
avs::game::DLL_INSTANCE,
pattern,
mask.c_str(),
0,
0,
replace,
mask.c_str()))
log_warning("bbc", "windowed mode failed");
}
}
}
+13 -13
View File
@@ -1,13 +1,13 @@
#pragma once
#include "games/game.h"
namespace games::bbc {
class BBCGame : public games::Game {
public:
BBCGame();
virtual void attach() override;
};
}
#pragma once
#include "games/game.h"
namespace games::bbc {
class BBCGame : public games::Game {
public:
BBCGame();
virtual void attach() override;
};
}
+105 -105
View File
@@ -1,105 +1,105 @@
#include "io.h"
std::vector<Button> &games::bbc::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Bishi Bashi Channel");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"P1 R",
"P1 G",
"P1 B",
"P1 Disk-",
"P1 Disk+",
"P1 Disk -/+ Slowdown",
"P2 R",
"P2 G",
"P2 B",
"P2 Disk-",
"P2 Disk+",
"P2 Disk -/+ Slowdown",
"P3 R",
"P3 G",
"P3 B",
"P3 Disk-",
"P3 Disk+",
"P3 Disk -/+ Slowdown",
"P4 R",
"P4 G",
"P4 B",
"P4 Disk-",
"P4 Disk+",
"P4 Disk -/+ Slowdown"
);
}
return buttons;
}
std::vector<Analog> &games::bbc::get_analogs() {
static std::vector<Analog> analogs;
if (analogs.empty()) {
analogs = GameAPI::Analogs::getAnalogs("Bishi Bashi Channel");
GameAPI::Analogs::sortAnalogs(
&analogs,
"P1 Disk",
"P2 Disk",
"P3 Disk",
"P4 Disk"
);
}
return analogs;
}
std::vector<Light> &games::bbc::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Bishi Bashi Channel");
GameAPI::Lights::sortLights(
&lights,
"P1 R",
"P1 B",
"P1 Disc R",
"P1 Disc G",
"P1 Disc B",
"P2 R",
"P2 B",
"P2 Disc R",
"P2 Disc G",
"P2 Disc B",
"P3 R",
"P3 B",
"P3 Disc R",
"P3 Disc G",
"P3 Disc B",
"P4 R",
"P4 B",
"P4 Disc R",
"P4 Disc G",
"P4 Disc B",
"IC Card R",
"IC Card G",
"IC Card B",
"Under LED1 R",
"Under LED1 G",
"Under LED1 B",
"Under LED2 R",
"Under LED2 G",
"Under LED2 B",
"Under LED3 R",
"Under LED3 G",
"Under LED3 B"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::bbc::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Bishi Bashi Channel");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"P1 R",
"P1 G",
"P1 B",
"P1 Disk-",
"P1 Disk+",
"P1 Disk -/+ Slowdown",
"P2 R",
"P2 G",
"P2 B",
"P2 Disk-",
"P2 Disk+",
"P2 Disk -/+ Slowdown",
"P3 R",
"P3 G",
"P3 B",
"P3 Disk-",
"P3 Disk+",
"P3 Disk -/+ Slowdown",
"P4 R",
"P4 G",
"P4 B",
"P4 Disk-",
"P4 Disk+",
"P4 Disk -/+ Slowdown"
);
}
return buttons;
}
std::vector<Analog> &games::bbc::get_analogs() {
static std::vector<Analog> analogs;
if (analogs.empty()) {
analogs = GameAPI::Analogs::getAnalogs("Bishi Bashi Channel");
GameAPI::Analogs::sortAnalogs(
&analogs,
"P1 Disk",
"P2 Disk",
"P3 Disk",
"P4 Disk"
);
}
return analogs;
}
std::vector<Light> &games::bbc::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Bishi Bashi Channel");
GameAPI::Lights::sortLights(
&lights,
"P1 R",
"P1 B",
"P1 Disc R",
"P1 Disc G",
"P1 Disc B",
"P2 R",
"P2 B",
"P2 Disc R",
"P2 Disc G",
"P2 Disc B",
"P3 R",
"P3 B",
"P3 Disc R",
"P3 Disc G",
"P3 Disc B",
"P4 R",
"P4 B",
"P4 Disc R",
"P4 Disc G",
"P4 Disc B",
"IC Card R",
"IC Card G",
"IC Card B",
"Under LED1 R",
"Under LED1 G",
"Under LED1 B",
"Under LED2 R",
"Under LED2 G",
"Under LED2 B",
"Under LED3 R",
"Under LED3 G",
"Under LED3 B"
);
}
return lights;
}
+92 -92
View File
@@ -1,92 +1,92 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::bbc {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
P1_R,
P1_G,
P1_B,
P1_DiskMinus,
P1_DiskPlus,
P1_DiskSlowdown,
P2_R,
P2_G,
P2_B,
P2_DiskMinus,
P2_DiskPlus,
P2_DiskSlowdown,
P3_R,
P3_G,
P3_B,
P3_DiskMinus,
P3_DiskPlus,
P3_DiskSlowdown,
P4_R,
P4_G,
P4_B,
P4_DiskMinus,
P4_DiskPlus,
P4_DiskSlowdown,
};
}
// all analogs in correct order
namespace Analogs {
enum {
P1_Disk,
P2_Disk,
P3_Disk,
P4_Disk,
};
}
// all lights in correct order
namespace Lights {
enum {
P1_R,
P1_B,
P1_DISC_R,
P1_DISC_G,
P1_DISC_B,
P2_R,
P2_B,
P2_DISC_R,
P2_DISC_G,
P2_DISC_B,
P3_R,
P3_B,
P3_DISC_R,
P3_DISC_G,
P3_DISC_B,
P4_R,
P4_B,
P4_DISC_R,
P4_DISC_G,
P4_DISC_B,
IC_CARD_R,
IC_CARD_G,
IC_CARD_B,
UNDER_LED1_R,
UNDER_LED1_G,
UNDER_LED1_B,
UNDER_LED2_R,
UNDER_LED2_G,
UNDER_LED2_B,
UNDER_LED3_R,
UNDER_LED3_G,
UNDER_LED3_B,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::bbc {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
P1_R,
P1_G,
P1_B,
P1_DiskMinus,
P1_DiskPlus,
P1_DiskSlowdown,
P2_R,
P2_G,
P2_B,
P2_DiskMinus,
P2_DiskPlus,
P2_DiskSlowdown,
P3_R,
P3_G,
P3_B,
P3_DiskMinus,
P3_DiskPlus,
P3_DiskSlowdown,
P4_R,
P4_G,
P4_B,
P4_DiskMinus,
P4_DiskPlus,
P4_DiskSlowdown,
};
}
// all analogs in correct order
namespace Analogs {
enum {
P1_Disk,
P2_Disk,
P3_Disk,
P4_Disk,
};
}
// all lights in correct order
namespace Lights {
enum {
P1_R,
P1_B,
P1_DISC_R,
P1_DISC_G,
P1_DISC_B,
P2_R,
P2_B,
P2_DISC_R,
P2_DISC_G,
P2_DISC_B,
P3_R,
P3_B,
P3_DISC_R,
P3_DISC_G,
P3_DISC_B,
P4_R,
P4_B,
P4_DISC_R,
P4_DISC_G,
P4_DISC_B,
IC_CARD_R,
IC_CARD_G,
IC_CARD_B,
UNDER_LED1_R,
UNDER_LED1_G,
UNDER_LED1_B,
UNDER_LED2_R,
UNDER_LED2_G,
UNDER_LED2_B,
UNDER_LED3_R,
UNDER_LED3_G,
UNDER_LED3_B,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
+53 -53
View File
@@ -1,53 +1,53 @@
#include "bs.h"
#include "avs/game.h"
#include "misc/wintouchemu.h"
#include "launcher/launcher.h"
#include "rawinput/rawinput.h"
#include "util/detour.h"
#include "util/logging.h"
namespace games::bs {
BSGame::BSGame() : Game("Beatstream") {
}
inline bool touchscreen_has_bug() {
// get devices
auto devices = RI_MGR->devices_get();
for (auto &device : devices) {
// filter by HID
if (device.type == rawinput::HID) {
auto &hid = device.hidInfo;
auto &attributes = hid->attributes;
// P2314T
// it apparently cannot do holds using Beatstream's wintouch code
if (attributes.VendorID == 0x2149 && attributes.ProductID == 0x2316)
return true;
// P2418HT
// it apparently cannot do holds using Beatstream's wintouch code
if (attributes.VendorID == 0x1FD2 && attributes.ProductID == 0x6103)
return true;
}
}
// looks all clean
return false;
}
void BSGame::attach() {
Game::attach();
// for bugged touch screens
if (touchscreen_has_bug()) {
log_info("bs", "detected bugged touchscreen, forcing wintouchemu");
wintouchemu::FORCE = true;
}
// for mouse support
wintouchemu::hook("BeatStream", avs::game::DLL_INSTANCE);
}
}
#include "bs.h"
#include "avs/game.h"
#include "misc/wintouchemu.h"
#include "launcher/launcher.h"
#include "rawinput/rawinput.h"
#include "util/detour.h"
#include "util/logging.h"
namespace games::bs {
BSGame::BSGame() : Game("Beatstream") {
}
inline bool touchscreen_has_bug() {
// get devices
auto devices = RI_MGR->devices_get();
for (auto &device : devices) {
// filter by HID
if (device.type == rawinput::HID) {
auto &hid = device.hidInfo;
auto &attributes = hid->attributes;
// P2314T
// it apparently cannot do holds using Beatstream's wintouch code
if (attributes.VendorID == 0x2149 && attributes.ProductID == 0x2316)
return true;
// P2418HT
// it apparently cannot do holds using Beatstream's wintouch code
if (attributes.VendorID == 0x1FD2 && attributes.ProductID == 0x6103)
return true;
}
}
// looks all clean
return false;
}
void BSGame::attach() {
Game::attach();
// for bugged touch screens
if (touchscreen_has_bug()) {
log_info("bs", "detected bugged touchscreen, forcing wintouchemu");
wintouchemu::FORCE = true;
}
// for mouse support
wintouchemu::hook("BeatStream", avs::game::DLL_INSTANCE);
}
}
+12 -12
View File
@@ -1,12 +1,12 @@
#pragma once
#include "games/game.h"
namespace games::bs {
class BSGame : public games::Game {
public:
BSGame();
virtual void attach() override;
};
}
#pragma once
#include "games/game.h"
namespace games::bs {
class BSGame : public games::Game {
public:
BSGame();
virtual void attach() override;
};
}
+41 -41
View File
@@ -1,41 +1,41 @@
#include "io.h"
std::vector<Button> &games::bs::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Beatstream");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech"
);
}
return buttons;
}
std::vector<Light> &games::bs::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Beatstream");
GameAPI::Lights::sortLights(
&lights,
"Bottom R",
"Bottom G",
"Bottom B",
"Left R",
"Left G",
"Left B",
"Right R",
"Right G",
"Right B"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::bs::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Beatstream");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech"
);
}
return buttons;
}
std::vector<Light> &games::bs::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Beatstream");
GameAPI::Lights::sortLights(
&lights,
"Bottom R",
"Bottom G",
"Bottom B",
"Left R",
"Left G",
"Left B",
"Right R",
"Right G",
"Right B"
);
}
return lights;
}
+35 -35
View File
@@ -1,35 +1,35 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::bs {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
};
}
// all lights in correct order
namespace Lights {
enum {
BottomR,
BottomG,
BottomB,
LeftR,
LeftG,
LeftB,
RightR,
RightG,
RightB,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::bs {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
};
}
// all lights in correct order
namespace Lights {
enum {
BottomR,
BottomG,
BottomB,
LeftR,
LeftG,
LeftB,
RightR,
RightG,
RightB,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
+117 -117
View File
@@ -1,117 +1,117 @@
#include "ddr.h"
#include "acioemu/handle.h"
#include "avs/game.h"
#include "hooks/devicehook.h"
#include "hooks/setupapihook.h"
#include "hooks/sleephook.h"
#include "hooks/input/dinput8/hook.h"
#include "util/utils.h"
#include "util/libutils.h"
#include "util/fileutils.h"
#include "util/detour.h"
#include "io.h"
#include "p3io/foot.h"
#include "p3io/p3io.h"
#include "p3io/sate.h"
#include "p3io/usbmem.h"
using namespace acioemu;
namespace games::ddr {
// settings
bool SDMODE = false;
static decltype(SendMessage) *SendMessage_real = nullptr;
static SHORT WINAPI GetAsyncKeyState_hook(int vKey) {
// disable debug keys
return 0;
}
static LRESULT WINAPI SendMessage_hook(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
// ignore broadcasts
if (hWnd == HWND_BROADCAST) {
return 1;
}
// fallback
return SendMessage_real(hWnd, Msg, wParam, lParam);
}
DDRGame::DDRGame() : Game("Dance Dance Revolution") {
}
void DDRGame::attach() {
Game::attach();
// dinput hook on this dll since the game dll doesn't load it
auto game_mdx = libutils::try_library(MODULE_PATH / "gamemdx.dll");
hooks::input::dinput8::init(game_mdx);
// init device hook
devicehook_init();
// add fake devices
if (avs::game::DLL_NAME == "arkmdxbio2.dll") {
devicehook_add(new acioemu::ACIOHandle(L"COM1"));
} else {
devicehook_add(new DDRFOOTHandle());
devicehook_add(new DDRSATEHandle());
devicehook_add(new DDRUSBMEMHandle());
devicehook_add(new DDRP3IOHandle());
}
// has nothing to do with P3IO, but is enough to trick the game into SD/HD mode
const char *settings_property = ddr::SDMODE ? "Generic Television" : "Generic Monitor";
const char settings_detail[] = R"(\\.\P3IO)";
// settings 1
SETUPAPI_SETTINGS settings1 {};
settings1.class_guid[0] = 0x1FA4A480;
settings1.class_guid[1] = 0x40C7AC60;
settings1.class_guid[2] = 0x7952ACA7;
settings1.class_guid[3] = 0x5A57340F;
memcpy(settings1.property_devicedesc, settings_property, strlen(settings_property) + 1);
memcpy(settings1.interface_detail, settings_detail, sizeof(settings_detail));
// settings 2
SETUPAPI_SETTINGS settings2 {};
settings2.class_guid[0] = 0x4D36E96E;
settings2.class_guid[1] = 0x11CEE325;
settings2.class_guid[2] = 0x8C1BF;
settings2.class_guid[3] = 0x1803E12B;
memcpy(settings2.property_devicedesc, settings_property, strlen(settings_property) + 1);
memcpy(settings2.interface_detail, settings_detail, sizeof(settings_detail));
// init SETUP API
setupapihook_init(avs::game::DLL_INSTANCE);
// DDR ACE actually uses another DLL for things
if (game_mdx != nullptr) {
setupapihook_init(game_mdx);
}
// add settings
setupapihook_add(settings1);
setupapihook_add(settings2);
// misc hooks
detour::iat_try("GetAsyncKeyState", GetAsyncKeyState_hook, avs::game::DLL_INSTANCE);
detour::iat_try("GetKeyState", GetAsyncKeyState_hook, avs::game::DLL_INSTANCE);
SendMessage_real = detour::iat_try("SendMessageW", SendMessage_hook, avs::game::DLL_INSTANCE);
detour::iat_try("SendMessageA", SendMessage_hook, avs::game::DLL_INSTANCE);
}
void DDRGame::detach() {
Game::detach();
// dispose device hook
devicehook_dispose();
}
}
#include "ddr.h"
#include "acioemu/handle.h"
#include "avs/game.h"
#include "hooks/devicehook.h"
#include "hooks/setupapihook.h"
#include "hooks/sleephook.h"
#include "hooks/input/dinput8/hook.h"
#include "util/utils.h"
#include "util/libutils.h"
#include "util/fileutils.h"
#include "util/detour.h"
#include "io.h"
#include "p3io/foot.h"
#include "p3io/p3io.h"
#include "p3io/sate.h"
#include "p3io/usbmem.h"
using namespace acioemu;
namespace games::ddr {
// settings
bool SDMODE = false;
static decltype(SendMessage) *SendMessage_real = nullptr;
static SHORT WINAPI GetAsyncKeyState_hook(int vKey) {
// disable debug keys
return 0;
}
static LRESULT WINAPI SendMessage_hook(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
// ignore broadcasts
if (hWnd == HWND_BROADCAST) {
return 1;
}
// fallback
return SendMessage_real(hWnd, Msg, wParam, lParam);
}
DDRGame::DDRGame() : Game("Dance Dance Revolution") {
}
void DDRGame::attach() {
Game::attach();
// dinput hook on this dll since the game dll doesn't load it
auto game_mdx = libutils::try_library(MODULE_PATH / "gamemdx.dll");
hooks::input::dinput8::init(game_mdx);
// init device hook
devicehook_init();
// add fake devices
if (avs::game::DLL_NAME == "arkmdxbio2.dll") {
devicehook_add(new acioemu::ACIOHandle(L"COM1"));
} else {
devicehook_add(new DDRFOOTHandle());
devicehook_add(new DDRSATEHandle());
devicehook_add(new DDRUSBMEMHandle());
devicehook_add(new DDRP3IOHandle());
}
// has nothing to do with P3IO, but is enough to trick the game into SD/HD mode
const char *settings_property = ddr::SDMODE ? "Generic Television" : "Generic Monitor";
const char settings_detail[] = R"(\\.\P3IO)";
// settings 1
SETUPAPI_SETTINGS settings1 {};
settings1.class_guid[0] = 0x1FA4A480;
settings1.class_guid[1] = 0x40C7AC60;
settings1.class_guid[2] = 0x7952ACA7;
settings1.class_guid[3] = 0x5A57340F;
memcpy(settings1.property_devicedesc, settings_property, strlen(settings_property) + 1);
memcpy(settings1.interface_detail, settings_detail, sizeof(settings_detail));
// settings 2
SETUPAPI_SETTINGS settings2 {};
settings2.class_guid[0] = 0x4D36E96E;
settings2.class_guid[1] = 0x11CEE325;
settings2.class_guid[2] = 0x8C1BF;
settings2.class_guid[3] = 0x1803E12B;
memcpy(settings2.property_devicedesc, settings_property, strlen(settings_property) + 1);
memcpy(settings2.interface_detail, settings_detail, sizeof(settings_detail));
// init SETUP API
setupapihook_init(avs::game::DLL_INSTANCE);
// DDR ACE actually uses another DLL for things
if (game_mdx != nullptr) {
setupapihook_init(game_mdx);
}
// add settings
setupapihook_add(settings1);
setupapihook_add(settings2);
// misc hooks
detour::iat_try("GetAsyncKeyState", GetAsyncKeyState_hook, avs::game::DLL_INSTANCE);
detour::iat_try("GetKeyState", GetAsyncKeyState_hook, avs::game::DLL_INSTANCE);
SendMessage_real = detour::iat_try("SendMessageW", SendMessage_hook, avs::game::DLL_INSTANCE);
detour::iat_try("SendMessageA", SendMessage_hook, avs::game::DLL_INSTANCE);
}
void DDRGame::detach() {
Game::detach();
// dispose device hook
devicehook_dispose();
}
}
+16 -16
View File
@@ -1,16 +1,16 @@
#pragma once
#include "games/game.h"
namespace games::ddr {
// settings
extern bool SDMODE;
class DDRGame : public games::Game {
public:
DDRGame();
virtual void attach() override;
virtual void detach() override;
};
}
#pragma once
#include "games/game.h"
namespace games::ddr {
// settings
extern bool SDMODE;
class DDRGame : public games::Game {
public:
DDRGame();
virtual void attach() override;
virtual void detach() override;
};
}
+87 -87
View File
@@ -1,87 +1,87 @@
#include "io.h"
std::vector<Button> &games::ddr::get_buttons() {
static std::vector<Button> analogs;
if (analogs.empty()) {
analogs = GameAPI::Buttons::getButtons("Dance Dance Revolution");
GameAPI::Buttons::sortButtons(
&analogs,
"Service",
"Test",
"Coin Mech",
"P1 Start",
"P1 Panel Up",
"P1 Panel Down",
"P1 Panel Left",
"P1 Panel Right",
"P1 Menu Up",
"P1 Menu Down",
"P1 Menu Left",
"P1 Menu Right",
"P2 Start",
"P2 Panel Up",
"P2 Panel Down",
"P2 Panel Left",
"P2 Panel Right",
"P2 Menu Up",
"P2 Menu Down",
"P2 Menu Left",
"P2 Menu Right"
);
}
return analogs;
}
std::vector<Light> &games::ddr::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Dance Dance Revolution");
GameAPI::Lights::sortLights(
&lights,
"P1 Foot Left",
"P1 Foot Up",
"P1 Foot Right",
"P1 Foot Down",
"P2 Foot Left",
"P2 Foot Up",
"P2 Foot Right",
"P2 Foot Down",
"Spot Red",
"Spot Blue",
"Top Spot Red",
"Top Spot Blue",
"P1 Halogen Upper",
"P1 Halogen Lower",
"P2 Halogen Upper",
"P2 Halogen Lower",
"P1 Button",
"P2 Button",
"Neon",
"HD P1 Start",
"HD P1 Menu Left-Right",
"HD P1 Menu Up-Down",
"HD P2 Start",
"HD P2 Menu Left-Right",
"HD P2 Menu Up-Down",
"HD P1 Speaker F R",
"HD P1 Speaker F G",
"HD P1 Speaker F B",
"HD P1 Speaker W R",
"HD P1 Speaker W G",
"HD P1 Speaker W B",
"HD P2 Speaker F R",
"HD P2 Speaker F G",
"HD P2 Speaker F B",
"HD P2 Speaker W R",
"HD P2 Speaker W G",
"HD P2 Speaker W B"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::ddr::get_buttons() {
static std::vector<Button> analogs;
if (analogs.empty()) {
analogs = GameAPI::Buttons::getButtons("Dance Dance Revolution");
GameAPI::Buttons::sortButtons(
&analogs,
"Service",
"Test",
"Coin Mech",
"P1 Start",
"P1 Panel Up",
"P1 Panel Down",
"P1 Panel Left",
"P1 Panel Right",
"P1 Menu Up",
"P1 Menu Down",
"P1 Menu Left",
"P1 Menu Right",
"P2 Start",
"P2 Panel Up",
"P2 Panel Down",
"P2 Panel Left",
"P2 Panel Right",
"P2 Menu Up",
"P2 Menu Down",
"P2 Menu Left",
"P2 Menu Right"
);
}
return analogs;
}
std::vector<Light> &games::ddr::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Dance Dance Revolution");
GameAPI::Lights::sortLights(
&lights,
"P1 Foot Left",
"P1 Foot Up",
"P1 Foot Right",
"P1 Foot Down",
"P2 Foot Left",
"P2 Foot Up",
"P2 Foot Right",
"P2 Foot Down",
"Spot Red",
"Spot Blue",
"Top Spot Red",
"Top Spot Blue",
"P1 Halogen Upper",
"P1 Halogen Lower",
"P2 Halogen Upper",
"P2 Halogen Lower",
"P1 Button",
"P2 Button",
"Neon",
"HD P1 Start",
"HD P1 Menu Left-Right",
"HD P1 Menu Up-Down",
"HD P2 Start",
"HD P2 Menu Left-Right",
"HD P2 Menu Up-Down",
"HD P1 Speaker F R",
"HD P1 Speaker F G",
"HD P1 Speaker F B",
"HD P1 Speaker W R",
"HD P1 Speaker W G",
"HD P1 Speaker W B",
"HD P2 Speaker F R",
"HD P2 Speaker F G",
"HD P2 Speaker F B",
"HD P2 Speaker W R",
"HD P2 Speaker W G",
"HD P2 Speaker W B"
);
}
return lights;
}
+82 -82
View File
@@ -1,82 +1,82 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::ddr {
// all buttons in correct order
namespace Buttons {
enum {
SERVICE,
TEST,
COIN_MECH,
P1_START,
P1_PANEL_UP,
P1_PANEL_DOWN,
P1_PANEL_LEFT,
P1_PANEL_RIGHT,
P1_MENU_UP,
P1_MENU_DOWN,
P1_MENU_LEFT,
P1_MENU_RIGHT,
P2_START,
P2_PANEL_UP,
P2_PANEL_DOWN,
P2_PANEL_LEFT,
P2_PANEL_RIGHT,
P2_MENU_UP,
P2_MENU_DOWN,
P2_MENU_LEFT,
P2_MENU_RIGHT,
};
}
// all lights in correct order
namespace Lights {
enum {
P1_FOOT_LEFT,
P1_FOOT_UP,
P1_FOOT_RIGHT,
P1_FOOT_DOWN,
P2_FOOT_LEFT,
P2_FOOT_UP,
P2_FOOT_RIGHT,
P2_FOOT_DOWN,
SPOT_RED,
SPOT_BLUE,
TOP_SPOT_RED,
TOP_SPOT_BLUE,
P1_HALOGEN_UPPER,
P1_HALOGEN_LOWER,
P2_HALOGEN_UPPER,
P2_HALOGEN_LOWER,
P1_BUTTON,
P2_BUTTON,
NEON,
HD_P1_START,
HD_P1_LEFT_RIGHT,
HD_P1_UP_DOWN,
HD_P2_START,
HD_P2_LEFT_RIGHT,
HD_P2_UP_DOWN,
HD_P1_SPEAKER_F_R,
HD_P1_SPEAKER_F_G,
HD_P1_SPEAKER_F_B,
HD_P1_SPEAKER_W_R,
HD_P1_SPEAKER_W_G,
HD_P1_SPEAKER_W_B,
HD_P2_SPEAKER_F_R,
HD_P2_SPEAKER_F_G,
HD_P2_SPEAKER_F_B,
HD_P2_SPEAKER_W_R,
HD_P2_SPEAKER_W_G,
HD_P2_SPEAKER_W_B,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::ddr {
// all buttons in correct order
namespace Buttons {
enum {
SERVICE,
TEST,
COIN_MECH,
P1_START,
P1_PANEL_UP,
P1_PANEL_DOWN,
P1_PANEL_LEFT,
P1_PANEL_RIGHT,
P1_MENU_UP,
P1_MENU_DOWN,
P1_MENU_LEFT,
P1_MENU_RIGHT,
P2_START,
P2_PANEL_UP,
P2_PANEL_DOWN,
P2_PANEL_LEFT,
P2_PANEL_RIGHT,
P2_MENU_UP,
P2_MENU_DOWN,
P2_MENU_LEFT,
P2_MENU_RIGHT,
};
}
// all lights in correct order
namespace Lights {
enum {
P1_FOOT_LEFT,
P1_FOOT_UP,
P1_FOOT_RIGHT,
P1_FOOT_DOWN,
P2_FOOT_LEFT,
P2_FOOT_UP,
P2_FOOT_RIGHT,
P2_FOOT_DOWN,
SPOT_RED,
SPOT_BLUE,
TOP_SPOT_RED,
TOP_SPOT_BLUE,
P1_HALOGEN_UPPER,
P1_HALOGEN_LOWER,
P2_HALOGEN_UPPER,
P2_HALOGEN_LOWER,
P1_BUTTON,
P2_BUTTON,
NEON,
HD_P1_START,
HD_P1_LEFT_RIGHT,
HD_P1_UP_DOWN,
HD_P2_START,
HD_P2_LEFT_RIGHT,
HD_P2_UP_DOWN,
HD_P1_SPEAKER_F_R,
HD_P1_SPEAKER_F_G,
HD_P1_SPEAKER_F_B,
HD_P1_SPEAKER_W_R,
HD_P1_SPEAKER_W_G,
HD_P1_SPEAKER_W_B,
HD_P2_SPEAKER_F_R,
HD_P2_SPEAKER_F_G,
HD_P2_SPEAKER_F_B,
HD_P2_SPEAKER_W_R,
HD_P2_SPEAKER_W_G,
HD_P2_SPEAKER_W_B,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
+92 -92
View File
@@ -1,92 +1,92 @@
#include "foot.h"
#include "rawinput/rawinput.h"
#include "util/logging.h"
#include "../ddr.h"
#include "../io.h"
bool games::ddr::DDRFOOTHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM1") != 0) {
return false;
}
log_info("ddr", "Opened COM1 (FOOT)");
return true;
}
int games::ddr::DDRFOOTHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
// check data trigger and buffer size
if (data_trigger && nNumberOfBytesToRead >= 1) {
data_trigger = false;
memset(lpBuffer, 0x11, 1);
return 1;
}
// no data
return 0;
}
int games::ddr::DDRFOOTHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
// check buffer size for lights
if (nNumberOfBytesToWrite == 4) {
// mappings
static const size_t mapping_bits[] = {
4, 6, 3, 5, // P1 L, U, R, D,
12, 14, 11, 13, // P2 L, U, R, D
22 // NEON
};
static const size_t mapping[] = {
Lights::P1_FOOT_LEFT,
Lights::P1_FOOT_UP,
Lights::P1_FOOT_RIGHT,
Lights::P1_FOOT_DOWN,
Lights::P2_FOOT_LEFT,
Lights::P2_FOOT_UP,
Lights::P2_FOOT_RIGHT,
Lights::P2_FOOT_DOWN,
Lights::NEON
};
// get light bits
uint32_t light_bits = *((uint32_t*) lpBuffer);
// get lights
auto &lights = get_lights();
// bit scan
for (size_t i = 0; i < 8; i++) {
float value = (light_bits & (1 << mapping_bits[i])) ? 1.f : 0.f;
GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[i]), value);
}
// only set the neon if in SD mode
// p3io sets it for HD mode.
if (games::ddr::SDMODE) {
float value = (light_bits & (1 << mapping_bits[8])) ? 1.f : 0.f;
GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[8]), value);
}
// flush
RI_MGR->devices_flush_output();
}
// trigger out data
data_trigger = true;
// return all data written
return (int) nNumberOfBytesToWrite;
}
int games::ddr::DDRFOOTHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) {
return -1;
}
bool games::ddr::DDRFOOTHandle::close() {
log_info("ddr", "Closed COM1 (FOOT).");
return true;
}
#include "foot.h"
#include "rawinput/rawinput.h"
#include "util/logging.h"
#include "../ddr.h"
#include "../io.h"
bool games::ddr::DDRFOOTHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM1") != 0) {
return false;
}
log_info("ddr", "Opened COM1 (FOOT)");
return true;
}
int games::ddr::DDRFOOTHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
// check data trigger and buffer size
if (data_trigger && nNumberOfBytesToRead >= 1) {
data_trigger = false;
memset(lpBuffer, 0x11, 1);
return 1;
}
// no data
return 0;
}
int games::ddr::DDRFOOTHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
// check buffer size for lights
if (nNumberOfBytesToWrite == 4) {
// mappings
static const size_t mapping_bits[] = {
4, 6, 3, 5, // P1 L, U, R, D,
12, 14, 11, 13, // P2 L, U, R, D
22 // NEON
};
static const size_t mapping[] = {
Lights::P1_FOOT_LEFT,
Lights::P1_FOOT_UP,
Lights::P1_FOOT_RIGHT,
Lights::P1_FOOT_DOWN,
Lights::P2_FOOT_LEFT,
Lights::P2_FOOT_UP,
Lights::P2_FOOT_RIGHT,
Lights::P2_FOOT_DOWN,
Lights::NEON
};
// get light bits
uint32_t light_bits = *((uint32_t*) lpBuffer);
// get lights
auto &lights = get_lights();
// bit scan
for (size_t i = 0; i < 8; i++) {
float value = (light_bits & (1 << mapping_bits[i])) ? 1.f : 0.f;
GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[i]), value);
}
// only set the neon if in SD mode
// p3io sets it for HD mode.
if (games::ddr::SDMODE) {
float value = (light_bits & (1 << mapping_bits[8])) ? 1.f : 0.f;
GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[8]), value);
}
// flush
RI_MGR->devices_flush_output();
}
// trigger out data
data_trigger = true;
// return all data written
return (int) nNumberOfBytesToWrite;
}
int games::ddr::DDRFOOTHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) {
return -1;
}
bool games::ddr::DDRFOOTHandle::close() {
log_info("ddr", "Closed COM1 (FOOT).");
return true;
}
+23 -23
View File
@@ -1,23 +1,23 @@
#pragma once
#include "hooks/devicehook.h"
namespace games::ddr {
class DDRFOOTHandle : public CustomHandle {
private:
bool data_trigger = false;
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
#pragma once
#include "hooks/devicehook.h"
namespace games::ddr {
class DDRFOOTHandle : public CustomHandle {
private:
bool data_trigger = false;
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
+550 -550
View File
File diff suppressed because it is too large Load Diff
+37 -37
View File
@@ -1,37 +1,37 @@
#pragma once
#include "acioemu/acioemu.h"
#include "hooks/devicehook.h"
namespace games::ddr {
class DDRP3IOHandle : public CustomHandle {
private:
acioemu::ACIOEmu *acio_emu;
circular_buffer<uint8_t> read_buf = circular_buffer<uint8_t>(1024);
class HDXSDevice : public acioemu::ACIODeviceEmu {
public:
HDXSDevice();
bool parse_msg(
acioemu::MessageData* msg_in,
circular_buffer<uint8_t> *response_buffer
) override;
};
void write_msg(const uint8_t *data, size_t len);
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
#pragma once
#include "acioemu/acioemu.h"
#include "hooks/devicehook.h"
namespace games::ddr {
class DDRP3IOHandle : public CustomHandle {
private:
acioemu::ACIOEmu *acio_emu;
circular_buffer<uint8_t> read_buf = circular_buffer<uint8_t>(1024);
class HDXSDevice : public acioemu::ACIODeviceEmu {
public:
HDXSDevice();
bool parse_msg(
acioemu::MessageData* msg_in,
circular_buffer<uint8_t> *response_buffer
) override;
};
void write_msg(const uint8_t *data, size_t len);
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
+102 -102
View File
@@ -1,102 +1,102 @@
#include "sate.h"
#include "util/logging.h"
using namespace acioemu;
games::ddr::DDRSATEHandle::SATEDevice::SATEDevice() {
this->node_count = 7;
}
bool games::ddr::DDRSATEHandle::SATEDevice::parse_msg(
acioemu::MessageData *msg_in,
circular_buffer<uint8_t> *response_buffer
) {
// check command
switch (msg_in->cmd.code) {
case ACIO_CMD_GET_VERSION: {
// send version data
auto msg = this->create_msg(msg_in, MSG_VERSION_SIZE);
this->set_version(msg, 0x105, 0, 1, 1, 0, "DDRS");
write_msg(msg, response_buffer);
delete msg;
break;
}
case ACIO_CMD_CLEAR:
case ACIO_CMD_STARTUP:
case 0xFF: // BROADCAST
{
// send status 0
auto msg = this->create_msg_status(msg_in, 0x00);
write_msg(msg, response_buffer);
delete msg;
break;
}
default:
return false;
}
// mark as handled
return true;
}
bool games::ddr::DDRSATEHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM2") != 0) {
return false;
}
log_info("ddr", "Opened COM2 (SATE)");
// ACIO device
acio_emu.add_device(new SATEDevice());
return true;
}
int games::ddr::DDRSATEHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
auto buffer = reinterpret_cast<uint8_t *>(lpBuffer);
// read from emu
DWORD bytes_read = 0;
while (bytes_read < nNumberOfBytesToRead) {
auto cur_byte = acio_emu.read();
if (cur_byte.has_value()) {
buffer[bytes_read++] = cur_byte.value();
} else {
break;
}
}
// return amount of bytes read
return (int) bytes_read;
}
int games::ddr::DDRSATEHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
auto buffer = reinterpret_cast<const uint8_t *>(lpBuffer);
// write to emu
for (DWORD i = 0; i < nNumberOfBytesToWrite; i++) {
acio_emu.write(buffer[i]);
}
// return all data written
return (int) nNumberOfBytesToWrite;
}
int games::ddr::DDRSATEHandle::device_io(
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize
) {
return -1;
}
bool games::ddr::DDRSATEHandle::close() {
log_info("ddr", "Closed COM2 (SATE).");
return true;
}
#include "sate.h"
#include "util/logging.h"
using namespace acioemu;
games::ddr::DDRSATEHandle::SATEDevice::SATEDevice() {
this->node_count = 7;
}
bool games::ddr::DDRSATEHandle::SATEDevice::parse_msg(
acioemu::MessageData *msg_in,
circular_buffer<uint8_t> *response_buffer
) {
// check command
switch (msg_in->cmd.code) {
case ACIO_CMD_GET_VERSION: {
// send version data
auto msg = this->create_msg(msg_in, MSG_VERSION_SIZE);
this->set_version(msg, 0x105, 0, 1, 1, 0, "DDRS");
write_msg(msg, response_buffer);
delete msg;
break;
}
case ACIO_CMD_CLEAR:
case ACIO_CMD_STARTUP:
case 0xFF: // BROADCAST
{
// send status 0
auto msg = this->create_msg_status(msg_in, 0x00);
write_msg(msg, response_buffer);
delete msg;
break;
}
default:
return false;
}
// mark as handled
return true;
}
bool games::ddr::DDRSATEHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM2") != 0) {
return false;
}
log_info("ddr", "Opened COM2 (SATE)");
// ACIO device
acio_emu.add_device(new SATEDevice());
return true;
}
int games::ddr::DDRSATEHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
auto buffer = reinterpret_cast<uint8_t *>(lpBuffer);
// read from emu
DWORD bytes_read = 0;
while (bytes_read < nNumberOfBytesToRead) {
auto cur_byte = acio_emu.read();
if (cur_byte.has_value()) {
buffer[bytes_read++] = cur_byte.value();
} else {
break;
}
}
// return amount of bytes read
return (int) bytes_read;
}
int games::ddr::DDRSATEHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
auto buffer = reinterpret_cast<const uint8_t *>(lpBuffer);
// write to emu
for (DWORD i = 0; i < nNumberOfBytesToWrite; i++) {
acio_emu.write(buffer[i]);
}
// return all data written
return (int) nNumberOfBytesToWrite;
}
int games::ddr::DDRSATEHandle::device_io(
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize
) {
return -1;
}
bool games::ddr::DDRSATEHandle::close() {
log_info("ddr", "Closed COM2 (SATE).");
return true;
}
+31 -31
View File
@@ -1,31 +1,31 @@
#pragma once
#include "hooks/devicehook.h"
#include "acioemu/acioemu.h"
namespace games::ddr {
class DDRSATEHandle : public CustomHandle {
private:
acioemu::ACIOEmu acio_emu;
class SATEDevice : public acioemu::ACIODeviceEmu {
public:
SATEDevice();
bool parse_msg(acioemu::MessageData *msg_in, circular_buffer<uint8_t> *response_buffer) override;
};
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
#pragma once
#include "hooks/devicehook.h"
#include "acioemu/acioemu.h"
namespace games::ddr {
class DDRSATEHandle : public CustomHandle {
private:
acioemu::ACIOEmu acio_emu;
class SATEDevice : public acioemu::ACIODeviceEmu {
public:
SATEDevice();
bool parse_msg(acioemu::MessageData *msg_in, circular_buffer<uint8_t> *response_buffer) override;
};
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
+60 -60
View File
@@ -1,60 +1,60 @@
#include "usbmem.h"
#include "util/logging.h"
void games::ddr::DDRUSBMEMHandle::respond(const char *data) {
size_t len = strlen(data) + 1;
memcpy(response_data, data, len);
memcpy(response_data + len, "\r>", 2);
response_data_size = len + 2;
}
bool games::ddr::DDRUSBMEMHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM3") != 0) {
return false;
}
log_info("ddr", "Opened COM3 (USBMEM)");
return true;
}
int games::ddr::DDRUSBMEMHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
// check for response
if (response_data_size && nNumberOfBytesToRead >= response_data_size) {
size_t bytes_read = response_data_size;
memcpy(lpBuffer, response_data, response_data_size);
response_data_size = 0;
return (int) bytes_read;
}
// no data
return 0;
}
int games::ddr::DDRUSBMEMHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
// check CMD
if (!memcmp(lpBuffer, "sver", 4))
respond("done GQHDXJAA SPICE");
else if (!memcmp(lpBuffer, "on_a", 4) ||
!memcmp(lpBuffer, "on_b", 4) ||
!memcmp(lpBuffer, "offa", 4) ||
!memcmp(lpBuffer, "offb", 4) ||
!memcmp(lpBuffer, "lma ", 4) ||
!memcmp(lpBuffer, "lmb ", 4))
respond("done");
else
respond("not connected");
// return all data written
return (int) nNumberOfBytesToWrite;
}
int games::ddr::DDRUSBMEMHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
return -1;
}
bool games::ddr::DDRUSBMEMHandle::close() {
log_info("ddr", "Closed COM3 (USBMEM).");
return true;
}
#include "usbmem.h"
#include "util/logging.h"
void games::ddr::DDRUSBMEMHandle::respond(const char *data) {
size_t len = strlen(data) + 1;
memcpy(response_data, data, len);
memcpy(response_data + len, "\r>", 2);
response_data_size = len + 2;
}
bool games::ddr::DDRUSBMEMHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM3") != 0) {
return false;
}
log_info("ddr", "Opened COM3 (USBMEM)");
return true;
}
int games::ddr::DDRUSBMEMHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
// check for response
if (response_data_size && nNumberOfBytesToRead >= response_data_size) {
size_t bytes_read = response_data_size;
memcpy(lpBuffer, response_data, response_data_size);
response_data_size = 0;
return (int) bytes_read;
}
// no data
return 0;
}
int games::ddr::DDRUSBMEMHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
// check CMD
if (!memcmp(lpBuffer, "sver", 4))
respond("done GQHDXJAA SPICE");
else if (!memcmp(lpBuffer, "on_a", 4) ||
!memcmp(lpBuffer, "on_b", 4) ||
!memcmp(lpBuffer, "offa", 4) ||
!memcmp(lpBuffer, "offb", 4) ||
!memcmp(lpBuffer, "lma ", 4) ||
!memcmp(lpBuffer, "lmb ", 4))
respond("done");
else
respond("not connected");
// return all data written
return (int) nNumberOfBytesToWrite;
}
int games::ddr::DDRUSBMEMHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
return -1;
}
bool games::ddr::DDRUSBMEMHandle::close() {
log_info("ddr", "Closed COM3 (USBMEM).");
return true;
}
+26 -26
View File
@@ -1,26 +1,26 @@
#pragma once
#include "hooks/devicehook.h"
namespace games::ddr {
class DDRUSBMEMHandle : public CustomHandle {
private:
char response_data[256]{};
size_t response_data_size = 0;
void respond(const char *data);
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
#pragma once
#include "hooks/devicehook.h"
namespace games::ddr {
class DDRUSBMEMHandle : public CustomHandle {
private:
char response_data[256]{};
size_t response_data_size = 0;
void respond(const char *data);
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
+26 -26
View File
@@ -1,26 +1,26 @@
#include "dea.h"
#include "launcher/launcher.h"
#include "util/libutils.h"
#include "util/logging.h"
namespace games::dea {
DEAGame::DEAGame() : Game("Dance Evolution") {
}
void DEAGame::attach() {
Game::attach();
// since this DLL isn't automatically loaded the hooks don't work unless we load it manually
libutils::try_library(MODULE_PATH / "gamekdm.dll");
// Has the user actually performed first-time setup?
auto kinect10 = libutils::try_library("Kinect10.dll");
if (!kinect10) {
log_warning("dea", "Failed to load 'Kinect10.dll'. Game will boot in Test Mode. Have you installed the Kinect SDK?");
} else {
FreeLibrary(kinect10);
}
}
}
#include "dea.h"
#include "launcher/launcher.h"
#include "util/libutils.h"
#include "util/logging.h"
namespace games::dea {
DEAGame::DEAGame() : Game("Dance Evolution") {
}
void DEAGame::attach() {
Game::attach();
// since this DLL isn't automatically loaded the hooks don't work unless we load it manually
libutils::try_library(MODULE_PATH / "gamekdm.dll");
// Has the user actually performed first-time setup?
auto kinect10 = libutils::try_library("Kinect10.dll");
if (!kinect10) {
log_warning("dea", "Failed to load 'Kinect10.dll'. Game will boot in Test Mode. Have you installed the Kinect SDK?");
} else {
FreeLibrary(kinect10);
}
}
}
+12 -12
View File
@@ -1,12 +1,12 @@
#pragma once
#include "games/game.h"
namespace games::dea {
class DEAGame : public games::Game {
public:
DEAGame();
virtual void attach() override;
};
}
#pragma once
#include "games/game.h"
namespace games::dea {
class DEAGame : public games::Game {
public:
DEAGame();
virtual void attach() override;
};
}
+68 -68
View File
@@ -1,68 +1,68 @@
#include "io.h"
std::vector<Button> &games::dea::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Dance Evolution");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"P1 Start",
"P1 Left",
"P1 Right",
"P2 Start",
"P2 Left",
"P2 Right"
);
}
return buttons;
}
std::vector<Light> &games::dea::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Dance Evolution");
GameAPI::Lights::sortLights(
&lights,
"Title R",
"Title G",
"Title B",
"Side Upper Left R",
"Side Upper Left G",
"Side Upper Left B",
"Side Upper Right R",
"Side Upper Right G",
"Side Upper Right B",
"P1 Start",
"P1 L/R Button",
"P2 Start",
"P2 L/R Button",
"Side Lower Left 1 R",
"Side Lower Left 1 G",
"Side Lower Left 1 B",
"Side Lower Left 2 R",
"Side Lower Left 2 G",
"Side Lower Left 2 B",
"Side Lower Left 3 R",
"Side Lower Left 3 G",
"Side Lower Left 3 B",
"Side Lower Right 1 R",
"Side Lower Right 1 G",
"Side Lower Right 1 B",
"Side Lower Right 2 R",
"Side Lower Right 2 G",
"Side Lower Right 2 B",
"Side Lower Right 3 R",
"Side Lower Right 3 G",
"Side Lower Right 3 B"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::dea::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Dance Evolution");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"P1 Start",
"P1 Left",
"P1 Right",
"P2 Start",
"P2 Left",
"P2 Right"
);
}
return buttons;
}
std::vector<Light> &games::dea::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Dance Evolution");
GameAPI::Lights::sortLights(
&lights,
"Title R",
"Title G",
"Title B",
"Side Upper Left R",
"Side Upper Left G",
"Side Upper Left B",
"Side Upper Right R",
"Side Upper Right G",
"Side Upper Right B",
"P1 Start",
"P1 L/R Button",
"P2 Start",
"P2 L/R Button",
"Side Lower Left 1 R",
"Side Lower Left 1 G",
"Side Lower Left 1 B",
"Side Lower Left 2 R",
"Side Lower Left 2 G",
"Side Lower Left 2 B",
"Side Lower Left 3 R",
"Side Lower Left 3 G",
"Side Lower Left 3 B",
"Side Lower Right 1 R",
"Side Lower Right 1 G",
"Side Lower Right 1 B",
"Side Lower Right 2 R",
"Side Lower Right 2 G",
"Side Lower Right 2 B",
"Side Lower Right 3 R",
"Side Lower Right 3 G",
"Side Lower Right 3 B"
);
}
return lights;
}
+62 -62
View File
@@ -1,62 +1,62 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::dea {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
P1Start,
P1Left,
P1Right,
P2Start,
P2Left,
P2Right
};
}
// all lights in correct order
namespace Lights {
enum {
TitleR,
TitleG,
TitleB,
SideUpperLeftR,
SideUpperLeftG,
SideUpperLeftB,
SideUpperRightR,
SideUpperRightG,
SideUpperRightB,
P1Start,
P1LRButton,
P2Start,
P2LRButton,
SideLowerLeft1R,
SideLowerLeft1G,
SideLowerLeft1B,
SideLowerLeft2R,
SideLowerLeft2G,
SideLowerLeft2B,
SideLowerLeft3R,
SideLowerLeft3G,
SideLowerLeft3B,
SideLowerRight1R,
SideLowerRight1G,
SideLowerRight1B,
SideLowerRight2R,
SideLowerRight2G,
SideLowerRight2B,
SideLowerRight3R,
SideLowerRight3G,
SideLowerRight3B,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::dea {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
P1Start,
P1Left,
P1Right,
P2Start,
P2Left,
P2Right
};
}
// all lights in correct order
namespace Lights {
enum {
TitleR,
TitleG,
TitleB,
SideUpperLeftR,
SideUpperLeftG,
SideUpperLeftB,
SideUpperRightR,
SideUpperRightG,
SideUpperRightB,
P1Start,
P1LRButton,
P2Start,
P2LRButton,
SideLowerLeft1R,
SideLowerLeft1G,
SideLowerLeft1B,
SideLowerLeft2R,
SideLowerLeft2G,
SideLowerLeft2B,
SideLowerLeft3R,
SideLowerLeft3G,
SideLowerLeft3B,
SideLowerRight1R,
SideLowerRight1G,
SideLowerRight1B,
SideLowerRight2R,
SideLowerRight2G,
SideLowerRight2B,
SideLowerRight3R,
SideLowerRight3G,
SideLowerRight3B,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
+409 -409
View File
@@ -1,409 +1,409 @@
#include "drs.h"
#include <windows.h>
#include <thread>
#include "avs/game.h"
#include "games/game.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/memutils.h"
#include "misc/vrutil.h"
#pragma pack(push)
typedef struct {
union {
struct {
WORD unk1;
WORD unk2;
WORD device_id;
WORD vid;
WORD pid;
WORD pvn;
WORD max_point_num;
};
uint8_t raw[2356];
};
} dev_info_t;
typedef struct {
DWORD cid;
DWORD type;
DWORD unused;
DWORD y;
DWORD x;
DWORD height;
DWORD width;
DWORD unk8;
} touch_data_t;
#pragma pack(pop)
enum touch_type {
TS_DOWN = 1,
TS_MOVE = 2,
TS_UP = 3,
};
void *user_data = nullptr;
void (*touch_callback)(
dev_info_t *dev_info,
const touch_data_t *touch_data,
int touch_points,
int unk1,
const void *user_data);
namespace games::drs {
void* TouchSDK_Constructor(void* in) {
return in;
}
bool TouchSDK_SendData(dev_info_t*,
unsigned char * const, int, unsigned char * const,
unsigned char* output, int output_size) {
// fake success
if (output_size >= 4) {
output[0] = 0xfc;
output[1] = 0xa5;
}
return true;
}
bool TouchSDK_SetSignalInit(dev_info_t*, int) {
return true;
}
void TouchSDK_Destructor(void* This) {
}
int TouchSDK_GetYLedTotal(dev_info_t*, int) {
return 53;
}
int TouchSDK_GetXLedTotal(dev_info_t*, int) {
return 41;
}
bool TouchSDK_DisableTouch(dev_info_t*, int) {
return true;
}
bool TouchSDK_DisableDrag(dev_info_t*, int) {
return true;
}
bool TouchSDK_DisableWheel(dev_info_t*, int) {
return true;
}
bool TouchSDK_DisableRightClick(dev_info_t*, int) {
return true;
}
bool TouchSDK_SetMultiTouchMode(dev_info_t*, int) {
return true;
}
bool TouchSDK_EnableTouchWidthData(dev_info_t*, int) {
return true;
}
bool TouchSDK_EnableRawData(dev_info_t*, int) {
return true;
}
bool TouchSDK_SetAllEnable(dev_info_t*, bool, int) {
return true;
}
int TouchSDK_GetTouchDeviceCount(void* This) {
return 1;
}
unsigned int TouchSDK_GetTouchSDKVersion(void) {
return 0x01030307;
}
int TouchSDK_InitTouch(void* This, dev_info_t *devices, int max_devices, void* touch_event_cb,
void* hotplug_callback, void* userdata) {
// fake touch device
memset(devices, 0, sizeof(devices[0].raw));
devices[0].unk1 = 0x1122;
devices[0].unk2 = 0x3344;
devices[0].device_id = 0;
devices[0].vid = 0xDEAD;
devices[0].pid = 0xBEEF;
devices[0].pvn = 0xC0DE;
devices[0].max_point_num = 16;
// remember provided callback and userdata
touch_callback = (decltype(touch_callback)) touch_event_cb;
user_data = userdata;
// success
return 1;
}
char DRS_TAPELED[38 * 49][3] {};
bool VR_STARTED = false;
linalg::aliases::float3 VR_SCALE(100, 100, 1.f);
linalg::aliases::float3 VR_OFFSET(0.f, 0.f, -0.1f);
float VR_ROTATION = 0.f;
VRFoot VR_FOOTS[2] {
{1},
{2},
};
inline DWORD scale_double_to_xy(double val) {
return static_cast<DWORD>(val * 32768);
}
inline DWORD scale_double_to_height(double val) {
return static_cast<DWORD>(val * 1312);
}
inline DWORD scale_double_to_width(double val) {
return static_cast<DWORD>(val * 1696);
}
void fire_touches(drs_touch_t *events, size_t event_count) {
// check callback first
if (!touch_callback) {
return;
}
// generate touch data
auto game_touches = std::make_unique<touch_data_t[]>(event_count);
for (size_t i = 0; i < event_count; i++) {
// initialize touch value
game_touches[i].cid = (DWORD) events[i].id;
game_touches[i].unk8 = 0;
// copy scaled values
game_touches[i].x = scale_double_to_xy(events[i].x);
game_touches[i].y = scale_double_to_xy(events[i].y);
game_touches[i].width = scale_double_to_width(events[i].width);
game_touches[i].height = scale_double_to_height(events[i].height);
// decide touch type
switch(events[i].type) {
case DRS_DOWN:
game_touches[i].type = TS_DOWN;
break;
case DRS_UP:
game_touches[i].type = TS_UP;
break;
case DRS_MOVE:
game_touches[i].type = TS_MOVE;
break;
default:
break;
}
}
// build device information
dev_info_t dev;
dev.unk1 = 0;
dev.unk2 = 0;
dev.device_id = 0;
dev.vid = 0xDEAD;
dev.pid = 0xBEEF;
dev.pvn = 0xC0DE;
dev.max_point_num = 16;
// fire callback
touch_callback(&dev, game_touches.get(), (int) event_count, 0, user_data);
}
uint32_t VRFoot::get_index() {
if (index == ~0u) {
if (id == 1) return vrutil::INDEX_LEFT;
if (id == 2) return vrutil::INDEX_RIGHT;
}
return index;
}
linalg::aliases::float3 VRFoot::to_world(linalg::aliases::float3 pos) {
pos = linalg::aliases::float3(-pos.z, pos.x, pos.y);
const float deg_to_rad = (float) (1 / 180.f * M_PI);
auto s = sinf(VR_ROTATION * deg_to_rad);
auto c = cosf(VR_ROTATION * deg_to_rad);
pos = linalg::aliases::float3(pos.x * c - pos.y * s,
pos.x * s + pos.y * c,
pos.z);
return pos * VR_SCALE + VR_OFFSET;
}
void start_vr() {
if (vrutil::STATUS != vrutil::VRStatus::Running) return;
if (!VR_STARTED) {
VR_STARTED = true;
std::thread t([] {
log_info("drs", "starting VR thread");
// dance floor plane
const linalg::aliases::float3 plane_normal(0, 0, 1);
const linalg::aliases::float3 plane_point(0, 0, 0);
const float touch_width = 1.f;
const float touch_height = 1.f;
// main loop
while (vrutil::STATUS == vrutil::VRStatus::Running) {
// iterate foots
for (auto &foot : VR_FOOTS) {
vr::TrackedDevicePose_t pose;
vr::VRControllerState_t state;
vrutil::get_con_pose(foot.get_index(), &pose, &state);
// only accept valid poses
if (pose.bPoseIsValid) {
auto length = std::max(foot.length, 0.001f);
// get components
auto translation = foot.to_world(vrutil::get_translation(
pose.mDeviceToAbsoluteTracking));
auto direction = -linalg::qzdir(linalg::qmul(
vrutil::get_rotation(pose.mDeviceToAbsoluteTracking.m),
foot.rotation));
direction = linalg::aliases::float3 {
-direction.z, direction.x, direction.y
};
// get intersection point
auto intersection = vrutil::intersect_point(
direction, translation,
plane_normal, plane_point);
auto distance = linalg::distance(
translation, intersection);
// update event details
foot.height = std::max(0.f, translation.z - intersection.z);
foot.event.id = foot.id;
foot.event.x = (intersection.x / 38.f) * touch_width;
foot.event.y = (intersection.y / 49.f) * touch_height;
if (translation.z > intersection.z) {
foot.event.width = foot.size_base
+ foot.size_scale * std::max(0.f, 1.f - distance / length);
} else {
foot.event.width = foot.size_base + foot.size_scale;
}
foot.event.height = foot.event.width;
// check if controller points down
if (direction.z < 0) {
// check if plane in range
if (distance <= length) {
// check previous event
switch (foot.event.type) {
case DRS_UP:
// generate down event
foot.event.type = DRS_DOWN;
break;
case DRS_DOWN:
case DRS_MOVE:
// generate move event
foot.event.type = DRS_MOVE;
break;
default:
break;
}
// send event
drs::fire_touches(&foot.event, 1);
continue;
}
}
// foot not intersecting with plane
switch (foot.event.type) {
case DRS_DOWN:
case DRS_MOVE:
// generate up event
foot.event.type = DRS_UP;
drs::fire_touches(&foot.event, 1);
break;
case DRS_UP:
default:
break;
}
}
}
// slow down
vrutil::scan();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
VR_STARTED = false;
return nullptr;
});
t.detach();
}
}
DRSGame::DRSGame() : Game("DANCERUSH") {
}
void DRSGame::attach() {
Game::attach();
// TouchSDK hooks
detour::iat("??0TouchSDK@@QEAA@XZ",
(void *) &TouchSDK_Constructor, avs::game::DLL_INSTANCE);
detour::iat("?SendData@TouchSDK@@QEAA_NU_DeviceInfo@@QEAEH1HH@Z",
(void *) &TouchSDK_SendData, avs::game::DLL_INSTANCE);
detour::iat("?SetSignalInit@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_SetSignalInit, avs::game::DLL_INSTANCE);
detour::iat("??1TouchSDK@@QEAA@XZ",
(void *) &TouchSDK_Destructor, avs::game::DLL_INSTANCE);
detour::iat("?GetYLedTotal@TouchSDK@@QEAAHU_DeviceInfo@@H@Z",
(void *) &TouchSDK_GetYLedTotal, avs::game::DLL_INSTANCE);
detour::iat("?GetXLedTotal@TouchSDK@@QEAAHU_DeviceInfo@@H@Z",
(void *) &TouchSDK_GetXLedTotal, avs::game::DLL_INSTANCE);
detour::iat("?DisableTouch@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_DisableTouch, avs::game::DLL_INSTANCE);
detour::iat("?DisableDrag@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_DisableDrag, avs::game::DLL_INSTANCE);
detour::iat("?DisableWheel@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_DisableWheel, avs::game::DLL_INSTANCE);
detour::iat("?DisableRightClick@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_DisableRightClick, avs::game::DLL_INSTANCE);
detour::iat("?SetMultiTouchMode@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_SetMultiTouchMode, avs::game::DLL_INSTANCE);
detour::iat("?EnableTouchWidthData@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_EnableTouchWidthData, avs::game::DLL_INSTANCE);
detour::iat("?EnableRawData@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_EnableRawData, avs::game::DLL_INSTANCE);
detour::iat("?SetAllEnable@TouchSDK@@QEAA_NU_DeviceInfo@@_NH@Z",
(void *) &TouchSDK_SetAllEnable, avs::game::DLL_INSTANCE);
detour::iat("?GetTouchDeviceCount@TouchSDK@@QEAAHXZ",
(void *) &TouchSDK_GetTouchDeviceCount, avs::game::DLL_INSTANCE);
detour::iat("?GetTouchSDKVersion@TouchSDK@@QEAAIXZ",
(void *) &TouchSDK_GetTouchSDKVersion, avs::game::DLL_INSTANCE);
detour::iat("?InitTouch@TouchSDK@@QEAAHPEAU_DeviceInfo@@HP6AXU2@PEBU_TouchPointData@@HHPEBX@ZP6AX1_N3@ZPEAX@Z",
(void *) &TouchSDK_InitTouch, avs::game::DLL_INSTANCE);
// VR
if (vrutil::STATUS == vrutil::VRStatus::Running) {
start_vr();
}
}
void DRSGame::detach() {
Game::detach();
}
}
#include "drs.h"
#include <windows.h>
#include <thread>
#include "avs/game.h"
#include "games/game.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/memutils.h"
#include "misc/vrutil.h"
#pragma pack(push)
typedef struct {
union {
struct {
WORD unk1;
WORD unk2;
WORD device_id;
WORD vid;
WORD pid;
WORD pvn;
WORD max_point_num;
};
uint8_t raw[2356];
};
} dev_info_t;
typedef struct {
DWORD cid;
DWORD type;
DWORD unused;
DWORD y;
DWORD x;
DWORD height;
DWORD width;
DWORD unk8;
} touch_data_t;
#pragma pack(pop)
enum touch_type {
TS_DOWN = 1,
TS_MOVE = 2,
TS_UP = 3,
};
void *user_data = nullptr;
void (*touch_callback)(
dev_info_t *dev_info,
const touch_data_t *touch_data,
int touch_points,
int unk1,
const void *user_data);
namespace games::drs {
void* TouchSDK_Constructor(void* in) {
return in;
}
bool TouchSDK_SendData(dev_info_t*,
unsigned char * const, int, unsigned char * const,
unsigned char* output, int output_size) {
// fake success
if (output_size >= 4) {
output[0] = 0xfc;
output[1] = 0xa5;
}
return true;
}
bool TouchSDK_SetSignalInit(dev_info_t*, int) {
return true;
}
void TouchSDK_Destructor(void* This) {
}
int TouchSDK_GetYLedTotal(dev_info_t*, int) {
return 53;
}
int TouchSDK_GetXLedTotal(dev_info_t*, int) {
return 41;
}
bool TouchSDK_DisableTouch(dev_info_t*, int) {
return true;
}
bool TouchSDK_DisableDrag(dev_info_t*, int) {
return true;
}
bool TouchSDK_DisableWheel(dev_info_t*, int) {
return true;
}
bool TouchSDK_DisableRightClick(dev_info_t*, int) {
return true;
}
bool TouchSDK_SetMultiTouchMode(dev_info_t*, int) {
return true;
}
bool TouchSDK_EnableTouchWidthData(dev_info_t*, int) {
return true;
}
bool TouchSDK_EnableRawData(dev_info_t*, int) {
return true;
}
bool TouchSDK_SetAllEnable(dev_info_t*, bool, int) {
return true;
}
int TouchSDK_GetTouchDeviceCount(void* This) {
return 1;
}
unsigned int TouchSDK_GetTouchSDKVersion(void) {
return 0x01030307;
}
int TouchSDK_InitTouch(void* This, dev_info_t *devices, int max_devices, void* touch_event_cb,
void* hotplug_callback, void* userdata) {
// fake touch device
memset(devices, 0, sizeof(devices[0].raw));
devices[0].unk1 = 0x1122;
devices[0].unk2 = 0x3344;
devices[0].device_id = 0;
devices[0].vid = 0xDEAD;
devices[0].pid = 0xBEEF;
devices[0].pvn = 0xC0DE;
devices[0].max_point_num = 16;
// remember provided callback and userdata
touch_callback = (decltype(touch_callback)) touch_event_cb;
user_data = userdata;
// success
return 1;
}
char DRS_TAPELED[38 * 49][3] {};
bool VR_STARTED = false;
linalg::aliases::float3 VR_SCALE(100, 100, 1.f);
linalg::aliases::float3 VR_OFFSET(0.f, 0.f, -0.1f);
float VR_ROTATION = 0.f;
VRFoot VR_FOOTS[2] {
{1},
{2},
};
inline DWORD scale_double_to_xy(double val) {
return static_cast<DWORD>(val * 32768);
}
inline DWORD scale_double_to_height(double val) {
return static_cast<DWORD>(val * 1312);
}
inline DWORD scale_double_to_width(double val) {
return static_cast<DWORD>(val * 1696);
}
void fire_touches(drs_touch_t *events, size_t event_count) {
// check callback first
if (!touch_callback) {
return;
}
// generate touch data
auto game_touches = std::make_unique<touch_data_t[]>(event_count);
for (size_t i = 0; i < event_count; i++) {
// initialize touch value
game_touches[i].cid = (DWORD) events[i].id;
game_touches[i].unk8 = 0;
// copy scaled values
game_touches[i].x = scale_double_to_xy(events[i].x);
game_touches[i].y = scale_double_to_xy(events[i].y);
game_touches[i].width = scale_double_to_width(events[i].width);
game_touches[i].height = scale_double_to_height(events[i].height);
// decide touch type
switch(events[i].type) {
case DRS_DOWN:
game_touches[i].type = TS_DOWN;
break;
case DRS_UP:
game_touches[i].type = TS_UP;
break;
case DRS_MOVE:
game_touches[i].type = TS_MOVE;
break;
default:
break;
}
}
// build device information
dev_info_t dev;
dev.unk1 = 0;
dev.unk2 = 0;
dev.device_id = 0;
dev.vid = 0xDEAD;
dev.pid = 0xBEEF;
dev.pvn = 0xC0DE;
dev.max_point_num = 16;
// fire callback
touch_callback(&dev, game_touches.get(), (int) event_count, 0, user_data);
}
uint32_t VRFoot::get_index() {
if (index == ~0u) {
if (id == 1) return vrutil::INDEX_LEFT;
if (id == 2) return vrutil::INDEX_RIGHT;
}
return index;
}
linalg::aliases::float3 VRFoot::to_world(linalg::aliases::float3 pos) {
pos = linalg::aliases::float3(-pos.z, pos.x, pos.y);
const float deg_to_rad = (float) (1 / 180.f * M_PI);
auto s = sinf(VR_ROTATION * deg_to_rad);
auto c = cosf(VR_ROTATION * deg_to_rad);
pos = linalg::aliases::float3(pos.x * c - pos.y * s,
pos.x * s + pos.y * c,
pos.z);
return pos * VR_SCALE + VR_OFFSET;
}
void start_vr() {
if (vrutil::STATUS != vrutil::VRStatus::Running) return;
if (!VR_STARTED) {
VR_STARTED = true;
std::thread t([] {
log_info("drs", "starting VR thread");
// dance floor plane
const linalg::aliases::float3 plane_normal(0, 0, 1);
const linalg::aliases::float3 plane_point(0, 0, 0);
const float touch_width = 1.f;
const float touch_height = 1.f;
// main loop
while (vrutil::STATUS == vrutil::VRStatus::Running) {
// iterate foots
for (auto &foot : VR_FOOTS) {
vr::TrackedDevicePose_t pose;
vr::VRControllerState_t state;
vrutil::get_con_pose(foot.get_index(), &pose, &state);
// only accept valid poses
if (pose.bPoseIsValid) {
auto length = std::max(foot.length, 0.001f);
// get components
auto translation = foot.to_world(vrutil::get_translation(
pose.mDeviceToAbsoluteTracking));
auto direction = -linalg::qzdir(linalg::qmul(
vrutil::get_rotation(pose.mDeviceToAbsoluteTracking.m),
foot.rotation));
direction = linalg::aliases::float3 {
-direction.z, direction.x, direction.y
};
// get intersection point
auto intersection = vrutil::intersect_point(
direction, translation,
plane_normal, plane_point);
auto distance = linalg::distance(
translation, intersection);
// update event details
foot.height = std::max(0.f, translation.z - intersection.z);
foot.event.id = foot.id;
foot.event.x = (intersection.x / 38.f) * touch_width;
foot.event.y = (intersection.y / 49.f) * touch_height;
if (translation.z > intersection.z) {
foot.event.width = foot.size_base
+ foot.size_scale * std::max(0.f, 1.f - distance / length);
} else {
foot.event.width = foot.size_base + foot.size_scale;
}
foot.event.height = foot.event.width;
// check if controller points down
if (direction.z < 0) {
// check if plane in range
if (distance <= length) {
// check previous event
switch (foot.event.type) {
case DRS_UP:
// generate down event
foot.event.type = DRS_DOWN;
break;
case DRS_DOWN:
case DRS_MOVE:
// generate move event
foot.event.type = DRS_MOVE;
break;
default:
break;
}
// send event
drs::fire_touches(&foot.event, 1);
continue;
}
}
// foot not intersecting with plane
switch (foot.event.type) {
case DRS_DOWN:
case DRS_MOVE:
// generate up event
foot.event.type = DRS_UP;
drs::fire_touches(&foot.event, 1);
break;
case DRS_UP:
default:
break;
}
}
}
// slow down
vrutil::scan();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
VR_STARTED = false;
return nullptr;
});
t.detach();
}
}
DRSGame::DRSGame() : Game("DANCERUSH") {
}
void DRSGame::attach() {
Game::attach();
// TouchSDK hooks
detour::iat("??0TouchSDK@@QEAA@XZ",
(void *) &TouchSDK_Constructor, avs::game::DLL_INSTANCE);
detour::iat("?SendData@TouchSDK@@QEAA_NU_DeviceInfo@@QEAEH1HH@Z",
(void *) &TouchSDK_SendData, avs::game::DLL_INSTANCE);
detour::iat("?SetSignalInit@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_SetSignalInit, avs::game::DLL_INSTANCE);
detour::iat("??1TouchSDK@@QEAA@XZ",
(void *) &TouchSDK_Destructor, avs::game::DLL_INSTANCE);
detour::iat("?GetYLedTotal@TouchSDK@@QEAAHU_DeviceInfo@@H@Z",
(void *) &TouchSDK_GetYLedTotal, avs::game::DLL_INSTANCE);
detour::iat("?GetXLedTotal@TouchSDK@@QEAAHU_DeviceInfo@@H@Z",
(void *) &TouchSDK_GetXLedTotal, avs::game::DLL_INSTANCE);
detour::iat("?DisableTouch@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_DisableTouch, avs::game::DLL_INSTANCE);
detour::iat("?DisableDrag@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_DisableDrag, avs::game::DLL_INSTANCE);
detour::iat("?DisableWheel@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_DisableWheel, avs::game::DLL_INSTANCE);
detour::iat("?DisableRightClick@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_DisableRightClick, avs::game::DLL_INSTANCE);
detour::iat("?SetMultiTouchMode@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_SetMultiTouchMode, avs::game::DLL_INSTANCE);
detour::iat("?EnableTouchWidthData@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_EnableTouchWidthData, avs::game::DLL_INSTANCE);
detour::iat("?EnableRawData@TouchSDK@@QEAA_NU_DeviceInfo@@H@Z",
(void *) &TouchSDK_EnableRawData, avs::game::DLL_INSTANCE);
detour::iat("?SetAllEnable@TouchSDK@@QEAA_NU_DeviceInfo@@_NH@Z",
(void *) &TouchSDK_SetAllEnable, avs::game::DLL_INSTANCE);
detour::iat("?GetTouchDeviceCount@TouchSDK@@QEAAHXZ",
(void *) &TouchSDK_GetTouchDeviceCount, avs::game::DLL_INSTANCE);
detour::iat("?GetTouchSDKVersion@TouchSDK@@QEAAIXZ",
(void *) &TouchSDK_GetTouchSDKVersion, avs::game::DLL_INSTANCE);
detour::iat("?InitTouch@TouchSDK@@QEAAHPEAU_DeviceInfo@@HP6AXU2@PEBU_TouchPointData@@HHPEBX@ZP6AX1_N3@ZPEAX@Z",
(void *) &TouchSDK_InitTouch, avs::game::DLL_INSTANCE);
// VR
if (vrutil::STATUS == vrutil::VRStatus::Running) {
start_vr();
}
}
void DRSGame::detach() {
Game::detach();
}
}
+51 -51
View File
@@ -1,51 +1,51 @@
#pragma once
#include "games/game.h"
#include "external/linalg.h"
namespace games::drs {
enum DRS_TOUCH_TYPE {
DRS_DOWN = 0,
DRS_UP = 1,
DRS_MOVE = 2,
};
typedef struct {
int type = DRS_UP;
int id = 0;
double x = 0.0;
double y = 0.0;
double width = 1;
double height = 1;
} drs_touch_t;
struct VRFoot {
uint32_t id;
uint32_t index = ~0u;
float length = 3.1f;
float size_base = 0.05f;
float size_scale = 0.1f;
float height = 3.f;
linalg::aliases::float4 rotation {0, 0, 0, 1};
drs_touch_t event {};
uint32_t get_index();
linalg::aliases::float3 to_world(linalg::aliases::float3 pos);
};
extern char DRS_TAPELED[38 * 49][3];
extern linalg::aliases::float3 VR_SCALE;
extern linalg::aliases::float3 VR_OFFSET;
extern float VR_ROTATION;
extern VRFoot VR_FOOTS[2];
void fire_touches(drs_touch_t *events, size_t event_count);
void start_vr();
class DRSGame : public games::Game {
public:
DRSGame();
virtual void attach() override;
virtual void detach() override;
};
}
#pragma once
#include "games/game.h"
#include "external/linalg.h"
namespace games::drs {
enum DRS_TOUCH_TYPE {
DRS_DOWN = 0,
DRS_UP = 1,
DRS_MOVE = 2,
};
typedef struct {
int type = DRS_UP;
int id = 0;
double x = 0.0;
double y = 0.0;
double width = 1;
double height = 1;
} drs_touch_t;
struct VRFoot {
uint32_t id;
uint32_t index = ~0u;
float length = 3.1f;
float size_base = 0.05f;
float size_scale = 0.1f;
float height = 3.f;
linalg::aliases::float4 rotation {0, 0, 0, 1};
drs_touch_t event {};
uint32_t get_index();
linalg::aliases::float3 to_world(linalg::aliases::float3 pos);
};
extern char DRS_TAPELED[38 * 49][3];
extern linalg::aliases::float3 VR_SCALE;
extern linalg::aliases::float3 VR_OFFSET;
extern float VR_ROTATION;
extern VRFoot VR_FOOTS[2];
void fire_touches(drs_touch_t *events, size_t event_count);
void start_vr();
class DRSGame : public games::Game {
public:
DRSGame();
virtual void attach() override;
virtual void detach() override;
};
}
+41 -41
View File
@@ -1,41 +1,41 @@
#include "io.h"
std::vector<Button> &games::drs::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("DANCERUSH");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"P1 Start",
"P1 Up",
"P1 Down",
"P1 Left",
"P1 Right",
"P2 Start",
"P2 Up",
"P2 Down",
"P2 Left",
"P2 Right"
);
}
return buttons;
}
std::vector<Light> &games::drs::get_lights() {
static std::vector<Light> lights;
//if (lights.empty()) {
//lights = GameAPI::Lights::getLights("DANCERUSH");
//GameAPI::Lights::sortLights(
// &lights,
//);
//}
return lights;
}
#include "io.h"
std::vector<Button> &games::drs::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("DANCERUSH");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"P1 Start",
"P1 Up",
"P1 Down",
"P1 Left",
"P1 Right",
"P2 Start",
"P2 Up",
"P2 Down",
"P2 Left",
"P2 Right"
);
}
return buttons;
}
std::vector<Light> &games::drs::get_lights() {
static std::vector<Light> lights;
//if (lights.empty()) {
//lights = GameAPI::Lights::getLights("DANCERUSH");
//GameAPI::Lights::sortLights(
// &lights,
//);
//}
return lights;
}
+36 -36
View File
@@ -1,36 +1,36 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::drs {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
P1_Start,
P1_Up,
P1_Down,
P1_Left,
P1_Right,
P2_Start,
P2_Up,
P2_Down,
P2_Left,
P2_Right
};
}
// all lights in correct order
namespace Lights {
enum {
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::drs {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
P1_Start,
P1_Up,
P1_Down,
P1_Left,
P1_Right,
P2_Start,
P2_Up,
P2_Down,
P2_Left,
P2_Right
};
}
// all lights in correct order
namespace Lights {
enum {
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
+152 -152
View File
@@ -1,152 +1,152 @@
#include "ftt.h"
#include "nui.h"
#include "launcher/launcher.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "util/sigscan.h"
#include "util/memutils.h"
typedef HRESULT (WINAPI *NuiGetSensorCount_t)(int *pCount);
typedef HRESULT (WINAPI *NuiCreateSensorByIndex_t)(int index, INuiSensor **ppNuiSensor);
static NuiGetSensorCount_t NuiGetSensorCount_orig = nullptr;
static NuiCreateSensorByIndex_t NuiCreateSensorByIndex_orig = nullptr;
static VTBL_TYPE(INuiSensor, NuiInitialize) INuiSensor_NuiInitialize_orig = nullptr;
static VTBL_TYPE(INuiSensor, NuiImageStreamOpen) INuiSensor_NuiImageStreamOpen_orig = nullptr;
static HRESULT __stdcall INuiSensor_NuiInitialize_hook(INuiSensor *This, DWORD dwFlags) {
log_misc("ftt", "INuiSensor::NuiInitialize hook hit (dwFlags: {})", dwFlags);
// call original function
HRESULT ret = INuiSensor_NuiInitialize_orig(This, dwFlags);
// check return value
if (FAILED(ret)) {
log_warning("ftt", "INuiSensor::NuiInitialize failed, hr={}", FMT_HRESULT(ret));
}
return ret;
}
static HRESULT __stdcall INuiSensor_NuiImageStreamOpen_hook(
INuiSensor *This,
NUI_IMAGE_TYPE eImageType,
NUI_IMAGE_RESOLUTION eResolution,
DWORD dwImageFrameFlags,
DWORD dwFrameLimit,
HANDLE hNextFrameEvent,
HANDLE *phStreamHandle) {
log_misc("ftt", "INuiSensor::NuiImageStreamOpen hook hit");
// fix unsupported flag
if (eImageType == NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX) {
dwImageFrameFlags = 0;
}
// call original function
HRESULT ret = INuiSensor_NuiImageStreamOpen_orig(This, eImageType, eResolution, dwImageFrameFlags, dwFrameLimit, hNextFrameEvent, phStreamHandle);
// check return value
if (FAILED(ret)) {
log_warning("ftt", "INuiSensor::NuiImageStreamOpen failed, hr={}", FMT_HRESULT(ret));
}
return ret;
}
static HRESULT WINAPI NuiGetSensorCount_hook(int *pCount) {
log_misc("ftt", "NuiGetSensorCount hook hit");
// call original function
HRESULT ret = NuiGetSensorCount_orig(pCount);
// check return value
if (FAILED(ret)) {
log_warning("ftt", "NuiGetSensorCount failed, hr={}", FMT_HRESULT(ret));
return ret;
}
if (pCount == nullptr) {
return ret;
}
log_info("ftt", "found {} Kinect sensors", *pCount);
return ret;
}
static HRESULT WINAPI NuiCreateSensorByIndex_hook(int index, INuiSensor **ppNuiSensor) {
log_misc("ftt", "NuiCreateSensorByIndex hook hit");
// call original function
HRESULT ret = NuiCreateSensorByIndex_orig(index, ppNuiSensor);
// check return value
if (FAILED(ret)) {
log_warning("ftt", "NuiCreateSensorByIndex failed, hr={}", FMT_HRESULT(ret));
return ret;
}
if (ppNuiSensor == nullptr) {
return ret;
}
// save original functions
INuiSensor *pNuiSensor = *ppNuiSensor;
if (INuiSensor_NuiInitialize_orig == nullptr) {
INuiSensor_NuiInitialize_orig = pNuiSensor->lpVtbl->NuiInitialize;
}
if (INuiSensor_NuiImageStreamOpen_orig == nullptr) {
INuiSensor_NuiImageStreamOpen_orig = pNuiSensor->lpVtbl->NuiImageStreamOpen;
}
// unlock interface
memutils::VProtectGuard pNuiSensor_guard(pNuiSensor->lpVtbl);
// hook interface
pNuiSensor->lpVtbl->NuiInitialize = INuiSensor_NuiInitialize_hook;
pNuiSensor->lpVtbl->NuiImageStreamOpen = INuiSensor_NuiImageStreamOpen_hook;
return ret;
}
namespace games::ftt {
FTTGame::FTTGame() : Game("FutureTomTom") {
}
void FTTGame::attach() {
Game::attach();
// load main game module so patches work
auto game_dll = libutils::load_library(MODULE_PATH / "gamemmd.dll");
// patch kinect to always poll
if (!replace_pattern(game_dll,
"78??837B340775??488BCBE8",
"????????????9090????????",
0,
0))
{
log_warning("ftt", "kinect polling patch failed");
}
// patch kinect to not time out
if (!replace_pattern(game_dll,
"3D3075000072??C74334060000004883C420",
"??????????????90909090909090????????",
0,
0))
{
log_warning("ftt", "kinect timeout patch failed");
}
// hook Kinect calls
NuiGetSensorCount_orig = (NuiGetSensorCount_t) detour::iat_ordinal(
"Kinect10.dll", 5, (void *) NuiGetSensorCount_hook, game_dll);
NuiCreateSensorByIndex_orig = (NuiCreateSensorByIndex_t) detour::iat_ordinal(
"Kinect10.dll", 6, (void *) NuiCreateSensorByIndex_hook, game_dll);
}
}
#include "ftt.h"
#include "nui.h"
#include "launcher/launcher.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "util/sigscan.h"
#include "util/memutils.h"
typedef HRESULT (WINAPI *NuiGetSensorCount_t)(int *pCount);
typedef HRESULT (WINAPI *NuiCreateSensorByIndex_t)(int index, INuiSensor **ppNuiSensor);
static NuiGetSensorCount_t NuiGetSensorCount_orig = nullptr;
static NuiCreateSensorByIndex_t NuiCreateSensorByIndex_orig = nullptr;
static VTBL_TYPE(INuiSensor, NuiInitialize) INuiSensor_NuiInitialize_orig = nullptr;
static VTBL_TYPE(INuiSensor, NuiImageStreamOpen) INuiSensor_NuiImageStreamOpen_orig = nullptr;
static HRESULT __stdcall INuiSensor_NuiInitialize_hook(INuiSensor *This, DWORD dwFlags) {
log_misc("ftt", "INuiSensor::NuiInitialize hook hit (dwFlags: {})", dwFlags);
// call original function
HRESULT ret = INuiSensor_NuiInitialize_orig(This, dwFlags);
// check return value
if (FAILED(ret)) {
log_warning("ftt", "INuiSensor::NuiInitialize failed, hr={}", FMT_HRESULT(ret));
}
return ret;
}
static HRESULT __stdcall INuiSensor_NuiImageStreamOpen_hook(
INuiSensor *This,
NUI_IMAGE_TYPE eImageType,
NUI_IMAGE_RESOLUTION eResolution,
DWORD dwImageFrameFlags,
DWORD dwFrameLimit,
HANDLE hNextFrameEvent,
HANDLE *phStreamHandle) {
log_misc("ftt", "INuiSensor::NuiImageStreamOpen hook hit");
// fix unsupported flag
if (eImageType == NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX) {
dwImageFrameFlags = 0;
}
// call original function
HRESULT ret = INuiSensor_NuiImageStreamOpen_orig(This, eImageType, eResolution, dwImageFrameFlags, dwFrameLimit, hNextFrameEvent, phStreamHandle);
// check return value
if (FAILED(ret)) {
log_warning("ftt", "INuiSensor::NuiImageStreamOpen failed, hr={}", FMT_HRESULT(ret));
}
return ret;
}
static HRESULT WINAPI NuiGetSensorCount_hook(int *pCount) {
log_misc("ftt", "NuiGetSensorCount hook hit");
// call original function
HRESULT ret = NuiGetSensorCount_orig(pCount);
// check return value
if (FAILED(ret)) {
log_warning("ftt", "NuiGetSensorCount failed, hr={}", FMT_HRESULT(ret));
return ret;
}
if (pCount == nullptr) {
return ret;
}
log_info("ftt", "found {} Kinect sensors", *pCount);
return ret;
}
static HRESULT WINAPI NuiCreateSensorByIndex_hook(int index, INuiSensor **ppNuiSensor) {
log_misc("ftt", "NuiCreateSensorByIndex hook hit");
// call original function
HRESULT ret = NuiCreateSensorByIndex_orig(index, ppNuiSensor);
// check return value
if (FAILED(ret)) {
log_warning("ftt", "NuiCreateSensorByIndex failed, hr={}", FMT_HRESULT(ret));
return ret;
}
if (ppNuiSensor == nullptr) {
return ret;
}
// save original functions
INuiSensor *pNuiSensor = *ppNuiSensor;
if (INuiSensor_NuiInitialize_orig == nullptr) {
INuiSensor_NuiInitialize_orig = pNuiSensor->lpVtbl->NuiInitialize;
}
if (INuiSensor_NuiImageStreamOpen_orig == nullptr) {
INuiSensor_NuiImageStreamOpen_orig = pNuiSensor->lpVtbl->NuiImageStreamOpen;
}
// unlock interface
memutils::VProtectGuard pNuiSensor_guard(pNuiSensor->lpVtbl);
// hook interface
pNuiSensor->lpVtbl->NuiInitialize = INuiSensor_NuiInitialize_hook;
pNuiSensor->lpVtbl->NuiImageStreamOpen = INuiSensor_NuiImageStreamOpen_hook;
return ret;
}
namespace games::ftt {
FTTGame::FTTGame() : Game("FutureTomTom") {
}
void FTTGame::attach() {
Game::attach();
// load main game module so patches work
auto game_dll = libutils::load_library(MODULE_PATH / "gamemmd.dll");
// patch kinect to always poll
if (!replace_pattern(game_dll,
"78??837B340775??488BCBE8",
"????????????9090????????",
0,
0))
{
log_warning("ftt", "kinect polling patch failed");
}
// patch kinect to not time out
if (!replace_pattern(game_dll,
"3D3075000072??C74334060000004883C420",
"??????????????90909090909090????????",
0,
0))
{
log_warning("ftt", "kinect timeout patch failed");
}
// hook Kinect calls
NuiGetSensorCount_orig = (NuiGetSensorCount_t) detour::iat_ordinal(
"Kinect10.dll", 5, (void *) NuiGetSensorCount_hook, game_dll);
NuiCreateSensorByIndex_orig = (NuiCreateSensorByIndex_t) detour::iat_ordinal(
"Kinect10.dll", 6, (void *) NuiCreateSensorByIndex_hook, game_dll);
}
}
+12 -12
View File
@@ -1,12 +1,12 @@
#pragma once
#include "games/game.h"
namespace games::ftt {
class FTTGame : public games::Game {
public:
FTTGame();
virtual void attach() override;
};
}
#pragma once
#include "games/game.h"
namespace games::ftt {
class FTTGame : public games::Game {
public:
FTTGame();
virtual void attach() override;
};
}
+65 -65
View File
@@ -1,65 +1,65 @@
#include "io.h"
std::vector<Button> &games::ftt::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("FutureTomTom");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Pad 1",
"Pad 2",
"Pad 3",
"Pad 4"
);
}
return buttons;
}
std::vector<Analog> &games::ftt::get_analogs() {
static std::vector<Analog> analogs;
if (analogs.empty()) {
analogs = GameAPI::Analogs::getAnalogs("FutureTomTom");
GameAPI::Analogs::sortAnalogs(
&analogs,
"Pad 1",
"Pad 2",
"Pad 3",
"Pad 4"
);
}
return analogs;
}
std::vector<Light> &games::ftt::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("FutureTomTom");
GameAPI::Lights::sortLights(
&lights,
"Pad 1 Red",
"Pad 1 Green",
"Pad 1 Blue",
"Pad 2 Red",
"Pad 2 Green",
"Pad 2 Blue",
"Pad 3 Red",
"Pad 3 Green",
"Pad 3 Blue",
"Pad 4 Red",
"Pad 4 Green",
"Pad 4 Blue"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::ftt::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("FutureTomTom");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Pad 1",
"Pad 2",
"Pad 3",
"Pad 4"
);
}
return buttons;
}
std::vector<Analog> &games::ftt::get_analogs() {
static std::vector<Analog> analogs;
if (analogs.empty()) {
analogs = GameAPI::Analogs::getAnalogs("FutureTomTom");
GameAPI::Analogs::sortAnalogs(
&analogs,
"Pad 1",
"Pad 2",
"Pad 3",
"Pad 4"
);
}
return analogs;
}
std::vector<Light> &games::ftt::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("FutureTomTom");
GameAPI::Lights::sortLights(
&lights,
"Pad 1 Red",
"Pad 1 Green",
"Pad 1 Blue",
"Pad 2 Red",
"Pad 2 Green",
"Pad 2 Blue",
"Pad 3 Red",
"Pad 3 Green",
"Pad 3 Blue",
"Pad 4 Red",
"Pad 4 Green",
"Pad 4 Blue"
);
}
return lights;
}
+52 -52
View File
@@ -1,52 +1,52 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::ftt {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
Pad1,
Pad2,
Pad3,
Pad4,
};
}
// all analogs in correct order
namespace Analogs {
enum {
Pad1,
Pad2,
Pad3,
Pad4,
};
}
// all lights in correct order
namespace Lights {
enum {
Pad1_R,
Pad1_G,
Pad1_B,
Pad2_R,
Pad2_G,
Pad2_B,
Pad3_R,
Pad3_G,
Pad3_B,
Pad4_R,
Pad4_G,
Pad4_B,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::ftt {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
Pad1,
Pad2,
Pad3,
Pad4,
};
}
// all analogs in correct order
namespace Analogs {
enum {
Pad1,
Pad2,
Pad3,
Pad4,
};
}
// all lights in correct order
namespace Lights {
enum {
Pad1_R,
Pad1_G,
Pad1_B,
Pad2_R,
Pad2_G,
Pad2_B,
Pad3_R,
Pad3_G,
Pad3_B,
Pad4_R,
Pad4_G,
Pad4_B,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
+183 -183
View File
@@ -1,183 +1,183 @@
#pragma once
#include <windows.h>
#include <unknwn.h>
enum NUI_IMAGE_TYPE {
NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX = 0x0,
NUI_IMAGE_TYPE_COLOR = 0x1,
NUI_IMAGE_TYPE_COLOR_YUV = 0x2,
NUI_IMAGE_TYPE_COLOR_RAW_YUV = 0x3,
NUI_IMAGE_TYPE_DEPTH = 0x4,
NUI_IMAGE_TYPE_COLOR_INFRARED = 0x5,
NUI_IMAGE_TYPE_COLOR_RAW_BAYER = 0x6,
};
enum NUI_IMAGE_RESOLUTION {
NUI_IMAGE_RESOLUTION_80x60 = 0x0,
NUI_IMAGE_RESOLUTION_320x240 = 0x1,
NUI_IMAGE_RESOLUTION_640x480 = 0x2,
NUI_IMAGE_RESOLUTION_1280x960 = 0x3,
NUI_IMAGE_RESOLUTION_INVALID = 0xFFFFFFFF,
};
#pragma pack(push, 8)
struct INuiSensor {
struct INuiSensorVtbl *lpVtbl;
};
struct INuiSensorVtbl {
HRESULT (__stdcall *QueryInterface)(IUnknown *This, const IID *const riid, void **ppvObject);
ULONG (__stdcall *AddRef)(IUnknown *This);
ULONG (__stdcall *Release)(IUnknown *This);
HRESULT (__stdcall *NuiInitialize)(
INuiSensor *This,
DWORD dwFlags);
void (__stdcall *NuiShutdown)(INuiSensor *This);
HRESULT (__stdcall *NuiSetFrameEndEvent)(
INuiSensor *This,
HANDLE hEvent,
DWORD dwFrameEventFlag);
HRESULT (__stdcall *NuiImageStreamOpen)(
INuiSensor *This,
NUI_IMAGE_TYPE eImageType,
NUI_IMAGE_RESOLUTION eResolution,
DWORD dwImageFrameFlags,
DWORD dwFrameLimit,
HANDLE hNextFrameEvent,
HANDLE *phStreamHandle);
HRESULT (__stdcall *NuiImageStreamSetImageFrameFlags)(
INuiSensor *This,
HANDLE hStream,
DWORD dwImageFrameFlags);
HRESULT (__stdcall *NuiImageStreamGetImageFrameFlags)(
INuiSensor *This,
HANDLE hStream,
DWORD *pdwImageFrameFlags);
HRESULT (__stdcall *NuiImageStreamGetNextFrame)(
INuiSensor *This,
HANDLE hStream,
DWORD dwMillisecondsToWait,
void *pImageFrame);
HRESULT (__stdcall *NuiImageStreamReleaseFrame)(
INuiSensor *This,
HANDLE hStream,
void *pImageFrame);
HRESULT (__stdcall *NuiImageGetColorPixelCoordinatesFromDepthPixel)(
INuiSensor *This,
DWORD eColorResolution,
const void *pcViewArea,
LONG lDepthX,
LONG lDepthY,
USHORT usDepthValue,
LONG *plColorX,
LONG *plColorY);
HRESULT (__stdcall *NuiImageGetColorPixelCoordinatesFromDepthPixelAtResolution)(
INuiSensor *This,
DWORD eColorResolution,
DWORD eDepthResolution,
const void *pcViewArea,
LONG lDepthX,
LONG lDepthY,
USHORT usDepthValue,
LONG *plColorX,
LONG *plColorY);
HRESULT (__stdcall *NuiImageGetColorPixelCoordinateFrameFromDepthPixelFrameAtResolution)(
INuiSensor *This,
DWORD eColorResolution,
DWORD eDepthResolution,
DWORD cDepthValues,
USHORT *pDepthValues,
DWORD cColorCoordinates,
LONG *pColorCoordinates);
HRESULT (__stdcall *NuiCameraElevationSetAngle)(
INuiSensor *This,
LONG lAngleDegrees);
HRESULT (__stdcall *NuiCameraElevationGetAngle)(
INuiSensor *This,
LONG *plAngleDegrees);
HRESULT (__stdcall *NuiSkeletonTrackingEnable)(
INuiSensor *This,
HANDLE hNextFrameEvent,
DWORD dwFlags);
HRESULT (__stdcall *NuiSkeletonTrackingDisable)(
INuiSensor *This);
HRESULT (__stdcall *NuiSkeletonSetTrackedSkeletons)(
INuiSensor *This,
DWORD *TrackingIDs);
HRESULT (__stdcall *NuiSkeletonGetNextFrame)(
INuiSensor *This,
DWORD dwMillisecondsToWait,
void *pSkeletonFrame);
HRESULT (__stdcall *NuiTransformSmooth)(
INuiSensor *This,
void *pSkeletonFrame,
const void *pSmoothingParams);
HRESULT (__stdcall *NuiGetAudioSource)(
INuiSensor *This,
void **ppDmo);
int (__stdcall *NuiInstanceIndex)(
INuiSensor *This);
BSTR (__stdcall *NuiDeviceConnectionId)(
INuiSensor *This);
BSTR (__stdcall *NuiUniqueId)(
INuiSensor *This);
BSTR (__stdcall *NuiAudioArrayId)(
INuiSensor *This);
HRESULT (__stdcall *NuiStatus)(
INuiSensor *This);
DWORD (__stdcall *NuiInitializationFlags)(
INuiSensor *This);
HRESULT (__stdcall *NuiGetCoordinateMapper)(
INuiSensor *This,
void **pMapping);
HRESULT (__stdcall *NuiImageFrameGetDepthImagePixelFrameTexture)(
INuiSensor *This,
HANDLE hStream,
void *pImageFrame,
BOOL *pNearMode,
void **ppFrameTexture);
HRESULT (__stdcall *NuiGetColorCameraSettings)(
INuiSensor *This,
void **pCameraSettings);
BOOL (__stdcall *NuiGetForceInfraredEmitterOff)(
INuiSensor *This);
HRESULT (__stdcall *NuiSetForceInfraredEmitterOff)(
INuiSensor *This,
BOOL fForceInfraredEmitterOff);
HRESULT (__stdcall *NuiAccelerometerGetCurrentReading)(
INuiSensor *This,
void *pReading);
};
#pragma pack(pop)
#pragma once
#include <windows.h>
#include <unknwn.h>
enum NUI_IMAGE_TYPE {
NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX = 0x0,
NUI_IMAGE_TYPE_COLOR = 0x1,
NUI_IMAGE_TYPE_COLOR_YUV = 0x2,
NUI_IMAGE_TYPE_COLOR_RAW_YUV = 0x3,
NUI_IMAGE_TYPE_DEPTH = 0x4,
NUI_IMAGE_TYPE_COLOR_INFRARED = 0x5,
NUI_IMAGE_TYPE_COLOR_RAW_BAYER = 0x6,
};
enum NUI_IMAGE_RESOLUTION {
NUI_IMAGE_RESOLUTION_80x60 = 0x0,
NUI_IMAGE_RESOLUTION_320x240 = 0x1,
NUI_IMAGE_RESOLUTION_640x480 = 0x2,
NUI_IMAGE_RESOLUTION_1280x960 = 0x3,
NUI_IMAGE_RESOLUTION_INVALID = 0xFFFFFFFF,
};
#pragma pack(push, 8)
struct INuiSensor {
struct INuiSensorVtbl *lpVtbl;
};
struct INuiSensorVtbl {
HRESULT (__stdcall *QueryInterface)(IUnknown *This, const IID *const riid, void **ppvObject);
ULONG (__stdcall *AddRef)(IUnknown *This);
ULONG (__stdcall *Release)(IUnknown *This);
HRESULT (__stdcall *NuiInitialize)(
INuiSensor *This,
DWORD dwFlags);
void (__stdcall *NuiShutdown)(INuiSensor *This);
HRESULT (__stdcall *NuiSetFrameEndEvent)(
INuiSensor *This,
HANDLE hEvent,
DWORD dwFrameEventFlag);
HRESULT (__stdcall *NuiImageStreamOpen)(
INuiSensor *This,
NUI_IMAGE_TYPE eImageType,
NUI_IMAGE_RESOLUTION eResolution,
DWORD dwImageFrameFlags,
DWORD dwFrameLimit,
HANDLE hNextFrameEvent,
HANDLE *phStreamHandle);
HRESULT (__stdcall *NuiImageStreamSetImageFrameFlags)(
INuiSensor *This,
HANDLE hStream,
DWORD dwImageFrameFlags);
HRESULT (__stdcall *NuiImageStreamGetImageFrameFlags)(
INuiSensor *This,
HANDLE hStream,
DWORD *pdwImageFrameFlags);
HRESULT (__stdcall *NuiImageStreamGetNextFrame)(
INuiSensor *This,
HANDLE hStream,
DWORD dwMillisecondsToWait,
void *pImageFrame);
HRESULT (__stdcall *NuiImageStreamReleaseFrame)(
INuiSensor *This,
HANDLE hStream,
void *pImageFrame);
HRESULT (__stdcall *NuiImageGetColorPixelCoordinatesFromDepthPixel)(
INuiSensor *This,
DWORD eColorResolution,
const void *pcViewArea,
LONG lDepthX,
LONG lDepthY,
USHORT usDepthValue,
LONG *plColorX,
LONG *plColorY);
HRESULT (__stdcall *NuiImageGetColorPixelCoordinatesFromDepthPixelAtResolution)(
INuiSensor *This,
DWORD eColorResolution,
DWORD eDepthResolution,
const void *pcViewArea,
LONG lDepthX,
LONG lDepthY,
USHORT usDepthValue,
LONG *plColorX,
LONG *plColorY);
HRESULT (__stdcall *NuiImageGetColorPixelCoordinateFrameFromDepthPixelFrameAtResolution)(
INuiSensor *This,
DWORD eColorResolution,
DWORD eDepthResolution,
DWORD cDepthValues,
USHORT *pDepthValues,
DWORD cColorCoordinates,
LONG *pColorCoordinates);
HRESULT (__stdcall *NuiCameraElevationSetAngle)(
INuiSensor *This,
LONG lAngleDegrees);
HRESULT (__stdcall *NuiCameraElevationGetAngle)(
INuiSensor *This,
LONG *plAngleDegrees);
HRESULT (__stdcall *NuiSkeletonTrackingEnable)(
INuiSensor *This,
HANDLE hNextFrameEvent,
DWORD dwFlags);
HRESULT (__stdcall *NuiSkeletonTrackingDisable)(
INuiSensor *This);
HRESULT (__stdcall *NuiSkeletonSetTrackedSkeletons)(
INuiSensor *This,
DWORD *TrackingIDs);
HRESULT (__stdcall *NuiSkeletonGetNextFrame)(
INuiSensor *This,
DWORD dwMillisecondsToWait,
void *pSkeletonFrame);
HRESULT (__stdcall *NuiTransformSmooth)(
INuiSensor *This,
void *pSkeletonFrame,
const void *pSmoothingParams);
HRESULT (__stdcall *NuiGetAudioSource)(
INuiSensor *This,
void **ppDmo);
int (__stdcall *NuiInstanceIndex)(
INuiSensor *This);
BSTR (__stdcall *NuiDeviceConnectionId)(
INuiSensor *This);
BSTR (__stdcall *NuiUniqueId)(
INuiSensor *This);
BSTR (__stdcall *NuiAudioArrayId)(
INuiSensor *This);
HRESULT (__stdcall *NuiStatus)(
INuiSensor *This);
DWORD (__stdcall *NuiInitializationFlags)(
INuiSensor *This);
HRESULT (__stdcall *NuiGetCoordinateMapper)(
INuiSensor *This,
void **pMapping);
HRESULT (__stdcall *NuiImageFrameGetDepthImagePixelFrameTexture)(
INuiSensor *This,
HANDLE hStream,
void *pImageFrame,
BOOL *pNearMode,
void **ppFrameTexture);
HRESULT (__stdcall *NuiGetColorCameraSettings)(
INuiSensor *This,
void **pCameraSettings);
BOOL (__stdcall *NuiGetForceInfraredEmitterOff)(
INuiSensor *This);
HRESULT (__stdcall *NuiSetForceInfraredEmitterOff)(
INuiSensor *This,
BOOL fForceInfraredEmitterOff);
HRESULT (__stdcall *NuiAccelerometerGetCurrentReading)(
INuiSensor *This,
void *pReading);
};
#pragma pack(pop)
+22 -22
View File
@@ -1,22 +1,22 @@
#include "game.h"
#include "util/logging.h"
games::Game::Game(std::string name) {
this->name = name;
}
void games::Game::attach() {
log_info("game", "attach: {}", name);
}
void games::Game::pre_attach() {
log_info("game", "pre_attach: {}", name);
}
void games::Game::post_attach() {
log_info("game", "post_attach: {}", name);
}
void games::Game::detach() {
log_info("game", "detach: {}", name);
}
#include "game.h"
#include "util/logging.h"
games::Game::Game(std::string name) {
this->name = name;
}
void games::Game::attach() {
log_info("game", "attach: {}", name);
}
void games::Game::pre_attach() {
log_info("game", "pre_attach: {}", name);
}
void games::Game::post_attach() {
log_info("game", "post_attach: {}", name);
}
void games::Game::detach() {
log_info("game", "detach: {}", name);
}
+24 -24
View File
@@ -1,24 +1,24 @@
#pragma once
#include <string>
namespace games {
class Game {
private:
std::string name;
public:
Game(std::string name);
virtual ~Game() = default;
// where the main magic will happen
virtual void attach();
// optional
virtual void pre_attach();
virtual void post_attach();
virtual void detach();
};
}
#pragma once
#include <string>
namespace games {
class Game {
private:
std::string name;
public:
Game(std::string name);
virtual ~Game() = default;
// where the main magic will happen
virtual void attach();
// optional
virtual void pre_attach();
virtual void post_attach();
virtual void detach();
};
}
+206 -206
View File
@@ -1,206 +1,206 @@
#include "gitadora.h"
#include <unordered_map>
#include "hooks/graphics/graphics.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "util/sigscan.h"
namespace games::gitadora {
// settings
bool TWOCHANNEL = false;
std::optional<unsigned int> CAB_TYPE = std::nullopt;
/*
* GitaDora checks if the IP address has changed, and if it has it throws 5-1506-0000 like jubeat.
* We don't want this so we patch it out.
*/
static char __cdecl eam_network_detected_ip_change() {
return 0;
}
/*
* GitaDora checks if the server it connects to is in the 192.168.0.0/16 or 169.254.0.0/16 subnet.
* If it is, it downright refuses to use it and errors with no visible indication.
* We don't want this so we patch it out.
*/
static char __cdecl eam_network_settings_conflict() {
return 0;
}
/*
* Prevent GitaDora from changing the volume setting.
*/
static long __cdecl bmsd2_set_windows_volume(int volume) {
return 0;
}
/*
* Two Channel Audio Mode
* We proxy bmsd2_boot_hook and modify the last parameter which is apparently the channel count.
* Since this apparently isn't the only thing required we need a signature scan to modify a value as well.
*/
typedef int (__cdecl *bmsd2_boot_t)(long a1, int a2, long a3, char channel_count);
static bmsd2_boot_t bmsd2_boot_orig = nullptr;
static int __cdecl bmsd2_boot_hook(long a1, int a2, long a3, char channel_count) {
return bmsd2_boot_orig(a1, a2, a3, 2);
}
/*
* Command Line Arguments
* We hook this to override specific values.
* This currently disables the ability to specify your own in the app-config.xml (param/cmdline __type="str")
*/
static bool __cdecl sys_code_get_cmdline(const char *cmdline) {
if (strcmp(cmdline, "-d") == 0) {
return true;
} else if (strcmp(cmdline, "-DM") == 0) {
return true;
} else if (strcmp(cmdline, "-WINDOW") == 0) {
return GRAPHICS_WINDOWED;
} else if (strcmp(cmdline, "-LOGOUT") == 0) {
return false;
} else if (strcmp(cmdline, "-AOU") == 0) {
return false;
} else if (strcmp(cmdline, "-QCMODE") == 0) {
return false;
} else if (strcmp(cmdline, "-FACTORY") == 0) {
return false;
}
return false;
}
/*
* System Setting Parameter Overrides
*/
static std::unordered_map<std::string, long> SYS_SETTINGS;
static std::unordered_map<std::string, long> SYS_DEBUG_DIPS;
static long __cdecl sys_setting_get_param(const char *param) {
// overrides
if (strcmp(param, "PRODUCTION_MODE") == 0) {
return 0;
} else if (strcmp(param, "ENABLE_DISP_ID") == 0) {
return 0;
} else if (CAB_TYPE.has_value() && strcmp(param, "VER_MACHINE") == 0) {
return CAB_TYPE.value() << 12;
}
// map lookup
auto it = SYS_SETTINGS.find(param);
if (it != SYS_SETTINGS.end()) {
return it->second;
}
return -1;
}
static long __cdecl sys_setting_set_param(const char *param, long value) {
SYS_SETTINGS[std::string(param)] = value;
return 1;
}
static long __cdecl sys_debug_dip_get_param(const char *param) {
// overrides
if (strcmp(param, "sysinfo") == 0) {
return 0;
} else if (strcmp(param, "jobbar1") == 0) {
return 0;
} else if (strcmp(param, "jobbar2") == 0) {
return 0;
} else if (strcmp(param, "serial") == 0) {
return 0;
} else if (strcmp(param, "warnvpf") == 0) {
return 0;
} else if (strcmp(param, "scrshot") == 0) {
return 0;
} else if (strcmp(param, "eamxml") == 0) {
return 0;
} else if (strcmp(param, "offset") == 0) {
return 0;
} else if (strcmp(param, "autodbg") == 0) {
return 0;
} else if (strcmp(param, "develop") == 0) {
return 0;
} else if (strcmp(param, "effect_test") == 0) {
return 0;
} else if (strcmp(param, "voice_type2") == 0) {
return 0;
}
// map lookup
auto it = SYS_DEBUG_DIPS.find(param);
if (it != SYS_DEBUG_DIPS.end()) {
return it->second;
}
return -1;
}
static long __cdecl sys_debug_dip_set_param(const char *param, long value) {
SYS_DEBUG_DIPS[std::string(param)] = value;
return 1;
}
GitaDoraGame::GitaDoraGame() : Game("GitaDora") {
}
void GitaDoraGame::attach() {
Game::attach();
// modules
HMODULE sharepj_module = libutils::try_module("libshare-pj.dll");
HMODULE bmsd_engine_module = libutils::try_module("libbmsd-engine.dll");
HMODULE bmsd_module = libutils::try_module("libbmsd.dll");
HMODULE bmsd2_module = libutils::try_module("libbmsd2.dll");
HMODULE gdme_module = libutils::try_module("libgdme.dll");
HMODULE system_module = libutils::try_module("libsystem.dll");
// patches
detour::inline_hook((void *) eam_network_detected_ip_change, libutils::try_proc(
sharepj_module, "eam_network_detected_ip_change"));
detour::inline_hook((void *) eam_network_settings_conflict, libutils::try_proc(
sharepj_module, "eam_network_settings_conflict"));
detour::inline_hook((void *) bmsd2_set_windows_volume, libutils::try_proc(
bmsd2_module, "bmsd2_set_windows_volume"));
detour::inline_hook((void *) bmsd2_set_windows_volume, libutils::try_proc(
bmsd2_module, "bmsd2_set_windows_volume"));
detour::inline_hook((void *) sys_code_get_cmdline, libutils::try_proc(
system_module, "sys_code_get_cmdline"));
detour::inline_hook((void *) sys_setting_get_param, libutils::try_proc(
system_module, "sys_setting_get_param"));
detour::inline_hook((void *) sys_setting_set_param, libutils::try_proc(
system_module, "sys_setting_set_param"));
detour::inline_hook((void *) sys_debug_dip_get_param, libutils::try_proc(
system_module, "sys_debug_dip_get_param"));
detour::inline_hook((void *) sys_debug_dip_set_param, libutils::try_proc(
system_module, "sys_debug_dip_set_param"));
// window patch
if (GRAPHICS_WINDOWED && !replace_pattern(
gdme_module,
"754185ED753D8B4118BF0000CB02",
"9090????9090??????????????12", 0, 0))
{
log_warning("gitadora", "windowed mode failed");
}
// two channel mod
if (TWOCHANNEL) {
bmsd2_boot_orig = detour::iat_try("bmsd2_boot", bmsd2_boot_hook, bmsd_module);
if (!(replace_pattern(bmsd_engine_module, "33000000488D", "03??????????", 0, 0) ||
replace_pattern(bmsd_engine_module, "330000000F10", "03??????????", 0, 0)))
{
log_warning("gitadora", "two channel mode failed");
}
}
}
}
#include "gitadora.h"
#include <unordered_map>
#include "hooks/graphics/graphics.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "util/sigscan.h"
namespace games::gitadora {
// settings
bool TWOCHANNEL = false;
std::optional<unsigned int> CAB_TYPE = std::nullopt;
/*
* GitaDora checks if the IP address has changed, and if it has it throws 5-1506-0000 like jubeat.
* We don't want this so we patch it out.
*/
static char __cdecl eam_network_detected_ip_change() {
return 0;
}
/*
* GitaDora checks if the server it connects to is in the 192.168.0.0/16 or 169.254.0.0/16 subnet.
* If it is, it downright refuses to use it and errors with no visible indication.
* We don't want this so we patch it out.
*/
static char __cdecl eam_network_settings_conflict() {
return 0;
}
/*
* Prevent GitaDora from changing the volume setting.
*/
static long __cdecl bmsd2_set_windows_volume(int volume) {
return 0;
}
/*
* Two Channel Audio Mode
* We proxy bmsd2_boot_hook and modify the last parameter which is apparently the channel count.
* Since this apparently isn't the only thing required we need a signature scan to modify a value as well.
*/
typedef int (__cdecl *bmsd2_boot_t)(long a1, int a2, long a3, char channel_count);
static bmsd2_boot_t bmsd2_boot_orig = nullptr;
static int __cdecl bmsd2_boot_hook(long a1, int a2, long a3, char channel_count) {
return bmsd2_boot_orig(a1, a2, a3, 2);
}
/*
* Command Line Arguments
* We hook this to override specific values.
* This currently disables the ability to specify your own in the app-config.xml (param/cmdline __type="str")
*/
static bool __cdecl sys_code_get_cmdline(const char *cmdline) {
if (strcmp(cmdline, "-d") == 0) {
return true;
} else if (strcmp(cmdline, "-DM") == 0) {
return true;
} else if (strcmp(cmdline, "-WINDOW") == 0) {
return GRAPHICS_WINDOWED;
} else if (strcmp(cmdline, "-LOGOUT") == 0) {
return false;
} else if (strcmp(cmdline, "-AOU") == 0) {
return false;
} else if (strcmp(cmdline, "-QCMODE") == 0) {
return false;
} else if (strcmp(cmdline, "-FACTORY") == 0) {
return false;
}
return false;
}
/*
* System Setting Parameter Overrides
*/
static std::unordered_map<std::string, long> SYS_SETTINGS;
static std::unordered_map<std::string, long> SYS_DEBUG_DIPS;
static long __cdecl sys_setting_get_param(const char *param) {
// overrides
if (strcmp(param, "PRODUCTION_MODE") == 0) {
return 0;
} else if (strcmp(param, "ENABLE_DISP_ID") == 0) {
return 0;
} else if (CAB_TYPE.has_value() && strcmp(param, "VER_MACHINE") == 0) {
return CAB_TYPE.value() << 12;
}
// map lookup
auto it = SYS_SETTINGS.find(param);
if (it != SYS_SETTINGS.end()) {
return it->second;
}
return -1;
}
static long __cdecl sys_setting_set_param(const char *param, long value) {
SYS_SETTINGS[std::string(param)] = value;
return 1;
}
static long __cdecl sys_debug_dip_get_param(const char *param) {
// overrides
if (strcmp(param, "sysinfo") == 0) {
return 0;
} else if (strcmp(param, "jobbar1") == 0) {
return 0;
} else if (strcmp(param, "jobbar2") == 0) {
return 0;
} else if (strcmp(param, "serial") == 0) {
return 0;
} else if (strcmp(param, "warnvpf") == 0) {
return 0;
} else if (strcmp(param, "scrshot") == 0) {
return 0;
} else if (strcmp(param, "eamxml") == 0) {
return 0;
} else if (strcmp(param, "offset") == 0) {
return 0;
} else if (strcmp(param, "autodbg") == 0) {
return 0;
} else if (strcmp(param, "develop") == 0) {
return 0;
} else if (strcmp(param, "effect_test") == 0) {
return 0;
} else if (strcmp(param, "voice_type2") == 0) {
return 0;
}
// map lookup
auto it = SYS_DEBUG_DIPS.find(param);
if (it != SYS_DEBUG_DIPS.end()) {
return it->second;
}
return -1;
}
static long __cdecl sys_debug_dip_set_param(const char *param, long value) {
SYS_DEBUG_DIPS[std::string(param)] = value;
return 1;
}
GitaDoraGame::GitaDoraGame() : Game("GitaDora") {
}
void GitaDoraGame::attach() {
Game::attach();
// modules
HMODULE sharepj_module = libutils::try_module("libshare-pj.dll");
HMODULE bmsd_engine_module = libutils::try_module("libbmsd-engine.dll");
HMODULE bmsd_module = libutils::try_module("libbmsd.dll");
HMODULE bmsd2_module = libutils::try_module("libbmsd2.dll");
HMODULE gdme_module = libutils::try_module("libgdme.dll");
HMODULE system_module = libutils::try_module("libsystem.dll");
// patches
detour::inline_hook((void *) eam_network_detected_ip_change, libutils::try_proc(
sharepj_module, "eam_network_detected_ip_change"));
detour::inline_hook((void *) eam_network_settings_conflict, libutils::try_proc(
sharepj_module, "eam_network_settings_conflict"));
detour::inline_hook((void *) bmsd2_set_windows_volume, libutils::try_proc(
bmsd2_module, "bmsd2_set_windows_volume"));
detour::inline_hook((void *) bmsd2_set_windows_volume, libutils::try_proc(
bmsd2_module, "bmsd2_set_windows_volume"));
detour::inline_hook((void *) sys_code_get_cmdline, libutils::try_proc(
system_module, "sys_code_get_cmdline"));
detour::inline_hook((void *) sys_setting_get_param, libutils::try_proc(
system_module, "sys_setting_get_param"));
detour::inline_hook((void *) sys_setting_set_param, libutils::try_proc(
system_module, "sys_setting_set_param"));
detour::inline_hook((void *) sys_debug_dip_get_param, libutils::try_proc(
system_module, "sys_debug_dip_get_param"));
detour::inline_hook((void *) sys_debug_dip_set_param, libutils::try_proc(
system_module, "sys_debug_dip_set_param"));
// window patch
if (GRAPHICS_WINDOWED && !replace_pattern(
gdme_module,
"754185ED753D8B4118BF0000CB02",
"9090????9090??????????????12", 0, 0))
{
log_warning("gitadora", "windowed mode failed");
}
// two channel mod
if (TWOCHANNEL) {
bmsd2_boot_orig = detour::iat_try("bmsd2_boot", bmsd2_boot_hook, bmsd_module);
if (!(replace_pattern(bmsd_engine_module, "33000000488D", "03??????????", 0, 0) ||
replace_pattern(bmsd_engine_module, "330000000F10", "03??????????", 0, 0)))
{
log_warning("gitadora", "two channel mode failed");
}
}
}
}
+18 -18
View File
@@ -1,18 +1,18 @@
#pragma once
#include <optional>
#include "games/game.h"
namespace games::gitadora {
// settings
extern bool TWOCHANNEL;
extern std::optional<unsigned int> CAB_TYPE;
class GitaDoraGame : public games::Game {
public:
GitaDoraGame();
virtual void attach();
};
}
#pragma once
#include <optional>
#include "games/game.h"
namespace games::gitadora {
// settings
extern bool TWOCHANNEL;
extern std::optional<unsigned int> CAB_TYPE;
class GitaDoraGame : public games::Game {
public:
GitaDoraGame();
virtual void attach();
};
}
+118 -118
View File
@@ -1,118 +1,118 @@
#include "io.h"
std::vector<Button> &games::gitadora::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("GitaDora");
GameAPI::Buttons::sortButtons(&buttons,
"Service",
"Test",
"Coin",
"Guitar P1 Start",
"Guitar P1 Up",
"Guitar P1 Down",
"Guitar P1 Left",
"Guitar P1 Right",
"Guitar P1 Help",
"Guitar P1 Effect 1",
"Guitar P1 Effect 2",
"Guitar P1 Effect 3",
"Guitar P1 Effect Pedal",
"Guitar P1 Button Extra 1",
"Guitar P1 Button Extra 2",
"Guitar P1 Pick Up",
"Guitar P1 Pick Down",
"Guitar P1 R",
"Guitar P1 G",
"Guitar P1 B",
"Guitar P1 Y",
"Guitar P1 P",
"Guitar P1 Knob Up",
"Guitar P1 Knob Down",
"Guitar P1 Wail Up",
"Guitar P1 Wail Down",
"Guitar P2 Start",
"Guitar P2 Up",
"Guitar P2 Down",
"Guitar P2 Left",
"Guitar P2 Right",
"Guitar P2 Help",
"Guitar P2 Effect 1",
"Guitar P2 Effect 2",
"Guitar P2 Effect 3",
"Guitar P2 Effect Pedal",
"Guitar P2 Button Extra 1",
"Guitar P2 Button Extra 2",
"Guitar P2 Pick Up",
"Guitar P2 Pick Down",
"Guitar P2 R",
"Guitar P2 G",
"Guitar P2 B",
"Guitar P2 Y",
"Guitar P2 P",
"Guitar P2 Knob Up",
"Guitar P2 Knob Down",
"Guitar P2 Wail Up",
"Guitar P2 Wail Down",
"Drum Start",
"Drum Up",
"Drum Down",
"Drum Left",
"Drum Right",
"Drum Help",
"Drum Button Extra 1",
"Drum Button Extra 2",
"Drum Hi-Hat",
"Drum Hi-Hat Closed",
"Drum Hi-Hat Half-Open",
"Drum Snare",
"Drum Hi-Tom",
"Drum Low-Tom",
"Drum Right Cymbal",
"Drum Bass Pedal",
"Drum Left Cymbal",
"Drum Left Pedal",
"Drum Floor Tom"
);
}
return buttons;
}
std::vector<Analog> &games::gitadora::get_analogs() {
static std::vector<Analog> analogs;
if (analogs.empty()) {
analogs = GameAPI::Analogs::getAnalogs("GitaDora");
GameAPI::Analogs::sortAnalogs(&analogs,
"Guitar P1 Wail X",
"Guitar P1 Wail Y",
"Guitar P1 Wail Z",
"Guitar P1 Knob",
"Guitar P2 Wail X",
"Guitar P2 Wail Y",
"Guitar P2 Wail Z",
"Guitar P2 Knob"
);
}
return analogs;
}
std::vector<Light> &games::gitadora::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("GitaDora");
GameAPI::Lights::sortLights(&lights,
"Guitar P1 Motor",
"Guitar P2 Motor"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::gitadora::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("GitaDora");
GameAPI::Buttons::sortButtons(&buttons,
"Service",
"Test",
"Coin",
"Guitar P1 Start",
"Guitar P1 Up",
"Guitar P1 Down",
"Guitar P1 Left",
"Guitar P1 Right",
"Guitar P1 Help",
"Guitar P1 Effect 1",
"Guitar P1 Effect 2",
"Guitar P1 Effect 3",
"Guitar P1 Effect Pedal",
"Guitar P1 Button Extra 1",
"Guitar P1 Button Extra 2",
"Guitar P1 Pick Up",
"Guitar P1 Pick Down",
"Guitar P1 R",
"Guitar P1 G",
"Guitar P1 B",
"Guitar P1 Y",
"Guitar P1 P",
"Guitar P1 Knob Up",
"Guitar P1 Knob Down",
"Guitar P1 Wail Up",
"Guitar P1 Wail Down",
"Guitar P2 Start",
"Guitar P2 Up",
"Guitar P2 Down",
"Guitar P2 Left",
"Guitar P2 Right",
"Guitar P2 Help",
"Guitar P2 Effect 1",
"Guitar P2 Effect 2",
"Guitar P2 Effect 3",
"Guitar P2 Effect Pedal",
"Guitar P2 Button Extra 1",
"Guitar P2 Button Extra 2",
"Guitar P2 Pick Up",
"Guitar P2 Pick Down",
"Guitar P2 R",
"Guitar P2 G",
"Guitar P2 B",
"Guitar P2 Y",
"Guitar P2 P",
"Guitar P2 Knob Up",
"Guitar P2 Knob Down",
"Guitar P2 Wail Up",
"Guitar P2 Wail Down",
"Drum Start",
"Drum Up",
"Drum Down",
"Drum Left",
"Drum Right",
"Drum Help",
"Drum Button Extra 1",
"Drum Button Extra 2",
"Drum Hi-Hat",
"Drum Hi-Hat Closed",
"Drum Hi-Hat Half-Open",
"Drum Snare",
"Drum Hi-Tom",
"Drum Low-Tom",
"Drum Right Cymbal",
"Drum Bass Pedal",
"Drum Left Cymbal",
"Drum Left Pedal",
"Drum Floor Tom"
);
}
return buttons;
}
std::vector<Analog> &games::gitadora::get_analogs() {
static std::vector<Analog> analogs;
if (analogs.empty()) {
analogs = GameAPI::Analogs::getAnalogs("GitaDora");
GameAPI::Analogs::sortAnalogs(&analogs,
"Guitar P1 Wail X",
"Guitar P1 Wail Y",
"Guitar P1 Wail Z",
"Guitar P1 Knob",
"Guitar P2 Wail X",
"Guitar P2 Wail Y",
"Guitar P2 Wail Z",
"Guitar P2 Knob"
);
}
return analogs;
}
std::vector<Light> &games::gitadora::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("GitaDora");
GameAPI::Lights::sortLights(&lights,
"Guitar P1 Motor",
"Guitar P2 Motor"
);
}
return lights;
}
+108 -108
View File
@@ -1,108 +1,108 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::gitadora {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
Coin,
GuitarP1Start,
GuitarP1Up,
GuitarP1Down,
GuitarP1Left,
GuitarP1Right,
GuitarP1Help,
GuitarP1Effect1,
GuitarP1Effect2,
GuitarP1Effect3,
GuitarP1EffectPedal,
GuitarP1ButtonExtra1,
GuitarP1ButtonExtra2,
GuitarP1PickUp,
GuitarP1PickDown,
GuitarP1R,
GuitarP1G,
GuitarP1B,
GuitarP1Y,
GuitarP1P,
GuitarP1KnobUp,
GuitarP1KnobDown,
GuitarP1WailUp,
GuitarP1WailDown,
GuitarP2Start,
GuitarP2Up,
GuitarP2Down,
GuitarP2Left,
GuitarP2Right,
GuitarP2Help,
GuitarP2Effect1,
GuitarP2Effect2,
GuitarP2Effect3,
GuitarP2EffectPedal,
GuitarP2ButtonExtra1,
GuitarP2ButtonExtra2,
GuitarP2PickUp,
GuitarP2PickDown,
GuitarP2R,
GuitarP2G,
GuitarP2B,
GuitarP2Y,
GuitarP2P,
GuitarP2KnobUp,
GuitarP2KnobDown,
GuitarP2WailUp,
GuitarP2WailDown,
DrumStart,
DrumUp,
DrumDown,
DrumLeft,
DrumRight,
DrumHelp,
DrumButtonExtra1,
DrumButtonExtra2,
DrumHiHat,
DrumHiHatClosed,
DrumHiHatHalfOpen,
DrumSnare,
DrumHiTom,
DrumLowTom,
DrumRightCymbal,
DrumBassPedal,
DrumLeftCymbal,
DrumLeftPedal,
DrumFloorTom
};
}
// all analogs in correct order
namespace Analogs {
enum {
GuitarP1WailX,
GuitarP1WailY,
GuitarP1WailZ,
GuitarP1Knob,
GuitarP2WailX,
GuitarP2WailY,
GuitarP2WailZ,
GuitarP2Knob
};
}
// all lights in correct order
namespace Lights {
enum {
GuitarP1Motor,
GuitarP2Motor,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::gitadora {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
Coin,
GuitarP1Start,
GuitarP1Up,
GuitarP1Down,
GuitarP1Left,
GuitarP1Right,
GuitarP1Help,
GuitarP1Effect1,
GuitarP1Effect2,
GuitarP1Effect3,
GuitarP1EffectPedal,
GuitarP1ButtonExtra1,
GuitarP1ButtonExtra2,
GuitarP1PickUp,
GuitarP1PickDown,
GuitarP1R,
GuitarP1G,
GuitarP1B,
GuitarP1Y,
GuitarP1P,
GuitarP1KnobUp,
GuitarP1KnobDown,
GuitarP1WailUp,
GuitarP1WailDown,
GuitarP2Start,
GuitarP2Up,
GuitarP2Down,
GuitarP2Left,
GuitarP2Right,
GuitarP2Help,
GuitarP2Effect1,
GuitarP2Effect2,
GuitarP2Effect3,
GuitarP2EffectPedal,
GuitarP2ButtonExtra1,
GuitarP2ButtonExtra2,
GuitarP2PickUp,
GuitarP2PickDown,
GuitarP2R,
GuitarP2G,
GuitarP2B,
GuitarP2Y,
GuitarP2P,
GuitarP2KnobUp,
GuitarP2KnobDown,
GuitarP2WailUp,
GuitarP2WailDown,
DrumStart,
DrumUp,
DrumDown,
DrumLeft,
DrumRight,
DrumHelp,
DrumButtonExtra1,
DrumButtonExtra2,
DrumHiHat,
DrumHiHatClosed,
DrumHiHatHalfOpen,
DrumSnare,
DrumHiTom,
DrumLowTom,
DrumRightCymbal,
DrumBassPedal,
DrumLeftCymbal,
DrumLeftPedal,
DrumFloorTom
};
}
// all analogs in correct order
namespace Analogs {
enum {
GuitarP1WailX,
GuitarP1WailY,
GuitarP1WailZ,
GuitarP1Knob,
GuitarP2WailX,
GuitarP2WailY,
GuitarP2WailZ,
GuitarP2Knob
};
}
// all lights in correct order
namespace Lights {
enum {
GuitarP1Motor,
GuitarP2Motor,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
+38 -38
View File
@@ -1,38 +1,38 @@
#include "avs/game.h"
#include "hpm.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include <mmsystem.h>
namespace games::hpm {
BOOL WINAPI SetCurrentDirectoryW_hook(LPCTSTR lpPathName) {
return true;
}
static decltype(mixerSetControlDetails)* mixerSetControlDetails_real = nullptr;
static MMRESULT WINAPI mixerSetControlDetails_hook(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) {
mixerSetControlDetails_real(hmxobj, pmxcd, fdwDetails);
return MMSYSERR_NOERROR;
}
HPMGame::HPMGame() : Game("HELLO! Pop'n Music") {
}
void HPMGame::attach() {
Game::attach();
HMODULE kernel32_module = libutils::try_module("kernel32.dll");
// patches
detour::inline_hook((void *) SetCurrentDirectoryW_hook, libutils::try_proc(
kernel32_module, "SetCurrentDirectoryW"));
mixerSetControlDetails_real = detour::iat_try("mixerSetControlDetails", mixerSetControlDetails_hook, avs::game::DLL_INSTANCE);
}
}
#include "avs/game.h"
#include "hpm.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include <mmsystem.h>
namespace games::hpm {
BOOL WINAPI SetCurrentDirectoryW_hook(LPCTSTR lpPathName) {
return true;
}
static decltype(mixerSetControlDetails)* mixerSetControlDetails_real = nullptr;
static MMRESULT WINAPI mixerSetControlDetails_hook(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) {
mixerSetControlDetails_real(hmxobj, pmxcd, fdwDetails);
return MMSYSERR_NOERROR;
}
HPMGame::HPMGame() : Game("HELLO! Pop'n Music") {
}
void HPMGame::attach() {
Game::attach();
HMODULE kernel32_module = libutils::try_module("kernel32.dll");
// patches
detour::inline_hook((void *) SetCurrentDirectoryW_hook, libutils::try_proc(
kernel32_module, "SetCurrentDirectoryW"));
mixerSetControlDetails_real = detour::iat_try("mixerSetControlDetails", mixerSetControlDetails_hook, avs::game::DLL_INSTANCE);
}
}
+13 -13
View File
@@ -1,13 +1,13 @@
#pragma once
#include "games/game.h"
namespace games::hpm {
class HPMGame : public games::Game {
public:
HPMGame();
virtual void attach() override;
};
}
#pragma once
#include "games/game.h"
namespace games::hpm {
class HPMGame : public games::Game {
public:
HPMGame();
virtual void attach() override;
};
}
+54 -54
View File
@@ -1,54 +1,54 @@
#include "io.h"
std::vector<Button> &games::hpm::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("HELLO! Pop'n Music");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"P1 Start",
"P1 1",
"P1 2",
"P1 3",
"P1 4",
"P2 Start",
"P2 1",
"P2 2",
"P2 3",
"P2 4"
);
}
return buttons;
}
std::vector<Light> &games::hpm::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("HELLO! Pop'n Music");
GameAPI::Lights::sortLights(
&lights,
"Speaker Red",
"Speaker Orange",
"Speaker Blue",
"P1 Start",
"P1 Red & P2 Green",
"P1 Blue",
"P1 Yellow",
"P1 Green",
"P2 Start",
"P2 Red",
"P2 Blue",
"P2 Yellow"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::hpm::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("HELLO! Pop'n Music");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"P1 Start",
"P1 1",
"P1 2",
"P1 3",
"P1 4",
"P2 Start",
"P2 1",
"P2 2",
"P2 3",
"P2 4"
);
}
return buttons;
}
std::vector<Light> &games::hpm::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("HELLO! Pop'n Music");
GameAPI::Lights::sortLights(
&lights,
"Speaker Red",
"Speaker Orange",
"Speaker Blue",
"P1 Start",
"P1 Red & P2 Green",
"P1 Blue",
"P1 Yellow",
"P1 Green",
"P2 Start",
"P2 Red",
"P2 Blue",
"P2 Yellow"
);
}
return lights;
}
+48 -48
View File
@@ -1,48 +1,48 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::hpm {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
P1_Start,
P1_1,
P1_2,
P1_3,
P1_4,
P2_Start,
P2_1,
P2_2,
P2_3,
P2_4,
};
}
// all lights in correct order
namespace Lights {
enum {
SPEAKER_RED,
SPEAKER_ORANGE,
SPEAKER_BLUE,
P1_START,
P1_RED_P2_GREEN,
P1_BLUE,
P1_YELLOW,
P1_GREEN,
P2_START,
P2_RED,
P2_BLUE,
P2_YELLOW,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::hpm {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
P1_Start,
P1_1,
P1_2,
P1_3,
P1_4,
P2_Start,
P2_1,
P2_2,
P2_3,
P2_4,
};
}
// all lights in correct order
namespace Lights {
enum {
SPEAKER_RED,
SPEAKER_ORANGE,
SPEAKER_BLUE,
P1_START,
P1_RED_P2_GREEN,
P1_BLUE,
P1_YELLOW,
P1_GREEN,
P2_START,
P2_RED,
P2_BLUE,
P2_YELLOW,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
+241 -241
View File
@@ -1,241 +1,241 @@
#include "bi2a.h"
#include "misc/eamuse.h"
#include "rawinput/rawinput.h"
#include "util/utils.h"
#include "iidx.h"
#include "io.h"
using namespace acioemu;
games::iidx::IIDXFMSerialHandle::FMSerialDevice::FMSerialDevice() {
this->node_count = 1;
}
bool games::iidx::IIDXFMSerialHandle::FMSerialDevice::parse_msg(
MessageData *msg_in,
circular_buffer<uint8_t> *response_buffer
) {
#ifdef ACIOEMU_LOG
log_info("iidx", "BI2A ADDR: {}, CMD: 0x{:04x}", msg_in->addr, msg_in->cmd.code);
#endif
// check command
switch (msg_in->cmd.code) {
case ACIO_CMD_GET_VERSION: {
// send version data
auto msg = this->create_msg(msg_in, MSG_VERSION_SIZE);
this->set_version(msg, 0x03, 0, 4, 2, 0, "BI2A");
write_msg(msg, response_buffer);
delete msg;
break;
}
case 0x0152: { // STATUS
// check input data length
if (msg_in->cmd.data_size == 0x30) {
// LED TICKER
IIDX_LED_TICKER_LOCK.lock();
if (!IIDXIO_LED_TICKER_READONLY)
memcpy(IIDXIO_LED_TICKER, &msg_in->cmd.raw[0x17], 9);
IIDX_LED_TICKER_LOCK.unlock();
// NEON LIGHT
bool neon_light = msg_in->cmd.raw[0x24] != 0;
write_top_neon(neon_light ? (uint8_t) 0xFF : (uint8_t) 0);
// SPOT LIGHT
uint8_t spot_light_bits = 0;
for (size_t i = 0; i < 8; i++) {
auto index = i > 3 ? i + 1 : i;
if (msg_in->cmd.raw[0x20 + index] != 0)
spot_light_bits |= 1 << i;
}
write_top_lamp(spot_light_bits);
// SWLED (DECK)
uint16_t lamp_bits = 0;
for (size_t i = 0; i < 14; i++) {
if (msg_in->cmd.raw[0x07 + i] != 0)
lamp_bits |= 1 << i;
}
write_lamp(lamp_bits);
// SWLED (PANEL)
uint8_t led_bits = 0;
for (size_t i = 0; i < 4; i++) {
if (msg_in->cmd.raw[0x03 + i] != 0)
led_bits |= 1 << i;
}
write_led(led_bits);
// flush device output
RI_MGR->devices_flush_output();
}
// sleep - otherwise the IO thread will go too hard on the CPU
Sleep(1);
// generate message
auto msg = this->create_msg(msg_in, 0x2E);
// get buttons
auto &buttons = get_buttons();
// player 1 buttons
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_1)))
ARRAY_SETB(msg->cmd.raw, 151);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_2)))
ARRAY_SETB(msg->cmd.raw, 167);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_3)))
ARRAY_SETB(msg->cmd.raw, 183);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_4)))
ARRAY_SETB(msg->cmd.raw, 199);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_5)))
ARRAY_SETB(msg->cmd.raw, 215);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_6)))
ARRAY_SETB(msg->cmd.raw, 231);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_7)))
ARRAY_SETB(msg->cmd.raw, 247);
// player 2 buttons
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_1)))
ARRAY_SETB(msg->cmd.raw, 263);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_2)))
ARRAY_SETB(msg->cmd.raw, 279);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_3)))
ARRAY_SETB(msg->cmd.raw, 295);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_4)))
ARRAY_SETB(msg->cmd.raw, 311);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_5)))
ARRAY_SETB(msg->cmd.raw, 327);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_6)))
ARRAY_SETB(msg->cmd.raw, 343);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_7)))
ARRAY_SETB(msg->cmd.raw, 359);
// player 1 start
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_Start)))
ARRAY_SETB(msg->cmd.raw, 79);
// player 2 start
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_Start)))
ARRAY_SETB(msg->cmd.raw, 78);
// VEFX
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::VEFX)))
ARRAY_SETB(msg->cmd.raw, 77);
// EFFECT
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Effect)))
ARRAY_SETB(msg->cmd.raw, 76);
// service
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Service)))
ARRAY_SETB(msg->cmd.raw, 10);
// test
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Test)))
ARRAY_SETB(msg->cmd.raw, 11);
// turntables
msg->cmd.raw[16] = get_tt(0, true);
msg->cmd.raw[17] = get_tt(1, true);
// slider
msg->cmd.raw[0] |= get_slider(0) << 4;
msg->cmd.raw[2] |= get_slider(1) << 4;
msg->cmd.raw[4] |= get_slider(2) << 4;
msg->cmd.raw[6] |= get_slider(3) << 4;
msg->cmd.raw[7] |= get_slider(4) << 4;
// coin
this->coin_counter += eamuse_coin_consume_stock();
msg->cmd.raw[8] |= this->coin_counter;
/*
* TODO
* bit 9 appears to be the coin mech
*/
// write message
write_msg(msg, response_buffer);
delete msg;
break;
}
case ACIO_CMD_CLEAR:
case ACIO_CMD_STARTUP:
case 0x0120: // WD COMMAND
case 0xFF: // BROADCAST
{
// send status 0
auto msg = this->create_msg_status(msg_in, 0);
write_msg(msg, response_buffer);
delete msg;
break;
}
default:
return false;
}
// mark as handled
return true;
}
bool games::iidx::IIDXFMSerialHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM2") != 0) {
return false;
}
log_info("iidx", "Opened COM2 (FM DEVICE)");
// ACIO device
acio_emu.add_device(new FMSerialDevice());
return true;
}
int games::iidx::IIDXFMSerialHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
auto buffer = reinterpret_cast<uint8_t *>(lpBuffer);
// read from emu
DWORD bytes_read = 0;
while (bytes_read < nNumberOfBytesToRead) {
auto cur_byte = acio_emu.read();
if (cur_byte.has_value()) {
buffer[bytes_read++] = cur_byte.value();
} else {
break;
}
}
// return amount of bytes read
return (int) bytes_read;
}
int games::iidx::IIDXFMSerialHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
auto buffer = reinterpret_cast<const uint8_t *>(lpBuffer);
// write to emu
for (DWORD i = 0; i < nNumberOfBytesToWrite; i++) {
acio_emu.write(buffer[i]);
}
// return all data written
return (int) nNumberOfBytesToWrite;
}
int games::iidx::IIDXFMSerialHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
return -1;
}
bool games::iidx::IIDXFMSerialHandle::close() {
log_info("iidx", "Closed COM2 (FM DEVICE)");
return true;
}
#include "bi2a.h"
#include "misc/eamuse.h"
#include "rawinput/rawinput.h"
#include "util/utils.h"
#include "iidx.h"
#include "io.h"
using namespace acioemu;
games::iidx::IIDXFMSerialHandle::FMSerialDevice::FMSerialDevice() {
this->node_count = 1;
}
bool games::iidx::IIDXFMSerialHandle::FMSerialDevice::parse_msg(
MessageData *msg_in,
circular_buffer<uint8_t> *response_buffer
) {
#ifdef ACIOEMU_LOG
log_info("iidx", "BI2A ADDR: {}, CMD: 0x{:04x}", msg_in->addr, msg_in->cmd.code);
#endif
// check command
switch (msg_in->cmd.code) {
case ACIO_CMD_GET_VERSION: {
// send version data
auto msg = this->create_msg(msg_in, MSG_VERSION_SIZE);
this->set_version(msg, 0x03, 0, 4, 2, 0, "BI2A");
write_msg(msg, response_buffer);
delete msg;
break;
}
case 0x0152: { // STATUS
// check input data length
if (msg_in->cmd.data_size == 0x30) {
// LED TICKER
IIDX_LED_TICKER_LOCK.lock();
if (!IIDXIO_LED_TICKER_READONLY)
memcpy(IIDXIO_LED_TICKER, &msg_in->cmd.raw[0x17], 9);
IIDX_LED_TICKER_LOCK.unlock();
// NEON LIGHT
bool neon_light = msg_in->cmd.raw[0x24] != 0;
write_top_neon(neon_light ? (uint8_t) 0xFF : (uint8_t) 0);
// SPOT LIGHT
uint8_t spot_light_bits = 0;
for (size_t i = 0; i < 8; i++) {
auto index = i > 3 ? i + 1 : i;
if (msg_in->cmd.raw[0x20 + index] != 0)
spot_light_bits |= 1 << i;
}
write_top_lamp(spot_light_bits);
// SWLED (DECK)
uint16_t lamp_bits = 0;
for (size_t i = 0; i < 14; i++) {
if (msg_in->cmd.raw[0x07 + i] != 0)
lamp_bits |= 1 << i;
}
write_lamp(lamp_bits);
// SWLED (PANEL)
uint8_t led_bits = 0;
for (size_t i = 0; i < 4; i++) {
if (msg_in->cmd.raw[0x03 + i] != 0)
led_bits |= 1 << i;
}
write_led(led_bits);
// flush device output
RI_MGR->devices_flush_output();
}
// sleep - otherwise the IO thread will go too hard on the CPU
Sleep(1);
// generate message
auto msg = this->create_msg(msg_in, 0x2E);
// get buttons
auto &buttons = get_buttons();
// player 1 buttons
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_1)))
ARRAY_SETB(msg->cmd.raw, 151);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_2)))
ARRAY_SETB(msg->cmd.raw, 167);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_3)))
ARRAY_SETB(msg->cmd.raw, 183);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_4)))
ARRAY_SETB(msg->cmd.raw, 199);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_5)))
ARRAY_SETB(msg->cmd.raw, 215);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_6)))
ARRAY_SETB(msg->cmd.raw, 231);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_7)))
ARRAY_SETB(msg->cmd.raw, 247);
// player 2 buttons
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_1)))
ARRAY_SETB(msg->cmd.raw, 263);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_2)))
ARRAY_SETB(msg->cmd.raw, 279);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_3)))
ARRAY_SETB(msg->cmd.raw, 295);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_4)))
ARRAY_SETB(msg->cmd.raw, 311);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_5)))
ARRAY_SETB(msg->cmd.raw, 327);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_6)))
ARRAY_SETB(msg->cmd.raw, 343);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_7)))
ARRAY_SETB(msg->cmd.raw, 359);
// player 1 start
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_Start)))
ARRAY_SETB(msg->cmd.raw, 79);
// player 2 start
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_Start)))
ARRAY_SETB(msg->cmd.raw, 78);
// VEFX
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::VEFX)))
ARRAY_SETB(msg->cmd.raw, 77);
// EFFECT
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Effect)))
ARRAY_SETB(msg->cmd.raw, 76);
// service
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Service)))
ARRAY_SETB(msg->cmd.raw, 10);
// test
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Test)))
ARRAY_SETB(msg->cmd.raw, 11);
// turntables
msg->cmd.raw[16] = get_tt(0, true);
msg->cmd.raw[17] = get_tt(1, true);
// slider
msg->cmd.raw[0] |= get_slider(0) << 4;
msg->cmd.raw[2] |= get_slider(1) << 4;
msg->cmd.raw[4] |= get_slider(2) << 4;
msg->cmd.raw[6] |= get_slider(3) << 4;
msg->cmd.raw[7] |= get_slider(4) << 4;
// coin
this->coin_counter += eamuse_coin_consume_stock();
msg->cmd.raw[8] |= this->coin_counter;
/*
* TODO
* bit 9 appears to be the coin mech
*/
// write message
write_msg(msg, response_buffer);
delete msg;
break;
}
case ACIO_CMD_CLEAR:
case ACIO_CMD_STARTUP:
case 0x0120: // WD COMMAND
case 0xFF: // BROADCAST
{
// send status 0
auto msg = this->create_msg_status(msg_in, 0);
write_msg(msg, response_buffer);
delete msg;
break;
}
default:
return false;
}
// mark as handled
return true;
}
bool games::iidx::IIDXFMSerialHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM2") != 0) {
return false;
}
log_info("iidx", "Opened COM2 (FM DEVICE)");
// ACIO device
acio_emu.add_device(new FMSerialDevice());
return true;
}
int games::iidx::IIDXFMSerialHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
auto buffer = reinterpret_cast<uint8_t *>(lpBuffer);
// read from emu
DWORD bytes_read = 0;
while (bytes_read < nNumberOfBytesToRead) {
auto cur_byte = acio_emu.read();
if (cur_byte.has_value()) {
buffer[bytes_read++] = cur_byte.value();
} else {
break;
}
}
// return amount of bytes read
return (int) bytes_read;
}
int games::iidx::IIDXFMSerialHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
auto buffer = reinterpret_cast<const uint8_t *>(lpBuffer);
// write to emu
for (DWORD i = 0; i < nNumberOfBytesToWrite; i++) {
acio_emu.write(buffer[i]);
}
// return all data written
return (int) nNumberOfBytesToWrite;
}
int games::iidx::IIDXFMSerialHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
return -1;
}
bool games::iidx::IIDXFMSerialHandle::close() {
log_info("iidx", "Closed COM2 (FM DEVICE)");
return true;
}
+30 -30
View File
@@ -1,30 +1,30 @@
#pragma once
#include "acioemu/acioemu.h"
#include "hooks/devicehook.h"
namespace games::iidx {
class IIDXFMSerialHandle : public CustomHandle {
private:
acioemu::ACIOEmu acio_emu;
class FMSerialDevice : public acioemu::ACIODeviceEmu {
private:
uint8_t coin_counter = 0;
public:
FMSerialDevice();
bool parse_msg(acioemu::MessageData *msg_in, circular_buffer<uint8_t> *response_buffer) override;
};
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
#pragma once
#include "acioemu/acioemu.h"
#include "hooks/devicehook.h"
namespace games::iidx {
class IIDXFMSerialHandle : public CustomHandle {
private:
acioemu::ACIOEmu acio_emu;
class FMSerialDevice : public acioemu::ACIODeviceEmu {
private:
uint8_t coin_counter = 0;
public:
FMSerialDevice();
bool parse_msg(acioemu::MessageData *msg_in, circular_buffer<uint8_t> *response_buffer) override;
};
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
+248 -248
View File
@@ -1,248 +1,248 @@
#include "bi2x.h"
#include "misc/eamuse.h"
#include "rawinput/rawinput.h"
#include "util/utils.h"
#include "iidx.h"
#include "io.h"
using namespace acioemu;
games::iidx::BI2XSerialHandle::BI2XDevice::BI2XDevice() {
this->node_count = 1;
}
bool games::iidx::BI2XSerialHandle::BI2XDevice::parse_msg(
MessageData *msg_in,
circular_buffer<uint8_t> *response_buffer
) {
#ifdef ACIOEMU_LOG
log_info("iidx", "BI2X ADDR: {}, CMD: 0x{:04x}", msg_in->addr, msg_in->cmd.code);
#endif
// check command
switch (msg_in->cmd.code) {
case ACIO_CMD_GET_VERSION: {
// send version data
auto msg = this->create_msg(msg_in, MSG_VERSION_SIZE);
this->set_version(msg, 0x03, 0, 4, 2, 0, "BI2X");
write_msg(msg, response_buffer);
delete msg;
break;
}
case 0x0152: { // STATUS
// check input data length
if (msg_in->cmd.data_size == 0x30) {
// LED TICKER
IIDX_LED_TICKER_LOCK.lock();
if (!IIDXIO_LED_TICKER_READONLY)
memcpy(IIDXIO_LED_TICKER, &msg_in->cmd.raw[0x17], 9);
IIDX_LED_TICKER_LOCK.unlock();
// NEON LIGHT
bool neon_light = msg_in->cmd.raw[0x24] != 0;
write_top_neon(neon_light ? (uint8_t) 0xFF : (uint8_t) 0);
// SPOT LIGHT
uint8_t spot_light_bits = 0;
for (size_t i = 0; i < 8; i++) {
auto index = i > 3 ? i + 1 : i;
if (msg_in->cmd.raw[0x20 + index] != 0)
spot_light_bits |= 1 << i;
}
write_top_lamp(spot_light_bits);
// SWLED (DECK)
uint16_t lamp_bits = 0;
for (size_t i = 0; i < 14; i++) {
if (msg_in->cmd.raw[0x07 + i] != 0)
lamp_bits |= 1 << i;
}
write_lamp(lamp_bits);
// SWLED (PANEL)
uint8_t led_bits = 0;
for (size_t i = 0; i < 4; i++) {
if (msg_in->cmd.raw[0x03 + i] != 0)
led_bits |= 1 << i;
}
write_led(led_bits);
// flush device output
RI_MGR->devices_flush_output();
}
// sleep - otherwise the IO thread will go too hard on the CPU
Sleep(1);
// generate message
auto msg = this->create_msg(msg_in, 0x2E);
// get buttons
auto &buttons = get_buttons();
// player 1 buttons
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_1)))
ARRAY_SETB(msg->cmd.raw, 151);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_2)))
ARRAY_SETB(msg->cmd.raw, 167);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_3)))
ARRAY_SETB(msg->cmd.raw, 183);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_4)))
ARRAY_SETB(msg->cmd.raw, 199);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_5)))
ARRAY_SETB(msg->cmd.raw, 215);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_6)))
ARRAY_SETB(msg->cmd.raw, 231);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_7)))
ARRAY_SETB(msg->cmd.raw, 247);
// player 2 buttons
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_1)))
ARRAY_SETB(msg->cmd.raw, 263);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_2)))
ARRAY_SETB(msg->cmd.raw, 279);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_3)))
ARRAY_SETB(msg->cmd.raw, 295);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_4)))
ARRAY_SETB(msg->cmd.raw, 311);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_5)))
ARRAY_SETB(msg->cmd.raw, 327);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_6)))
ARRAY_SETB(msg->cmd.raw, 343);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_7)))
ARRAY_SETB(msg->cmd.raw, 359);
// player 1 start
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_Start)))
ARRAY_SETB(msg->cmd.raw, 79);
// player 2 start
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_Start)))
ARRAY_SETB(msg->cmd.raw, 78);
// VEFX
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::VEFX)))
ARRAY_SETB(msg->cmd.raw, 77);
// EFFECT
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Effect)))
ARRAY_SETB(msg->cmd.raw, 76);
// service
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Service)))
ARRAY_SETB(msg->cmd.raw, 10);
// test
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Test)))
ARRAY_SETB(msg->cmd.raw, 11);
// turntables
msg->cmd.raw[16] = get_tt(0, true);
msg->cmd.raw[17] = get_tt(1, true);
// slider
msg->cmd.raw[0] |= get_slider(0) << 4;
msg->cmd.raw[2] |= get_slider(1) << 4;
msg->cmd.raw[4] |= get_slider(2) << 4;
msg->cmd.raw[6] |= get_slider(3) << 4;
msg->cmd.raw[7] |= get_slider(4) << 4;
// coin
this->coin_counter += eamuse_coin_consume_stock();
msg->cmd.raw[8] |= this->coin_counter;
/*
* TODO
* bit 9 appears to be the coin mech
*/
// write message
write_msg(msg, response_buffer);
delete msg;
break;
}
case ACIO_CMD_CLEAR:
case ACIO_CMD_STARTUP:
case 0x0120: // WD COMMAND
case 0xFF: // BROADCAST
{
// send status 0
auto msg = this->create_msg_status(msg_in, 0);
write_msg(msg, response_buffer);
delete msg;
break;
}
default:
return false;
}
// mark as handled
return true;
}
bool games::iidx::BI2XSerialHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM3") != 0) {
return false;
}
log_info("iidx", "Opened COM3 (BIO2)");
// ACIO device
//acio_emu.add_device(new FMSerialDevice());
return true;
}
int games::iidx::BI2XSerialHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
//auto buffer = reinterpret_cast<uint8_t *>(lpBuffer);
// read from emu
/*
DWORD bytes_read = 0;
while (bytes_read < nNumberOfBytesToRead) {
auto cur_byte = acio_emu.read();
if (cur_byte.has_value()) {
buffer[bytes_read++] = cur_byte.value();
} else {
break;
}
}
*/
// return amount of bytes read
//return (int) bytes_read;
return (int) nNumberOfBytesToRead;
}
int games::iidx::BI2XSerialHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
auto buffer = reinterpret_cast<const uint8_t *>(lpBuffer);
log_info("iidx", "BIO2 Data: {}", bin2hex(buffer, nNumberOfBytesToWrite));
// write to emu
/*
for (DWORD i = 0; i < nNumberOfBytesToWrite; i++) {
acio_emu.write(buffer[i]);
}
*/
// return all data written
return (int) nNumberOfBytesToWrite;
}
int games::iidx::BI2XSerialHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
return -1;
}
bool games::iidx::BI2XSerialHandle::close() {
log_info("iidx", "Closed COM3 (BIO2)");
return true;
}
#include "bi2x.h"
#include "misc/eamuse.h"
#include "rawinput/rawinput.h"
#include "util/utils.h"
#include "iidx.h"
#include "io.h"
using namespace acioemu;
games::iidx::BI2XSerialHandle::BI2XDevice::BI2XDevice() {
this->node_count = 1;
}
bool games::iidx::BI2XSerialHandle::BI2XDevice::parse_msg(
MessageData *msg_in,
circular_buffer<uint8_t> *response_buffer
) {
#ifdef ACIOEMU_LOG
log_info("iidx", "BI2X ADDR: {}, CMD: 0x{:04x}", msg_in->addr, msg_in->cmd.code);
#endif
// check command
switch (msg_in->cmd.code) {
case ACIO_CMD_GET_VERSION: {
// send version data
auto msg = this->create_msg(msg_in, MSG_VERSION_SIZE);
this->set_version(msg, 0x03, 0, 4, 2, 0, "BI2X");
write_msg(msg, response_buffer);
delete msg;
break;
}
case 0x0152: { // STATUS
// check input data length
if (msg_in->cmd.data_size == 0x30) {
// LED TICKER
IIDX_LED_TICKER_LOCK.lock();
if (!IIDXIO_LED_TICKER_READONLY)
memcpy(IIDXIO_LED_TICKER, &msg_in->cmd.raw[0x17], 9);
IIDX_LED_TICKER_LOCK.unlock();
// NEON LIGHT
bool neon_light = msg_in->cmd.raw[0x24] != 0;
write_top_neon(neon_light ? (uint8_t) 0xFF : (uint8_t) 0);
// SPOT LIGHT
uint8_t spot_light_bits = 0;
for (size_t i = 0; i < 8; i++) {
auto index = i > 3 ? i + 1 : i;
if (msg_in->cmd.raw[0x20 + index] != 0)
spot_light_bits |= 1 << i;
}
write_top_lamp(spot_light_bits);
// SWLED (DECK)
uint16_t lamp_bits = 0;
for (size_t i = 0; i < 14; i++) {
if (msg_in->cmd.raw[0x07 + i] != 0)
lamp_bits |= 1 << i;
}
write_lamp(lamp_bits);
// SWLED (PANEL)
uint8_t led_bits = 0;
for (size_t i = 0; i < 4; i++) {
if (msg_in->cmd.raw[0x03 + i] != 0)
led_bits |= 1 << i;
}
write_led(led_bits);
// flush device output
RI_MGR->devices_flush_output();
}
// sleep - otherwise the IO thread will go too hard on the CPU
Sleep(1);
// generate message
auto msg = this->create_msg(msg_in, 0x2E);
// get buttons
auto &buttons = get_buttons();
// player 1 buttons
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_1)))
ARRAY_SETB(msg->cmd.raw, 151);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_2)))
ARRAY_SETB(msg->cmd.raw, 167);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_3)))
ARRAY_SETB(msg->cmd.raw, 183);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_4)))
ARRAY_SETB(msg->cmd.raw, 199);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_5)))
ARRAY_SETB(msg->cmd.raw, 215);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_6)))
ARRAY_SETB(msg->cmd.raw, 231);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_7)))
ARRAY_SETB(msg->cmd.raw, 247);
// player 2 buttons
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_1)))
ARRAY_SETB(msg->cmd.raw, 263);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_2)))
ARRAY_SETB(msg->cmd.raw, 279);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_3)))
ARRAY_SETB(msg->cmd.raw, 295);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_4)))
ARRAY_SETB(msg->cmd.raw, 311);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_5)))
ARRAY_SETB(msg->cmd.raw, 327);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_6)))
ARRAY_SETB(msg->cmd.raw, 343);
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_7)))
ARRAY_SETB(msg->cmd.raw, 359);
// player 1 start
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P1_Start)))
ARRAY_SETB(msg->cmd.raw, 79);
// player 2 start
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::P2_Start)))
ARRAY_SETB(msg->cmd.raw, 78);
// VEFX
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::VEFX)))
ARRAY_SETB(msg->cmd.raw, 77);
// EFFECT
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Effect)))
ARRAY_SETB(msg->cmd.raw, 76);
// service
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Service)))
ARRAY_SETB(msg->cmd.raw, 10);
// test
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Test)))
ARRAY_SETB(msg->cmd.raw, 11);
// turntables
msg->cmd.raw[16] = get_tt(0, true);
msg->cmd.raw[17] = get_tt(1, true);
// slider
msg->cmd.raw[0] |= get_slider(0) << 4;
msg->cmd.raw[2] |= get_slider(1) << 4;
msg->cmd.raw[4] |= get_slider(2) << 4;
msg->cmd.raw[6] |= get_slider(3) << 4;
msg->cmd.raw[7] |= get_slider(4) << 4;
// coin
this->coin_counter += eamuse_coin_consume_stock();
msg->cmd.raw[8] |= this->coin_counter;
/*
* TODO
* bit 9 appears to be the coin mech
*/
// write message
write_msg(msg, response_buffer);
delete msg;
break;
}
case ACIO_CMD_CLEAR:
case ACIO_CMD_STARTUP:
case 0x0120: // WD COMMAND
case 0xFF: // BROADCAST
{
// send status 0
auto msg = this->create_msg_status(msg_in, 0);
write_msg(msg, response_buffer);
delete msg;
break;
}
default:
return false;
}
// mark as handled
return true;
}
bool games::iidx::BI2XSerialHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM3") != 0) {
return false;
}
log_info("iidx", "Opened COM3 (BIO2)");
// ACIO device
//acio_emu.add_device(new FMSerialDevice());
return true;
}
int games::iidx::BI2XSerialHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
//auto buffer = reinterpret_cast<uint8_t *>(lpBuffer);
// read from emu
/*
DWORD bytes_read = 0;
while (bytes_read < nNumberOfBytesToRead) {
auto cur_byte = acio_emu.read();
if (cur_byte.has_value()) {
buffer[bytes_read++] = cur_byte.value();
} else {
break;
}
}
*/
// return amount of bytes read
//return (int) bytes_read;
return (int) nNumberOfBytesToRead;
}
int games::iidx::BI2XSerialHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
auto buffer = reinterpret_cast<const uint8_t *>(lpBuffer);
log_info("iidx", "BIO2 Data: {}", bin2hex(buffer, nNumberOfBytesToWrite));
// write to emu
/*
for (DWORD i = 0; i < nNumberOfBytesToWrite; i++) {
acio_emu.write(buffer[i]);
}
*/
// return all data written
return (int) nNumberOfBytesToWrite;
}
int games::iidx::BI2XSerialHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
return -1;
}
bool games::iidx::BI2XSerialHandle::close() {
log_info("iidx", "Closed COM3 (BIO2)");
return true;
}
+30 -30
View File
@@ -1,30 +1,30 @@
#pragma once
#include "acioemu/acioemu.h"
#include "hooks/devicehook.h"
namespace games::iidx {
class BI2XSerialHandle : public CustomHandle {
private:
acioemu::ACIOEmu acio_emu;
class BI2XDevice : public acioemu::ACIODeviceEmu {
private:
uint8_t coin_counter = 0;
public:
BI2XDevice();
bool parse_msg(acioemu::MessageData *msg_in, circular_buffer<uint8_t> *response_buffer) override;
};
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
#pragma once
#include "acioemu/acioemu.h"
#include "hooks/devicehook.h"
namespace games::iidx {
class BI2XSerialHandle : public CustomHandle {
private:
acioemu::ACIOEmu acio_emu;
class BI2XDevice : public acioemu::ACIODeviceEmu {
private:
uint8_t coin_counter = 0;
public:
BI2XDevice();
bool parse_msg(acioemu::MessageData *msg_in, circular_buffer<uint8_t> *response_buffer) override;
};
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
+6 -6
View File
@@ -1,6 +1,6 @@
#pragma once
namespace games::iidx {
void bi2x_hook_init();
}
#pragma once
namespace games::iidx {
void bi2x_hook_init();
}
+277 -277
View File
@@ -1,277 +1,277 @@
#include "ezusb.h"
#include "rawinput/rawinput.h"
#include "util/logging.h"
#include "iidx.h"
#include "io.h"
bool games::iidx::EZUSBHandle::open(LPCWSTR lpFileName) {
return wcscmp(lpFileName, L"\\\\.\\Ezusb-0") == 0;
}
int games::iidx::EZUSBHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
log_warning("iidx", "EZUSB invalid read operation!");
return -1;
}
int games::iidx::EZUSBHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
log_warning("iidx", "EZUSB invalid write operation!");
return -1;
}
int games::iidx::EZUSBHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
// initialize check
if (!init) {
// TODO: initialize input
init = true;
init_success = true;
}
if (init_success) {
switch (dwIoControlCode) {
// device descriptor
case 0x222004:
// check output buffer size
if (nOutBufferSize >= 18) {
// set descriptor data
*((char *) lpOutBuffer + 8) = 0x47;
*((char *) lpOutBuffer + 9) = 0x05;
*((char *) lpOutBuffer + 10) = 0x35;
*((char *) lpOutBuffer + 11) = 0x22;
// return output buffer size
return 18;
} else // buffer too small
return -1;
// vendor
case 0x222014:
// check input buffer size
if (nInBufferSize >= 10)
return 0;
else
return -1;
// data read
case 0x22204E:
// check input buffer size
if (nInBufferSize < 4)
return -1;
// read 0x01
if (*(DWORD *) lpInBuffer == 0x01) {
*((DWORD *) lpOutBuffer) = get_pad();
*((char *) lpOutBuffer + 4) = FPGA_CMD_STATE;
*((char *) lpOutBuffer + 7) = get_tt(1, false);
*((char *) lpOutBuffer + 8) = get_tt(0, false);
*((char *) lpOutBuffer + 9) = FPGA_COUNTER++;
*((char *) lpOutBuffer + 11) = 1; // 1 success; 0 failed
*((char *) lpOutBuffer + 13) = get_slider(1) << 4 | get_slider(0);
*((char *) lpOutBuffer + 14) = get_slider(3) << 4 | get_slider(2);
*((char *) lpOutBuffer + 15) = get_slider(4);
return (int) nOutBufferSize;
}
// read 0x03
if (*(DWORD *) lpInBuffer == 0x03) {
// check output buffer size
if (nOutBufferSize < 64)
return -1;
// null node read
if (FPGA_CUR_NODE == 0) {
*(int *) lpOutBuffer = 0;
return (int) nOutBufferSize;
}
// check node size
if (FPGA_CUR_NODE != 64)
return -1;
// check command
if (SRAM_CMD != 2)
return -1;
// check if page exists
if (SRAM_PAGE >= 12)
return -1;
// write page
*((char *) lpOutBuffer + 1) = (char) SRAM_PAGE;
// copy page
memcpy((uint8_t*) lpOutBuffer + 2, SRAM_DATA + 62 * SRAM_PAGE, 62);
SRAM_PAGE++;
// write node
*((char *) lpOutBuffer) = (char) FPGA_CUR_NODE;
return (int) nOutBufferSize;
}
// unknown
return -1;
// data write
case 0x222051:
// check in buffer size
if (nInBufferSize < 4)
return -1;
// write 0x00
if (*(DWORD *) lpInBuffer == 0x00) {
// check out buffer size
if (nOutBufferSize < 10)
return -1;
// get data
uint16_t lamp = *((uint16_t *) lpOutBuffer + 0);
uint8_t led = *((uint8_t *) lpOutBuffer + 6);
uint8_t top_lamp = *((uint8_t *) lpOutBuffer + 8);
uint8_t top_neon = *((uint8_t *) lpOutBuffer + 9);
// process data
write_lamp(lamp);
write_led(led);
write_top_lamp(top_lamp);
write_top_neon(top_neon);
// flush device output
RI_MGR->devices_flush_output();
char write_node = *((char *) lpOutBuffer + 2);
if (write_node != 0) {
switch (write_node) {
case 4:
switch (*((char *) lpOutBuffer + 3)) {
case 1: // init
FPGA_CMD_STATE = 65;
break;
case 2: // check
FPGA_CMD_STATE = 66;
break;
case 3: // write
{
//int write_data = *((short *) lpOutBuffer + 4);
break;
}
case 4: // write done
FPGA_CMD_STATE = 67;
break;
default: // unknown
return -1;
}
break;
case 5:
break;
case 9:
break;
case 64: // SRAM command
SRAM_CMD = *((char *) lpOutBuffer + 3);
switch (SRAM_CMD) {
case 2: // read
SRAM_PAGE = 0;
break;
case 3: // write
SRAM_PAGE = 0;
break;
case 4: // done
break;
default: // unknown
return -1;
}
break;
default: // unknown node
return -1;
}
}
// save node
FPGA_CUR_NODE = write_node;
// return out buffer size
return (int) nOutBufferSize;
}
// write 0x02
if (*(DWORD *) lpInBuffer == 0x02) {
// check out buffer size
if (nOutBufferSize < 64)
return -1;
int cmd = *(char *) lpOutBuffer;
switch (cmd) {
case 0: // null write
break;
case 4: // unknown
break;
case 5: // 16seg
{
// write to status
IIDX_LED_TICKER_LOCK.lock();
if (!IIDXIO_LED_TICKER_READONLY)
memcpy(IIDXIO_LED_TICKER, (char *) lpOutBuffer + 2, 9);
IIDX_LED_TICKER_LOCK.unlock();
break;
}
case 64: // SRAM write
{
// get page
static char page = *((char *) lpOutBuffer + 1);
page = (char) SRAM_PAGE++;
// check page
if (page >= 12)
return -1;
// copy data
memcpy(SRAM_DATA + 62 * page, (uint8_t*) lpOutBuffer + 2, 62);
break;
}
default: // unknown node
return -1;
}
// return out buffer size
return (int) nOutBufferSize;
}
// unknown write
return -1;
// firmware upload
case 0x22206D:
// check buffer size
if (nInBufferSize >= 2)
return (int) nOutBufferSize;
else
return -1;
// unknown control code
default:
log_warning("iidx", "EZUSB unknown: {}", dwIoControlCode);
return -1;
}
} else
return -1;
}
bool games::iidx::EZUSBHandle::close() {
return true;
}
#include "ezusb.h"
#include "rawinput/rawinput.h"
#include "util/logging.h"
#include "iidx.h"
#include "io.h"
bool games::iidx::EZUSBHandle::open(LPCWSTR lpFileName) {
return wcscmp(lpFileName, L"\\\\.\\Ezusb-0") == 0;
}
int games::iidx::EZUSBHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
log_warning("iidx", "EZUSB invalid read operation!");
return -1;
}
int games::iidx::EZUSBHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
log_warning("iidx", "EZUSB invalid write operation!");
return -1;
}
int games::iidx::EZUSBHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
// initialize check
if (!init) {
// TODO: initialize input
init = true;
init_success = true;
}
if (init_success) {
switch (dwIoControlCode) {
// device descriptor
case 0x222004:
// check output buffer size
if (nOutBufferSize >= 18) {
// set descriptor data
*((char *) lpOutBuffer + 8) = 0x47;
*((char *) lpOutBuffer + 9) = 0x05;
*((char *) lpOutBuffer + 10) = 0x35;
*((char *) lpOutBuffer + 11) = 0x22;
// return output buffer size
return 18;
} else // buffer too small
return -1;
// vendor
case 0x222014:
// check input buffer size
if (nInBufferSize >= 10)
return 0;
else
return -1;
// data read
case 0x22204E:
// check input buffer size
if (nInBufferSize < 4)
return -1;
// read 0x01
if (*(DWORD *) lpInBuffer == 0x01) {
*((DWORD *) lpOutBuffer) = get_pad();
*((char *) lpOutBuffer + 4) = FPGA_CMD_STATE;
*((char *) lpOutBuffer + 7) = get_tt(1, false);
*((char *) lpOutBuffer + 8) = get_tt(0, false);
*((char *) lpOutBuffer + 9) = FPGA_COUNTER++;
*((char *) lpOutBuffer + 11) = 1; // 1 success; 0 failed
*((char *) lpOutBuffer + 13) = get_slider(1) << 4 | get_slider(0);
*((char *) lpOutBuffer + 14) = get_slider(3) << 4 | get_slider(2);
*((char *) lpOutBuffer + 15) = get_slider(4);
return (int) nOutBufferSize;
}
// read 0x03
if (*(DWORD *) lpInBuffer == 0x03) {
// check output buffer size
if (nOutBufferSize < 64)
return -1;
// null node read
if (FPGA_CUR_NODE == 0) {
*(int *) lpOutBuffer = 0;
return (int) nOutBufferSize;
}
// check node size
if (FPGA_CUR_NODE != 64)
return -1;
// check command
if (SRAM_CMD != 2)
return -1;
// check if page exists
if (SRAM_PAGE >= 12)
return -1;
// write page
*((char *) lpOutBuffer + 1) = (char) SRAM_PAGE;
// copy page
memcpy((uint8_t*) lpOutBuffer + 2, SRAM_DATA + 62 * SRAM_PAGE, 62);
SRAM_PAGE++;
// write node
*((char *) lpOutBuffer) = (char) FPGA_CUR_NODE;
return (int) nOutBufferSize;
}
// unknown
return -1;
// data write
case 0x222051:
// check in buffer size
if (nInBufferSize < 4)
return -1;
// write 0x00
if (*(DWORD *) lpInBuffer == 0x00) {
// check out buffer size
if (nOutBufferSize < 10)
return -1;
// get data
uint16_t lamp = *((uint16_t *) lpOutBuffer + 0);
uint8_t led = *((uint8_t *) lpOutBuffer + 6);
uint8_t top_lamp = *((uint8_t *) lpOutBuffer + 8);
uint8_t top_neon = *((uint8_t *) lpOutBuffer + 9);
// process data
write_lamp(lamp);
write_led(led);
write_top_lamp(top_lamp);
write_top_neon(top_neon);
// flush device output
RI_MGR->devices_flush_output();
char write_node = *((char *) lpOutBuffer + 2);
if (write_node != 0) {
switch (write_node) {
case 4:
switch (*((char *) lpOutBuffer + 3)) {
case 1: // init
FPGA_CMD_STATE = 65;
break;
case 2: // check
FPGA_CMD_STATE = 66;
break;
case 3: // write
{
//int write_data = *((short *) lpOutBuffer + 4);
break;
}
case 4: // write done
FPGA_CMD_STATE = 67;
break;
default: // unknown
return -1;
}
break;
case 5:
break;
case 9:
break;
case 64: // SRAM command
SRAM_CMD = *((char *) lpOutBuffer + 3);
switch (SRAM_CMD) {
case 2: // read
SRAM_PAGE = 0;
break;
case 3: // write
SRAM_PAGE = 0;
break;
case 4: // done
break;
default: // unknown
return -1;
}
break;
default: // unknown node
return -1;
}
}
// save node
FPGA_CUR_NODE = write_node;
// return out buffer size
return (int) nOutBufferSize;
}
// write 0x02
if (*(DWORD *) lpInBuffer == 0x02) {
// check out buffer size
if (nOutBufferSize < 64)
return -1;
int cmd = *(char *) lpOutBuffer;
switch (cmd) {
case 0: // null write
break;
case 4: // unknown
break;
case 5: // 16seg
{
// write to status
IIDX_LED_TICKER_LOCK.lock();
if (!IIDXIO_LED_TICKER_READONLY)
memcpy(IIDXIO_LED_TICKER, (char *) lpOutBuffer + 2, 9);
IIDX_LED_TICKER_LOCK.unlock();
break;
}
case 64: // SRAM write
{
// get page
static char page = *((char *) lpOutBuffer + 1);
page = (char) SRAM_PAGE++;
// check page
if (page >= 12)
return -1;
// copy data
memcpy(SRAM_DATA + 62 * page, (uint8_t*) lpOutBuffer + 2, 62);
break;
}
default: // unknown node
return -1;
}
// return out buffer size
return (int) nOutBufferSize;
}
// unknown write
return -1;
// firmware upload
case 0x22206D:
// check buffer size
if (nInBufferSize >= 2)
return (int) nOutBufferSize;
else
return -1;
// unknown control code
default:
log_warning("iidx", "EZUSB unknown: {}", dwIoControlCode);
return -1;
}
} else
return -1;
}
bool games::iidx::EZUSBHandle::close() {
return true;
}
+32 -32
View File
@@ -1,32 +1,32 @@
#pragma once
#include "hooks/devicehook.h"
namespace games::iidx {
class EZUSBHandle : public CustomHandle {
private:
// state
bool init = false;
bool init_success = false;
char FPGA_CMD_STATE = 67;
char FPGA_COUNTER = 0;
int FPGA_CUR_NODE = 0;
int SRAM_CMD = 0;
int SRAM_PAGE = 0;
char SRAM_DATA[62 * 12]{};
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
#pragma once
#include "hooks/devicehook.h"
namespace games::iidx {
class EZUSBHandle : public CustomHandle {
private:
// state
bool init = false;
bool init_success = false;
char FPGA_CMD_STATE = 67;
char FPGA_COUNTER = 0;
int FPGA_CUR_NODE = 0;
int SRAM_CMD = 0;
int SRAM_PAGE = 0;
char SRAM_DATA[62 * 12]{};
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
+161 -161
View File
@@ -1,161 +1,161 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::iidx {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
P1_1,
P1_2,
P1_3,
P1_4,
P1_5,
P1_6,
P1_7,
P1_TTPlus,
P1_TTMinus,
P1_TTPlusMinus,
P1_Start,
P2_1,
P2_2,
P2_3,
P2_4,
P2_5,
P2_6,
P2_7,
P2_TTPlus,
P2_TTMinus,
P2_TTPlusMinus,
P2_Start,
Effect,
VEFX,
P1_Headphone,
P2_Headphone,
};
}
// all analogs in correct order
namespace Analogs {
enum {
TT_P1,
TT_P2,
VEFX,
LowEQ,
HiEQ,
Filter,
PlayVolume
};
}
// all lights in correct order
namespace Lights {
enum {
P1_1,
P1_2,
P1_3,
P1_4,
P1_5,
P1_6,
P1_7,
P2_1,
P2_2,
P2_3,
P2_4,
P2_5,
P2_6,
P2_7,
P1_Start,
P2_Start,
VEFX,
Effect,
SpotLight1,
SpotLight2,
SpotLight3,
SpotLight4,
SpotLight5,
SpotLight6,
SpotLight7,
SpotLight8,
NeonLamp,
WooferR,
WooferG,
WooferB,
ICCR_P1_R,
ICCR_P1_G,
ICCR_P1_B,
ICCR_P2_R,
ICCR_P2_G,
ICCR_P2_B,
TT_P1_R,
TT_P1_G,
TT_P1_B,
TT_P2_R,
TT_P2_G,
TT_P2_B,
TT_P1_Resistance,
TT_P2_Resistance,
StageLeftAvgR,
StageLeftAvgG,
StageLeftAvgB,
StageRightAvgR,
StageRightAvgG,
StageRightAvgB,
CabinetLeftAvgR,
CabinetLeftAvgG,
CabinetLeftAvgB,
CabinetRightAvgR,
CabinetRightAvgG,
CabinetRightAvgB,
ControlPanelUnderAvgR,
ControlPanelUnderAvgG,
ControlPanelUnderAvgB,
CeilingLeftAvgR,
CeilingLeftAvgG,
CeilingLeftAvgB,
TitleLeftAvgR,
TitleLeftAvgG,
TitleLeftAvgB,
TitleRightAvgR,
TitleRightAvgG,
TitleRightAvgB,
CeilingRightAvgR,
CeilingRightAvgG,
CeilingRightAvgB,
TouchPanelLeftAvgR,
TouchPanelLeftAvgG,
TouchPanelLeftAvgB,
TouchPanelRightAvgR,
TouchPanelRightAvgG,
TouchPanelRightAvgB,
SidePanelLeftInnerAvgR,
SidePanelLeftInnerAvgG,
SidePanelLeftInnerAvgB,
SidePanelLeftOuterAvgR,
SidePanelLeftOuterAvgG,
SidePanelLeftOuterAvgB,
SidePanelLeftAvgR,
SidePanelLeftAvgG,
SidePanelLeftAvgB,
SidePanelRightOuterAvgR,
SidePanelRightOuterAvgG,
SidePanelRightOuterAvgB,
SidePanelRightInnerAvgR,
SidePanelRightInnerAvgG,
SidePanelRightInnerAvgB,
SidePanelRightAvgR,
SidePanelRightAvgG,
SidePanelRightAvgB,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::iidx {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
P1_1,
P1_2,
P1_3,
P1_4,
P1_5,
P1_6,
P1_7,
P1_TTPlus,
P1_TTMinus,
P1_TTPlusMinus,
P1_Start,
P2_1,
P2_2,
P2_3,
P2_4,
P2_5,
P2_6,
P2_7,
P2_TTPlus,
P2_TTMinus,
P2_TTPlusMinus,
P2_Start,
Effect,
VEFX,
P1_Headphone,
P2_Headphone,
};
}
// all analogs in correct order
namespace Analogs {
enum {
TT_P1,
TT_P2,
VEFX,
LowEQ,
HiEQ,
Filter,
PlayVolume
};
}
// all lights in correct order
namespace Lights {
enum {
P1_1,
P1_2,
P1_3,
P1_4,
P1_5,
P1_6,
P1_7,
P2_1,
P2_2,
P2_3,
P2_4,
P2_5,
P2_6,
P2_7,
P1_Start,
P2_Start,
VEFX,
Effect,
SpotLight1,
SpotLight2,
SpotLight3,
SpotLight4,
SpotLight5,
SpotLight6,
SpotLight7,
SpotLight8,
NeonLamp,
WooferR,
WooferG,
WooferB,
ICCR_P1_R,
ICCR_P1_G,
ICCR_P1_B,
ICCR_P2_R,
ICCR_P2_G,
ICCR_P2_B,
TT_P1_R,
TT_P1_G,
TT_P1_B,
TT_P2_R,
TT_P2_G,
TT_P2_B,
TT_P1_Resistance,
TT_P2_Resistance,
StageLeftAvgR,
StageLeftAvgG,
StageLeftAvgB,
StageRightAvgR,
StageRightAvgG,
StageRightAvgB,
CabinetLeftAvgR,
CabinetLeftAvgG,
CabinetLeftAvgB,
CabinetRightAvgR,
CabinetRightAvgG,
CabinetRightAvgB,
ControlPanelUnderAvgR,
ControlPanelUnderAvgG,
ControlPanelUnderAvgB,
CeilingLeftAvgR,
CeilingLeftAvgG,
CeilingLeftAvgB,
TitleLeftAvgR,
TitleLeftAvgG,
TitleLeftAvgB,
TitleRightAvgR,
TitleRightAvgG,
TitleRightAvgB,
CeilingRightAvgR,
CeilingRightAvgG,
CeilingRightAvgB,
TouchPanelLeftAvgR,
TouchPanelLeftAvgG,
TouchPanelLeftAvgB,
TouchPanelRightAvgR,
TouchPanelRightAvgG,
TouchPanelRightAvgB,
SidePanelLeftInnerAvgR,
SidePanelLeftInnerAvgG,
SidePanelLeftInnerAvgB,
SidePanelLeftOuterAvgR,
SidePanelLeftOuterAvgG,
SidePanelLeftOuterAvgB,
SidePanelLeftAvgR,
SidePanelLeftAvgG,
SidePanelLeftAvgB,
SidePanelRightOuterAvgR,
SidePanelRightOuterAvgG,
SidePanelRightOuterAvgB,
SidePanelRightInnerAvgR,
SidePanelRightInnerAvgG,
SidePanelRightInnerAvgB,
SidePanelRightAvgR,
SidePanelRightAvgG,
SidePanelRightAvgB,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
+63 -63
View File
@@ -1,63 +1,63 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games {
namespace OverlayButtons {
enum {
InsertCoin,
ToggleConfig,
ToggleVirtualKeypadP1,
ToggleVirtualKeypadP2,
ToggleCardManager,
ToggleLog,
ToggleControl,
TogglePatchManager,
ToggleSubScreen,
ToggleVRControl,
ToggleOverlay,
NavigatorActivate,
NavigatorCancel,
NavigatorUp,
NavigatorDown,
NavigatorLeft,
NavigatorRight,
Screenshot,
HotkeyEnable1,
HotkeyEnable2,
HotkeyToggle,
ScreenResize,
ToggleScreenResize,
};
}
namespace KeypadButtons {
enum {
Keypad0,
Keypad1,
Keypad2,
Keypad3,
Keypad4,
Keypad5,
Keypad6,
Keypad7,
Keypad8,
Keypad9,
Keypad00,
KeypadDecimal,
InsertCard,
Size,
};
}
const std::vector<std::string> &get_games();
std::vector<Button> *get_buttons(const std::string &game);
std::vector<Button> *get_buttons_keypads(const std::string &game);
std::vector<Button> *get_buttons_overlay(const std::string &game);
std::vector<Analog> *get_analogs(const std::string &game);
std::vector<Light> *get_lights(const std::string &game);
std::vector<Option> *get_options(const std::string &game);
std::vector<std::string> *get_game_file_hints(const std::string &game);
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games {
namespace OverlayButtons {
enum {
InsertCoin,
ToggleConfig,
ToggleVirtualKeypadP1,
ToggleVirtualKeypadP2,
ToggleCardManager,
ToggleLog,
ToggleControl,
TogglePatchManager,
ToggleSubScreen,
ToggleVRControl,
ToggleOverlay,
NavigatorActivate,
NavigatorCancel,
NavigatorUp,
NavigatorDown,
NavigatorLeft,
NavigatorRight,
Screenshot,
HotkeyEnable1,
HotkeyEnable2,
HotkeyToggle,
ScreenResize,
ToggleScreenResize,
};
}
namespace KeypadButtons {
enum {
Keypad0,
Keypad1,
Keypad2,
Keypad3,
Keypad4,
Keypad5,
Keypad6,
Keypad7,
Keypad8,
Keypad9,
Keypad00,
KeypadDecimal,
InsertCard,
Size,
};
}
const std::vector<std::string> &get_games();
std::vector<Button> *get_buttons(const std::string &game);
std::vector<Button> *get_buttons_keypads(const std::string &game);
std::vector<Button> *get_buttons_overlay(const std::string &game);
std::vector<Analog> *get_analogs(const std::string &game);
std::vector<Light> *get_lights(const std::string &game);
std::vector<Option> *get_options(const std::string &game);
std::vector<std::string> *get_game_file_hints(const std::string &game);
}
+66 -66
View File
@@ -1,66 +1,66 @@
#include "io.h"
std::vector<Button> &games::jb::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Jubeat");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"Button 1",
"Button 2",
"Button 3",
"Button 4",
"Button 5",
"Button 6",
"Button 7",
"Button 8",
"Button 9",
"Button 10",
"Button 11",
"Button 12",
"Button 13",
"Button 14",
"Button 15",
"Button 16"
);
}
return buttons;
}
std::vector<Light> &games::jb::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Jubeat");
GameAPI::Lights::sortLights(
&lights,
"Panel Front R",
"Panel Front G",
"Panel Front B",
"Panel Title R",
"Panel Title G",
"Panel Title B",
"Panel Top R",
"Panel Top G",
"Panel Top B",
"Panel Left R",
"Panel Left G",
"Panel Left B",
"Panel Right R",
"Panel Right G",
"Panel Right B",
"Panel Woofer R",
"Panel Woofer G",
"Panel Woofer B"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::jb::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Jubeat");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"Button 1",
"Button 2",
"Button 3",
"Button 4",
"Button 5",
"Button 6",
"Button 7",
"Button 8",
"Button 9",
"Button 10",
"Button 11",
"Button 12",
"Button 13",
"Button 14",
"Button 15",
"Button 16"
);
}
return buttons;
}
std::vector<Light> &games::jb::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Jubeat");
GameAPI::Lights::sortLights(
&lights,
"Panel Front R",
"Panel Front G",
"Panel Front B",
"Panel Title R",
"Panel Title G",
"Panel Title B",
"Panel Top R",
"Panel Top G",
"Panel Top B",
"Panel Left R",
"Panel Left G",
"Panel Left B",
"Panel Right R",
"Panel Right G",
"Panel Right B",
"Panel Woofer R",
"Panel Woofer G",
"Panel Woofer B"
);
}
return lights;
}
+60 -60
View File
@@ -1,60 +1,60 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::jb {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
Button1,
Button2,
Button3,
Button4,
Button5,
Button6,
Button7,
Button8,
Button9,
Button10,
Button11,
Button12,
Button13,
Button14,
Button15,
Button16,
};
}
// all lights in correct order
namespace Lights {
enum {
PANEL_FRONT_R,
PANEL_FRONT_G,
PANEL_FRONT_B,
PANEL_TITLE_R,
PANEL_TITLE_G,
PANEL_TITLE_B,
PANEL_TOP_R,
PANEL_TOP_G,
PANEL_TOP_B,
PANEL_LEFT_R,
PANEL_LEFT_G,
PANEL_LEFT_B,
PANEL_RIGHT_R,
PANEL_RIGHT_G,
PANEL_RIGHT_B,
PANEL_WOOFER_R,
PANEL_WOOFER_G,
PANEL_WOOFER_B,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::jb {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
Button1,
Button2,
Button3,
Button4,
Button5,
Button6,
Button7,
Button8,
Button9,
Button10,
Button11,
Button12,
Button13,
Button14,
Button15,
Button16,
};
}
// all lights in correct order
namespace Lights {
enum {
PANEL_FRONT_R,
PANEL_FRONT_G,
PANEL_FRONT_B,
PANEL_TITLE_R,
PANEL_TITLE_G,
PANEL_TITLE_B,
PANEL_TOP_R,
PANEL_TOP_G,
PANEL_TOP_B,
PANEL_LEFT_R,
PANEL_LEFT_G,
PANEL_LEFT_B,
PANEL_RIGHT_R,
PANEL_RIGHT_G,
PANEL_RIGHT_B,
PANEL_WOOFER_R,
PANEL_WOOFER_G,
PANEL_WOOFER_B,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
+145 -145
View File
@@ -1,145 +1,145 @@
#include "jb.h"
#include <windows.h>
#include "avs/game.h"
#include "hooks/graphics/graphics.h"
#include "touch/touch.h"
#include "util/logging.h"
#include "util/utils.h"
#include "util/detour.h"
#include "util/libutils.h"
namespace games::jb {
// touch stuff
static bool TOUCH_ENABLE = false;
static bool TOUCH_ATTACHED = false;
static bool IS_PORTRAIT = true;
static std::vector<TouchPoint> TOUCH_POINTS;
bool TOUCH_STATE[16];
void touch_update() {
// check if touch enabled
if (!TOUCH_ENABLE) {
return;
}
// attach touch module
if (!TOUCH_ATTACHED) {
/*
* Find the game window.
* We check the foreground window first, then fall back to searching for the window title
* All game versions seem to have their model first in the window title
*/
HWND wnd = GetForegroundWindow();
if (!string_begins_with(GetActiveWindowTitle(), avs::game::MODEL)) {
wnd = FindWindowBeginsWith(avs::game::MODEL);
}
// check if we have a window handle
if (!wnd) {
log_warning("jubeat", "could not find window handle for touch");
TOUCH_ENABLE = false;
return;
}
// attach touch hook
log_info("jubeat", "using window handle for touch: {}", fmt::ptr(wnd));
touch_create_wnd(wnd, true);
// show cursor
if (GRAPHICS_SHOW_CURSOR) {
ShowCursor(TRUE);
}
// earlier games use a different screen orientation
if (!avs::game::is_model("L44")) {
IS_PORTRAIT = false;
}
// set attached
TOUCH_ATTACHED = true;
}
// reset touch state
memset(TOUCH_STATE, 0, sizeof(TOUCH_STATE));
// check touch points
TOUCH_POINTS.clear();
touch_get_points(TOUCH_POINTS);
auto offset = IS_PORTRAIT ? 580 : 0;
for (auto &tp : TOUCH_POINTS) {
// get grid coordinates
int x = tp.x * 4 / 768;
int y = (tp.y - offset) * 4 / (1360 - 580);
// set the corresponding state
int index = y * 4 + x;
if (index >= 0 && index < 16) {
TOUCH_STATE[index] = true;
}
}
}
/*
* to fix "IP ADDR CHANGE" errors on boot and in-game when using weird network setups such as a VPN
*/
static BOOL __stdcall network_addr_is_changed() {
return 0;
}
/*
* to fix lag spikes when game tries to ping "eamuse.konami.fun" every few minutes
*/
static BOOL __stdcall network_get_network_check_info() {
return 0;
}
/*
* to fix network error on non DHCP interfaces
*/
static BOOL __cdecl network_get_dhcp_result() {
return 1;
}
static int __cdecl GFDbgSetReportFunc(void *func) {
log_misc("jubeat", "GFDbgSetReportFunc hook hit");
return 0;
}
JBGame::JBGame() : Game("Jubeat") {
}
void JBGame::attach() {
Game::attach();
// enable touch
TOUCH_ENABLE = true;
// enable debug logging of gftools
HMODULE gftools = libutils::try_module("gftools.dll");
detour::inline_hook((void *) GFDbgSetReportFunc, libutils::try_proc(
gftools, "GFDbgSetReportFunc"));
// apply patches
HMODULE network = libutils::try_module("network.dll");
detour::inline_hook((void *) network_addr_is_changed, libutils::try_proc(
network, "network_addr_is_changed"));
detour::inline_hook((void *) network_get_network_check_info, libutils::try_proc(
network, "network_get_network_check_info"));
detour::inline_hook((void *) network_get_dhcp_result, libutils::try_proc(
network, "network_get_dhcp_result"));
}
void JBGame::detach() {
Game::detach();
// disable touch
TOUCH_ENABLE = false;
}
}
#include "jb.h"
#include <windows.h>
#include "avs/game.h"
#include "hooks/graphics/graphics.h"
#include "touch/touch.h"
#include "util/logging.h"
#include "util/utils.h"
#include "util/detour.h"
#include "util/libutils.h"
namespace games::jb {
// touch stuff
static bool TOUCH_ENABLE = false;
static bool TOUCH_ATTACHED = false;
static bool IS_PORTRAIT = true;
static std::vector<TouchPoint> TOUCH_POINTS;
bool TOUCH_STATE[16];
void touch_update() {
// check if touch enabled
if (!TOUCH_ENABLE) {
return;
}
// attach touch module
if (!TOUCH_ATTACHED) {
/*
* Find the game window.
* We check the foreground window first, then fall back to searching for the window title
* All game versions seem to have their model first in the window title
*/
HWND wnd = GetForegroundWindow();
if (!string_begins_with(GetActiveWindowTitle(), avs::game::MODEL)) {
wnd = FindWindowBeginsWith(avs::game::MODEL);
}
// check if we have a window handle
if (!wnd) {
log_warning("jubeat", "could not find window handle for touch");
TOUCH_ENABLE = false;
return;
}
// attach touch hook
log_info("jubeat", "using window handle for touch: {}", fmt::ptr(wnd));
touch_create_wnd(wnd, true);
// show cursor
if (GRAPHICS_SHOW_CURSOR) {
ShowCursor(TRUE);
}
// earlier games use a different screen orientation
if (!avs::game::is_model("L44")) {
IS_PORTRAIT = false;
}
// set attached
TOUCH_ATTACHED = true;
}
// reset touch state
memset(TOUCH_STATE, 0, sizeof(TOUCH_STATE));
// check touch points
TOUCH_POINTS.clear();
touch_get_points(TOUCH_POINTS);
auto offset = IS_PORTRAIT ? 580 : 0;
for (auto &tp : TOUCH_POINTS) {
// get grid coordinates
int x = tp.x * 4 / 768;
int y = (tp.y - offset) * 4 / (1360 - 580);
// set the corresponding state
int index = y * 4 + x;
if (index >= 0 && index < 16) {
TOUCH_STATE[index] = true;
}
}
}
/*
* to fix "IP ADDR CHANGE" errors on boot and in-game when using weird network setups such as a VPN
*/
static BOOL __stdcall network_addr_is_changed() {
return 0;
}
/*
* to fix lag spikes when game tries to ping "eamuse.konami.fun" every few minutes
*/
static BOOL __stdcall network_get_network_check_info() {
return 0;
}
/*
* to fix network error on non DHCP interfaces
*/
static BOOL __cdecl network_get_dhcp_result() {
return 1;
}
static int __cdecl GFDbgSetReportFunc(void *func) {
log_misc("jubeat", "GFDbgSetReportFunc hook hit");
return 0;
}
JBGame::JBGame() : Game("Jubeat") {
}
void JBGame::attach() {
Game::attach();
// enable touch
TOUCH_ENABLE = true;
// enable debug logging of gftools
HMODULE gftools = libutils::try_module("gftools.dll");
detour::inline_hook((void *) GFDbgSetReportFunc, libutils::try_proc(
gftools, "GFDbgSetReportFunc"));
// apply patches
HMODULE network = libutils::try_module("network.dll");
detour::inline_hook((void *) network_addr_is_changed, libutils::try_proc(
network, "network_addr_is_changed"));
detour::inline_hook((void *) network_get_network_check_info, libutils::try_proc(
network, "network_get_network_check_info"));
detour::inline_hook((void *) network_get_dhcp_result, libutils::try_proc(
network, "network_get_dhcp_result"));
}
void JBGame::detach() {
Game::detach();
// disable touch
TOUCH_ENABLE = false;
}
}
+17 -17
View File
@@ -1,17 +1,17 @@
#pragma once
#include "games/game.h"
namespace games::jb {
// touch stuff
extern bool TOUCH_STATE[16];
void touch_update();
class JBGame : public games::Game {
public:
JBGame();
virtual void attach() override;
virtual void detach() override;
};
}
#pragma once
#include "games/game.h"
namespace games::jb {
// touch stuff
extern bool TOUCH_STATE[16];
void touch_update();
class JBGame : public games::Game {
public:
JBGame();
virtual void attach() override;
virtual void detach() override;
};
}
+38 -38
View File
@@ -1,38 +1,38 @@
#include "io.h"
std::vector<Button> &games::loveplus::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("LovePlus");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Left",
"Right"
);
}
return buttons;
}
std::vector<Light> &games::loveplus::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("LovePlus");
GameAPI::Lights::sortLights(
&lights,
"Red",
"Green",
"Blue",
"Left",
"Right"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::loveplus::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("LovePlus");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Left",
"Right"
);
}
return buttons;
}
std::vector<Light> &games::loveplus::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("LovePlus");
GameAPI::Lights::sortLights(
&lights,
"Red",
"Green",
"Blue",
"Left",
"Right"
);
}
return lights;
}
+32 -32
View File
@@ -1,32 +1,32 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::loveplus {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
Left,
Right,
};
}
// all lights in correct order
namespace Lights {
enum {
Red,
Green,
Blue,
Left,
Right,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::loveplus {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
Left,
Right,
};
}
// all lights in correct order
namespace Lights {
enum {
Red,
Green,
Blue,
Left,
Right,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
+171 -171
View File
@@ -1,171 +1,171 @@
#include "loveplus.h"
#include <windows.h>
#include "avs/game.h"
#include "hooks/graphics/graphics.h"
#include "hooks/devicehook.h"
#include "touch/touch.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "util/utils.h"
namespace games::loveplus {
// touch stuff
static bool TOUCH_ENABLE = false;
static bool TOUCH_ATTACHED = false;
void touch_update() {
// check if touch enabled
if (!TOUCH_ENABLE) {
return;
}
// attach touch module
if (!TOUCH_ATTACHED) {
// Find the game window.
// We check the foreground window first, then fall back to searching for the window title
// All game versions seem to have their model first in the window title
HWND wnd = GetForegroundWindow();
if (!string_begins_with(GetActiveWindowTitle(), "LovePlus")) {
wnd = FindWindowBeginsWith(avs::game::MODEL);
}
// attach touch hook
if (wnd) {
log_info("loveplus", "using window handle for touch: {}", fmt::ptr(wnd));
touch_create_wnd(wnd);
} else {
log_info("loveplus", "falling back to the DirectX window handle for touch");
touch_attach_dx_hook();
}
// show cursor
if (GRAPHICS_SHOW_CURSOR) {
ShowCursor(1);
}
// set attached
TOUCH_ATTACHED = true;
}
}
static int __cdecl lib_touchpanel_init() {
touch_update();
return 0;
}
static int __cdecl lib_touchpanel_calibrate(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) {
return 0;
}
// FIXME: test this calling convention change!
static int __cdecl lib_touchpanel_diagnostics(void *a1) {
return 0;
}
static int __cdecl lib_touchpanel_get_touch(DWORD *a1) {
touch_update();
// get touch points
std::vector<TouchPoint> touch_points;
touch_get_points(touch_points);
// check first touch point
if (!touch_points.empty()) {
auto &tp = touch_points[0];
a1[0] = tp.y;
a1[1] = tp.x;
a1[2] = 0;
a1[3] = 1;
a1[4] = 0;
} else {
a1[0] = 0;
a1[1] = 0;
a1[2] = 0;
a1[3] = 0;
a1[4] = 0;
}
return 0;
}
static int __cdecl lib_touchpanel_get_touch_direct(DWORD *a1) {
return lib_touchpanel_get_touch(a1);
}
static int __cdecl lib_touchpanel_update() {
return 1;
}
static bool __cdecl lib_touchpanel_term() {
return 0;
}
static bool __cdecl lib_touchpanel_instance_term() {
return 0;
}
static BOOL __cdecl SetEqualizer(char *a1) {
return FALSE;
}
static LPSTR __stdcall GetCommandLineA_hook() {
static std::string lp_args = "-win -noCamera -noWatchDog -noIOError -noIrda -notarget";
return lp_args.data();
}
LovePlusGame::LovePlusGame() : Game("LovePlus") {
}
void LovePlusGame::attach() {
Game::attach();
// init stuff
devicehook_init();
// enable touch
TOUCH_ENABLE = true;
// touchpanel emulation
HMODULE lib_touchpanel = libutils::try_library("lib_touchpanel.dll");
detour::inline_hook((void *) lib_touchpanel_init, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_init"));
detour::inline_hook((void *) lib_touchpanel_calibrate, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_calibrate"));
detour::inline_hook((void *) lib_touchpanel_diagnostics, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_diagnostics"));
detour::inline_hook((void *) lib_touchpanel_get_touch, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_get_touch_direct"));
detour::inline_hook((void *) lib_touchpanel_get_touch_direct, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_get_touch"));
detour::inline_hook((void *) lib_touchpanel_update, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_update"));
detour::inline_hook((void *) lib_touchpanel_term, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_term"));
detour::inline_hook((void *) lib_touchpanel_instance_term, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_instance_term"));
// equalizer crash fix
HMODULE seteq = libutils::try_library("ad_hd_seteq_dll.dll");
detour::inline_hook((void *) SetEqualizer, libutils::try_proc(seteq, "SetEqualizer"));
// get command line hook
HMODULE lpac = libutils::try_library("lpac.dll");
detour::iat("GetCommandLineA", GetCommandLineA_hook, lpac);
}
void LovePlusGame::detach() {
Game::detach();
// disable touch
TOUCH_ENABLE = false;
}
}
#include "loveplus.h"
#include <windows.h>
#include "avs/game.h"
#include "hooks/graphics/graphics.h"
#include "hooks/devicehook.h"
#include "touch/touch.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "util/utils.h"
namespace games::loveplus {
// touch stuff
static bool TOUCH_ENABLE = false;
static bool TOUCH_ATTACHED = false;
void touch_update() {
// check if touch enabled
if (!TOUCH_ENABLE) {
return;
}
// attach touch module
if (!TOUCH_ATTACHED) {
// Find the game window.
// We check the foreground window first, then fall back to searching for the window title
// All game versions seem to have their model first in the window title
HWND wnd = GetForegroundWindow();
if (!string_begins_with(GetActiveWindowTitle(), "LovePlus")) {
wnd = FindWindowBeginsWith(avs::game::MODEL);
}
// attach touch hook
if (wnd) {
log_info("loveplus", "using window handle for touch: {}", fmt::ptr(wnd));
touch_create_wnd(wnd);
} else {
log_info("loveplus", "falling back to the DirectX window handle for touch");
touch_attach_dx_hook();
}
// show cursor
if (GRAPHICS_SHOW_CURSOR) {
ShowCursor(1);
}
// set attached
TOUCH_ATTACHED = true;
}
}
static int __cdecl lib_touchpanel_init() {
touch_update();
return 0;
}
static int __cdecl lib_touchpanel_calibrate(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) {
return 0;
}
// FIXME: test this calling convention change!
static int __cdecl lib_touchpanel_diagnostics(void *a1) {
return 0;
}
static int __cdecl lib_touchpanel_get_touch(DWORD *a1) {
touch_update();
// get touch points
std::vector<TouchPoint> touch_points;
touch_get_points(touch_points);
// check first touch point
if (!touch_points.empty()) {
auto &tp = touch_points[0];
a1[0] = tp.y;
a1[1] = tp.x;
a1[2] = 0;
a1[3] = 1;
a1[4] = 0;
} else {
a1[0] = 0;
a1[1] = 0;
a1[2] = 0;
a1[3] = 0;
a1[4] = 0;
}
return 0;
}
static int __cdecl lib_touchpanel_get_touch_direct(DWORD *a1) {
return lib_touchpanel_get_touch(a1);
}
static int __cdecl lib_touchpanel_update() {
return 1;
}
static bool __cdecl lib_touchpanel_term() {
return 0;
}
static bool __cdecl lib_touchpanel_instance_term() {
return 0;
}
static BOOL __cdecl SetEqualizer(char *a1) {
return FALSE;
}
static LPSTR __stdcall GetCommandLineA_hook() {
static std::string lp_args = "-win -noCamera -noWatchDog -noIOError -noIrda -notarget";
return lp_args.data();
}
LovePlusGame::LovePlusGame() : Game("LovePlus") {
}
void LovePlusGame::attach() {
Game::attach();
// init stuff
devicehook_init();
// enable touch
TOUCH_ENABLE = true;
// touchpanel emulation
HMODULE lib_touchpanel = libutils::try_library("lib_touchpanel.dll");
detour::inline_hook((void *) lib_touchpanel_init, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_init"));
detour::inline_hook((void *) lib_touchpanel_calibrate, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_calibrate"));
detour::inline_hook((void *) lib_touchpanel_diagnostics, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_diagnostics"));
detour::inline_hook((void *) lib_touchpanel_get_touch, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_get_touch_direct"));
detour::inline_hook((void *) lib_touchpanel_get_touch_direct, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_get_touch"));
detour::inline_hook((void *) lib_touchpanel_update, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_update"));
detour::inline_hook((void *) lib_touchpanel_term, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_term"));
detour::inline_hook((void *) lib_touchpanel_instance_term, libutils::try_proc(
lib_touchpanel, "lib_touchpanel_instance_term"));
// equalizer crash fix
HMODULE seteq = libutils::try_library("ad_hd_seteq_dll.dll");
detour::inline_hook((void *) SetEqualizer, libutils::try_proc(seteq, "SetEqualizer"));
// get command line hook
HMODULE lpac = libutils::try_library("lpac.dll");
detour::iat("GetCommandLineA", GetCommandLineA_hook, lpac);
}
void LovePlusGame::detach() {
Game::detach();
// disable touch
TOUCH_ENABLE = false;
}
}
+16 -16
View File
@@ -1,16 +1,16 @@
#pragma once
#include "games/game.h"
namespace games::loveplus {
// touch stuff
void touch_update();
class LovePlusGame : public games::Game {
public:
LovePlusGame();
virtual void attach() override;
virtual void detach() override;
};
}
#pragma once
#include "games/game.h"
namespace games::loveplus {
// touch stuff
void touch_update();
class LovePlusGame : public games::Game {
public:
LovePlusGame();
virtual void attach() override;
virtual void detach() override;
};
}
+22 -22
View File
@@ -1,22 +1,22 @@
#include "io.h"
std::vector<Button> &games::mfc::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Mahjong Fight Club");
GameAPI::Buttons::sortButtons(
&buttons,
"Select",
"Service",
"Test",
"Coin",
"Joystick Up",
"Joystick Down",
"Joystick Enter"
);
}
return buttons;
}
#include "io.h"
std::vector<Button> &games::mfc::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Mahjong Fight Club");
GameAPI::Buttons::sortButtons(
&buttons,
"Select",
"Service",
"Test",
"Coin",
"Joystick Up",
"Joystick Down",
"Joystick Enter"
);
}
return buttons;
}
+21 -21
View File
@@ -1,21 +1,21 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::mfc {
namespace Buttons {
enum {
Select,
Service,
Test,
Coin,
JoystickUp,
JoystickDown,
JoystickStart,
};
}
// getters
std::vector<Button> &get_buttons();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::mfc {
namespace Buttons {
enum {
Select,
Service,
Test,
Coin,
JoystickUp,
JoystickDown,
JoystickStart,
};
}
// getters
std::vector<Button> &get_buttons();
}
+382 -382
View File
@@ -1,382 +1,382 @@
#include "mfc.h"
#include "acio/icca/icca.h"
#include "avs/game.h"
#include "hooks/graphics/graphics.h"
#include "misc/eamuse.h"
#include "touch/touch.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "util/utils.h"
#include "io.h"
namespace games::mfc {
// touch stuff
static int TOUCH_MAX_X = 1360;
static int TOUCH_MAX_Y = 768;
static bool TOUCH_ATTACHED = false;
static bool TOUCH_PRESENT = false;
static bool TOUCH_LAST_PRESENT = false;
static TouchPoint TOUCH_CURRENT {};
static TouchPoint TOUCH_LAST {};
// general i/o stuff
static struct joystick_state JOY_STATE {};
static struct joystick_state JOY_PREVIOUS_STATE {};
// ic card stuff
static bool CARD_IN = false;
static uint8_t CARD_TYPE = 0;
static uint8_t CARD_UID[8];
typedef int (__cdecl *inifile_param_num_t)(const char *, int *);
static inifile_param_num_t inifile_param_num_real;
static int __cdecl inifile_param_num_hook(const char *a1, int *a2) {
if (strcmp(a1, "WINDOWED") == 0) {
*a2 = GRAPHICS_WINDOWED ? 1 : 0;
return 1;
}
return inifile_param_num_real(a1, a2);
}
static bool __cdecl nic_dhcp_maybe_exist() {
return true;
}
static void __cdecl touch_init(int width, int height) {
log_info("mfc", "call touch_init(width: {}, height: {})", width, height);
// attach touch module
if (!TOUCH_ATTACHED) {
// store touch size specification
TOUCH_MAX_X = width;
TOUCH_MAX_Y = height;
// attach touch hook
touch_attach_dx_hook();
// show cursor
if (GRAPHICS_SHOW_CURSOR) {
ShowCursor(TRUE);
}
// set attached
TOUCH_ATTACHED = true;
}
}
static void __cdecl touch_step() {
if (TOUCH_ATTACHED) {
// get touch points
std::vector<TouchPoint> touch_points;
touch_get_points(touch_points);
/*
log_info("MFC", "touch points: " + to_string(touch_points.size()));
for (TouchPoint tp : touch_points) {
log_info("MFC", "touch point (id: {}, x: {}, y: {})", tp.id, tp.x, tp.y);
}
*/
TOUCH_LAST = TOUCH_CURRENT;
TOUCH_LAST_PRESENT = TOUCH_PRESENT;
if (!touch_points.empty()) {
auto &tp = touch_points[0];
TOUCH_CURRENT = tp;
TOUCH_PRESENT = true;
} else {
TOUCH_PRESENT = false;
}
}
}
static int __cdecl h8io_touch_getpos(int *pX, int *pY) {
if (!TOUCH_PRESENT) {
// false value means no touch present
return 0;
}
*pX = TOUCH_CURRENT.x > TOUCH_MAX_X ? TOUCH_MAX_X : TOUCH_CURRENT.x;
*pY = TOUCH_CURRENT.y > TOUCH_MAX_Y ? TOUCH_MAX_Y : TOUCH_CURRENT.y;
// true value means touch present
return 1;
}
static int __cdecl h8io_touch_getpos_trig(int *pX, int *pY) {
// following the game logic, a trigger check bails early if there was a touch detected
// during the last frame
if (TOUCH_LAST_PRESENT) {
return 0;
}
return h8io_touch_getpos(pX, pY);
}
static void __cdecl touch_get_raw_data(int *pX, int *pY) {
h8io_touch_getpos(pX, pY);
}
static int __cdecl touch_get_raw_data_trig(int *pX, int *pY) {
return h8io_touch_getpos_trig(pX, pY);
}
static char __cdecl mfc5_begin_io_mng(int a1, int a2) {
log_info("mfc", "call mfc5_begin_io_mng");
return 1;
}
static int __cdecl mfc5_is_io_mng_ready() {
log_info("mfc", "call mfc5_is_io_mng_ready");
return 1;
}
// the joystick state functions return the current state that is updated
// in `joystick_step` while ensuring to track the previous state to detect
// held buttons and newly pressed buttons
static void __cdecl joystick_step() {
// set last state
JOY_PREVIOUS_STATE = JOY_STATE;
// get buttons
auto &buttons = get_buttons();
// set new state
JOY_STATE.up = GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::JoystickUp));
JOY_STATE.down = GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::JoystickDown));
JOY_STATE.start = GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::JoystickStart));
JOY_STATE.service = GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Service));
JOY_STATE.test = GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Test));
}
static bool __cdecl joy_up(int a1) {
return JOY_STATE.up;
}
static bool __cdecl joy_up_on(int a1) {
return JOY_STATE.up && !JOY_PREVIOUS_STATE.up;
}
static bool __cdecl joy_up_rep(int a1) {
return JOY_STATE.up && JOY_PREVIOUS_STATE.up;
}
static bool __cdecl joy_down(int a1) {
return JOY_STATE.down;
}
static bool __cdecl joy_down_on(int a1) {
return JOY_STATE.down && !JOY_PREVIOUS_STATE.down;
}
static bool __cdecl joy_down_rep(int a1) {
return JOY_STATE.down && JOY_PREVIOUS_STATE.down;
}
static bool __cdecl joy_start(int a1) {
static bool FIRST_CHECK = true;
// following the game logic, the first poll of the start button must
// be true for center mode
if (FIRST_CHECK) {
FIRST_CHECK = false;
return true;
}
return JOY_STATE.start;
}
static bool __cdecl joy_start_on(int a1) {
return JOY_STATE.start && !JOY_PREVIOUS_STATE.start;
}
static bool __cdecl joy_start_rep(int a1) {
return JOY_STATE.start && JOY_PREVIOUS_STATE.start;
}
static bool __cdecl joy_service() {
return JOY_STATE.service;
}
static bool __cdecl joy_service_on() {
return JOY_STATE.service && !JOY_PREVIOUS_STATE.service;
}
static bool __cdecl joy_test() {
return JOY_STATE.test;
}
static bool __cdecl joy_test_on() {
return JOY_STATE.test && !JOY_PREVIOUS_STATE.test;
}
static void update_card() {
if (eamuse_card_insert_consume(1, 0)) {
if (!CARD_IN) {
CARD_IN = true;
eamuse_get_card(1, 0, CARD_UID);
CARD_TYPE = is_card_uid_felica(CARD_UID) ? 1 : 0;
}
} else {
CARD_IN = false;
}
}
static int __cdecl mfc5_ic_card_read_init() {
//log_misc("mfc", "mfc5_ic_card_read_init");
CARD_IN = false;
CARD_TYPE = 0;
memset(CARD_UID, 0, sizeof(CARD_UID));
return 0;
}
static int __cdecl mfc5_ic_card_read_step() {
//log_misc("mfc", "mfc5_ic_card_read_step");
update_card();
return CARD_IN ? 0 : 1;
}
static int __cdecl mfc5_ic_card_status() {
//log_misc("mfc", "mfc5_ic_card_status");
return CARD_IN ? 2 : 0;
}
static void __cdecl mfc5_get_ic_card_id_type(uint8_t *a1) {
//log_misc("mfc", "mfc5_get_ic_card_id_type(a1: {})", fmt::ptr(a1));
*a1 = CARD_TYPE;
}
static void __cdecl mfc5_get_ic_card_id(uint8_t *a1) {
//log_misc("mfc", "mfc5_get_ic_card_id(a1: {})", fmt::ptr(a1));
memcpy(a1, CARD_UID, 8);
}
static void __cdecl mouse_utl_step() {
return;
}
static HCURSOR WINAPI SetCursor_hook(HCURSOR hCursor) {
log_misc("mfc", "SetCursor hook hit");
return nullptr;
}
MFCGame::MFCGame() : Game("Mahjong Fight Club") {
}
void MFCGame::attach() {
Game::attach();
// NOTE:
//
// develop key binds
// F2 SERVICE
// S SERVICE
// ENTER SELECT
// ENTER ENTER (center)
// ESC TEST
// UP SELECT1 (center)
// DOWN SELECT2 (center)
inifile_param_num_real = (inifile_param_num_t) detour::iat_try(
"?inifile_param_num@@YAHPBDPAH@Z", (void *) &inifile_param_num_hook, avs::game::DLL_INSTANCE);
auto allinone_module = libutils::try_module("allinone.dll");
auto system_module = libutils::try_module("system.dll");
// network fix
detour::iat_try("?nic_dhcp_maybe_exist@@YAEXZ", nic_dhcp_maybe_exist, system_module);
// touch i/o
detour::inline_hook((void *) h8io_touch_getpos, libutils::try_proc(
allinone_module, "?h8io_touch_getpos@@YAHPAH0@Z"));
detour::inline_hook((void *) h8io_touch_getpos_trig, libutils::try_proc(
allinone_module, "?h8io_touch_getpos_trig@@YAHPAH0@Z"));
detour::inline_hook((void *) touch_get_raw_data, libutils::try_proc(
allinone_module, "?touch_get_raw_data@@YAXPAH0@Z"));
detour::inline_hook((void *) touch_get_raw_data_trig, libutils::try_proc(
allinone_module, "?touch_get_raw_data_trig@@YAHPAH0@Z"));
detour::inline_hook((void *) touch_init, libutils::try_proc(
allinone_module, "?touch_init@@YAXHH@Z"));
detour::inline_hook((void *) touch_step, libutils::try_proc(
allinone_module, "?touch_step@@YAXXZ"));
// general i/o
detour::inline_hook((void *) mfc5_begin_io_mng, libutils::try_proc(
allinone_module, "?mfc5_begin_io_mng@@YAEHH@Z"));
detour::inline_hook((void *) mfc5_is_io_mng_ready, libutils::try_proc(
allinone_module, "?mfc5_is_io_mng_ready@@YAHXZ"));
detour::inline_hook((void *) joystick_step, libutils::try_proc(
allinone_module, "?joystick_step@@YAXXZ"));
detour::inline_hook((void *) joy_up, libutils::try_proc(
allinone_module, "?joy_up@@YAHH@Z"));
detour::inline_hook((void *) joy_up_on, libutils::try_proc(
allinone_module, "?joy_up_on@@YAHH@Z"));
detour::inline_hook((void *) joy_up_rep, libutils::try_proc(
allinone_module, "?joy_up_rep@@YAHH@Z"));
detour::inline_hook((void *) joy_down, libutils::try_proc(
allinone_module, "?joy_down@@YAHH@Z"));
detour::inline_hook((void *) joy_down_on, libutils::try_proc(
allinone_module, "?joy_down_on@@YAHH@Z"));
detour::inline_hook((void *) joy_down_rep, libutils::try_proc(
allinone_module, "?joy_down_rep@@YAHH@Z"));
detour::inline_hook((void *) joy_start, libutils::try_proc(
allinone_module, "?joy_start@@YAHH@Z"));
detour::inline_hook((void *) joy_start_on, libutils::try_proc(
allinone_module, "?joy_start_on@@YAHH@Z"));
detour::inline_hook((void *) joy_start_rep, libutils::try_proc(
allinone_module, "?joy_start_rep@@YAHH@Z"));
detour::inline_hook((void *) joy_service, libutils::try_proc(
allinone_module, "?joy_service@@YAHXZ"));
detour::inline_hook((void *) joy_service_on, libutils::try_proc(
allinone_module, "?joy_service_on@@YAHXZ"));
detour::inline_hook((void *) joy_test, libutils::try_proc(
allinone_module, "?joy_test@@YAHXZ"));
detour::inline_hook((void *) joy_test_on, libutils::try_proc(
allinone_module, "?joy_test_on@@YAHXZ"));
// ic card
detour::inline_hook((void *) mfc5_ic_card_read_init, libutils::try_proc(
allinone_module, "?mfc5_ic_card_read_init@@YAHXZ"));
detour::inline_hook((void *) mfc5_ic_card_read_step, libutils::try_proc(
allinone_module, "?mfc5_ic_card_read_step@@YAHXZ"));
detour::inline_hook((void *) mfc5_ic_card_status, libutils::try_proc(
allinone_module, "?mfc5_ic_card_status@@YAHXZ"));
detour::inline_hook((void *) mfc5_get_ic_card_id_type, libutils::try_proc(
allinone_module, "?mfc5_get_ic_card_id_type@@YAXPAE@Z"));
detour::inline_hook((void *) mfc5_get_ic_card_id, libutils::try_proc(
allinone_module, "?mfc5_get_ic_card_id@@YAXQAE@Z"));
if (GRAPHICS_SHOW_CURSOR) {
detour::iat_try("SetCursor", (void *) SetCursor_hook, avs::game::DLL_INSTANCE);
detour::iat_try("SetCursor", (void *) SetCursor_hook, allinone_module);
detour::inline_hook((void *) mouse_utl_step, libutils::try_proc(
allinone_module, "?mouse_utl_step@@YAXXZ"));
}
}
}
#include "mfc.h"
#include "acio/icca/icca.h"
#include "avs/game.h"
#include "hooks/graphics/graphics.h"
#include "misc/eamuse.h"
#include "touch/touch.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "util/utils.h"
#include "io.h"
namespace games::mfc {
// touch stuff
static int TOUCH_MAX_X = 1360;
static int TOUCH_MAX_Y = 768;
static bool TOUCH_ATTACHED = false;
static bool TOUCH_PRESENT = false;
static bool TOUCH_LAST_PRESENT = false;
static TouchPoint TOUCH_CURRENT {};
static TouchPoint TOUCH_LAST {};
// general i/o stuff
static struct joystick_state JOY_STATE {};
static struct joystick_state JOY_PREVIOUS_STATE {};
// ic card stuff
static bool CARD_IN = false;
static uint8_t CARD_TYPE = 0;
static uint8_t CARD_UID[8];
typedef int (__cdecl *inifile_param_num_t)(const char *, int *);
static inifile_param_num_t inifile_param_num_real;
static int __cdecl inifile_param_num_hook(const char *a1, int *a2) {
if (strcmp(a1, "WINDOWED") == 0) {
*a2 = GRAPHICS_WINDOWED ? 1 : 0;
return 1;
}
return inifile_param_num_real(a1, a2);
}
static bool __cdecl nic_dhcp_maybe_exist() {
return true;
}
static void __cdecl touch_init(int width, int height) {
log_info("mfc", "call touch_init(width: {}, height: {})", width, height);
// attach touch module
if (!TOUCH_ATTACHED) {
// store touch size specification
TOUCH_MAX_X = width;
TOUCH_MAX_Y = height;
// attach touch hook
touch_attach_dx_hook();
// show cursor
if (GRAPHICS_SHOW_CURSOR) {
ShowCursor(TRUE);
}
// set attached
TOUCH_ATTACHED = true;
}
}
static void __cdecl touch_step() {
if (TOUCH_ATTACHED) {
// get touch points
std::vector<TouchPoint> touch_points;
touch_get_points(touch_points);
/*
log_info("MFC", "touch points: " + to_string(touch_points.size()));
for (TouchPoint tp : touch_points) {
log_info("MFC", "touch point (id: {}, x: {}, y: {})", tp.id, tp.x, tp.y);
}
*/
TOUCH_LAST = TOUCH_CURRENT;
TOUCH_LAST_PRESENT = TOUCH_PRESENT;
if (!touch_points.empty()) {
auto &tp = touch_points[0];
TOUCH_CURRENT = tp;
TOUCH_PRESENT = true;
} else {
TOUCH_PRESENT = false;
}
}
}
static int __cdecl h8io_touch_getpos(int *pX, int *pY) {
if (!TOUCH_PRESENT) {
// false value means no touch present
return 0;
}
*pX = TOUCH_CURRENT.x > TOUCH_MAX_X ? TOUCH_MAX_X : TOUCH_CURRENT.x;
*pY = TOUCH_CURRENT.y > TOUCH_MAX_Y ? TOUCH_MAX_Y : TOUCH_CURRENT.y;
// true value means touch present
return 1;
}
static int __cdecl h8io_touch_getpos_trig(int *pX, int *pY) {
// following the game logic, a trigger check bails early if there was a touch detected
// during the last frame
if (TOUCH_LAST_PRESENT) {
return 0;
}
return h8io_touch_getpos(pX, pY);
}
static void __cdecl touch_get_raw_data(int *pX, int *pY) {
h8io_touch_getpos(pX, pY);
}
static int __cdecl touch_get_raw_data_trig(int *pX, int *pY) {
return h8io_touch_getpos_trig(pX, pY);
}
static char __cdecl mfc5_begin_io_mng(int a1, int a2) {
log_info("mfc", "call mfc5_begin_io_mng");
return 1;
}
static int __cdecl mfc5_is_io_mng_ready() {
log_info("mfc", "call mfc5_is_io_mng_ready");
return 1;
}
// the joystick state functions return the current state that is updated
// in `joystick_step` while ensuring to track the previous state to detect
// held buttons and newly pressed buttons
static void __cdecl joystick_step() {
// set last state
JOY_PREVIOUS_STATE = JOY_STATE;
// get buttons
auto &buttons = get_buttons();
// set new state
JOY_STATE.up = GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::JoystickUp));
JOY_STATE.down = GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::JoystickDown));
JOY_STATE.start = GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::JoystickStart));
JOY_STATE.service = GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Service));
JOY_STATE.test = GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Test));
}
static bool __cdecl joy_up(int a1) {
return JOY_STATE.up;
}
static bool __cdecl joy_up_on(int a1) {
return JOY_STATE.up && !JOY_PREVIOUS_STATE.up;
}
static bool __cdecl joy_up_rep(int a1) {
return JOY_STATE.up && JOY_PREVIOUS_STATE.up;
}
static bool __cdecl joy_down(int a1) {
return JOY_STATE.down;
}
static bool __cdecl joy_down_on(int a1) {
return JOY_STATE.down && !JOY_PREVIOUS_STATE.down;
}
static bool __cdecl joy_down_rep(int a1) {
return JOY_STATE.down && JOY_PREVIOUS_STATE.down;
}
static bool __cdecl joy_start(int a1) {
static bool FIRST_CHECK = true;
// following the game logic, the first poll of the start button must
// be true for center mode
if (FIRST_CHECK) {
FIRST_CHECK = false;
return true;
}
return JOY_STATE.start;
}
static bool __cdecl joy_start_on(int a1) {
return JOY_STATE.start && !JOY_PREVIOUS_STATE.start;
}
static bool __cdecl joy_start_rep(int a1) {
return JOY_STATE.start && JOY_PREVIOUS_STATE.start;
}
static bool __cdecl joy_service() {
return JOY_STATE.service;
}
static bool __cdecl joy_service_on() {
return JOY_STATE.service && !JOY_PREVIOUS_STATE.service;
}
static bool __cdecl joy_test() {
return JOY_STATE.test;
}
static bool __cdecl joy_test_on() {
return JOY_STATE.test && !JOY_PREVIOUS_STATE.test;
}
static void update_card() {
if (eamuse_card_insert_consume(1, 0)) {
if (!CARD_IN) {
CARD_IN = true;
eamuse_get_card(1, 0, CARD_UID);
CARD_TYPE = is_card_uid_felica(CARD_UID) ? 1 : 0;
}
} else {
CARD_IN = false;
}
}
static int __cdecl mfc5_ic_card_read_init() {
//log_misc("mfc", "mfc5_ic_card_read_init");
CARD_IN = false;
CARD_TYPE = 0;
memset(CARD_UID, 0, sizeof(CARD_UID));
return 0;
}
static int __cdecl mfc5_ic_card_read_step() {
//log_misc("mfc", "mfc5_ic_card_read_step");
update_card();
return CARD_IN ? 0 : 1;
}
static int __cdecl mfc5_ic_card_status() {
//log_misc("mfc", "mfc5_ic_card_status");
return CARD_IN ? 2 : 0;
}
static void __cdecl mfc5_get_ic_card_id_type(uint8_t *a1) {
//log_misc("mfc", "mfc5_get_ic_card_id_type(a1: {})", fmt::ptr(a1));
*a1 = CARD_TYPE;
}
static void __cdecl mfc5_get_ic_card_id(uint8_t *a1) {
//log_misc("mfc", "mfc5_get_ic_card_id(a1: {})", fmt::ptr(a1));
memcpy(a1, CARD_UID, 8);
}
static void __cdecl mouse_utl_step() {
return;
}
static HCURSOR WINAPI SetCursor_hook(HCURSOR hCursor) {
log_misc("mfc", "SetCursor hook hit");
return nullptr;
}
MFCGame::MFCGame() : Game("Mahjong Fight Club") {
}
void MFCGame::attach() {
Game::attach();
// NOTE:
//
// develop key binds
// F2 SERVICE
// S SERVICE
// ENTER SELECT
// ENTER ENTER (center)
// ESC TEST
// UP SELECT1 (center)
// DOWN SELECT2 (center)
inifile_param_num_real = (inifile_param_num_t) detour::iat_try(
"?inifile_param_num@@YAHPBDPAH@Z", (void *) &inifile_param_num_hook, avs::game::DLL_INSTANCE);
auto allinone_module = libutils::try_module("allinone.dll");
auto system_module = libutils::try_module("system.dll");
// network fix
detour::iat_try("?nic_dhcp_maybe_exist@@YAEXZ", nic_dhcp_maybe_exist, system_module);
// touch i/o
detour::inline_hook((void *) h8io_touch_getpos, libutils::try_proc(
allinone_module, "?h8io_touch_getpos@@YAHPAH0@Z"));
detour::inline_hook((void *) h8io_touch_getpos_trig, libutils::try_proc(
allinone_module, "?h8io_touch_getpos_trig@@YAHPAH0@Z"));
detour::inline_hook((void *) touch_get_raw_data, libutils::try_proc(
allinone_module, "?touch_get_raw_data@@YAXPAH0@Z"));
detour::inline_hook((void *) touch_get_raw_data_trig, libutils::try_proc(
allinone_module, "?touch_get_raw_data_trig@@YAHPAH0@Z"));
detour::inline_hook((void *) touch_init, libutils::try_proc(
allinone_module, "?touch_init@@YAXHH@Z"));
detour::inline_hook((void *) touch_step, libutils::try_proc(
allinone_module, "?touch_step@@YAXXZ"));
// general i/o
detour::inline_hook((void *) mfc5_begin_io_mng, libutils::try_proc(
allinone_module, "?mfc5_begin_io_mng@@YAEHH@Z"));
detour::inline_hook((void *) mfc5_is_io_mng_ready, libutils::try_proc(
allinone_module, "?mfc5_is_io_mng_ready@@YAHXZ"));
detour::inline_hook((void *) joystick_step, libutils::try_proc(
allinone_module, "?joystick_step@@YAXXZ"));
detour::inline_hook((void *) joy_up, libutils::try_proc(
allinone_module, "?joy_up@@YAHH@Z"));
detour::inline_hook((void *) joy_up_on, libutils::try_proc(
allinone_module, "?joy_up_on@@YAHH@Z"));
detour::inline_hook((void *) joy_up_rep, libutils::try_proc(
allinone_module, "?joy_up_rep@@YAHH@Z"));
detour::inline_hook((void *) joy_down, libutils::try_proc(
allinone_module, "?joy_down@@YAHH@Z"));
detour::inline_hook((void *) joy_down_on, libutils::try_proc(
allinone_module, "?joy_down_on@@YAHH@Z"));
detour::inline_hook((void *) joy_down_rep, libutils::try_proc(
allinone_module, "?joy_down_rep@@YAHH@Z"));
detour::inline_hook((void *) joy_start, libutils::try_proc(
allinone_module, "?joy_start@@YAHH@Z"));
detour::inline_hook((void *) joy_start_on, libutils::try_proc(
allinone_module, "?joy_start_on@@YAHH@Z"));
detour::inline_hook((void *) joy_start_rep, libutils::try_proc(
allinone_module, "?joy_start_rep@@YAHH@Z"));
detour::inline_hook((void *) joy_service, libutils::try_proc(
allinone_module, "?joy_service@@YAHXZ"));
detour::inline_hook((void *) joy_service_on, libutils::try_proc(
allinone_module, "?joy_service_on@@YAHXZ"));
detour::inline_hook((void *) joy_test, libutils::try_proc(
allinone_module, "?joy_test@@YAHXZ"));
detour::inline_hook((void *) joy_test_on, libutils::try_proc(
allinone_module, "?joy_test_on@@YAHXZ"));
// ic card
detour::inline_hook((void *) mfc5_ic_card_read_init, libutils::try_proc(
allinone_module, "?mfc5_ic_card_read_init@@YAHXZ"));
detour::inline_hook((void *) mfc5_ic_card_read_step, libutils::try_proc(
allinone_module, "?mfc5_ic_card_read_step@@YAHXZ"));
detour::inline_hook((void *) mfc5_ic_card_status, libutils::try_proc(
allinone_module, "?mfc5_ic_card_status@@YAHXZ"));
detour::inline_hook((void *) mfc5_get_ic_card_id_type, libutils::try_proc(
allinone_module, "?mfc5_get_ic_card_id_type@@YAXPAE@Z"));
detour::inline_hook((void *) mfc5_get_ic_card_id, libutils::try_proc(
allinone_module, "?mfc5_get_ic_card_id@@YAXQAE@Z"));
if (GRAPHICS_SHOW_CURSOR) {
detour::iat_try("SetCursor", (void *) SetCursor_hook, avs::game::DLL_INSTANCE);
detour::iat_try("SetCursor", (void *) SetCursor_hook, allinone_module);
detour::inline_hook((void *) mouse_utl_step, libutils::try_proc(
allinone_module, "?mouse_utl_step@@YAXXZ"));
}
}
}
+20 -20
View File
@@ -1,20 +1,20 @@
#pragma once
#include "games/game.h"
namespace games::mfc {
struct joystick_state {
bool up = false;
bool down = false;
bool start = false;
bool service = false;
bool test = false;
};
class MFCGame : public games::Game {
public:
MFCGame();
virtual void attach() override;
};
}
#pragma once
#include "games/game.h"
namespace games::mfc {
struct joystick_state {
bool up = false;
bool down = false;
bool start = false;
bool service = false;
bool test = false;
};
class MFCGame : public games::Game {
public:
MFCGame();
virtual void attach() override;
};
}
+158 -158
View File
@@ -1,158 +1,158 @@
#include "gunio.h"
#include "util/logging.h"
bool games::mga::SpiceGearGunHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM1") != 0) {
return false;
}
log_info("metalgear", "Opened gun device on COM1");
return true;
}
int games::mga::SpiceGearGunHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
// minimum buffer size
if ((command == 0u) || nNumberOfBytesToRead < 2)
return 0;
// execute command
int bytes_read = 0;
switch (command) {
case 0x04: // get version
// write version
*((unsigned char *) lpBuffer + bytes_read++) = version;
break;
case 0x08: // get input state
{
// check buffer size
if (nNumberOfBytesToRead < 12)
return 0;
// get cursor position
POINT cursor_pos{};
GetCursorPos(&cursor_pos);
// get screen size
RECT screen_size{};
GetWindowRect(GetDesktopWindow(), &screen_size);
auto screen_width = (unsigned short) (screen_size.right - screen_size.left);
auto screen_height = (unsigned short) (screen_size.bottom - screen_size.top);
// calculate cursor position
p1_x = (unsigned short) (((cursor_pos.x * 1024) / screen_width) % 1024);
p1_y = (unsigned short) (1024 - (((cursor_pos.y * 1024) / screen_height) % 1024));
// gun P1
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
*((unsigned char *) lpBuffer + bytes_read++) = HIBYTE(p1_x);
*((unsigned char *) lpBuffer + bytes_read++) = LOBYTE(p1_x);
*((unsigned char *) lpBuffer + bytes_read++) = HIBYTE(p1_y);
*((unsigned char *) lpBuffer + bytes_read++) = LOBYTE(p1_y);
bytes_read += 3;
// fill buffer
*((unsigned char *) lpBuffer + bytes_read++) = 0x75;
*((unsigned char *) lpBuffer + bytes_read++) = 0x75;
*((unsigned char *) lpBuffer + bytes_read++) = 0x75;
break;
}
case 0x0C: // not called in game - empty
// empty data
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x10: // get DIP switches
// clear bits
*((unsigned char *) lpBuffer + bytes_read) = 0x00;
// set bits
if (frequency == 1)
*((unsigned char *) lpBuffer + bytes_read) |= 0x80;
if (frequency == 2)
*((unsigned char *) lpBuffer + bytes_read) |= 0x40;
if (frequency == 3)
*((unsigned char *) lpBuffer + bytes_read) |= 0x20;
if (frequency == 4)
*((unsigned char *) lpBuffer + bytes_read) |= 0x10;
break;
case 0x14: // frequency 1
// set frequency and return empty data
frequency = 1;
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x18: // frequency 2
// set frequency and return empty data
frequency = 2;
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x19: // frequency 3
// set frequency and return empty data
frequency = 3;
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x1A: // frequency 4
// set frequency and return empty data
frequency = 4;
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x1C: // led board check
// check buffer size
if (nNumberOfBytesToRead < 11)
return 0;
// set all bits
memset(lpBuffer, 0xFF, 10);
bytes_read += 10;
break;
default:
log_warning("metalgear", "unknown opcode: 0x{:02X}", command);
*((unsigned char *) lpBuffer + bytes_read++) = 0x01;
}
// reset command
command = 0;
// calculate checksum
unsigned char checksum = 0xFF;
for (int i = 0; i < bytes_read; i++)
checksum -= *((unsigned char *) lpBuffer + i);
*((unsigned char *) lpBuffer + bytes_read++) = checksum;
// return amount of bytes read
return bytes_read;
}
int games::mga::SpiceGearGunHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
// save command
if (nNumberOfBytesToWrite > 0)
command = *((unsigned char *) lpBuffer);
return (int) nNumberOfBytesToWrite;
}
int games::mga::SpiceGearGunHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
return -1;
}
bool games::mga::SpiceGearGunHandle::close() {
log_info("metalgear", "Closed gun device on COM1");
return true;
}
#include "gunio.h"
#include "util/logging.h"
bool games::mga::SpiceGearGunHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM1") != 0) {
return false;
}
log_info("metalgear", "Opened gun device on COM1");
return true;
}
int games::mga::SpiceGearGunHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
// minimum buffer size
if ((command == 0u) || nNumberOfBytesToRead < 2)
return 0;
// execute command
int bytes_read = 0;
switch (command) {
case 0x04: // get version
// write version
*((unsigned char *) lpBuffer + bytes_read++) = version;
break;
case 0x08: // get input state
{
// check buffer size
if (nNumberOfBytesToRead < 12)
return 0;
// get cursor position
POINT cursor_pos{};
GetCursorPos(&cursor_pos);
// get screen size
RECT screen_size{};
GetWindowRect(GetDesktopWindow(), &screen_size);
auto screen_width = (unsigned short) (screen_size.right - screen_size.left);
auto screen_height = (unsigned short) (screen_size.bottom - screen_size.top);
// calculate cursor position
p1_x = (unsigned short) (((cursor_pos.x * 1024) / screen_width) % 1024);
p1_y = (unsigned short) (1024 - (((cursor_pos.y * 1024) / screen_height) % 1024));
// gun P1
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
*((unsigned char *) lpBuffer + bytes_read++) = HIBYTE(p1_x);
*((unsigned char *) lpBuffer + bytes_read++) = LOBYTE(p1_x);
*((unsigned char *) lpBuffer + bytes_read++) = HIBYTE(p1_y);
*((unsigned char *) lpBuffer + bytes_read++) = LOBYTE(p1_y);
bytes_read += 3;
// fill buffer
*((unsigned char *) lpBuffer + bytes_read++) = 0x75;
*((unsigned char *) lpBuffer + bytes_read++) = 0x75;
*((unsigned char *) lpBuffer + bytes_read++) = 0x75;
break;
}
case 0x0C: // not called in game - empty
// empty data
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x10: // get DIP switches
// clear bits
*((unsigned char *) lpBuffer + bytes_read) = 0x00;
// set bits
if (frequency == 1)
*((unsigned char *) lpBuffer + bytes_read) |= 0x80;
if (frequency == 2)
*((unsigned char *) lpBuffer + bytes_read) |= 0x40;
if (frequency == 3)
*((unsigned char *) lpBuffer + bytes_read) |= 0x20;
if (frequency == 4)
*((unsigned char *) lpBuffer + bytes_read) |= 0x10;
break;
case 0x14: // frequency 1
// set frequency and return empty data
frequency = 1;
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x18: // frequency 2
// set frequency and return empty data
frequency = 2;
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x19: // frequency 3
// set frequency and return empty data
frequency = 3;
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x1A: // frequency 4
// set frequency and return empty data
frequency = 4;
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x1C: // led board check
// check buffer size
if (nNumberOfBytesToRead < 11)
return 0;
// set all bits
memset(lpBuffer, 0xFF, 10);
bytes_read += 10;
break;
default:
log_warning("metalgear", "unknown opcode: 0x{:02X}", command);
*((unsigned char *) lpBuffer + bytes_read++) = 0x01;
}
// reset command
command = 0;
// calculate checksum
unsigned char checksum = 0xFF;
for (int i = 0; i < bytes_read; i++)
checksum -= *((unsigned char *) lpBuffer + i);
*((unsigned char *) lpBuffer + bytes_read++) = checksum;
// return amount of bytes read
return bytes_read;
}
int games::mga::SpiceGearGunHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
// save command
if (nNumberOfBytesToWrite > 0)
command = *((unsigned char *) lpBuffer);
return (int) nNumberOfBytesToWrite;
}
int games::mga::SpiceGearGunHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
return -1;
}
bool games::mga::SpiceGearGunHandle::close() {
log_info("metalgear", "Closed gun device on COM1");
return true;
}
+29 -29
View File
@@ -1,29 +1,29 @@
#pragma once
#include "hooks/devicehook.h"
namespace games::mga {
// Team FrontLine GUN IO
class SpiceGearGunHandle : public CustomHandle {
private:
unsigned char version = 62;
unsigned char command = 0x00;
unsigned short p1_x = 0;
unsigned short p1_y = 0;
int frequency = 1;
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
#pragma once
#include "hooks/devicehook.h"
namespace games::mga {
// Team FrontLine GUN IO
class SpiceGearGunHandle : public CustomHandle {
private:
unsigned char version = 62;
unsigned char command = 0x00;
unsigned short p1_x = 0;
unsigned short p1_y = 0;
int frequency = 1;
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}
+73 -73
View File
@@ -1,73 +1,73 @@
#include "io.h"
std::vector<Button> &games::mga::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Metal Gear");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"Start",
"Top",
"Front Top",
"Front Bottom",
"Side Left",
"Side Right",
"Side Lever",
"Trigger Button",
"Switch Button",
"Joy Forwards",
"Joy Backwards",
"Joy Left",
"Joy Right"
);
}
return buttons;
}
std::vector<Analog> &games::mga::get_analogs() {
static std::vector<Analog> analogs;
if (analogs.empty()) {
analogs = GameAPI::Analogs::getAnalogs("Metal Gear");
GameAPI::Analogs::sortAnalogs(
&analogs,
"Joy X",
"Joy Y"
);
}
return analogs;
}
std::vector<Light> &games::mga::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Metal Gear");
GameAPI::Lights::sortLights(
&lights,
"Start",
"Left R",
"Left G",
"Left B",
"Right R",
"Right G",
"Right B",
"Gun R",
"Gun G",
"Gun B",
"Gun Vibration"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::mga::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Metal Gear");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"Start",
"Top",
"Front Top",
"Front Bottom",
"Side Left",
"Side Right",
"Side Lever",
"Trigger Button",
"Switch Button",
"Joy Forwards",
"Joy Backwards",
"Joy Left",
"Joy Right"
);
}
return buttons;
}
std::vector<Analog> &games::mga::get_analogs() {
static std::vector<Analog> analogs;
if (analogs.empty()) {
analogs = GameAPI::Analogs::getAnalogs("Metal Gear");
GameAPI::Analogs::sortAnalogs(
&analogs,
"Joy X",
"Joy Y"
);
}
return analogs;
}
std::vector<Light> &games::mga::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Metal Gear");
GameAPI::Lights::sortLights(
&lights,
"Start",
"Left R",
"Left G",
"Left B",
"Right R",
"Right G",
"Right B",
"Gun R",
"Gun G",
"Gun B",
"Gun Vibration"
);
}
return lights;
}
+59 -59
View File
@@ -1,59 +1,59 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::mga {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
Start,
Top,
FrontTop,
FrontBottom,
SideLeft,
SideRight,
SideLever,
TriggerButton,
SwitchButton,
JoyForwards,
JoyBackwards,
JoyLeft,
JoyRight,
};
}
// all analogs in correct order
namespace Analogs {
enum {
JoyX,
JoyY,
};
}
// all lights in correct order
namespace Lights {
enum {
Start,
LeftR,
LeftG,
LeftB,
RightR,
RightG,
RightB,
GunR,
GunG,
GunB,
GunVibration,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::mga {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
Start,
Top,
FrontTop,
FrontBottom,
SideLeft,
SideRight,
SideLever,
TriggerButton,
SwitchButton,
JoyForwards,
JoyBackwards,
JoyLeft,
JoyRight,
};
}
// all analogs in correct order
namespace Analogs {
enum {
JoyX,
JoyY,
};
}
// all lights in correct order
namespace Lights {
enum {
Start,
LeftR,
LeftG,
LeftB,
RightR,
RightG,
RightB,
GunR,
GunG,
GunB,
GunVibration,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
+82 -82
View File
@@ -1,82 +1,82 @@
#include "mga.h"
#include "acio/icca/icca.h"
#include "hooks/devicehook.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "util/detour.h"
#include "util/sigscan.h"
#include "gunio.h"
namespace games::mga {
void (__cdecl *ess_eventlog_request_error_orig)(const char *, unsigned int, int, int);
static int __cdecl log_change_level_hook(int level) {
log_misc("mga", "ignoring log_change_level({})", level);
return 1;
}
static uintptr_t __cdecl log_change_output_hook(uintptr_t target, uintptr_t a2) {
log_misc("mga", "ignoring log_change_output(0x{:x}, 0x{:x})", target, a2);
return 0;
}
static bool __cdecl setvolume_hook(uint8_t volume) {
log_misc("mga", "ignoring setvolume {}", static_cast<int>(volume));
return false;
}
static void __cdecl ess_eventlog_request_error_hook(const char *a1, unsigned int a2, int a3, int a4) {
log_info("mga", "ess_eventlog_request_error({}, {}, {}, {})", a1, a2, a3, a4);
//ess_eventlog_request_error_orig(a1, a2, a3, a4);
}
MGAGame::MGAGame() : Game("Metal Gear Arcade") {
}
void MGAGame::attach() {
Game::attach();
// load system.dll (along with the serial functions)
auto system = libutils::load_library("system.dll");
// add the gun
devicehook_init();
devicehook_add(new SpiceGearGunHandle());
// fix ICCA
acio::ICCA_COMPAT_ACTIVE = true;
// ignore sound engine failure
if (!replace_pattern(
system,
"E8????????84C0750A68F4010000E8????????E8????????E8????????3BF3750433C0EB0C",
"??????????????????90909090909090909090????????????????????????????????????",
0, 0))
{
log_warning("mga", "failed to patch sound engine");
}
// hook setvolume
if (!detour::iat_try("?setvolume@@YAHPAD@Z", setvolume_hook)) {
log_warning("mga", "setvolume hook failed");
}
// stop the game from redirecting AVS log calls
detour::iat_try("log_change_level", log_change_level_hook);
detour::iat_try("log_change_output", log_change_output_hook);
ess_eventlog_request_error_orig = detour::iat_try("ess_eventlog_request_error", ess_eventlog_request_error_hook);
}
void MGAGame::detach() {
Game::detach();
devicehook_dispose();
}
}
#include "mga.h"
#include "acio/icca/icca.h"
#include "hooks/devicehook.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "util/detour.h"
#include "util/sigscan.h"
#include "gunio.h"
namespace games::mga {
void (__cdecl *ess_eventlog_request_error_orig)(const char *, unsigned int, int, int);
static int __cdecl log_change_level_hook(int level) {
log_misc("mga", "ignoring log_change_level({})", level);
return 1;
}
static uintptr_t __cdecl log_change_output_hook(uintptr_t target, uintptr_t a2) {
log_misc("mga", "ignoring log_change_output(0x{:x}, 0x{:x})", target, a2);
return 0;
}
static bool __cdecl setvolume_hook(uint8_t volume) {
log_misc("mga", "ignoring setvolume {}", static_cast<int>(volume));
return false;
}
static void __cdecl ess_eventlog_request_error_hook(const char *a1, unsigned int a2, int a3, int a4) {
log_info("mga", "ess_eventlog_request_error({}, {}, {}, {})", a1, a2, a3, a4);
//ess_eventlog_request_error_orig(a1, a2, a3, a4);
}
MGAGame::MGAGame() : Game("Metal Gear Arcade") {
}
void MGAGame::attach() {
Game::attach();
// load system.dll (along with the serial functions)
auto system = libutils::load_library("system.dll");
// add the gun
devicehook_init();
devicehook_add(new SpiceGearGunHandle());
// fix ICCA
acio::ICCA_COMPAT_ACTIVE = true;
// ignore sound engine failure
if (!replace_pattern(
system,
"E8????????84C0750A68F4010000E8????????E8????????E8????????3BF3750433C0EB0C",
"??????????????????90909090909090909090????????????????????????????????????",
0, 0))
{
log_warning("mga", "failed to patch sound engine");
}
// hook setvolume
if (!detour::iat_try("?setvolume@@YAHPAD@Z", setvolume_hook)) {
log_warning("mga", "setvolume hook failed");
}
// stop the game from redirecting AVS log calls
detour::iat_try("log_change_level", log_change_level_hook);
detour::iat_try("log_change_output", log_change_output_hook);
ess_eventlog_request_error_orig = detour::iat_try("ess_eventlog_request_error", ess_eventlog_request_error_hook);
}
void MGAGame::detach() {
Game::detach();
devicehook_dispose();
}
}
+13 -13
View File
@@ -1,13 +1,13 @@
#pragma once
#include "games/game.h"
namespace games::mga {
class MGAGame : public games::Game {
public:
MGAGame();
virtual void attach() override;
virtual void detach() override;
};
}
#pragma once
#include "games/game.h"
namespace games::mga {
class MGAGame : public games::Game {
public:
MGAGame();
virtual void attach() override;
virtual void detach() override;
};
}
+98 -98
View File
@@ -1,98 +1,98 @@
#include "io.h"
std::vector<Button> &games::museca::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Museca");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Start",
"Disk1-",
"Disk1+",
"Disk1 Press",
"Disk2-",
"Disk2+",
"Disk2 Press",
"Disk3-",
"Disk3+",
"Disk3 Press",
"Disk4-",
"Disk4+",
"Disk4 Press",
"Disk5-",
"Disk5+",
"Disk5 Press",
"Foot Pedal",
"Analog Slowdown"
);
}
return buttons;
}
std::vector<Analog> &games::museca::get_analogs() {
static std::vector<Analog> analogs;
if (analogs.empty()) {
analogs = GameAPI::Analogs::getAnalogs("Museca");
GameAPI::Analogs::sortAnalogs(
&analogs,
"Disk1",
"Disk2",
"Disk3",
"Disk4",
"Disk5"
);
}
return analogs;
}
std::vector<Light> &games::museca::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Museca");
GameAPI::Lights::sortLights(
&lights,
"Title R",
"Title G",
"Title B",
"Side R",
"Side G",
"Side B",
"Spinner1 R",
"Spinner1 G",
"Spinner1 B",
"Spinner2 R",
"Spinner2 G",
"Spinner2 B",
"Spinner3 R",
"Spinner3 G",
"Spinner3 B",
"Spinner4 R",
"Spinner4 G",
"Spinner4 B",
"Spinner5 R",
"Spinner5 G",
"Spinner5 B",
"Under-LED1 R",
"Under-LED1 G",
"Under-LED1 B",
"Under-LED2 R",
"Under-LED2 G",
"Under-LED2 B",
"Under-LED3 R",
"Under-LED3 G",
"Under-LED3 B"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::museca::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Museca");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Start",
"Disk1-",
"Disk1+",
"Disk1 Press",
"Disk2-",
"Disk2+",
"Disk2 Press",
"Disk3-",
"Disk3+",
"Disk3 Press",
"Disk4-",
"Disk4+",
"Disk4 Press",
"Disk5-",
"Disk5+",
"Disk5 Press",
"Foot Pedal",
"Analog Slowdown"
);
}
return buttons;
}
std::vector<Analog> &games::museca::get_analogs() {
static std::vector<Analog> analogs;
if (analogs.empty()) {
analogs = GameAPI::Analogs::getAnalogs("Museca");
GameAPI::Analogs::sortAnalogs(
&analogs,
"Disk1",
"Disk2",
"Disk3",
"Disk4",
"Disk5"
);
}
return analogs;
}
std::vector<Light> &games::museca::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Museca");
GameAPI::Lights::sortLights(
&lights,
"Title R",
"Title G",
"Title B",
"Side R",
"Side G",
"Side B",
"Spinner1 R",
"Spinner1 G",
"Spinner1 B",
"Spinner2 R",
"Spinner2 G",
"Spinner2 B",
"Spinner3 R",
"Spinner3 G",
"Spinner3 B",
"Spinner4 R",
"Spinner4 G",
"Spinner4 B",
"Spinner5 R",
"Spinner5 G",
"Spinner5 B",
"Under-LED1 R",
"Under-LED1 G",
"Under-LED1 B",
"Under-LED2 R",
"Under-LED2 G",
"Under-LED2 B",
"Under-LED3 R",
"Under-LED3 G",
"Under-LED3 B"
);
}
return lights;
}
+86 -86
View File
@@ -1,86 +1,86 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::museca {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
Start,
Disk1Minus,
Disk1Plus,
Disk1Press,
Disk2Minus,
Disk2Plus,
Disk2Press,
Disk3Minus,
Disk3Plus,
Disk3Press,
Disk4Minus,
Disk4Plus,
Disk4Press,
Disk5Minus,
Disk5Plus,
Disk5Press,
FootPedal,
AnalogSlowdown
};
}
// all analogs in correct order
namespace Analogs {
enum {
Disk1,
Disk2,
Disk3,
Disk4,
Disk5
};
}
// all lights in correct order
namespace Lights {
enum {
TitleR,
TitleG,
TitleB,
SideR,
SideG,
SideB,
Spinner1R,
Spinner1G,
Spinner1B,
Spinner2R,
Spinner2G,
Spinner2B,
Spinner3R,
Spinner3G,
Spinner3B,
Spinner4R,
Spinner4G,
Spinner4B,
Spinner5R,
Spinner5G,
Spinner5B,
UnderLED1R,
UnderLED1G,
UnderLED1B,
UnderLED2R,
UnderLED2G,
UnderLED2B,
UnderLED3R,
UnderLED3G,
UnderLED3B
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::museca {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
Start,
Disk1Minus,
Disk1Plus,
Disk1Press,
Disk2Minus,
Disk2Plus,
Disk2Press,
Disk3Minus,
Disk3Plus,
Disk3Press,
Disk4Minus,
Disk4Plus,
Disk4Press,
Disk5Minus,
Disk5Plus,
Disk5Press,
FootPedal,
AnalogSlowdown
};
}
// all analogs in correct order
namespace Analogs {
enum {
Disk1,
Disk2,
Disk3,
Disk4,
Disk5
};
}
// all lights in correct order
namespace Lights {
enum {
TitleR,
TitleG,
TitleB,
SideR,
SideG,
SideB,
Spinner1R,
Spinner1G,
Spinner1B,
Spinner2R,
Spinner2G,
Spinner2B,
Spinner3R,
Spinner3G,
Spinner3B,
Spinner4R,
Spinner4G,
Spinner4B,
Spinner5R,
Spinner5G,
Spinner5B,
UnderLED1R,
UnderLED1G,
UnderLED1B,
UnderLED2R,
UnderLED2G,
UnderLED2B,
UnderLED3R,
UnderLED3G,
UnderLED3B
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
+191 -191
View File
@@ -1,191 +1,191 @@
#include "io.h"
std::vector<Button> &games::nost::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Nostalgia");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"Key 1",
"Key 2",
"Key 3",
"Key 4",
"Key 5",
"Key 6",
"Key 7",
"Key 8",
"Key 9",
"Key 10",
"Key 11",
"Key 12",
"Key 13",
"Key 14",
"Key 15",
"Key 16",
"Key 17",
"Key 18",
"Key 19",
"Key 20",
"Key 21",
"Key 22",
"Key 23",
"Key 24",
"Key 25",
"Key 26",
"Key 27",
"Key 28"
);
}
return buttons;
}
std::vector<Analog> &games::nost::get_analogs() {
static std::vector<Analog> analogs;
if (analogs.empty()) {
analogs = GameAPI::Analogs::getAnalogs("Nostalgia");
GameAPI::Analogs::sortAnalogs(
&analogs,
"Key 1",
"Key 2",
"Key 3",
"Key 4",
"Key 5",
"Key 6",
"Key 7",
"Key 8",
"Key 9",
"Key 10",
"Key 11",
"Key 12",
"Key 13",
"Key 14",
"Key 15",
"Key 16",
"Key 17",
"Key 18",
"Key 19",
"Key 20",
"Key 21",
"Key 22",
"Key 23",
"Key 24",
"Key 25",
"Key 26",
"Key 27",
"Key 28"
);
}
return analogs;
}
std::vector<Light> &games::nost::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Nostalgia");
GameAPI::Lights::sortLights(
&lights,
"Title R",
"Title G",
"Title B",
"Bottom R",
"Bottom G",
"Bottom B",
"Key 1 R",
"Key 1 G",
"Key 1 B",
"Key 2 R",
"Key 2 G",
"Key 2 B",
"Key 3 R",
"Key 3 G",
"Key 3 B",
"Key 4 R",
"Key 4 G",
"Key 4 B",
"Key 5 R",
"Key 5 G",
"Key 5 B",
"Key 6 R",
"Key 6 G",
"Key 6 B",
"Key 7 R",
"Key 7 G",
"Key 7 B",
"Key 8 R",
"Key 8 G",
"Key 8 B",
"Key 9 R",
"Key 9 G",
"Key 9 B",
"Key 10 R",
"Key 10 G",
"Key 10 B",
"Key 11 R",
"Key 11 G",
"Key 11 B",
"Key 12 R",
"Key 12 G",
"Key 12 B",
"Key 13 R",
"Key 13 G",
"Key 13 B",
"Key 14 R",
"Key 14 G",
"Key 14 B",
"Key 15 R",
"Key 15 G",
"Key 15 B",
"Key 16 R",
"Key 16 G",
"Key 16 B",
"Key 17 R",
"Key 17 G",
"Key 17 B",
"Key 18 R",
"Key 18 G",
"Key 18 B",
"Key 19 R",
"Key 19 G",
"Key 19 B",
"Key 20 R",
"Key 20 G",
"Key 20 B",
"Key 21 R",
"Key 21 G",
"Key 21 B",
"Key 22 R",
"Key 22 G",
"Key 22 B",
"Key 23 R",
"Key 23 G",
"Key 23 B",
"Key 24 R",
"Key 24 G",
"Key 24 B",
"Key 25 R",
"Key 25 G",
"Key 25 B",
"Key 26 R",
"Key 26 G",
"Key 26 B",
"Key 27 R",
"Key 27 G",
"Key 27 B",
"Key 28 R",
"Key 28 G",
"Key 28 B"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::nost::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Nostalgia");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"Key 1",
"Key 2",
"Key 3",
"Key 4",
"Key 5",
"Key 6",
"Key 7",
"Key 8",
"Key 9",
"Key 10",
"Key 11",
"Key 12",
"Key 13",
"Key 14",
"Key 15",
"Key 16",
"Key 17",
"Key 18",
"Key 19",
"Key 20",
"Key 21",
"Key 22",
"Key 23",
"Key 24",
"Key 25",
"Key 26",
"Key 27",
"Key 28"
);
}
return buttons;
}
std::vector<Analog> &games::nost::get_analogs() {
static std::vector<Analog> analogs;
if (analogs.empty()) {
analogs = GameAPI::Analogs::getAnalogs("Nostalgia");
GameAPI::Analogs::sortAnalogs(
&analogs,
"Key 1",
"Key 2",
"Key 3",
"Key 4",
"Key 5",
"Key 6",
"Key 7",
"Key 8",
"Key 9",
"Key 10",
"Key 11",
"Key 12",
"Key 13",
"Key 14",
"Key 15",
"Key 16",
"Key 17",
"Key 18",
"Key 19",
"Key 20",
"Key 21",
"Key 22",
"Key 23",
"Key 24",
"Key 25",
"Key 26",
"Key 27",
"Key 28"
);
}
return analogs;
}
std::vector<Light> &games::nost::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Nostalgia");
GameAPI::Lights::sortLights(
&lights,
"Title R",
"Title G",
"Title B",
"Bottom R",
"Bottom G",
"Bottom B",
"Key 1 R",
"Key 1 G",
"Key 1 B",
"Key 2 R",
"Key 2 G",
"Key 2 B",
"Key 3 R",
"Key 3 G",
"Key 3 B",
"Key 4 R",
"Key 4 G",
"Key 4 B",
"Key 5 R",
"Key 5 G",
"Key 5 B",
"Key 6 R",
"Key 6 G",
"Key 6 B",
"Key 7 R",
"Key 7 G",
"Key 7 B",
"Key 8 R",
"Key 8 G",
"Key 8 B",
"Key 9 R",
"Key 9 G",
"Key 9 B",
"Key 10 R",
"Key 10 G",
"Key 10 B",
"Key 11 R",
"Key 11 G",
"Key 11 B",
"Key 12 R",
"Key 12 G",
"Key 12 B",
"Key 13 R",
"Key 13 G",
"Key 13 B",
"Key 14 R",
"Key 14 G",
"Key 14 B",
"Key 15 R",
"Key 15 G",
"Key 15 B",
"Key 16 R",
"Key 16 G",
"Key 16 B",
"Key 17 R",
"Key 17 G",
"Key 17 B",
"Key 18 R",
"Key 18 G",
"Key 18 B",
"Key 19 R",
"Key 19 G",
"Key 19 B",
"Key 20 R",
"Key 20 G",
"Key 20 B",
"Key 21 R",
"Key 21 G",
"Key 21 B",
"Key 22 R",
"Key 22 G",
"Key 22 B",
"Key 23 R",
"Key 23 G",
"Key 23 B",
"Key 24 R",
"Key 24 G",
"Key 24 B",
"Key 25 R",
"Key 25 G",
"Key 25 B",
"Key 26 R",
"Key 26 G",
"Key 26 B",
"Key 27 R",
"Key 27 G",
"Key 27 B",
"Key 28 R",
"Key 28 G",
"Key 28 B"
);
}
return lights;
}
+179 -179
View File
@@ -1,179 +1,179 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::nost {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
Key1,
Key2,
Key3,
Key4,
Key5,
Key6,
Key7,
Key8,
Key9,
Key10,
Key11,
Key12,
Key13,
Key14,
Key15,
Key16,
Key17,
Key18,
Key19,
Key20,
Key21,
Key22,
Key23,
Key24,
Key25,
Key26,
Key27,
Key28,
};
}
// all analogs in correct order
namespace Analogs {
enum {
Key1,
Key2,
Key3,
Key4,
Key5,
Key6,
Key7,
Key8,
Key9,
Key10,
Key11,
Key12,
Key13,
Key14,
Key15,
Key16,
Key17,
Key18,
Key19,
Key20,
Key21,
Key22,
Key23,
Key24,
Key25,
Key26,
Key27,
Key28,
};
}
// all lights in correct order
namespace Lights {
enum {
TitleR,
TitleG,
TitleB,
BottomR,
BottomG,
BottomB,
Key1R,
Key1G,
Key1B,
Key2R,
Key2G,
Key2B,
Key3R,
Key3G,
Key3B,
Key4R,
Key4G,
Key4B,
Key5R,
Key5G,
Key5B,
Key6R,
Key6G,
Key6B,
Key7R,
Key7G,
Key7B,
Key8R,
Key8G,
Key8B,
Key9R,
Key9G,
Key9B,
Key10R,
Key10G,
Key10B,
Key11R,
Key11G,
Key11B,
Key12R,
Key12G,
Key12B,
Key13R,
Key13G,
Key13B,
Key14R,
Key14G,
Key14B,
Key15R,
Key15G,
Key15B,
Key16R,
Key16G,
Key16B,
Key17R,
Key17G,
Key17B,
Key18R,
Key18G,
Key18B,
Key19R,
Key19G,
Key19B,
Key20R,
Key20G,
Key20B,
Key21R,
Key21G,
Key21B,
Key22R,
Key22G,
Key22B,
Key23R,
Key23G,
Key23B,
Key24R,
Key24G,
Key24B,
Key25R,
Key25G,
Key25B,
Key26R,
Key26G,
Key26B,
Key27R,
Key27G,
Key27B,
Key28R,
Key28G,
Key28B,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::nost {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
Key1,
Key2,
Key3,
Key4,
Key5,
Key6,
Key7,
Key8,
Key9,
Key10,
Key11,
Key12,
Key13,
Key14,
Key15,
Key16,
Key17,
Key18,
Key19,
Key20,
Key21,
Key22,
Key23,
Key24,
Key25,
Key26,
Key27,
Key28,
};
}
// all analogs in correct order
namespace Analogs {
enum {
Key1,
Key2,
Key3,
Key4,
Key5,
Key6,
Key7,
Key8,
Key9,
Key10,
Key11,
Key12,
Key13,
Key14,
Key15,
Key16,
Key17,
Key18,
Key19,
Key20,
Key21,
Key22,
Key23,
Key24,
Key25,
Key26,
Key27,
Key28,
};
}
// all lights in correct order
namespace Lights {
enum {
TitleR,
TitleG,
TitleB,
BottomR,
BottomG,
BottomB,
Key1R,
Key1G,
Key1B,
Key2R,
Key2G,
Key2B,
Key3R,
Key3G,
Key3B,
Key4R,
Key4G,
Key4B,
Key5R,
Key5G,
Key5B,
Key6R,
Key6G,
Key6B,
Key7R,
Key7G,
Key7B,
Key8R,
Key8G,
Key8B,
Key9R,
Key9G,
Key9B,
Key10R,
Key10G,
Key10B,
Key11R,
Key11G,
Key11B,
Key12R,
Key12G,
Key12B,
Key13R,
Key13G,
Key13B,
Key14R,
Key14G,
Key14B,
Key15R,
Key15G,
Key15B,
Key16R,
Key16G,
Key16B,
Key17R,
Key17G,
Key17B,
Key18R,
Key18G,
Key18B,
Key19R,
Key19G,
Key19B,
Key20R,
Key20G,
Key20B,
Key21R,
Key21G,
Key21B,
Key22R,
Key22G,
Key22B,
Key23R,
Key23G,
Key23B,
Key24R,
Key24G,
Key24B,
Key25R,
Key25G,
Key25B,
Key26R,
Key26G,
Key26B,
Key27R,
Key27G,
Key27B,
Key28R,
Key28G,
Key28B,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
+46 -46
View File
@@ -1,46 +1,46 @@
// enable touch functions - set version to windows 7
// mingw otherwise doesn't load touch stuff
#define _WIN32_WINNT 0x0601
#include "nost.h"
#include "hooks/setupapihook.h"
#include "misc/wintouchemu.h"
#include "avs/game.h"
namespace games::nost {
NostGame::NostGame() : Game("Nostalgia") {
}
void NostGame::attach() {
Game::attach();
// fake touchscreen
///////////////////
SETUPAPI_SETTINGS touch_settings{};
// GUID must be set to 0 to make SETUPAPI hook working
touch_settings.class_guid[0] = 0x00000000;
touch_settings.class_guid[1] = 0x00000000;
touch_settings.class_guid[2] = 0x00000000;
touch_settings.class_guid[3] = 0x00000000;
/*
* set hardware ID containing VID and PID
* there is 3 known VID/PID combinations known to the game:
* VID_04DD&PID_97CB
* VID_0EEF&PID_C000
* VID_29BD&PID_4101
*/
const char touch_hardwareid[] = "VID_29BD&PID_4101";
memcpy(touch_settings.property_hardwareid, touch_hardwareid, sizeof(touch_hardwareid));
// apply settings
setupapihook_init(avs::game::DLL_INSTANCE);
setupapihook_add(touch_settings);
// custom touch
wintouchemu::hook("nostalgia", avs::game::DLL_INSTANCE);
}
}
// enable touch functions - set version to windows 7
// mingw otherwise doesn't load touch stuff
#define _WIN32_WINNT 0x0601
#include "nost.h"
#include "hooks/setupapihook.h"
#include "misc/wintouchemu.h"
#include "avs/game.h"
namespace games::nost {
NostGame::NostGame() : Game("Nostalgia") {
}
void NostGame::attach() {
Game::attach();
// fake touchscreen
///////////////////
SETUPAPI_SETTINGS touch_settings{};
// GUID must be set to 0 to make SETUPAPI hook working
touch_settings.class_guid[0] = 0x00000000;
touch_settings.class_guid[1] = 0x00000000;
touch_settings.class_guid[2] = 0x00000000;
touch_settings.class_guid[3] = 0x00000000;
/*
* set hardware ID containing VID and PID
* there is 3 known VID/PID combinations known to the game:
* VID_04DD&PID_97CB
* VID_0EEF&PID_C000
* VID_29BD&PID_4101
*/
const char touch_hardwareid[] = "VID_29BD&PID_4101";
memcpy(touch_settings.property_hardwareid, touch_hardwareid, sizeof(touch_hardwareid));
// apply settings
setupapihook_init(avs::game::DLL_INSTANCE);
setupapihook_add(touch_settings);
// custom touch
wintouchemu::hook("nostalgia", avs::game::DLL_INSTANCE);
}
}
+12 -12
View File
@@ -1,12 +1,12 @@
#pragma once
#include "games/game.h"
namespace games::nost {
class NostGame : public games::Game {
public:
NostGame();
virtual void attach() override;
};
}
#pragma once
#include "games/game.h"
namespace games::nost {
class NostGame : public games::Game {
public:
NostGame();
virtual void attach() override;
};
}
+40 -40
View File
@@ -1,40 +1,40 @@
#include "io.h"
std::vector<Button> &games::otoca::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Otoca D'or");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"Button Left",
"Button Right",
"Lever Up",
"Lever Down",
"Lever Left",
"Lever Right"
);
}
return buttons;
}
std::vector<Light> &games::otoca::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Otoca D'or");
GameAPI::Lights::sortLights(
&lights,
"Left Button",
"Right Button"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::otoca::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Otoca D'or");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"Button Left",
"Button Right",
"Lever Up",
"Lever Down",
"Lever Left",
"Lever Right"
);
}
return buttons;
}
std::vector<Light> &games::otoca::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Otoca D'or");
GameAPI::Lights::sortLights(
&lights,
"Left Button",
"Right Button"
);
}
return lights;
}
+34 -34
View File
@@ -1,34 +1,34 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::otoca {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
ButtonLeft,
ButtonRight,
LeverUp,
LeverDown,
LeverLeft,
LeverRight,
};
}
// all lights in correct order
namespace Lights {
enum {
LeftButton,
RightButton,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::otoca {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
ButtonLeft,
ButtonRight,
LeverUp,
LeverDown,
LeverLeft,
LeverRight,
};
}
// all lights in correct order
namespace Lights {
enum {
LeftButton,
RightButton,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
+27 -27
View File
@@ -1,27 +1,27 @@
#include "otoca.h"
#include "p4io.h"
#include "games/shared/printer.h"
#include "util/libutils.h"
namespace games::otoca {
OtocaGame::OtocaGame() : Game("Otoca D'or") {
}
OtocaGame::~OtocaGame() {
}
void OtocaGame::attach() {
Game::attach();
/*
* arkkep.dll uses LoadLibrary to access game.dll
* we preload it so that hooks (e.g. for graphics) will work
*/
libutils::try_library("game.dll");
// initialize IO hooks
p4io_hook();
games::shared::printer_attach();
}
}
#include "otoca.h"
#include "p4io.h"
#include "games/shared/printer.h"
#include "util/libutils.h"
namespace games::otoca {
OtocaGame::OtocaGame() : Game("Otoca D'or") {
}
OtocaGame::~OtocaGame() {
}
void OtocaGame::attach() {
Game::attach();
/*
* arkkep.dll uses LoadLibrary to access game.dll
* we preload it so that hooks (e.g. for graphics) will work
*/
libutils::try_library("game.dll");
// initialize IO hooks
p4io_hook();
games::shared::printer_attach();
}
}
+14 -14
View File
@@ -1,14 +1,14 @@
#pragma once
#include "games/game.h"
namespace games::otoca {
class OtocaGame : public games::Game {
public:
OtocaGame();
~OtocaGame() override;
virtual void attach() override;
};
}
#pragma once
#include "games/game.h"
namespace games::otoca {
class OtocaGame : public games::Game {
public:
OtocaGame();
~OtocaGame() override;
virtual void attach() override;
};
}
+133 -133
View File
@@ -1,133 +1,133 @@
#include "p4io.h"
#include "util/logging.h"
#include "util/detour.h"
#include "misc/eamuse.h"
#include "acio/icca/icca.h"
#include "rawinput/rawinput.h"
#include "io.h"
namespace games::otoca {
// button mapping
static size_t MAPPING[] {
~0u,
Buttons::Test,
Buttons::Service,
Buttons::CoinMech,
~0u,
Buttons::LeverUp,
Buttons::LeverDown,
Buttons::LeverLeft,
Buttons::LeverRight,
Buttons::ButtonLeft,
Buttons::ButtonRight,
~0u,
~0u,
};
static uint8_t INPUT_STATE[std::size(MAPPING)] {};
static uint8_t *CARD_DATA = nullptr;
static int __cdecl P4io_Boot_step() {
return 1;
}
static int __cdecl P4ioInputIsOn(int input_no) {
if (input_no < (int) std::size(MAPPING)) {
return INPUT_STATE[input_no] > 0 && INPUT_STATE[input_no] < 3;
}
return 0;
}
static bool __cdecl P4ioInputIsOnTrg(int input_no) {
if (input_no < (int) std::size(MAPPING)) {
return INPUT_STATE[input_no] == 1;
}
return 0;
}
static bool __cdecl P4ioInputIsOffTrg(int input_no) {
if (input_no < (int) std::size(MAPPING)) {
return INPUT_STATE[input_no] == 3;
}
return 0;
}
static void __cdecl P4ioInput_Polling() {
auto &buttons = get_buttons();
for (size_t i = 0; i < std::size(MAPPING); i++) {
if (MAPPING[i] != ~0u) {
// reset release event
if (INPUT_STATE[i] == 3) {
INPUT_STATE[i] = 0;
}
// apply new button state
auto state = GameAPI::Buttons::getState(RI_MGR, buttons.at(MAPPING[i]));
if (state && INPUT_STATE[i] < 2) {
INPUT_STATE[i]++;
} else if (!state && INPUT_STATE[i] > 0 && INPUT_STATE[i] < 3) {
INPUT_STATE[i] = 3;
}
}
}
}
static int __cdecl P4ioOutputPolling(uint32_t data) {
auto &lights = get_lights();
GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::LeftButton), (data & 1) ? 1.f : 0.f);
GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::RightButton), (data & 2) ? 1.f : 0.f);
RI_MGR->devices_flush_output();
return 0;
}
static int __cdecl P4ioCoinCount() {
return eamuse_coin_get_stock();
}
static bool __cdecl P4ioInputIsICCardHold() {
bool kb_insert_press = false;
// eamio keypress
kb_insert_press |= eamuse_get_keypad_state(0) & (1 << EAM_IO_INSERT);
// check for card
if (CARD_DATA == nullptr && (eamuse_card_insert_consume(1, 0) || kb_insert_press)) {
auto card = new uint8_t[8];
if (!eamuse_get_card(1, 0, card)) {
// invalid card found
delete[] card;
} else {
CARD_DATA = card;
}
}
// check if hold
return CARD_DATA != nullptr;
}
static void __cdecl P4ioInputIsICCardRead(uint8_t *data) {
if (CARD_DATA != nullptr) {
memcpy(data, CARD_DATA, 8);
}
}
void p4io_hook() {
detour::iat_try("?P4io_Boot_step@@YA?AW4P4IO_STATUS@@XZ", P4io_Boot_step);
detour::iat_try("?P4ioInputIsOn@@YAHH@Z", P4ioInputIsOn);
detour::iat_try("?P4ioInputIsOnTrg@@YAHH@Z", P4ioInputIsOnTrg);
detour::iat_try("?P4ioInputIsOffTrg@@YAHH@Z", P4ioInputIsOffTrg);
detour::iat_try("?P4ioInput_Polling@@YAXXZ", P4ioInput_Polling);
detour::iat_try("?P4ioOutputPolling@@YAHU_P4IO_POLLING_DATA_t@@@Z", P4ioOutputPolling);
detour::iat_try("?P4ioCoinCount@@YAHXZ", P4ioCoinCount);
detour::iat_try("?P4ioInputIsICCardHold@@YA_NXZ", (void*) P4ioInputIsICCardHold);
detour::iat_try("?P4ioInputIsICCardRead@@YAXPAU_P4IO_ICCARDDATA@@@Z", P4ioInputIsICCardRead);
}
}
#include "p4io.h"
#include "util/logging.h"
#include "util/detour.h"
#include "misc/eamuse.h"
#include "acio/icca/icca.h"
#include "rawinput/rawinput.h"
#include "io.h"
namespace games::otoca {
// button mapping
static size_t MAPPING[] {
~0u,
Buttons::Test,
Buttons::Service,
Buttons::CoinMech,
~0u,
Buttons::LeverUp,
Buttons::LeverDown,
Buttons::LeverLeft,
Buttons::LeverRight,
Buttons::ButtonLeft,
Buttons::ButtonRight,
~0u,
~0u,
};
static uint8_t INPUT_STATE[std::size(MAPPING)] {};
static uint8_t *CARD_DATA = nullptr;
static int __cdecl P4io_Boot_step() {
return 1;
}
static int __cdecl P4ioInputIsOn(int input_no) {
if (input_no < (int) std::size(MAPPING)) {
return INPUT_STATE[input_no] > 0 && INPUT_STATE[input_no] < 3;
}
return 0;
}
static bool __cdecl P4ioInputIsOnTrg(int input_no) {
if (input_no < (int) std::size(MAPPING)) {
return INPUT_STATE[input_no] == 1;
}
return 0;
}
static bool __cdecl P4ioInputIsOffTrg(int input_no) {
if (input_no < (int) std::size(MAPPING)) {
return INPUT_STATE[input_no] == 3;
}
return 0;
}
static void __cdecl P4ioInput_Polling() {
auto &buttons = get_buttons();
for (size_t i = 0; i < std::size(MAPPING); i++) {
if (MAPPING[i] != ~0u) {
// reset release event
if (INPUT_STATE[i] == 3) {
INPUT_STATE[i] = 0;
}
// apply new button state
auto state = GameAPI::Buttons::getState(RI_MGR, buttons.at(MAPPING[i]));
if (state && INPUT_STATE[i] < 2) {
INPUT_STATE[i]++;
} else if (!state && INPUT_STATE[i] > 0 && INPUT_STATE[i] < 3) {
INPUT_STATE[i] = 3;
}
}
}
}
static int __cdecl P4ioOutputPolling(uint32_t data) {
auto &lights = get_lights();
GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::LeftButton), (data & 1) ? 1.f : 0.f);
GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::RightButton), (data & 2) ? 1.f : 0.f);
RI_MGR->devices_flush_output();
return 0;
}
static int __cdecl P4ioCoinCount() {
return eamuse_coin_get_stock();
}
static bool __cdecl P4ioInputIsICCardHold() {
bool kb_insert_press = false;
// eamio keypress
kb_insert_press |= eamuse_get_keypad_state(0) & (1 << EAM_IO_INSERT);
// check for card
if (CARD_DATA == nullptr && (eamuse_card_insert_consume(1, 0) || kb_insert_press)) {
auto card = new uint8_t[8];
if (!eamuse_get_card(1, 0, card)) {
// invalid card found
delete[] card;
} else {
CARD_DATA = card;
}
}
// check if hold
return CARD_DATA != nullptr;
}
static void __cdecl P4ioInputIsICCardRead(uint8_t *data) {
if (CARD_DATA != nullptr) {
memcpy(data, CARD_DATA, 8);
}
}
void p4io_hook() {
detour::iat_try("?P4io_Boot_step@@YA?AW4P4IO_STATUS@@XZ", P4io_Boot_step);
detour::iat_try("?P4ioInputIsOn@@YAHH@Z", P4ioInputIsOn);
detour::iat_try("?P4ioInputIsOnTrg@@YAHH@Z", P4ioInputIsOnTrg);
detour::iat_try("?P4ioInputIsOffTrg@@YAHH@Z", P4ioInputIsOffTrg);
detour::iat_try("?P4ioInput_Polling@@YAXXZ", P4ioInput_Polling);
detour::iat_try("?P4ioOutputPolling@@YAHU_P4IO_POLLING_DATA_t@@@Z", P4ioOutputPolling);
detour::iat_try("?P4ioCoinCount@@YAHXZ", P4ioCoinCount);
detour::iat_try("?P4ioInputIsICCardHold@@YA_NXZ", (void*) P4ioInputIsICCardHold);
detour::iat_try("?P4ioInputIsICCardRead@@YAXPAU_P4IO_ICCARDDATA@@@Z", P4ioInputIsICCardRead);
}
}
+6 -6
View File
@@ -1,6 +1,6 @@
#pragma once
namespace games::otoca {
void p4io_hook();
}
#pragma once
namespace games::otoca {
void p4io_hook();
}
+22 -22
View File
@@ -1,22 +1,22 @@
#include "io.h"
namespace games::pcm {
std::vector <Button> &get_buttons() {
static std::vector <Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Charge Machine");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Insert 1000 Yen Bill",
"Insert 2000 Yen Bill",
"Insert 5000 Yen Bill",
"Insert 10000 Yen Bill"
);
}
return buttons;
}
}
#include "io.h"
namespace games::pcm {
std::vector <Button> &get_buttons() {
static std::vector <Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Charge Machine");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Insert 1000 Yen Bill",
"Insert 2000 Yen Bill",
"Insert 5000 Yen Bill",
"Insert 10000 Yen Bill"
);
}
return buttons;
}
}
+20 -20
View File
@@ -1,20 +1,20 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::pcm {
namespace Buttons {
enum {
Service,
Test,
Insert1000YenBill,
Insert2000YenBill,
Insert5000YenBill,
Insert10000YenBill,
};
}
std::vector <Button> &get_buttons();
};
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::pcm {
namespace Buttons {
enum {
Service,
Test,
Insert1000YenBill,
Insert2000YenBill,
Insert5000YenBill,
Insert10000YenBill,
};
}
std::vector <Button> &get_buttons();
};
+118 -118
View File
@@ -1,118 +1,118 @@
#include "pcm.h"
#include "io.h"
#include "misc/wintouchemu.h"
#include "util/detour.h"
#include "util/utils.h"
#include "util/libutils.h"
namespace games::pcm {
uint32_t *(__cdecl *GsIo_GetState_orig)(uint32_t *state);
static int BillKind = 0;
static int __cdecl BillVali_GetEscrowBillKind() {
return BillKind;
}
static int __cdecl BillVali_GetCurrentStep() {
return 0;
}
static int __cdecl BillVali_GetError() {
return 1;
}
static char __cdecl BillVali_IsEscrowNow() {
auto &buttons = games::pcm::get_buttons();
if (GameAPI::Buttons::getState(RI_MGR, buttons[games::pcm::Buttons::Insert1000YenBill])) {
log_misc("pcm", "1000 yen bill inserted");
BillKind = 1;
return true;
}
if (GameAPI::Buttons::getState(RI_MGR, buttons[games::pcm::Buttons::Insert2000YenBill])) {
log_misc("pcm", "2000 yen bill inserted");
BillKind = 2;
return true;
}
if (GameAPI::Buttons::getState(RI_MGR, buttons[games::pcm::Buttons::Insert5000YenBill])) {
log_misc("pcm", "5000 yen bill inserted");
BillKind = 3;
return true;
}
if (GameAPI::Buttons::getState(RI_MGR, buttons[games::pcm::Buttons::Insert10000YenBill])) {
log_misc("pcm", "10000 yen bill inserted");
BillKind = 4;
return true;
}
return false;
}
static bool __cdecl BillVali_IsIdling() {
return true;
}
static bool __cdecl BillVali_IsReady() {
return true;
}
static bool __cdecl BillVali_IsWaiting() {
return true;
}
static int __cdecl BillVali_GetReceivedBill() {
static int bills_received = 0;
return ++bills_received;
}
static bool __cdecl BillVali_ReceiveBill(int) {
return true;
}
static uint32_t* __cdecl GsIo_GetState_hook(uint32_t *state) {
GsIo_GetState_orig(state);
// "bill validator is happy" flag :]
*state |= 4;
return state;
}
PCMGame::PCMGame() : Game("Charge Machine") {}
void PCMGame::attach() {
Game::attach();
// system.dll doesn't get loaded until later so load it now for hooking.
HMODULE system = libutils::try_library("system.dll");
// apply hooks
detour::trampoline("system.dll", "?GetState@GsIo@@SA?BVSTATE@1@XZ",
GsIo_GetState_hook, &GsIo_GetState_orig);
detour::inline_hook(BillVali_GetCurrentStep, libutils::try_proc(
system, "?GetCurrentStep@GsBillVali@@SAHXZ"));
detour::inline_hook(BillVali_GetError, libutils::try_proc(
system, "?GetError@GsBillVali@@SAHXZ"));
detour::inline_hook(BillVali_GetReceivedBill, libutils::try_proc(
system, "?GetReceivedBill@GsBillVali@@SAHXZ"));
detour::inline_hook(BillVali_IsEscrowNow, libutils::try_proc(
system, "?IsEscrowNow@GsBillVali@@SA_NXZ"));
detour::inline_hook(BillVali_IsIdling, libutils::try_proc(
system, "?IsIdling@GsBillVali@@SA_NXZ"));
detour::inline_hook(BillVali_IsWaiting, libutils::try_proc(
system, "?IsWaiting@GsBillVali@@SA_NXZ"));
detour::inline_hook(BillVali_IsReady, libutils::try_proc(
system, "?IsReady@GsBillVali@@SA_NXZ"));
detour::inline_hook(BillVali_ReceiveBill, libutils::try_proc(
system, "?ReceiveBill@GsBillVali@@SA_NH@Z"));
detour::inline_hook(BillVali_GetEscrowBillKind, libutils::try_proc(
system, "?GetEscrowBillKind@GsBillVali@@SAHXZ"));
}
}
#include "pcm.h"
#include "io.h"
#include "misc/wintouchemu.h"
#include "util/detour.h"
#include "util/utils.h"
#include "util/libutils.h"
namespace games::pcm {
uint32_t *(__cdecl *GsIo_GetState_orig)(uint32_t *state);
static int BillKind = 0;
static int __cdecl BillVali_GetEscrowBillKind() {
return BillKind;
}
static int __cdecl BillVali_GetCurrentStep() {
return 0;
}
static int __cdecl BillVali_GetError() {
return 1;
}
static char __cdecl BillVali_IsEscrowNow() {
auto &buttons = games::pcm::get_buttons();
if (GameAPI::Buttons::getState(RI_MGR, buttons[games::pcm::Buttons::Insert1000YenBill])) {
log_misc("pcm", "1000 yen bill inserted");
BillKind = 1;
return true;
}
if (GameAPI::Buttons::getState(RI_MGR, buttons[games::pcm::Buttons::Insert2000YenBill])) {
log_misc("pcm", "2000 yen bill inserted");
BillKind = 2;
return true;
}
if (GameAPI::Buttons::getState(RI_MGR, buttons[games::pcm::Buttons::Insert5000YenBill])) {
log_misc("pcm", "5000 yen bill inserted");
BillKind = 3;
return true;
}
if (GameAPI::Buttons::getState(RI_MGR, buttons[games::pcm::Buttons::Insert10000YenBill])) {
log_misc("pcm", "10000 yen bill inserted");
BillKind = 4;
return true;
}
return false;
}
static bool __cdecl BillVali_IsIdling() {
return true;
}
static bool __cdecl BillVali_IsReady() {
return true;
}
static bool __cdecl BillVali_IsWaiting() {
return true;
}
static int __cdecl BillVali_GetReceivedBill() {
static int bills_received = 0;
return ++bills_received;
}
static bool __cdecl BillVali_ReceiveBill(int) {
return true;
}
static uint32_t* __cdecl GsIo_GetState_hook(uint32_t *state) {
GsIo_GetState_orig(state);
// "bill validator is happy" flag :]
*state |= 4;
return state;
}
PCMGame::PCMGame() : Game("Charge Machine") {}
void PCMGame::attach() {
Game::attach();
// system.dll doesn't get loaded until later so load it now for hooking.
HMODULE system = libutils::try_library("system.dll");
// apply hooks
detour::trampoline("system.dll", "?GetState@GsIo@@SA?BVSTATE@1@XZ",
GsIo_GetState_hook, &GsIo_GetState_orig);
detour::inline_hook(BillVali_GetCurrentStep, libutils::try_proc(
system, "?GetCurrentStep@GsBillVali@@SAHXZ"));
detour::inline_hook(BillVali_GetError, libutils::try_proc(
system, "?GetError@GsBillVali@@SAHXZ"));
detour::inline_hook(BillVali_GetReceivedBill, libutils::try_proc(
system, "?GetReceivedBill@GsBillVali@@SAHXZ"));
detour::inline_hook(BillVali_IsEscrowNow, libutils::try_proc(
system, "?IsEscrowNow@GsBillVali@@SA_NXZ"));
detour::inline_hook(BillVali_IsIdling, libutils::try_proc(
system, "?IsIdling@GsBillVali@@SA_NXZ"));
detour::inline_hook(BillVali_IsWaiting, libutils::try_proc(
system, "?IsWaiting@GsBillVali@@SA_NXZ"));
detour::inline_hook(BillVali_IsReady, libutils::try_proc(
system, "?IsReady@GsBillVali@@SA_NXZ"));
detour::inline_hook(BillVali_ReceiveBill, libutils::try_proc(
system, "?ReceiveBill@GsBillVali@@SA_NH@Z"));
detour::inline_hook(BillVali_GetEscrowBillKind, libutils::try_proc(
system, "?GetEscrowBillKind@GsBillVali@@SAHXZ"));
}
}
+11 -11
View File
@@ -1,12 +1,12 @@
#pragma once
#include "games/game.h"
namespace games::pcm {
class PCMGame : public Game {
public:
PCMGame();
void attach() override;
};
#pragma once
#include "games/game.h"
namespace games::pcm {
class PCMGame : public Game {
public:
PCMGame();
void attach() override;
};
}
+94 -94
View File
@@ -1,94 +1,94 @@
#include "io.h"
std::vector<Button> &games::popn::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Pop'n Music");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"Button 1",
"Button 2",
"Button 3",
"Button 4",
"Button 5",
"Button 6",
"Button 7",
"Button 8",
"Button 9"
);
}
return buttons;
}
std::vector<Light> &games::popn::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Pop'n Music");
GameAPI::Lights::sortLights(
&lights,
"Button 1",
"Button 2",
"Button 3",
"Button 4",
"Button 5",
"Button 6",
"Button 7",
"Button 8",
"Button 9",
"Top LED 1",
"Top LED 2",
"Top LED 3",
"Top LED 4",
"Top LED 5",
"Top LED 6",
"Top LED 7",
"Top LED 8",
"Top LED 9",
"Top LED 10",
"Top LED 11",
"Top LED 12",
"Top LED 13",
"Top LED 14",
"Top LED 15",
"Top LED 16",
"Top LED 17",
"Top LED 18",
"Top LED 19",
"Top LED 20",
"Top LED 21",
"Top LED 22",
"Top LED 23",
"Top LED 24",
"Top LED 25",
"Top LED 26",
"Top LED 27",
"Top LED 28",
"Top LED 29",
"Top LED 30",
"Top LED 31",
"Top LED 32",
"Top LED R",
"Top LED G",
"Top LED B",
"Hi Lamp 1",
"Hi Lamp 2",
"Hi Lamp 3",
"Hi Lamp 4",
"Hi Lamp 5",
"Left Lamp 1",
"Left Lamp 2",
"Right Lamp 1",
"Right Lamp 2"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::popn::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Pop'n Music");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"Button 1",
"Button 2",
"Button 3",
"Button 4",
"Button 5",
"Button 6",
"Button 7",
"Button 8",
"Button 9"
);
}
return buttons;
}
std::vector<Light> &games::popn::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Pop'n Music");
GameAPI::Lights::sortLights(
&lights,
"Button 1",
"Button 2",
"Button 3",
"Button 4",
"Button 5",
"Button 6",
"Button 7",
"Button 8",
"Button 9",
"Top LED 1",
"Top LED 2",
"Top LED 3",
"Top LED 4",
"Top LED 5",
"Top LED 6",
"Top LED 7",
"Top LED 8",
"Top LED 9",
"Top LED 10",
"Top LED 11",
"Top LED 12",
"Top LED 13",
"Top LED 14",
"Top LED 15",
"Top LED 16",
"Top LED 17",
"Top LED 18",
"Top LED 19",
"Top LED 20",
"Top LED 21",
"Top LED 22",
"Top LED 23",
"Top LED 24",
"Top LED 25",
"Top LED 26",
"Top LED 27",
"Top LED 28",
"Top LED 29",
"Top LED 30",
"Top LED 31",
"Top LED 32",
"Top LED R",
"Top LED G",
"Top LED B",
"Hi Lamp 1",
"Hi Lamp 2",
"Hi Lamp 3",
"Hi Lamp 4",
"Hi Lamp 5",
"Left Lamp 1",
"Left Lamp 2",
"Right Lamp 1",
"Right Lamp 2"
);
}
return lights;
}
+88 -88
View File
@@ -1,88 +1,88 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::popn {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
Button1,
Button2,
Button3,
Button4,
Button5,
Button6,
Button7,
Button8,
Button9,
};
}
// all lights in correct order
namespace Lights {
enum {
Button1,
Button2,
Button3,
Button4,
Button5,
Button6,
Button7,
Button8,
Button9,
TopLED1,
TopLED2,
TopLED3,
TopLED4,
TopLED5,
TopLED6,
TopLED7,
TopLED8,
TopLED9,
TopLED10,
TopLED11,
TopLED12,
TopLED13,
TopLED14,
TopLED15,
TopLED16,
TopLED17,
TopLED18,
TopLED19,
TopLED20,
TopLED21,
TopLED22,
TopLED23,
TopLED24,
TopLED25,
TopLED26,
TopLED27,
TopLED28,
TopLED29,
TopLED30,
TopLED31,
TopLED32,
TopLED_R,
TopLED_G,
TopLED_B,
HiLamp1,
HiLamp2,
HiLamp3,
HiLamp4,
HiLamp5,
LeftLamp1,
LeftLamp2,
RightLamp1,
RightLamp2,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::popn {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
Button1,
Button2,
Button3,
Button4,
Button5,
Button6,
Button7,
Button8,
Button9,
};
}
// all lights in correct order
namespace Lights {
enum {
Button1,
Button2,
Button3,
Button4,
Button5,
Button6,
Button7,
Button8,
Button9,
TopLED1,
TopLED2,
TopLED3,
TopLED4,
TopLED5,
TopLED6,
TopLED7,
TopLED8,
TopLED9,
TopLED10,
TopLED11,
TopLED12,
TopLED13,
TopLED14,
TopLED15,
TopLED16,
TopLED17,
TopLED18,
TopLED19,
TopLED20,
TopLED21,
TopLED22,
TopLED23,
TopLED24,
TopLED25,
TopLED26,
TopLED27,
TopLED28,
TopLED29,
TopLED30,
TopLED31,
TopLED32,
TopLED_R,
TopLED_G,
TopLED_B,
HiLamp1,
HiLamp2,
HiLamp3,
HiLamp4,
HiLamp5,
LeftLamp1,
LeftLamp2,
RightLamp1,
RightLamp2,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
+299 -299
View File
@@ -1,299 +1,299 @@
#include "avs/game.h"
#include "popn.h"
#include <cstdint>
#include <cstring>
#include "rawinput/rawinput.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/utils.h"
#include "cfg/button.h"
#include "cfg/api.h"
#include "hooks/sleephook.h"
#include "launcher/launcher.h"
#include "launcher/logger.h"
#include "misc/eamuse.h"
#include "io.h"
namespace games::popn {
static int __cdecl usbCheckAlive() {
return 1;
}
static int __cdecl usbCheckSecurityNew() {
return 0;
}
static int __cdecl usbCoinGet() {
return eamuse_coin_get_stock();
}
static int __cdecl usbCoinMode() {
return 0;
}
static int __cdecl usbEnd() {
return 0;
}
static int __cdecl usbFirmResult() {
return 0;
}
static int __cdecl usbGetKEYID() {
return 0;
}
static int __cdecl usbGetSecurity() {
return 0;
}
static int __cdecl usbLamp(uint32_t lamp_bits) {
// get lights
auto &lights = get_lights();
// bit scan
static const size_t mapping[] = {
Lights::Button1,
Lights::Button2,
Lights::Button3,
Lights::Button4,
Lights::Button5,
Lights::Button6,
Lights::Button7,
Lights::Button8,
Lights::Button9,
Lights::HiLamp1,
Lights::HiLamp2,
Lights::HiLamp3,
Lights::HiLamp4,
Lights::HiLamp5,
Lights::LeftLamp1,
Lights::LeftLamp2,
Lights::RightLamp1,
Lights::RightLamp2,
};
// sw lamps
for (size_t i = 0; i < 9; i++) {
float value = (lamp_bits & (1 << (i + 23))) ? 1.f : 0.f;
GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[i]), value);
}
// neon lamps
for (size_t i = 0; i < 5; i++) {
float value = (lamp_bits & (1 << i)) ? 1.f : 0.f;
GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[i + 9]), value);
}
// screen lamps
for (size_t i = 0; i < 4; i++) {
float value = (lamp_bits & (1 << (i + 8))) ? 1.f : 0.f;
GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[i + 14]), value);
}
// flush output
RI_MGR->devices_flush_output();
// return no error
return 0;
}
static int __cdecl usbPadRead(unsigned int *pad_bits) {
// get buttons
auto &buttons = get_buttons();
// reset
*pad_bits = 0;
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Service))) {
*pad_bits |= 1 << 6;
}
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Test))) {
*pad_bits |= 1 << 7;
}
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::CoinMech))) {
*pad_bits |= 1 << 22;
}
// buttons
static const size_t mapping[] = {
Buttons::Button1,
Buttons::Button2,
Buttons::Button3,
Buttons::Button4,
Buttons::Button5,
Buttons::Button6,
Buttons::Button7,
Buttons::Button8,
Buttons::Button9,
};
for (size_t i = 0; i < 9; i++) {
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(mapping[i]))) {
*pad_bits |= 1 << (8 + i);
}
}
// return no error
return 0;
}
static int __cdecl usbPadReadLast(uint8_t *a1) {
memset(a1, 0, 40);
return 0;
}
static int __cdecl usbSecurityInit() {
return 0;
}
static int __cdecl usbSecurityInitDone() {
return 0;
}
static int __cdecl usbSecuritySearch() {
return 0;
}
static int __cdecl usbSecuritySearchDone() {
return 0;
}
static int __cdecl usbSecuritySelect() {
return 0;
}
static int __cdecl usbSecuritySelectDone() {
return 0;
}
static int __cdecl usbSetExtIo() {
return 0;
}
static int __cdecl usbStart() {
return 0;
}
static int __cdecl usbWdtReset() {
return 0;
}
static int __cdecl usbWdtStart() {
return 0;
}
static int __cdecl usbWdtStartDone() {
return 0;
}
static decltype(DeleteFileA)* DeleteFileA_real = nullptr;
static BOOL WINAPI DeleteFileA_hook(LPCSTR lpFileName) {
// fantasia deletes a bunch of drmfs files in dll_entry_init
if (string_begins_with(lpFileName, "D:\\L39\\contents")) {
return true;
}
return DeleteFileA_real(lpFileName);
}
static decltype(mixerSetControlDetails)* mixerSetControlDetails_real = nullptr;
static MMRESULT WINAPI mixerSetControlDetails_hook(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) {
mixerSetControlDetails_real(hmxobj, pmxcd, fdwDetails);
return MMSYSERR_NOERROR;
}
static bool log_hook(void *user, const std::string &data, logger::Style style, std::string &out) {
// get rid of the log spam
if (data.find(" I:CabinetSettingFile: label:") != std::string::npos) {
out.clear();
return true;
} else {
return false;
}
}
POPNGame::POPNGame() : Game("Pop'n Music") {
logger::hook_add(log_hook, this);
}
POPNGame::~POPNGame() {
logger::hook_remove(log_hook, this);
}
void POPNGame::pre_attach() {
Game::pre_attach();
// load without resolving references
// makes game not trigger DLLMain which results in an error due to missing EZUSB device
LoadLibraryExW((MODULE_PATH / "ezusb.dll").c_str(), nullptr, DONT_RESOLVE_DLL_REFERENCES);
}
void POPNGame::attach() {
Game::attach();
/*
* Fast Boot (TM) Patch
* Game tries to create some directories and if it fails it will sleep for 1 second
* We make it sleep 1ms each time instead
*/
hooks::sleep::init(999, 1);
DeleteFileA_real = detour::iat_try("DeleteFileA", DeleteFileA_hook, avs::game::DLL_INSTANCE);
mixerSetControlDetails_real = detour::iat_try("mixerSetControlDetails", mixerSetControlDetails_hook, avs::game::DLL_INSTANCE);
// EZUSB hooks
HINSTANCE ezusb = libutils::try_library("ezusb.dll");
if (ezusb) {
detour::inline_hook((void *) usbCheckAlive,
libutils::try_proc(ezusb, "?usbCheckAlive@@YAHXZ"));
detour::inline_hook((void *) usbCheckSecurityNew,
libutils::try_proc(ezusb, "?usbCheckSecurityNew@@YAHH@Z"));
detour::inline_hook((void *) usbCoinGet,
libutils::try_proc(ezusb, "?usbCoinGet@@YAHH@Z"));
detour::inline_hook((void *) usbCoinMode,
libutils::try_proc(ezusb, "?usbCoinMode@@YAHH@Z"));
detour::inline_hook((void *) usbEnd,
libutils::try_proc(ezusb, "?usbEnd@@YAHXZ"));
detour::inline_hook((void *) usbFirmResult,
libutils::try_proc(ezusb, "?usbFirmResult@@YAHXZ"));
detour::inline_hook((void *) usbGetKEYID,
libutils::try_proc(ezusb, "?usbGetKEYID@@YAHPAEH@Z"));
detour::inline_hook((void *) usbGetSecurity,
libutils::try_proc(ezusb, "?usbGetSecurity@@YAHHPAE@Z"));
detour::inline_hook((void *) usbLamp,
libutils::try_proc(ezusb, "?usbLamp@@YAHH@Z"));
detour::inline_hook((void *) usbPadRead,
libutils::try_proc(ezusb, "?usbPadRead@@YAHPAK@Z"));
detour::inline_hook((void *) usbPadReadLast,
libutils::try_proc(ezusb, "?usbPadReadLast@@YAHPAE@Z"));
detour::inline_hook((void *) usbSecurityInit,
libutils::try_proc(ezusb, "?usbSecurityInit@@YAHXZ"));
detour::inline_hook((void *) usbSecurityInitDone,
libutils::try_proc(ezusb, "?usbSecurityInitDone@@YAHXZ"));
detour::inline_hook((void *) usbSecuritySearch,
libutils::try_proc(ezusb, "?usbSecuritySearch@@YAHXZ"));
detour::inline_hook((void *) usbSecuritySearchDone,
libutils::try_proc(ezusb, "?usbSecuritySearchDone@@YAHXZ"));
detour::inline_hook((void *) usbSecuritySelect,
libutils::try_proc(ezusb, "?usbSecuritySelect@@YAHH@Z"));
detour::inline_hook((void *) usbSecuritySelectDone,
libutils::try_proc(ezusb, "?usbSecuritySelectDone@@YAHXZ"));
detour::inline_hook((void *) usbSetExtIo,
libutils::try_proc(ezusb, "?usbSetExtIo@@YAHH@Z"));
detour::inline_hook((void *) usbStart,
libutils::try_proc(ezusb, "?usbStart@@YAHH@Z"));
detour::inline_hook((void *) usbWdtReset,
libutils::try_proc(ezusb, "?usbWdtReset@@YAHXZ"));
detour::inline_hook((void *) usbWdtStart,
libutils::try_proc(ezusb, "?usbWdtStart@@YAHH@Z"));
detour::inline_hook((void *) usbWdtStartDone,
libutils::try_proc(ezusb, "?usbWdtStartDone@@YAHXZ"));
}
}
}
#include "avs/game.h"
#include "popn.h"
#include <cstdint>
#include <cstring>
#include "rawinput/rawinput.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/utils.h"
#include "cfg/button.h"
#include "cfg/api.h"
#include "hooks/sleephook.h"
#include "launcher/launcher.h"
#include "launcher/logger.h"
#include "misc/eamuse.h"
#include "io.h"
namespace games::popn {
static int __cdecl usbCheckAlive() {
return 1;
}
static int __cdecl usbCheckSecurityNew() {
return 0;
}
static int __cdecl usbCoinGet() {
return eamuse_coin_get_stock();
}
static int __cdecl usbCoinMode() {
return 0;
}
static int __cdecl usbEnd() {
return 0;
}
static int __cdecl usbFirmResult() {
return 0;
}
static int __cdecl usbGetKEYID() {
return 0;
}
static int __cdecl usbGetSecurity() {
return 0;
}
static int __cdecl usbLamp(uint32_t lamp_bits) {
// get lights
auto &lights = get_lights();
// bit scan
static const size_t mapping[] = {
Lights::Button1,
Lights::Button2,
Lights::Button3,
Lights::Button4,
Lights::Button5,
Lights::Button6,
Lights::Button7,
Lights::Button8,
Lights::Button9,
Lights::HiLamp1,
Lights::HiLamp2,
Lights::HiLamp3,
Lights::HiLamp4,
Lights::HiLamp5,
Lights::LeftLamp1,
Lights::LeftLamp2,
Lights::RightLamp1,
Lights::RightLamp2,
};
// sw lamps
for (size_t i = 0; i < 9; i++) {
float value = (lamp_bits & (1 << (i + 23))) ? 1.f : 0.f;
GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[i]), value);
}
// neon lamps
for (size_t i = 0; i < 5; i++) {
float value = (lamp_bits & (1 << i)) ? 1.f : 0.f;
GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[i + 9]), value);
}
// screen lamps
for (size_t i = 0; i < 4; i++) {
float value = (lamp_bits & (1 << (i + 8))) ? 1.f : 0.f;
GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[i + 14]), value);
}
// flush output
RI_MGR->devices_flush_output();
// return no error
return 0;
}
static int __cdecl usbPadRead(unsigned int *pad_bits) {
// get buttons
auto &buttons = get_buttons();
// reset
*pad_bits = 0;
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Service))) {
*pad_bits |= 1 << 6;
}
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::Test))) {
*pad_bits |= 1 << 7;
}
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(Buttons::CoinMech))) {
*pad_bits |= 1 << 22;
}
// buttons
static const size_t mapping[] = {
Buttons::Button1,
Buttons::Button2,
Buttons::Button3,
Buttons::Button4,
Buttons::Button5,
Buttons::Button6,
Buttons::Button7,
Buttons::Button8,
Buttons::Button9,
};
for (size_t i = 0; i < 9; i++) {
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(mapping[i]))) {
*pad_bits |= 1 << (8 + i);
}
}
// return no error
return 0;
}
static int __cdecl usbPadReadLast(uint8_t *a1) {
memset(a1, 0, 40);
return 0;
}
static int __cdecl usbSecurityInit() {
return 0;
}
static int __cdecl usbSecurityInitDone() {
return 0;
}
static int __cdecl usbSecuritySearch() {
return 0;
}
static int __cdecl usbSecuritySearchDone() {
return 0;
}
static int __cdecl usbSecuritySelect() {
return 0;
}
static int __cdecl usbSecuritySelectDone() {
return 0;
}
static int __cdecl usbSetExtIo() {
return 0;
}
static int __cdecl usbStart() {
return 0;
}
static int __cdecl usbWdtReset() {
return 0;
}
static int __cdecl usbWdtStart() {
return 0;
}
static int __cdecl usbWdtStartDone() {
return 0;
}
static decltype(DeleteFileA)* DeleteFileA_real = nullptr;
static BOOL WINAPI DeleteFileA_hook(LPCSTR lpFileName) {
// fantasia deletes a bunch of drmfs files in dll_entry_init
if (string_begins_with(lpFileName, "D:\\L39\\contents")) {
return true;
}
return DeleteFileA_real(lpFileName);
}
static decltype(mixerSetControlDetails)* mixerSetControlDetails_real = nullptr;
static MMRESULT WINAPI mixerSetControlDetails_hook(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) {
mixerSetControlDetails_real(hmxobj, pmxcd, fdwDetails);
return MMSYSERR_NOERROR;
}
static bool log_hook(void *user, const std::string &data, logger::Style style, std::string &out) {
// get rid of the log spam
if (data.find(" I:CabinetSettingFile: label:") != std::string::npos) {
out.clear();
return true;
} else {
return false;
}
}
POPNGame::POPNGame() : Game("Pop'n Music") {
logger::hook_add(log_hook, this);
}
POPNGame::~POPNGame() {
logger::hook_remove(log_hook, this);
}
void POPNGame::pre_attach() {
Game::pre_attach();
// load without resolving references
// makes game not trigger DLLMain which results in an error due to missing EZUSB device
LoadLibraryExW((MODULE_PATH / "ezusb.dll").c_str(), nullptr, DONT_RESOLVE_DLL_REFERENCES);
}
void POPNGame::attach() {
Game::attach();
/*
* Fast Boot (TM) Patch
* Game tries to create some directories and if it fails it will sleep for 1 second
* We make it sleep 1ms each time instead
*/
hooks::sleep::init(999, 1);
DeleteFileA_real = detour::iat_try("DeleteFileA", DeleteFileA_hook, avs::game::DLL_INSTANCE);
mixerSetControlDetails_real = detour::iat_try("mixerSetControlDetails", mixerSetControlDetails_hook, avs::game::DLL_INSTANCE);
// EZUSB hooks
HINSTANCE ezusb = libutils::try_library("ezusb.dll");
if (ezusb) {
detour::inline_hook((void *) usbCheckAlive,
libutils::try_proc(ezusb, "?usbCheckAlive@@YAHXZ"));
detour::inline_hook((void *) usbCheckSecurityNew,
libutils::try_proc(ezusb, "?usbCheckSecurityNew@@YAHH@Z"));
detour::inline_hook((void *) usbCoinGet,
libutils::try_proc(ezusb, "?usbCoinGet@@YAHH@Z"));
detour::inline_hook((void *) usbCoinMode,
libutils::try_proc(ezusb, "?usbCoinMode@@YAHH@Z"));
detour::inline_hook((void *) usbEnd,
libutils::try_proc(ezusb, "?usbEnd@@YAHXZ"));
detour::inline_hook((void *) usbFirmResult,
libutils::try_proc(ezusb, "?usbFirmResult@@YAHXZ"));
detour::inline_hook((void *) usbGetKEYID,
libutils::try_proc(ezusb, "?usbGetKEYID@@YAHPAEH@Z"));
detour::inline_hook((void *) usbGetSecurity,
libutils::try_proc(ezusb, "?usbGetSecurity@@YAHHPAE@Z"));
detour::inline_hook((void *) usbLamp,
libutils::try_proc(ezusb, "?usbLamp@@YAHH@Z"));
detour::inline_hook((void *) usbPadRead,
libutils::try_proc(ezusb, "?usbPadRead@@YAHPAK@Z"));
detour::inline_hook((void *) usbPadReadLast,
libutils::try_proc(ezusb, "?usbPadReadLast@@YAHPAE@Z"));
detour::inline_hook((void *) usbSecurityInit,
libutils::try_proc(ezusb, "?usbSecurityInit@@YAHXZ"));
detour::inline_hook((void *) usbSecurityInitDone,
libutils::try_proc(ezusb, "?usbSecurityInitDone@@YAHXZ"));
detour::inline_hook((void *) usbSecuritySearch,
libutils::try_proc(ezusb, "?usbSecuritySearch@@YAHXZ"));
detour::inline_hook((void *) usbSecuritySearchDone,
libutils::try_proc(ezusb, "?usbSecuritySearchDone@@YAHXZ"));
detour::inline_hook((void *) usbSecuritySelect,
libutils::try_proc(ezusb, "?usbSecuritySelect@@YAHH@Z"));
detour::inline_hook((void *) usbSecuritySelectDone,
libutils::try_proc(ezusb, "?usbSecuritySelectDone@@YAHXZ"));
detour::inline_hook((void *) usbSetExtIo,
libutils::try_proc(ezusb, "?usbSetExtIo@@YAHH@Z"));
detour::inline_hook((void *) usbStart,
libutils::try_proc(ezusb, "?usbStart@@YAHH@Z"));
detour::inline_hook((void *) usbWdtReset,
libutils::try_proc(ezusb, "?usbWdtReset@@YAHXZ"));
detour::inline_hook((void *) usbWdtStart,
libutils::try_proc(ezusb, "?usbWdtStart@@YAHH@Z"));
detour::inline_hook((void *) usbWdtStartDone,
libutils::try_proc(ezusb, "?usbWdtStartDone@@YAHXZ"));
}
}
}
+14 -14
View File
@@ -1,14 +1,14 @@
#pragma once
#include "games/game.h"
namespace games::popn {
class POPNGame : public games::Game {
public:
POPNGame();
~POPNGame() override;
virtual void pre_attach() override;
virtual void attach() override;
};
}
#pragma once
#include "games/game.h"
namespace games::popn {
class POPNGame : public games::Game {
public:
POPNGame();
~POPNGame() override;
virtual void pre_attach() override;
virtual void attach() override;
};
}
+301 -301
View File
@@ -1,301 +1,301 @@
#include "ezusb.h"
#include "cfg/api.h"
#include "cfg/button.h"
#include "misc/eamuse.h"
#include "rawinput/rawinput.h"
#include "touch/touch.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "io.h"
namespace games::qma {
static long DISPLAY_SIZE_X = 1360L;
static long DISPLAY_SIZE_Y = 768L;
std::array<bool, 39> TOUCH_STATUS = {};
std::array<int, 39> TOUCH_X_COORD = {230, 277, 323, 369, 417, 463, 510, 555, 601, 647, 695, 250, 296, 344, 389, 435, 483, 528, 575, 621, 667, 259, 308, 353, 398, 444, 491, 537, 582, 638, 280, 324, 370, 422, 465, 510, 557, 760, 759};
std::array<int, 39> TOUCH_Y_COORD = {642, 642, 642, 642, 642, 642, 642, 642, 642, 642, 642, 728, 728, 728, 728, 728, 728, 728, 728, 728, 728, 813, 813, 813, 813, 813, 813, 813, 813, 813, 894, 894, 894, 894, 894, 894, 894, 771, 886};
static int __cdecl usbCheckAlive() {
return 1;
}
static int __cdecl usbCheckSecurityNew() {
return 0;
}
static int __cdecl usbCoinGet() {
return eamuse_coin_get_stock();
}
static int __cdecl usbCoinMode() {
return 0;
}
static int __cdecl usbEnd() {
return 0;
}
static int __cdecl usbFirmResult() {
return 0;
}
static int __cdecl usbGetKEYID() {
return 0;
}
static int __cdecl usbGetSecurity() {
return 0;
}
static int __cdecl usbLamp(uint32_t lamp_bits) {
// get lights
auto &lights = get_lights();
// mapping
static const size_t bits[] = {
0x20, 0x40, 0x80,
0x08, 0x10, 0x20
};
static const size_t vals[] = {
Lights::LampRed, Lights::LampGreen, Lights::LampBlue,
Lights::ButtonLeft, Lights::ButtonRight, Lights::ButtonOK
};
for (size_t i = 0; i < 3; i++) {
float value = (lamp_bits & bits[i]) ? 1.f : 0.f;
GameAPI::Lights::writeLight(RI_MGR, lights.at(vals[i]), value);
}
// return no error
return 0;
}
static int __cdecl usbPadRead(unsigned int *pad_bits) {
// get buttons
auto &buttons = get_buttons();
// reset
*pad_bits = 0;
// mappings
static const struct {
size_t button, shift;
} mappings[] = {
{ Buttons::Service, 19 },
{ Buttons::Test, 18 },
{ Buttons::Select, 17 },
{ Buttons::CoinMech, 16 },
{ Buttons::Select1, 0 },
{ Buttons::Select2, 1 },
{ Buttons::OK, 2 },
{ Buttons::Left, 6 },
{ Buttons::Right, 7 },
{ Buttons::TouchKey1, 100 },
{ Buttons::TouchKey2, 101 },
{ Buttons::TouchKey3, 102 },
{ Buttons::TouchKey4, 103 },
{ Buttons::TouchKey5, 104 },
{ Buttons::TouchKey6, 105 },
{ Buttons::TouchKey7, 106 },
{ Buttons::TouchKey8, 107 },
{ Buttons::TouchKey9, 108 },
{ Buttons::TouchKey0, 109 },
{ Buttons::TouchKeyDash, 110 },
{ Buttons::TouchKeyQ, 111 },
{ Buttons::TouchKeyW, 112 },
{ Buttons::TouchKeyE, 113 },
{ Buttons::TouchKeyR, 114 },
{ Buttons::TouchKeyT, 115 },
{ Buttons::TouchKeyY, 116 },
{ Buttons::TouchKeyU, 117 },
{ Buttons::TouchKeyI, 118 },
{ Buttons::TouchKeyO, 119 },
{ Buttons::TouchKeyP, 120 },
{ Buttons::TouchKeyA, 121 },
{ Buttons::TouchKeyS, 122 },
{ Buttons::TouchKeyD, 123 },
{ Buttons::TouchKeyF, 124 },
{ Buttons::TouchKeyG, 125 },
{ Buttons::TouchKeyH, 126 },
{ Buttons::TouchKeyJ, 127 },
{ Buttons::TouchKeyK, 128 },
{ Buttons::TouchKeyL, 129 },
{ Buttons::TouchKeyZ, 130 },
{ Buttons::TouchKeyX, 131 },
{ Buttons::TouchKeyC, 132 },
{ Buttons::TouchKeyV, 133 },
{ Buttons::TouchKeyB, 134 },
{ Buttons::TouchKeyN, 135 },
{ Buttons::TouchKeyM, 136 },
{ Buttons::TouchKeyBackspace, 137 },
{ Buttons::TouchKeyEnter, 138 }
};
// set buttons
for (auto &mapping : mappings) {
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(mapping.button))) {
if (mapping.shift > 99) {
if (!TOUCH_STATUS[mapping.shift - 100]) {
static RECT display_rect;
GetWindowRect(GetDesktopWindow(), &display_rect);
DISPLAY_SIZE_X = display_rect.right - display_rect.left;
DISPLAY_SIZE_Y = display_rect.bottom - display_rect.top;
std::vector<TouchPoint> touch_write;
std::vector<DWORD> touch_point_ids;
TouchPoint tp {
.id = 0,
.x = (long)(TOUCH_X_COORD[mapping.shift - 100] * DISPLAY_SIZE_X / 1000),
.y = (long)(TOUCH_Y_COORD[mapping.shift - 100] * DISPLAY_SIZE_Y / 1000),
.mouse = false,
};
TOUCH_STATUS[mapping.shift - 100] = true;
touch_write.emplace_back(tp);
touch_write_points(&touch_write);
touch_point_ids.emplace_back(0);
touch_remove_points(&touch_point_ids);
}
continue;
} else {
*pad_bits |= 1 << mapping.shift;
}
} else {
if (mapping.shift > 99) {
TOUCH_STATUS[mapping.shift - 100] = false;
}
}
}
// return no error
return 0;
}
static int __cdecl usbPadReadLast(uint8_t *a1) {
memset(a1, 0, 40);
return 0;
}
static int __cdecl usbSecurityInit() {
return 0;
}
static int __cdecl usbSecurityInitDone() {
return 0;
}
static int __cdecl usbSecuritySearch() {
return 0;
}
static int __cdecl usbSecuritySearchDone() {
return 0;
}
static int __cdecl usbSecuritySelect() {
return 0;
}
static int __cdecl usbSecuritySelectDone() {
return 0;
}
static int __cdecl usbSetExtIo() {
return 0;
}
static int __cdecl usbStart() {
return 0;
}
static int __cdecl usbWdtReset() {
return 0;
}
static int __cdecl usbWdtStart() {
return 0;
}
static int __cdecl usbWdtStartDone() {
return 0;
}
static int __cdecl usbCoinBlocker(int a1) {
return 0;
}
static int __cdecl usbMute(int a1) {
return 0;
}
static int __cdecl usbIsHiSpeed() {
return 1;
}
void ezusb_init() {
TOUCH_STATUS.fill(false);
// load the library
HINSTANCE ezusb = libutils::try_library("ezusb.dll");
// insert hooks
if (ezusb) {
detour::inline_hook((void *) usbCheckAlive,
libutils::try_proc(ezusb, "?usbCheckAlive@@YAHXZ"));
detour::inline_hook((void *) usbCheckSecurityNew,
libutils::try_proc(ezusb, "?usbCheckSecurityNew@@YAHH@Z"));
detour::inline_hook((void *) usbCoinGet,
libutils::try_proc(ezusb, "?usbCoinGet@@YAHH@Z"));
detour::inline_hook((void *) usbCoinMode,
libutils::try_proc(ezusb, "?usbCoinMode@@YAHH@Z"));
detour::inline_hook((void *) usbEnd,
libutils::try_proc(ezusb, "?usbEnd@@YAHXZ"));
detour::inline_hook((void *) usbFirmResult,
libutils::try_proc(ezusb, "?usbFirmResult@@YAHXZ"));
detour::inline_hook((void *) usbGetKEYID,
libutils::try_proc(ezusb, "?usbGetKEYID@@YAHPAEH@Z"));
detour::inline_hook((void *) usbGetSecurity,
libutils::try_proc(ezusb, "?usbGetSecurity@@YAHHPAE@Z"));
detour::inline_hook((void *) usbLamp,
libutils::try_proc(ezusb, "?usbLamp@@YAHH@Z"));
detour::inline_hook((void *) usbPadRead,
libutils::try_proc(ezusb, "?usbPadRead@@YAHPAK@Z"));
detour::inline_hook((void *) usbPadReadLast,
libutils::try_proc(ezusb, "?usbPadReadLast@@YAHPAE@Z"));
detour::inline_hook((void *) usbSecurityInit,
libutils::try_proc(ezusb, "?usbSecurityInit@@YAHXZ"));
detour::inline_hook((void *) usbSecurityInitDone,
libutils::try_proc(ezusb, "?usbSecurityInitDone@@YAHXZ"));
detour::inline_hook((void *) usbSecuritySearch,
libutils::try_proc(ezusb, "?usbSecuritySearch@@YAHXZ"));
detour::inline_hook((void *) usbSecuritySearchDone,
libutils::try_proc(ezusb, "?usbSecuritySearchDone@@YAHXZ"));
detour::inline_hook((void *) usbSecuritySelect,
libutils::try_proc(ezusb, "?usbSecuritySelect@@YAHH@Z"));
detour::inline_hook((void *) usbSecuritySelectDone,
libutils::try_proc(ezusb, "?usbSecuritySelectDone@@YAHXZ"));
detour::inline_hook((void *) usbSetExtIo,
libutils::try_proc(ezusb, "?usbSetExtIo@@YAHH@Z"));
detour::inline_hook((void *) usbStart,
libutils::try_proc(ezusb, "?usbStart@@YAHH@Z"));
detour::inline_hook((void *) usbWdtReset,
libutils::try_proc(ezusb, "?usbWdtReset@@YAHXZ"));
detour::inline_hook((void *) usbWdtStart,
libutils::try_proc(ezusb, "?usbWdtStart@@YAHH@Z"));
detour::inline_hook((void *) usbWdtStartDone,
libutils::try_proc(ezusb, "?usbWdtStartDone@@YAHXZ"));
detour::inline_hook((void *) usbCoinBlocker,
libutils::try_proc(ezusb, "?usbCoinBlocker@@YAHH@Z"));
detour::inline_hook((void *) usbMute,
libutils::try_proc(ezusb, "?usbMute@@YAHH@Z"));
detour::inline_hook((void *) usbIsHiSpeed,
libutils::try_proc(ezusb, "?usbIsHiSpeed@@YAHXZ"));
}
}
}
#include "ezusb.h"
#include "cfg/api.h"
#include "cfg/button.h"
#include "misc/eamuse.h"
#include "rawinput/rawinput.h"
#include "touch/touch.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "io.h"
namespace games::qma {
static long DISPLAY_SIZE_X = 1360L;
static long DISPLAY_SIZE_Y = 768L;
std::array<bool, 39> TOUCH_STATUS = {};
std::array<int, 39> TOUCH_X_COORD = {230, 277, 323, 369, 417, 463, 510, 555, 601, 647, 695, 250, 296, 344, 389, 435, 483, 528, 575, 621, 667, 259, 308, 353, 398, 444, 491, 537, 582, 638, 280, 324, 370, 422, 465, 510, 557, 760, 759};
std::array<int, 39> TOUCH_Y_COORD = {642, 642, 642, 642, 642, 642, 642, 642, 642, 642, 642, 728, 728, 728, 728, 728, 728, 728, 728, 728, 728, 813, 813, 813, 813, 813, 813, 813, 813, 813, 894, 894, 894, 894, 894, 894, 894, 771, 886};
static int __cdecl usbCheckAlive() {
return 1;
}
static int __cdecl usbCheckSecurityNew() {
return 0;
}
static int __cdecl usbCoinGet() {
return eamuse_coin_get_stock();
}
static int __cdecl usbCoinMode() {
return 0;
}
static int __cdecl usbEnd() {
return 0;
}
static int __cdecl usbFirmResult() {
return 0;
}
static int __cdecl usbGetKEYID() {
return 0;
}
static int __cdecl usbGetSecurity() {
return 0;
}
static int __cdecl usbLamp(uint32_t lamp_bits) {
// get lights
auto &lights = get_lights();
// mapping
static const size_t bits[] = {
0x20, 0x40, 0x80,
0x08, 0x10, 0x20
};
static const size_t vals[] = {
Lights::LampRed, Lights::LampGreen, Lights::LampBlue,
Lights::ButtonLeft, Lights::ButtonRight, Lights::ButtonOK
};
for (size_t i = 0; i < 3; i++) {
float value = (lamp_bits & bits[i]) ? 1.f : 0.f;
GameAPI::Lights::writeLight(RI_MGR, lights.at(vals[i]), value);
}
// return no error
return 0;
}
static int __cdecl usbPadRead(unsigned int *pad_bits) {
// get buttons
auto &buttons = get_buttons();
// reset
*pad_bits = 0;
// mappings
static const struct {
size_t button, shift;
} mappings[] = {
{ Buttons::Service, 19 },
{ Buttons::Test, 18 },
{ Buttons::Select, 17 },
{ Buttons::CoinMech, 16 },
{ Buttons::Select1, 0 },
{ Buttons::Select2, 1 },
{ Buttons::OK, 2 },
{ Buttons::Left, 6 },
{ Buttons::Right, 7 },
{ Buttons::TouchKey1, 100 },
{ Buttons::TouchKey2, 101 },
{ Buttons::TouchKey3, 102 },
{ Buttons::TouchKey4, 103 },
{ Buttons::TouchKey5, 104 },
{ Buttons::TouchKey6, 105 },
{ Buttons::TouchKey7, 106 },
{ Buttons::TouchKey8, 107 },
{ Buttons::TouchKey9, 108 },
{ Buttons::TouchKey0, 109 },
{ Buttons::TouchKeyDash, 110 },
{ Buttons::TouchKeyQ, 111 },
{ Buttons::TouchKeyW, 112 },
{ Buttons::TouchKeyE, 113 },
{ Buttons::TouchKeyR, 114 },
{ Buttons::TouchKeyT, 115 },
{ Buttons::TouchKeyY, 116 },
{ Buttons::TouchKeyU, 117 },
{ Buttons::TouchKeyI, 118 },
{ Buttons::TouchKeyO, 119 },
{ Buttons::TouchKeyP, 120 },
{ Buttons::TouchKeyA, 121 },
{ Buttons::TouchKeyS, 122 },
{ Buttons::TouchKeyD, 123 },
{ Buttons::TouchKeyF, 124 },
{ Buttons::TouchKeyG, 125 },
{ Buttons::TouchKeyH, 126 },
{ Buttons::TouchKeyJ, 127 },
{ Buttons::TouchKeyK, 128 },
{ Buttons::TouchKeyL, 129 },
{ Buttons::TouchKeyZ, 130 },
{ Buttons::TouchKeyX, 131 },
{ Buttons::TouchKeyC, 132 },
{ Buttons::TouchKeyV, 133 },
{ Buttons::TouchKeyB, 134 },
{ Buttons::TouchKeyN, 135 },
{ Buttons::TouchKeyM, 136 },
{ Buttons::TouchKeyBackspace, 137 },
{ Buttons::TouchKeyEnter, 138 }
};
// set buttons
for (auto &mapping : mappings) {
if (GameAPI::Buttons::getState(RI_MGR, buttons.at(mapping.button))) {
if (mapping.shift > 99) {
if (!TOUCH_STATUS[mapping.shift - 100]) {
static RECT display_rect;
GetWindowRect(GetDesktopWindow(), &display_rect);
DISPLAY_SIZE_X = display_rect.right - display_rect.left;
DISPLAY_SIZE_Y = display_rect.bottom - display_rect.top;
std::vector<TouchPoint> touch_write;
std::vector<DWORD> touch_point_ids;
TouchPoint tp {
.id = 0,
.x = (long)(TOUCH_X_COORD[mapping.shift - 100] * DISPLAY_SIZE_X / 1000),
.y = (long)(TOUCH_Y_COORD[mapping.shift - 100] * DISPLAY_SIZE_Y / 1000),
.mouse = false,
};
TOUCH_STATUS[mapping.shift - 100] = true;
touch_write.emplace_back(tp);
touch_write_points(&touch_write);
touch_point_ids.emplace_back(0);
touch_remove_points(&touch_point_ids);
}
continue;
} else {
*pad_bits |= 1 << mapping.shift;
}
} else {
if (mapping.shift > 99) {
TOUCH_STATUS[mapping.shift - 100] = false;
}
}
}
// return no error
return 0;
}
static int __cdecl usbPadReadLast(uint8_t *a1) {
memset(a1, 0, 40);
return 0;
}
static int __cdecl usbSecurityInit() {
return 0;
}
static int __cdecl usbSecurityInitDone() {
return 0;
}
static int __cdecl usbSecuritySearch() {
return 0;
}
static int __cdecl usbSecuritySearchDone() {
return 0;
}
static int __cdecl usbSecuritySelect() {
return 0;
}
static int __cdecl usbSecuritySelectDone() {
return 0;
}
static int __cdecl usbSetExtIo() {
return 0;
}
static int __cdecl usbStart() {
return 0;
}
static int __cdecl usbWdtReset() {
return 0;
}
static int __cdecl usbWdtStart() {
return 0;
}
static int __cdecl usbWdtStartDone() {
return 0;
}
static int __cdecl usbCoinBlocker(int a1) {
return 0;
}
static int __cdecl usbMute(int a1) {
return 0;
}
static int __cdecl usbIsHiSpeed() {
return 1;
}
void ezusb_init() {
TOUCH_STATUS.fill(false);
// load the library
HINSTANCE ezusb = libutils::try_library("ezusb.dll");
// insert hooks
if (ezusb) {
detour::inline_hook((void *) usbCheckAlive,
libutils::try_proc(ezusb, "?usbCheckAlive@@YAHXZ"));
detour::inline_hook((void *) usbCheckSecurityNew,
libutils::try_proc(ezusb, "?usbCheckSecurityNew@@YAHH@Z"));
detour::inline_hook((void *) usbCoinGet,
libutils::try_proc(ezusb, "?usbCoinGet@@YAHH@Z"));
detour::inline_hook((void *) usbCoinMode,
libutils::try_proc(ezusb, "?usbCoinMode@@YAHH@Z"));
detour::inline_hook((void *) usbEnd,
libutils::try_proc(ezusb, "?usbEnd@@YAHXZ"));
detour::inline_hook((void *) usbFirmResult,
libutils::try_proc(ezusb, "?usbFirmResult@@YAHXZ"));
detour::inline_hook((void *) usbGetKEYID,
libutils::try_proc(ezusb, "?usbGetKEYID@@YAHPAEH@Z"));
detour::inline_hook((void *) usbGetSecurity,
libutils::try_proc(ezusb, "?usbGetSecurity@@YAHHPAE@Z"));
detour::inline_hook((void *) usbLamp,
libutils::try_proc(ezusb, "?usbLamp@@YAHH@Z"));
detour::inline_hook((void *) usbPadRead,
libutils::try_proc(ezusb, "?usbPadRead@@YAHPAK@Z"));
detour::inline_hook((void *) usbPadReadLast,
libutils::try_proc(ezusb, "?usbPadReadLast@@YAHPAE@Z"));
detour::inline_hook((void *) usbSecurityInit,
libutils::try_proc(ezusb, "?usbSecurityInit@@YAHXZ"));
detour::inline_hook((void *) usbSecurityInitDone,
libutils::try_proc(ezusb, "?usbSecurityInitDone@@YAHXZ"));
detour::inline_hook((void *) usbSecuritySearch,
libutils::try_proc(ezusb, "?usbSecuritySearch@@YAHXZ"));
detour::inline_hook((void *) usbSecuritySearchDone,
libutils::try_proc(ezusb, "?usbSecuritySearchDone@@YAHXZ"));
detour::inline_hook((void *) usbSecuritySelect,
libutils::try_proc(ezusb, "?usbSecuritySelect@@YAHH@Z"));
detour::inline_hook((void *) usbSecuritySelectDone,
libutils::try_proc(ezusb, "?usbSecuritySelectDone@@YAHXZ"));
detour::inline_hook((void *) usbSetExtIo,
libutils::try_proc(ezusb, "?usbSetExtIo@@YAHH@Z"));
detour::inline_hook((void *) usbStart,
libutils::try_proc(ezusb, "?usbStart@@YAHH@Z"));
detour::inline_hook((void *) usbWdtReset,
libutils::try_proc(ezusb, "?usbWdtReset@@YAHXZ"));
detour::inline_hook((void *) usbWdtStart,
libutils::try_proc(ezusb, "?usbWdtStart@@YAHH@Z"));
detour::inline_hook((void *) usbWdtStartDone,
libutils::try_proc(ezusb, "?usbWdtStartDone@@YAHXZ"));
detour::inline_hook((void *) usbCoinBlocker,
libutils::try_proc(ezusb, "?usbCoinBlocker@@YAHH@Z"));
detour::inline_hook((void *) usbMute,
libutils::try_proc(ezusb, "?usbMute@@YAHH@Z"));
detour::inline_hook((void *) usbIsHiSpeed,
libutils::try_proc(ezusb, "?usbIsHiSpeed@@YAHXZ"));
}
}
}
+6 -6
View File
@@ -1,6 +1,6 @@
#pragma once
namespace games::qma {
void ezusb_init();
}
#pragma once
namespace games::qma {
void ezusb_init();
}
+83 -83
View File
@@ -1,83 +1,83 @@
#include "io.h"
std::vector<Button> &games::qma::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Quiz Magic Academy");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Select",
"Coin Mech",
"Select 1",
"Select 2",
"Left",
"Right",
"OK",
"Touch Keyboard - 1",
"Touch Keyboard - 2",
"Touch Keyboard - 3",
"Touch Keyboard - 4",
"Touch Keyboard - 5",
"Touch Keyboard - 6",
"Touch Keyboard - 7",
"Touch Keyboard - 8",
"Touch Keyboard - 9",
"Touch Keyboard - 0",
"Touch Keyboard - -",
"Touch Keyboard - Q",
"Touch Keyboard - W",
"Touch Keyboard - E",
"Touch Keyboard - R",
"Touch Keyboard - T",
"Touch Keyboard - Y",
"Touch Keyboard - U",
"Touch Keyboard - I",
"Touch Keyboard - O",
"Touch Keyboard - P",
"Touch Keyboard - A",
"Touch Keyboard - S",
"Touch Keyboard - D",
"Touch Keyboard - F",
"Touch Keyboard - G",
"Touch Keyboard - H",
"Touch Keyboard - J",
"Touch Keyboard - K",
"Touch Keyboard - L",
"Touch Keyboard - Z",
"Touch Keyboard - X",
"Touch Keyboard - C",
"Touch Keyboard - V",
"Touch Keyboard - B",
"Touch Keyboard - N",
"Touch Keyboard - M",
"Touch Keyboard - Backspace",
"Touch Keyboard - Enter"
);
}
return buttons;
}
std::vector<Light> &games::qma::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Quiz Magic Academy");
GameAPI::Lights::sortLights(
&lights,
"Lamp Red",
"Lamp Green",
"Lamp Blue",
"Button Left",
"Button Right",
"Button OK"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::qma::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Quiz Magic Academy");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Select",
"Coin Mech",
"Select 1",
"Select 2",
"Left",
"Right",
"OK",
"Touch Keyboard - 1",
"Touch Keyboard - 2",
"Touch Keyboard - 3",
"Touch Keyboard - 4",
"Touch Keyboard - 5",
"Touch Keyboard - 6",
"Touch Keyboard - 7",
"Touch Keyboard - 8",
"Touch Keyboard - 9",
"Touch Keyboard - 0",
"Touch Keyboard - -",
"Touch Keyboard - Q",
"Touch Keyboard - W",
"Touch Keyboard - E",
"Touch Keyboard - R",
"Touch Keyboard - T",
"Touch Keyboard - Y",
"Touch Keyboard - U",
"Touch Keyboard - I",
"Touch Keyboard - O",
"Touch Keyboard - P",
"Touch Keyboard - A",
"Touch Keyboard - S",
"Touch Keyboard - D",
"Touch Keyboard - F",
"Touch Keyboard - G",
"Touch Keyboard - H",
"Touch Keyboard - J",
"Touch Keyboard - K",
"Touch Keyboard - L",
"Touch Keyboard - Z",
"Touch Keyboard - X",
"Touch Keyboard - C",
"Touch Keyboard - V",
"Touch Keyboard - B",
"Touch Keyboard - N",
"Touch Keyboard - M",
"Touch Keyboard - Backspace",
"Touch Keyboard - Enter"
);
}
return buttons;
}
std::vector<Light> &games::qma::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Quiz Magic Academy");
GameAPI::Lights::sortLights(
&lights,
"Lamp Red",
"Lamp Green",
"Lamp Blue",
"Button Left",
"Button Right",
"Button OK"
);
}
return lights;
}
+77 -77
View File
@@ -1,77 +1,77 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::qma {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
Select,
CoinMech,
Select1,
Select2,
Left,
Right,
OK,
TouchKey1,
TouchKey2,
TouchKey3,
TouchKey4,
TouchKey5,
TouchKey6,
TouchKey7,
TouchKey8,
TouchKey9,
TouchKey0,
TouchKeyDash,
TouchKeyQ,
TouchKeyW,
TouchKeyE,
TouchKeyR,
TouchKeyT,
TouchKeyY,
TouchKeyU,
TouchKeyI,
TouchKeyO,
TouchKeyP,
TouchKeyA,
TouchKeyS,
TouchKeyD,
TouchKeyF,
TouchKeyG,
TouchKeyH,
TouchKeyJ,
TouchKeyK,
TouchKeyL,
TouchKeyZ,
TouchKeyX,
TouchKeyC,
TouchKeyV,
TouchKeyB,
TouchKeyN,
TouchKeyM,
TouchKeyBackspace,
TouchKeyEnter
};
}
// all lights in correct order
namespace Lights {
enum {
LampRed,
LampGreen,
LampBlue,
ButtonLeft,
ButtonRight,
ButtonOK
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::qma {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
Select,
CoinMech,
Select1,
Select2,
Left,
Right,
OK,
TouchKey1,
TouchKey2,
TouchKey3,
TouchKey4,
TouchKey5,
TouchKey6,
TouchKey7,
TouchKey8,
TouchKey9,
TouchKey0,
TouchKeyDash,
TouchKeyQ,
TouchKeyW,
TouchKeyE,
TouchKeyR,
TouchKeyT,
TouchKeyY,
TouchKeyU,
TouchKeyI,
TouchKeyO,
TouchKeyP,
TouchKeyA,
TouchKeyS,
TouchKeyD,
TouchKeyF,
TouchKeyG,
TouchKeyH,
TouchKeyJ,
TouchKeyK,
TouchKeyL,
TouchKeyZ,
TouchKeyX,
TouchKeyC,
TouchKeyV,
TouchKeyB,
TouchKeyN,
TouchKeyM,
TouchKeyBackspace,
TouchKeyEnter
};
}
// all lights in correct order
namespace Lights {
enum {
LampRed,
LampGreen,
LampBlue,
ButtonLeft,
ButtonRight,
ButtonOK
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
+135 -135
View File
@@ -1,135 +1,135 @@
#include "qma.h"
#include <cstring>
#include <d3d9.h>
#include "games/shared/lcdhandle.h"
#include "games/shared/twtouch.h"
#include "hooks/graphics/graphics.h"
#include "hooks/devicehook.h"
#include "launcher/launcher.h"
#include "util/detour.h"
#include "util/fileutils.h"
#include "util/utils.h"
#include "ezusb.h"
namespace games::qma {
/**
* Overridden touchscreen for attaching the touch hooks to the window.
*/
class QMATouchDevice : public games::shared::TwTouchDevice {
public:
bool open(LPCWSTR lpFileName) override {
// check if device was opened
auto result = TwTouchDevice::open(lpFileName);
if (result) {
if (GRAPHICS_WINDOWED) {
// get game window
HWND wnd = GetForegroundWindow();
if (!string_begins_with(GetActiveWindowTitle(), "QMA")) {
wnd = FindWindowBeginsWith("QMA");
}
if (wnd != nullptr) {
// get client area
RECT rect {};
GetClientRect(wnd, &rect);
// remove style borders
LONG lStyle = GetWindowLong(wnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
SetWindowLongPtr(wnd, GWL_STYLE, lStyle);
// remove ex style borders
LONG lExStyle = GetWindowLong(wnd, GWL_EXSTYLE);
lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
SetWindowLongPtr(wnd, GWL_EXSTYLE, lExStyle);
// update window
AdjustWindowRect(&rect, lStyle, FALSE);
SetWindowPos(wnd, nullptr,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOOWNERZORDER);
}
}
// attach touch
touch_attach_dx_hook();
// cursor
if (!is_touch_available()) {
ShowCursor(true);
}
}
// return result
return result;
}
};
/*
* The game likes to crash if E:\LMA\quiz13 does not exist.
* Therefore we create it when the game tries to access E:\LMA the first time.
*/
namespace dirfix {
static decltype(CreateFileW) *CreateFileW_real = nullptr;
static HANDLE WINAPI CreateFileW_Hook(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
// create quiz directory
static bool dirs_created = false;
if (!dirs_created && _wcsnicmp(lpFileName, L"E:\\LMA", 6) == 0) {
fileutils::dir_create_recursive("E:\\LMA\\quiz11");
fileutils::dir_create_recursive("E:\\LMA\\quiz13");
fileutils::dir_create_recursive("E:\\LMA\\quiz15");
dirs_created = true;
}
// return result
return CreateFileW_real(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
void apply() {
CreateFileW_real = detour::iat_try("CreateFileW", CreateFileW_Hook);
}
}
QMAGame::QMAGame() : Game("Quiz Magic Academy") {
}
void QMAGame::pre_attach() {
Game::pre_attach();
// load without resolving references
// makes game not trigger DLLMain since that does some EZUSB device stuff
LoadLibraryExW((MODULE_PATH / "ezusb.dll").c_str(), nullptr, DONT_RESOLVE_DLL_REFERENCES);
}
void QMAGame::attach() {
Game::attach();
// init device hooks
devicehook_init();
devicehook_add(new games::shared::LCDHandle());
devicehook_add(new games::qma::QMATouchDevice());
// EZUSB for button input
ezusb_init();
// disable multi-head mode
D3D9_BEHAVIOR_DISABLE = D3DCREATE_ADAPTERGROUP_DEVICE;
// directory fix
dirfix::apply();
}
}
#include "qma.h"
#include <cstring>
#include <d3d9.h>
#include "games/shared/lcdhandle.h"
#include "games/shared/twtouch.h"
#include "hooks/graphics/graphics.h"
#include "hooks/devicehook.h"
#include "launcher/launcher.h"
#include "util/detour.h"
#include "util/fileutils.h"
#include "util/utils.h"
#include "ezusb.h"
namespace games::qma {
/**
* Overridden touchscreen for attaching the touch hooks to the window.
*/
class QMATouchDevice : public games::shared::TwTouchDevice {
public:
bool open(LPCWSTR lpFileName) override {
// check if device was opened
auto result = TwTouchDevice::open(lpFileName);
if (result) {
if (GRAPHICS_WINDOWED) {
// get game window
HWND wnd = GetForegroundWindow();
if (!string_begins_with(GetActiveWindowTitle(), "QMA")) {
wnd = FindWindowBeginsWith("QMA");
}
if (wnd != nullptr) {
// get client area
RECT rect {};
GetClientRect(wnd, &rect);
// remove style borders
LONG lStyle = GetWindowLong(wnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
SetWindowLongPtr(wnd, GWL_STYLE, lStyle);
// remove ex style borders
LONG lExStyle = GetWindowLong(wnd, GWL_EXSTYLE);
lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
SetWindowLongPtr(wnd, GWL_EXSTYLE, lExStyle);
// update window
AdjustWindowRect(&rect, lStyle, FALSE);
SetWindowPos(wnd, nullptr,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOOWNERZORDER);
}
}
// attach touch
touch_attach_dx_hook();
// cursor
if (!is_touch_available()) {
ShowCursor(true);
}
}
// return result
return result;
}
};
/*
* The game likes to crash if E:\LMA\quiz13 does not exist.
* Therefore we create it when the game tries to access E:\LMA the first time.
*/
namespace dirfix {
static decltype(CreateFileW) *CreateFileW_real = nullptr;
static HANDLE WINAPI CreateFileW_Hook(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
// create quiz directory
static bool dirs_created = false;
if (!dirs_created && _wcsnicmp(lpFileName, L"E:\\LMA", 6) == 0) {
fileutils::dir_create_recursive("E:\\LMA\\quiz11");
fileutils::dir_create_recursive("E:\\LMA\\quiz13");
fileutils::dir_create_recursive("E:\\LMA\\quiz15");
dirs_created = true;
}
// return result
return CreateFileW_real(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
void apply() {
CreateFileW_real = detour::iat_try("CreateFileW", CreateFileW_Hook);
}
}
QMAGame::QMAGame() : Game("Quiz Magic Academy") {
}
void QMAGame::pre_attach() {
Game::pre_attach();
// load without resolving references
// makes game not trigger DLLMain since that does some EZUSB device stuff
LoadLibraryExW((MODULE_PATH / "ezusb.dll").c_str(), nullptr, DONT_RESOLVE_DLL_REFERENCES);
}
void QMAGame::attach() {
Game::attach();
// init device hooks
devicehook_init();
devicehook_add(new games::shared::LCDHandle());
devicehook_add(new games::qma::QMATouchDevice());
// EZUSB for button input
ezusb_init();
// disable multi-head mode
D3D9_BEHAVIOR_DISABLE = D3DCREATE_ADAPTERGROUP_DEVICE;
// directory fix
dirfix::apply();
}
}
+13 -13
View File
@@ -1,13 +1,13 @@
#pragma once
#include "games/game.h"
namespace games::qma {
class QMAGame : public games::Game {
public:
QMAGame();
virtual void pre_attach() override;
virtual void attach() override;
};
}
#pragma once
#include "games/game.h"
namespace games::qma {
class QMAGame : public games::Game {
public:
QMAGame();
virtual void pre_attach() override;
virtual void attach() override;
};
}
+45 -45
View File
@@ -1,45 +1,45 @@
#include "io.h"
std::vector<Button> &games::rb::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Reflec Beat");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test"
);
}
return buttons;
}
std::vector<Light> &games::rb::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Reflec Beat");
GameAPI::Lights::sortLights(
&lights,
"Pole R",
"Pole G",
"Pole B",
"Escutcheon R",
"Escutcheon G",
"Escutcheon B",
"Woofer R",
"Woofer G",
"Woofer B",
"Title R",
"Title G",
"Title B",
"Title Up R",
"Title Up G",
"Title Up B"
);
}
return lights;
}
#include "io.h"
std::vector<Button> &games::rb::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Reflec Beat");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test"
);
}
return buttons;
}
std::vector<Light> &games::rb::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Reflec Beat");
GameAPI::Lights::sortLights(
&lights,
"Pole R",
"Pole G",
"Pole B",
"Escutcheon R",
"Escutcheon G",
"Escutcheon B",
"Woofer R",
"Woofer G",
"Woofer B",
"Title R",
"Title G",
"Title B",
"Title Up R",
"Title Up G",
"Title Up B"
);
}
return lights;
}
+40 -40
View File
@@ -1,40 +1,40 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::rb {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test
};
}
// all lights in correct order
namespace Lights {
enum {
PoleR,
PoleG,
PoleB,
EscutcheonR,
EscutcheonG,
EscutcheonB,
WooferR,
WooferG,
WooferB,
TitleR,
TitleG,
TitleB,
TitleUpR,
TitleUpG,
TitleUpB
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::rb {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test
};
}
// all lights in correct order
namespace Lights {
enum {
PoleR,
PoleG,
PoleB,
EscutcheonR,
EscutcheonG,
EscutcheonB,
WooferR,
WooferG,
WooferB,
TitleR,
TitleG,
TitleB,
TitleUpR,
TitleUpG,
TitleUpB
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Light> &get_lights();
}
+13 -13
View File
@@ -1,13 +1,13 @@
#pragma once
#include "games/game.h"
namespace games::rb {
class RBGame : public games::Game {
public:
RBGame();
virtual void attach();
virtual void detach();
};
}
#pragma once
#include "games/game.h"
namespace games::rb {
class RBGame : public games::Game {
public:
RBGame();
virtual void attach();
virtual void detach();
};
}
+192 -192
View File
@@ -1,192 +1,192 @@
#include "touch.h"
#include <windows.h>
#include "avs/game.h"
#include "hooks/graphics/graphics.h"
#include "touch/touch.h"
#include "util/logging.h"
#include "util/time.h"
#include "util/utils.h"
static std::string WINDOW_TITLE = "REFLEC BEAT";
games::rb::ReflecBeatTouchDeviceHandle::ReflecBeatTouchDeviceHandle(bool log_fps) {
this->log_fps = log_fps;
}
void games::rb::ReflecBeatTouchDeviceHandle::grid_insert(unsigned char *data, int cursor_x, int cursor_y) {
// scale to grid position
int grid_x = CLAMP((cursor_x * 48) / window_width, 0, 47);
int grid_y = CLAMP((cursor_y * 76) / window_height, 0, 75);
// get bit positions
int bit_x = 88 + grid_x;
int bit_y = 74 - grid_y;
// insert bits
data[3 + bit_x / 8] |= (char) 1 << (bit_x % 8);
data[3 + bit_y / 8] |= (char) 1 << (bit_y % 8);
}
bool games::rb::ReflecBeatTouchDeviceHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM1") != 0) {
return false;
}
// attach touch module
HWND wnd = GetForegroundWindow();
if (!string_begins_with(GetActiveWindowTitle(), WINDOW_TITLE)) {
wnd = FindWindowBeginsWith(WINDOW_TITLE);
}
if (wnd != nullptr) {
// reset window process to make the game not crash
SetWindowLongPtr(wnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(DefWindowProc));
// check if windowed
if (GRAPHICS_WINDOWED) {
// remove style borders
LONG lStyle = GetWindowLong(wnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
SetWindowLongPtr(wnd, GWL_STYLE, lStyle);
// remove ex style borders
LONG lExStyle = GetWindowLong(wnd, GWL_EXSTYLE);
lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
SetWindowLongPtr(wnd, GWL_EXSTYLE, lExStyle);
// update window
SetWindowPos(wnd, nullptr, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
// create touch window
touch_create_wnd(wnd);
} else {
// create touch window
touch_create_wnd(wnd);
// show game window because it lost focus
ShowWindow(wnd, SW_SHOW);
}
} else {
// fallback to dx hook
touch_attach_dx_hook();
}
// show cursor on window if mouse is used
if (!is_touch_available()) {
ShowCursor(TRUE);
}
return true;
}
int games::rb::ReflecBeatTouchDeviceHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
// check buffer size
if (nNumberOfBytesToRead < 20) {
return 0;
}
// get window
HWND window = GetForegroundWindow();
if (window == nullptr) {
return 0;
}
// update width and height
RECT rect {};
GetWindowRect(window, &rect);
// check for landscape (KBR)
bool is_landscape = (rect.right - rect.left) > (rect.bottom - rect.top);
if (is_landscape) {
window_height = rect.right - rect.left;
window_width = rect.bottom - rect.top;
} else {
window_width = rect.right - rect.left;
window_height = rect.bottom - rect.top;
}
// create data
unsigned char data[20] {};
// data header
data[0] = 0x55;
data[2] = 0x4C;
// iterate all touch points
auto offset_x = (int) (window_width / 48.0 / 3.0);
auto offset_y = (int) (window_height / 76.0 / 3.0);
std::vector<TouchPoint> touch_points;
touch_get_points(touch_points);
for (auto &point : touch_points) {
// get touch point coordinates
auto x = point.x;
auto y = point.y;
// rotate touch points for KBR as it runs in landscape
if (is_landscape) {
x = point.y;
y = window_height - point.x;
}
// point scaling
auto point_x = (int) ((x - window_width / 2.0) * 48.0 / 54.0 + window_width / 2.0);
auto point_y = (int) (y - window_height / 76);
// insert 9 times with offset to double the precision
grid_insert(data, point_x, point_y);
grid_insert(data, point_x - offset_x, point_y);
grid_insert(data, point_x - offset_x, point_y - offset_y);
grid_insert(data, point_x - offset_x, point_y + offset_y);
grid_insert(data, point_x + offset_x, point_y);
grid_insert(data, point_x + offset_x, point_y + offset_y);
grid_insert(data, point_x + offset_x, point_y - offset_y);
grid_insert(data, point_x, point_y - offset_y);
grid_insert(data, point_x, point_y + offset_y);
}
// copy data to buffer
memcpy(lpBuffer, data, 20);
// update frame logging
if (log_fps) {
log_frames++;
if (log_time < get_system_seconds()) {
if (log_time > 0) {
log_info("reflecbeat", "polling at {} touch frames per second", log_frames);
}
log_frames = 0;
log_time = get_system_seconds();
}
}
// return amount of bytes written
return 20;
}
int games::rb::ReflecBeatTouchDeviceHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
return (int) nNumberOfBytesToWrite;
}
int games::rb::ReflecBeatTouchDeviceHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
return -1;
}
bool games::rb::ReflecBeatTouchDeviceHandle::close() {
// detach touch module
touch_detach();
return true;
}
#include "touch.h"
#include <windows.h>
#include "avs/game.h"
#include "hooks/graphics/graphics.h"
#include "touch/touch.h"
#include "util/logging.h"
#include "util/time.h"
#include "util/utils.h"
static std::string WINDOW_TITLE = "REFLEC BEAT";
games::rb::ReflecBeatTouchDeviceHandle::ReflecBeatTouchDeviceHandle(bool log_fps) {
this->log_fps = log_fps;
}
void games::rb::ReflecBeatTouchDeviceHandle::grid_insert(unsigned char *data, int cursor_x, int cursor_y) {
// scale to grid position
int grid_x = CLAMP((cursor_x * 48) / window_width, 0, 47);
int grid_y = CLAMP((cursor_y * 76) / window_height, 0, 75);
// get bit positions
int bit_x = 88 + grid_x;
int bit_y = 74 - grid_y;
// insert bits
data[3 + bit_x / 8] |= (char) 1 << (bit_x % 8);
data[3 + bit_y / 8] |= (char) 1 << (bit_y % 8);
}
bool games::rb::ReflecBeatTouchDeviceHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM1") != 0) {
return false;
}
// attach touch module
HWND wnd = GetForegroundWindow();
if (!string_begins_with(GetActiveWindowTitle(), WINDOW_TITLE)) {
wnd = FindWindowBeginsWith(WINDOW_TITLE);
}
if (wnd != nullptr) {
// reset window process to make the game not crash
SetWindowLongPtr(wnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(DefWindowProc));
// check if windowed
if (GRAPHICS_WINDOWED) {
// remove style borders
LONG lStyle = GetWindowLong(wnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
SetWindowLongPtr(wnd, GWL_STYLE, lStyle);
// remove ex style borders
LONG lExStyle = GetWindowLong(wnd, GWL_EXSTYLE);
lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
SetWindowLongPtr(wnd, GWL_EXSTYLE, lExStyle);
// update window
SetWindowPos(wnd, nullptr, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
// create touch window
touch_create_wnd(wnd);
} else {
// create touch window
touch_create_wnd(wnd);
// show game window because it lost focus
ShowWindow(wnd, SW_SHOW);
}
} else {
// fallback to dx hook
touch_attach_dx_hook();
}
// show cursor on window if mouse is used
if (!is_touch_available()) {
ShowCursor(TRUE);
}
return true;
}
int games::rb::ReflecBeatTouchDeviceHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
// check buffer size
if (nNumberOfBytesToRead < 20) {
return 0;
}
// get window
HWND window = GetForegroundWindow();
if (window == nullptr) {
return 0;
}
// update width and height
RECT rect {};
GetWindowRect(window, &rect);
// check for landscape (KBR)
bool is_landscape = (rect.right - rect.left) > (rect.bottom - rect.top);
if (is_landscape) {
window_height = rect.right - rect.left;
window_width = rect.bottom - rect.top;
} else {
window_width = rect.right - rect.left;
window_height = rect.bottom - rect.top;
}
// create data
unsigned char data[20] {};
// data header
data[0] = 0x55;
data[2] = 0x4C;
// iterate all touch points
auto offset_x = (int) (window_width / 48.0 / 3.0);
auto offset_y = (int) (window_height / 76.0 / 3.0);
std::vector<TouchPoint> touch_points;
touch_get_points(touch_points);
for (auto &point : touch_points) {
// get touch point coordinates
auto x = point.x;
auto y = point.y;
// rotate touch points for KBR as it runs in landscape
if (is_landscape) {
x = point.y;
y = window_height - point.x;
}
// point scaling
auto point_x = (int) ((x - window_width / 2.0) * 48.0 / 54.0 + window_width / 2.0);
auto point_y = (int) (y - window_height / 76);
// insert 9 times with offset to double the precision
grid_insert(data, point_x, point_y);
grid_insert(data, point_x - offset_x, point_y);
grid_insert(data, point_x - offset_x, point_y - offset_y);
grid_insert(data, point_x - offset_x, point_y + offset_y);
grid_insert(data, point_x + offset_x, point_y);
grid_insert(data, point_x + offset_x, point_y + offset_y);
grid_insert(data, point_x + offset_x, point_y - offset_y);
grid_insert(data, point_x, point_y - offset_y);
grid_insert(data, point_x, point_y + offset_y);
}
// copy data to buffer
memcpy(lpBuffer, data, 20);
// update frame logging
if (log_fps) {
log_frames++;
if (log_time < get_system_seconds()) {
if (log_time > 0) {
log_info("reflecbeat", "polling at {} touch frames per second", log_frames);
}
log_frames = 0;
log_time = get_system_seconds();
}
}
// return amount of bytes written
return 20;
}
int games::rb::ReflecBeatTouchDeviceHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
return (int) nNumberOfBytesToWrite;
}
int games::rb::ReflecBeatTouchDeviceHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
return -1;
}
bool games::rb::ReflecBeatTouchDeviceHandle::close() {
// detach touch module
touch_detach();
return true;
}

Some files were not shown because too many files have changed in this diff Show More