Initial re-upload of spice2x-24-08-24
This commit is contained in:
19
games/onpara/io.cpp
Normal file
19
games/onpara/io.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "io.h"
|
||||
|
||||
std::vector<Button> &games::onpara::get_buttons() {
|
||||
static std::vector<Button> buttons;
|
||||
|
||||
if (buttons.empty()) {
|
||||
buttons = GameAPI::Buttons::getButtons("Ongaku Paradise");
|
||||
|
||||
GameAPI::Buttons::sortButtons(
|
||||
&buttons,
|
||||
"Service",
|
||||
"Test",
|
||||
"Start",
|
||||
"Headphone"
|
||||
);
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
17
games/onpara/io.h
Normal file
17
games/onpara/io.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "cfg/api.h"
|
||||
|
||||
namespace games::onpara {
|
||||
namespace Buttons {
|
||||
enum {
|
||||
Service,
|
||||
Test,
|
||||
Start,
|
||||
Headphone,
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<Button> &get_buttons();
|
||||
}
|
||||
74
games/onpara/onpara.cpp
Normal file
74
games/onpara/onpara.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "onpara.h"
|
||||
|
||||
#include "avs/game.h"
|
||||
#include "util/detour.h"
|
||||
#include "util/utils.h"
|
||||
#include "util/libutils.h"
|
||||
#include "util/sigscan.h"
|
||||
#include "hooks/devicehook.h"
|
||||
#include "hooks/sleephook.h"
|
||||
#include "hooks/graphics/graphics.h"
|
||||
#include "touch/touch.h"
|
||||
#include "touchpanel.h"
|
||||
#include "westboard.h"
|
||||
|
||||
static decltype(BuildCommDCBA)* orig_BuildCommDCBA = BuildCommDCBA;
|
||||
|
||||
games::onpara::OnparaGame::OnparaGame() : games::Game("Ongaku Paradise") { }
|
||||
|
||||
static BOOL WINAPI my_BuildCommDCBA(LPCSTR lpDef, LPDCB lpDCB) {
|
||||
if (lpDef == nullptr || lpDCB == nullptr) {
|
||||
return orig_BuildCommDCBA(lpDef, lpDCB);
|
||||
}
|
||||
|
||||
log_misc("onpara", "BuildCommDCBA({})", lpDef);
|
||||
|
||||
// remove the device name if present
|
||||
if (string_begins_with(lpDef, "COM") && std::strlen(lpDef) >= 5) {
|
||||
lpDef += 6;
|
||||
}
|
||||
|
||||
return orig_BuildCommDCBA(lpDef, lpDCB);
|
||||
}
|
||||
|
||||
static int __cdecl setvolume_and_setequalizer_stub(const char*) {
|
||||
// log_misc("onpara", "setvolume_and_setequalizer_stub()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void games::onpara::OnparaGame::attach() {
|
||||
Game::attach();
|
||||
|
||||
// make the game start faster
|
||||
auto gamejc9_module = libutils::try_library("gamejc9.dll");
|
||||
if (gamejc9_module != nullptr) {
|
||||
hooks::sleep::init(29999, 1, gamejc9_module);
|
||||
}
|
||||
|
||||
// attach touch handler
|
||||
log_info("onpara", "attach touch handler");
|
||||
touch_attach_dx_hook();
|
||||
if (GRAPHICS_SHOW_CURSOR) {
|
||||
ShowCursor(1);
|
||||
}
|
||||
|
||||
// patch the CRC check
|
||||
// TODO: I don't like patching, make this not a patch
|
||||
replace_pattern(avs::game::DLL_INSTANCE, "8D4C240851E8????????83C404", "8D4C240851B80000000083C404", 0, 0);
|
||||
|
||||
detour::iat_try("BuildCommDCBA", my_BuildCommDCBA);
|
||||
|
||||
// load this now so that we can hook its dependencies
|
||||
libutils::try_library("gamejc9.dll");
|
||||
// stub annoying functions
|
||||
detour::iat_try("?setvolume@@YAHPAD@Z", setvolume_and_setequalizer_stub);
|
||||
detour::iat_try("SetEqualizer", setvolume_and_setequalizer_stub);
|
||||
|
||||
devicehook_init(avs::game::DLL_INSTANCE);
|
||||
devicehook_add(new TouchPanelHandle());
|
||||
devicehook_add(new WestBoardHandle());
|
||||
}
|
||||
|
||||
void games::onpara::OnparaGame::detach() {
|
||||
Game::detach();
|
||||
}
|
||||
12
games/onpara/onpara.h
Normal file
12
games/onpara/onpara.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "games/game.h"
|
||||
|
||||
namespace games::onpara {
|
||||
class OnparaGame : public games::Game {
|
||||
public:
|
||||
OnparaGame();
|
||||
virtual void attach() override;
|
||||
virtual void detach() override;
|
||||
};
|
||||
}
|
||||
136
games/onpara/touchpanel.cpp
Normal file
136
games/onpara/touchpanel.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#include "touchpanel.h"
|
||||
|
||||
#include "util/logging.h"
|
||||
#include "touch/touch.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
void games::onpara::TouchPanelHandle::set_state(touch_panel_state state) {
|
||||
state_ = state;
|
||||
// reset the output queue as well for good measure
|
||||
output_queue_ = {};
|
||||
}
|
||||
|
||||
void games::onpara::TouchPanelHandle::enqueue_packet(touch_panel_message const &message) {
|
||||
// push magic
|
||||
output_queue_.push('U');
|
||||
|
||||
// push message
|
||||
for (auto b : message.raw) {
|
||||
output_queue_.push(b);
|
||||
}
|
||||
|
||||
// push checksum
|
||||
output_queue_.push(message.raw[0] +
|
||||
message.raw[1] +
|
||||
message.raw[2] +
|
||||
message.raw[3] +
|
||||
message.raw[4] +
|
||||
message.raw[5] +
|
||||
message.raw[6] +
|
||||
message.raw[7] - 1);
|
||||
}
|
||||
|
||||
bool games::onpara::TouchPanelHandle::open(LPCWSTR lpFileName) {
|
||||
if (wcscmp(lpFileName, L"COM1: baud=9600 parity=N data=8 stop=1") != 0) {
|
||||
return false;
|
||||
}
|
||||
log_info("touchpanel", "Opened COM1 (Touch Panel)");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int games::onpara::TouchPanelHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
|
||||
DWORD i;
|
||||
auto buffer = reinterpret_cast<uint8_t *>(lpBuffer);
|
||||
|
||||
if (state_ == TOUCH_PANEL_STATE_REPORT && output_queue_.empty()) {
|
||||
// create a new status report message
|
||||
touch_panel_message report = {
|
||||
'T', 'K', 0, 0, 0
|
||||
};
|
||||
|
||||
std::vector<TouchPoint> touch_points;
|
||||
touch_get_points(touch_points);
|
||||
|
||||
if (!touch_points.empty()) {
|
||||
auto &touch_point = touch_points[0];
|
||||
|
||||
report.x = static_cast<uint16_t>(touch_point.x);
|
||||
report.y = 768 - static_cast<uint16_t>(touch_point.y);
|
||||
report.z = ~0;
|
||||
}
|
||||
|
||||
enqueue_packet(report);
|
||||
|
||||
// prevent cpu bullying
|
||||
std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
|
||||
// copy from output queue
|
||||
for (i = 0; i < nNumberOfBytesToRead && !output_queue_.empty(); i++) {
|
||||
buffer[i] = output_queue_.front();
|
||||
output_queue_.pop();
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int games::onpara::TouchPanelHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
|
||||
// static messages
|
||||
static const touch_panel_message acknowledge_message = {
|
||||
'A', 0, 0, 0, 0
|
||||
};
|
||||
static const touch_panel_message diagnostics_message = {
|
||||
'D', 0, 0, 0, 0
|
||||
};
|
||||
|
||||
// make sure that we received the correct amount of data
|
||||
if (nNumberOfBytesToWrite != 10) {
|
||||
log_warning("touchscreen", "invalid packet size");
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto op = reinterpret_cast<const char *>(lpBuffer)[1];
|
||||
switch (op) {
|
||||
case 'R': // reset
|
||||
set_state(TOUCH_PANEL_STATE_INACTIVE);
|
||||
break;
|
||||
|
||||
case 'a': // acknowledge
|
||||
if (state_ == TOUCH_PANEL_STATE_INACTIVE) {
|
||||
set_state(TOUCH_PANEL_STATE_ACKNOWLEDGE);
|
||||
enqueue_packet(acknowledge_message);
|
||||
}
|
||||
else if (state_ == TOUCH_PANEL_STATE_DIAGNOSTICS) {
|
||||
// start reporting
|
||||
set_state(TOUCH_PANEL_STATE_REPORT);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'D': // diagnositcs
|
||||
set_state(TOUCH_PANEL_STATE_DIAGNOSTICS);
|
||||
enqueue_packet(diagnostics_message);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_warning("touchpanel", "invalid operation: {:c}", op);
|
||||
break;
|
||||
}
|
||||
|
||||
return nNumberOfBytesToWrite;
|
||||
}
|
||||
|
||||
int games::onpara::TouchPanelHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
|
||||
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool games::onpara::TouchPanelHandle::close() {
|
||||
log_info("touchpanel", "Closed COM1 (Touch Panel)");
|
||||
|
||||
return true;
|
||||
}
|
||||
42
games/onpara/touchpanel.h
Normal file
42
games/onpara/touchpanel.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <queue>
|
||||
|
||||
#include "hooks/devicehook.h"
|
||||
|
||||
namespace games::onpara {
|
||||
class TouchPanelHandle : public CustomHandle {
|
||||
private:
|
||||
union touch_panel_message {
|
||||
struct {
|
||||
char op;
|
||||
char something;
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint16_t z;
|
||||
};
|
||||
char raw[8];
|
||||
};
|
||||
|
||||
enum touch_panel_state {
|
||||
TOUCH_PANEL_STATE_INACTIVE,
|
||||
TOUCH_PANEL_STATE_ACKNOWLEDGE,
|
||||
TOUCH_PANEL_STATE_DIAGNOSTICS,
|
||||
TOUCH_PANEL_STATE_REPORT
|
||||
};
|
||||
|
||||
touch_panel_state state_ = TOUCH_PANEL_STATE_INACTIVE;
|
||||
std::queue<uint8_t> output_queue_;
|
||||
|
||||
void set_state(touch_panel_state state);
|
||||
void enqueue_packet(touch_panel_message const &message);
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
166
games/onpara/westboard.cpp
Normal file
166
games/onpara/westboard.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#include "westboard.h"
|
||||
|
||||
#include "io.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/secplug.h"
|
||||
#include "misc/eamuse.h"
|
||||
|
||||
using namespace acioemu;
|
||||
|
||||
games::onpara::WestBoardHandle::WestBoardDevice::WestBoardDevice() {
|
||||
/*
|
||||
* Node 1 -> Buttons
|
||||
* Node 2 -> Card Reader
|
||||
* Node 3-5 -> Lights
|
||||
*/
|
||||
this->node_count = 5;
|
||||
}
|
||||
|
||||
games::onpara::WestBoardHandle::WestBoardHandle() {
|
||||
acio_emu_.add_device(new games::onpara::WestBoardHandle::WestBoardDevice);
|
||||
}
|
||||
|
||||
bool games::onpara::WestBoardHandle::WestBoardDevice::parse_msg(MessageData *msg_in, circular_buffer<uint8_t> *response_buffer) {
|
||||
response_ = {};
|
||||
|
||||
switch (msg_in->cmd.code) {
|
||||
case ACIO_CMD_GET_VERSION:
|
||||
set_version(&response_, ':', '^', ')', ':', '(', ":^)");
|
||||
response_.cmd.data_size = MSG_VERSION_SIZE;
|
||||
break;
|
||||
|
||||
case ACIO_WESTBOARD_CMD_LOAD_SECPLUG_MODEL:
|
||||
if (msg_in->cmd.raw[0] == SECURITY_PLUG_LICENSE) {
|
||||
secplug_model_ = secplug::encode_secplug_model("GQJC9JAA");
|
||||
}
|
||||
else if (msg_in->cmd.raw[0] == SECURITY_PLUG_ACCOUNT) {
|
||||
secplug_model_ = secplug::encode_secplug_model("@@@@@@@@");
|
||||
}
|
||||
else {
|
||||
log_warning("westboard", "invalid security plug type: {}", msg_in->cmd.raw[0]);
|
||||
}
|
||||
|
||||
// empty response body
|
||||
response_.cmd.data_size = 0;
|
||||
break;
|
||||
|
||||
case ACIO_WESTBOARD_CMD_QUERY_SECPLUG:
|
||||
// write security plug id
|
||||
response_.cmd.raw[3] = 4;
|
||||
response_.cmd.raw[4] = 3;
|
||||
response_.cmd.raw[5] = 4;
|
||||
response_.cmd.raw[6] = 3;
|
||||
|
||||
// write security plug model
|
||||
std::copy(secplug_model_.begin(), secplug_model_.end(), response_.cmd.raw + 7);
|
||||
|
||||
response_.cmd.data_size = 33;
|
||||
break;
|
||||
|
||||
case ACIO_WESTBOARD_CMD_POLL_BUTTONS_0:
|
||||
case ACIO_WESTBOARD_CMD_POLL_BUTTONS_1: {
|
||||
auto &buttons = games::onpara::get_buttons();
|
||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[games::onpara::Buttons::Test])) {
|
||||
response_.cmd.raw[1] |= 1 << 5;
|
||||
}
|
||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[games::onpara::Buttons::Service])) {
|
||||
response_.cmd.raw[1] |= 1 << 4;
|
||||
}
|
||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[games::onpara::Buttons::Start])) {
|
||||
response_.cmd.raw[8] |= 1;
|
||||
}
|
||||
if (GameAPI::Buttons::getState(RI_MGR, buttons[games::onpara::Buttons::Headphone])) {
|
||||
response_.cmd.raw[8] |= 1 << 1;
|
||||
}
|
||||
|
||||
response_.cmd.data_size = 15;
|
||||
break;
|
||||
}
|
||||
|
||||
case ACIO_WESTBOARD_CMD_ENABLE_CARD_READER:
|
||||
// send status "1"
|
||||
response_.cmd.status = 1;
|
||||
response_.cmd.data_size = 1;
|
||||
break;
|
||||
|
||||
case ACIO_WESTBOARD_CMD_POLL_CARD_READER:
|
||||
response_.cmd.data_size = 24;
|
||||
response_.cmd.raw[0] = 2;
|
||||
|
||||
if (eamuse_card_insert_consume(1, 0)) {
|
||||
eamuse_get_card(1, 0, &response_.cmd.raw[2]);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACIO_WESTBOARD_CMD_LOAD_SECPLUG_ID:
|
||||
case ACIO_WESTBOARD_CMD_SET_LIGHTS:
|
||||
// empty response body
|
||||
response_.cmd.data_size = 0;
|
||||
break;
|
||||
|
||||
case ACIO_CMD_STARTUP:
|
||||
case ACIO_CMD_CLEAR:
|
||||
case ACIO_WESTBOARD_CMD_EXECUTE:
|
||||
// send status "0"
|
||||
response_.cmd.status = 0;
|
||||
response_.cmd.data_size = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_warning("westboard", "unknown cmd: {}", msg_in->cmd.code);
|
||||
return false;
|
||||
}
|
||||
|
||||
// set acio header
|
||||
set_header(&response_, msg_in->addr, msg_in->cmd.code, msg_in->cmd.pid, response_.cmd.data_size);
|
||||
// write message
|
||||
write_msg(&response_, response_buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool games::onpara::WestBoardHandle::open(LPCWSTR lpFileName) {
|
||||
if (wcscmp(lpFileName, L"COM2: baud=57600 parity=N data=8 stop=1") != 0){
|
||||
return false;
|
||||
}
|
||||
log_info("westboard", "Opened COM2 (West Board)");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int games::onpara::WestBoardHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
|
||||
auto buffer = reinterpret_cast<const uint8_t *>(lpBuffer);
|
||||
for (DWORD i = 0; i < nNumberOfBytesToWrite; i++) {
|
||||
acio_emu_.write(buffer[i]);
|
||||
}
|
||||
|
||||
return nNumberOfBytesToWrite;
|
||||
}
|
||||
|
||||
int games::onpara::WestBoardHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
|
||||
auto buffer = reinterpret_cast<uint8_t *>(lpBuffer);
|
||||
|
||||
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 bytes_read;
|
||||
}
|
||||
|
||||
int games::onpara::WestBoardHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
|
||||
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool games::onpara::WestBoardHandle::close() {
|
||||
log_info("westboard", "Closed COM2 (West Board)");
|
||||
|
||||
return true;
|
||||
}
|
||||
49
games/onpara/westboard.h
Normal file
49
games/onpara/westboard.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "hooks/devicehook.h"
|
||||
#include "acioemu/acioemu.h"
|
||||
|
||||
namespace games::onpara {
|
||||
class WestBoardHandle : public CustomHandle {
|
||||
private:
|
||||
acioemu::ACIOEmu acio_emu_;
|
||||
|
||||
class WestBoardDevice : public acioemu::ACIODeviceEmu {
|
||||
private:
|
||||
enum security_plug {
|
||||
SECURITY_PLUG_LICENSE,
|
||||
SECURITY_PLUG_ACCOUNT,
|
||||
};
|
||||
|
||||
enum acio_westboard_cmd {
|
||||
ACIO_WESTBOARD_CMD_SET_LIGHTS = 0x0112,
|
||||
ACIO_WESTBOARD_CMD_EXECUTE = 0x0130,
|
||||
ACIO_WESTBOARD_CMD_POLL_BUTTONS_0 = 0x0111,
|
||||
ACIO_WESTBOARD_CMD_POLL_BUTTONS_1 = 0x0113,
|
||||
ACIO_WESTBOARD_CMD_ENABLE_CARD_READER = 0x0131,
|
||||
ACIO_WESTBOARD_CMD_POLL_CARD_READER = 0x0134,
|
||||
ACIO_WESTBOARD_CMD_LOAD_SECPLUG_ID = 0x0140,
|
||||
ACIO_WESTBOARD_CMD_LOAD_SECPLUG_MODEL = 0x0141,
|
||||
ACIO_WESTBOARD_CMD_QUERY_SECPLUG = 0x0148
|
||||
};
|
||||
|
||||
std::array<uint8_t, 6> secplug_model_;
|
||||
acioemu::MessageData response_;
|
||||
|
||||
public:
|
||||
WestBoardDevice();
|
||||
bool parse_msg(acioemu::MessageData *msg_in, circular_buffer<uint8_t> *response_buffer) override;
|
||||
};
|
||||
|
||||
public:
|
||||
WestBoardHandle();
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user