Initial re-upload of spice2x-24-08-24

This commit is contained in:
2024-08-28 11:10:34 -04:00
commit caa9e02285
1181 changed files with 380065 additions and 0 deletions

19
games/onpara/io.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
};
}