1
0
mirror of https://github.com/djhackersdev/bemanitools.git synced 2024-11-12 01:10:49 +01:00

sdvxhook2: Add sdvxhook2

This commit is contained in:
Will Xyen 2019-11-26 15:59:57 -05:00
parent 2011bfafd6
commit 1d247d44d5
17 changed files with 1333 additions and 0 deletions

View File

@ -134,6 +134,7 @@ include src/main/p3ioemu/Module.mk
include src/main/p4ioemu/Module.mk
include src/main/pcbidgen/Module.mk
include src/main/sdvxhook/Module.mk
include src/main/sdvxhook2/Module.mk
include src/main/sdvxio/Module.mk
include src/main/sdvxio-kfca/Module.mk
include src/main/security/Module.mk
@ -419,6 +420,21 @@ $(zipdir)/sdvx.zip: \
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/sdvx5.zip: \
build/bin/avs2_1700-64/launcher.exe \
build/bin/avs2_1700-64/sdvxhook2.dll \
build/bin/indep-64/config.exe \
build/bin/indep-64/eamio.dll \
build/bin/indep-64/geninput.dll \
build/bin/indep-64/sdvxio.dll \
build/bin/indep-64/sdvxio-kfca.dll \
dist/sdvx5/config.bat \
dist/sdvx5/gamestart.bat \
dist/sdvx5/sdvxhook.conf \
| $(zipdir)/
$(V)echo ... $@
$(V)zip -j $@ $^
$(zipdir)/ddr-12-to-16.zip: \
build/bin/avs2_1508-32/launcher.exe \
build/bin/avs2_1508-32/ddrhook.dll \
@ -504,6 +520,7 @@ $(BUILDDIR)/bemanitools.zip: \
$(zipdir)/jb-08.zip \
$(zipdir)/src.zip \
$(zipdir)/sdvx.zip \
$(zipdir)/sdvx5.zip \
$(zipdir)/tools.zip \
$(zipdir)/tools-x64.zip \
CHANGELOG.md \

1
dist/sdvx5/config.bat vendored Normal file
View File

@ -0,0 +1 @@
@start config.exe sdvx

16
dist/sdvx5/gamestart.bat vendored Normal file
View File

@ -0,0 +1,16 @@
@echo off
cd /d %~dp0
if not exist dev mkdir dev
if not exist dev\e mkdir dev\e
if not exist dev\g mkdir dev\g
if not exist dev\nvram mkdir dev\nvram
if not exist dev\raw mkdir dev\raw
if not exist dev\raw\log mkdir dev\raw\log
if not exist dev\raw\fscache mkdir dev\raw\fscache
for /R prop\defaults %%D in (*.*) do (
if not exist dev\nvram\%%~nxD copy /y prop\defaults\%%~nxD dev\nvram
)
launcher -H 268435456 -K sdvxhook5.dll soundvoltex.dll --options sdvxhook.conf %*

21
dist/sdvx5/sdvxhook.conf vendored Normal file
View File

@ -0,0 +1,21 @@
# [bool (0/1)]: Run the game in a framed window (requires windowed option)
gfx.framed=1
# [bool (0/1)]: Run the game windowed
gfx.windowed=0
# [bool (0/1)]: Disable card reader emulation and enable usage of real card reader hardware on COM0 (for games supporting slotted readers)
io.disable_card_reader_emulation=0
# [bool (0/1)]: Disable BIO2 emulation and enable usage of real BIO2 hardware
io.disable_bio2_emu=0
# [bool (0/1)]: Disables the poll limiter, warning very high CPU usage may arise
io.disable_poll_limiter=0
# [bool (0/1)]: Disables the camera emulation
cam.disable_emu=0
# [str]: Override camera device ID detection (copy from device manager, do not escape)
cam.device_id=

View File

@ -0,0 +1,31 @@
avsdlls += sdvxhook2
ldflags_sdvxhook2 := \
-liphlpapi \
-lsetupapi \
-lcfgmgr32 \
-lmf \
-lmfplat \
-lole32 \
deplibs_sdvxhook2 := \
avs \
libs_sdvxhook2 := \
acioemu \
bio2emu \
camhook \
sdvxio \
hook \
hooklib \
cconfig \
util \
eamio \
src_sdvxhook2 := \
acio.c \
bi2a.c \
dllmain.c \
d3d9.c \
config-gfx.c \
config-io.c \

93
src/main/sdvxhook2/acio.c Normal file
View File

@ -0,0 +1,93 @@
// clang-format off
// Don't format because the order is important here
#include <windows.h>
#include <devioctl.h>
#include <ntdef.h>
#include <ntddser.h>
// clang-format on
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <wchar.h>
#include "acioemu/addr.h"
#include "acioemu/emu.h"
#include "acioemu/icca.h"
#include "hook/iohook.h"
#include "hooklib/rs232.h"
#include "sdvxhook2/acio.h"
#include "imports/avs.h"
#include "util/defs.h"
#include "util/iobuf.h"
#include "util/log.h"
#include "util/str.h"
static struct ac_io_emu ac_io_emu;
static struct ac_io_emu_icca ac_io_emu_icca;
void ac_io_port_init(void)
{
ac_io_emu_init(&ac_io_emu, L"\\\\.\\COM2");
ac_io_emu_icca_init(&ac_io_emu_icca, &ac_io_emu, 0);
rs232_hook_add_fd(ac_io_emu.fd);
}
void ac_io_port_fini(void)
{
ac_io_emu_fini(&ac_io_emu);
}
HRESULT ac_io_port_dispatch_irp(struct irp *irp)
{
const struct ac_io_message *msg;
HRESULT hr;
log_assert(irp != NULL);
if (!ac_io_emu_match_irp(&ac_io_emu, irp)) {
return irp_invoke_next(irp);
}
for (;;) {
hr = ac_io_emu_dispatch_irp(&ac_io_emu, irp);
if (hr != S_OK) {
return hr;
}
msg = ac_io_emu_request_peek(&ac_io_emu);
switch (msg->addr) {
case 0:
ac_io_emu_cmd_assign_addrs(&ac_io_emu, msg, 1);
log_warning("ac_io_emu_cmd_assign_addrs");
break;
case 1:
ac_io_emu_icca_dispatch_request(&ac_io_emu_icca, msg);
break;
case AC_IO_BROADCAST:
log_warning("Broadcast(?) message on IIDX ACIO bus?");
break;
default:
log_warning(
"ACIO message on unhandled bus address: %d", msg->addr);
break;
}
ac_io_emu_request_pop(&ac_io_emu);
}
}

14
src/main/sdvxhook2/acio.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef SDVXHOOK2_AC_IO_H
#define SDVXHOOK2_AC_IO_H
#include <windows.h>
#include <stdbool.h>
#include "hook/iohook.h"
void ac_io_port_init(void);
void ac_io_port_fini(void);
HRESULT ac_io_port_dispatch_irp(struct irp *irp);
#endif

251
src/main/sdvxhook2/bi2a.c Normal file
View File

@ -0,0 +1,251 @@
#define LOG_MODULE "sdvxhook2-bi2a"
#include "sdvxhook2/bi2a.h"
#include "bio2emu/emu.h"
#include <windows.h> /* for _BitScanForward */
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "acioemu/emu.h"
#include "bemanitools/sdvxio.h"
static void bio2_emu_bi2a_cmd_send_version(
struct ac_io_emu *emu, const struct ac_io_message *req);
static void bio2_emu_bi2a_send_state(
struct ac_io_emu *emu, const struct ac_io_message *req);
static void bio2_emu_bi2a_send_empty(
struct ac_io_emu *emu, const struct ac_io_message *req);
static void bio2_emu_bi2a_send_status(
struct ac_io_emu *emu, const struct ac_io_message *req, uint8_t status);
static void
kfca_amp_control(struct ac_io_emu *emu, const struct ac_io_message *req);
static bool poll_delay;
void bio2_emu_bi2a_init(
struct bio2emu_port *bio2_emu, bool disable_poll_limiter)
{
bio2emu_port_init(bio2_emu);
poll_delay = !disable_poll_limiter;
if (!poll_delay) {
log_warning("bio2_emu_bi2a_init: poll_delay has been disabled");
}
}
void bio2_emu_bi2a_dispatch_request(
struct bio2emu_port *bio2port, const struct ac_io_message *req)
{
uint16_t cmd_code;
cmd_code = ac_io_u16(req->cmd.code);
switch (cmd_code) {
case AC_IO_CMD_KFCA_WATCHDOG:
log_misc("BIO2_BI2A_CMD_WATCHDOG(%d)", req->addr);
bio2_emu_bi2a_send_status(&bio2port->acio, req, 0x00);
break;
case AC_IO_CMD_KFCA_POLL:
// log_misc("BIO2_BI2A_CMD_POLL");
bio2_emu_bi2a_send_state(&bio2port->acio, req);
break;
case AC_IO_CMD_GET_VERSION:
log_misc("BIO2_CMD_GET_VERSION(%d)", req->addr);
bio2_emu_bi2a_cmd_send_version(&bio2port->acio, req);
break;
case AC_IO_CMD_CLEAR:
log_misc("BIO2_BI2A_CMD_CLEAR(%d)", req->addr);
bio2_emu_bi2a_send_status(&bio2port->acio, req, 0x00);
break;
case AC_IO_CMD_START_UP:
log_misc("BIO2_BI2A_CMD_START_UP(%d)", req->addr);
bio2_emu_bi2a_send_status(&bio2port->acio, req, 0x00);
break;
case AC_IO_CMD_KEEPALIVE:
log_misc("BIO2_BI2A_CMD_KEEPALIVE(%d)", req->addr);
bio2_emu_bi2a_send_empty(&bio2port->acio, req);
break;
case AC_IO_CMD_KFCA_AMP_CONTROL:
log_misc("BIO2_BI2A_CMD_AMP_CONTROL(%d)", req->addr);
kfca_amp_control(&bio2port->acio, req);
break;
default:
log_warning(
"Unknown BIO2 message %04x on BI2A node, addr=%d",
cmd_code,
req->addr);
break;
}
}
static void
kfca_amp_control(struct ac_io_emu *emu, const struct ac_io_message *req)
{
struct ac_io_message resp;
resp.addr = req->addr | AC_IO_RESPONSE_FLAG;
resp.cmd.code = req->cmd.code;
resp.cmd.seq_no = req->cmd.seq_no;
resp.cmd.nbytes = req->cmd.nbytes;
memcpy(resp.cmd.raw, req->cmd.raw, req->cmd.nbytes);
// log_misc("sz %d: %d, %d, %d, %d", req->cmd.nbytes, req->cmd.raw[0],
// req->cmd.raw[1], req->cmd.raw[2], req->cmd.raw[3]);
ac_io_emu_response_push(emu, &resp, 0);
}
static void bio2_emu_bi2a_cmd_send_version(
struct ac_io_emu *emu, const struct ac_io_message *req)
{
struct ac_io_message resp;
resp.addr = req->addr | AC_IO_RESPONSE_FLAG;
resp.cmd.code = req->cmd.code;
resp.cmd.seq_no = req->cmd.seq_no;
resp.cmd.nbytes = sizeof(resp.cmd.version);
resp.cmd.version.type = ac_io_u32(AC_IO_NODE_TYPE_BI2A);
resp.cmd.version.flag = 0x00;
resp.cmd.version.major = 0x01;
resp.cmd.version.minor = 0x02;
resp.cmd.version.revision = 0x09;
memcpy(
resp.cmd.version.product_code,
"BI2A",
sizeof(resp.cmd.version.product_code));
strncpy(resp.cmd.version.date, __DATE__, sizeof(resp.cmd.version.date));
strncpy(resp.cmd.version.time, __TIME__, sizeof(resp.cmd.version.time));
ac_io_emu_response_push(emu, &resp, 0);
}
static void
bio2_emu_bi2a_send_empty(struct ac_io_emu *emu, const struct ac_io_message *req)
{
struct ac_io_message resp;
resp.addr = req->addr | AC_IO_RESPONSE_FLAG;
resp.cmd.code = req->cmd.code;
resp.cmd.seq_no = req->cmd.seq_no;
resp.cmd.nbytes = 0;
ac_io_emu_response_push(emu, &resp, 0);
}
static void bio2_emu_bi2a_send_status(
struct ac_io_emu *emu, const struct ac_io_message *req, uint8_t status)
{
struct ac_io_message resp;
resp.addr = req->addr | AC_IO_RESPONSE_FLAG;
resp.cmd.code = req->cmd.code;
resp.cmd.seq_no = req->cmd.seq_no;
resp.cmd.nbytes = sizeof(resp.cmd.status);
resp.cmd.status = status;
ac_io_emu_response_push(emu, &resp, 0);
}
static uint8_t check_pin(uint16_t value, uint8_t pin)
{
return (value >> pin) & 1;
}
static uint32_t _assign_light(uint32_t shift, uint32_t value)
{
if (!value) {
return 0;
} else {
return 1 << shift;
}
}
static void
bio2_emu_bi2a_send_state(struct ac_io_emu *emu, const struct ac_io_message *req)
{
struct ac_io_message resp;
struct bio2_bi2a_state *pin;
struct bio2_bi2a_state_out *pout;
resp.addr = req->addr | AC_IO_RESPONSE_FLAG;
resp.cmd.code = req->cmd.code;
resp.cmd.seq_no = req->cmd.seq_no;
resp.cmd.nbytes = sizeof(*pin);
pout = (struct bio2_bi2a_state_out *) &req->cmd.raw;
pin = (struct bio2_bi2a_state *) &resp.cmd.raw;
memset(pin, 0, sizeof(*pin));
uint32_t gpio = 0;
gpio |= _assign_light(0x0C, pout->gpio[0]);
gpio |= _assign_light(0x0D, pout->gpio[1]);
gpio |= _assign_light(0x0E, pout->gpio[2]);
gpio |= _assign_light(0x0F, pout->gpio[3]);
gpio |= _assign_light(0x00, pout->gpio[4]);
gpio |= _assign_light(0x01, pout->gpio[5]);
gpio |= _assign_light(0x02, pout->gpio[6]);
sdvx_io_set_gpio_lights(gpio);
sdvx_io_set_pwm_light(0x0, pout->wingUpper[0]);
sdvx_io_set_pwm_light(0x1, pout->wingUpper[1]);
sdvx_io_set_pwm_light(0x2, pout->wingUpper[2]);
sdvx_io_set_pwm_light(0x3, pout->wingUpper[0]);
sdvx_io_set_pwm_light(0x4, pout->wingUpper[1]);
sdvx_io_set_pwm_light(0x5, pout->wingUpper[2]);
sdvx_io_set_pwm_light(0x6, pout->wingLower[0]);
sdvx_io_set_pwm_light(0x7, pout->wingLower[1]);
sdvx_io_set_pwm_light(0x8, pout->wingLower[2]);
sdvx_io_set_pwm_light(0x9, pout->wingLower[0]);
sdvx_io_set_pwm_light(0xA, pout->wingLower[1]);
sdvx_io_set_pwm_light(0xB, pout->wingLower[2]);
sdvx_io_set_pwm_light(0xC, pout->woof_r);
sdvx_io_set_pwm_light(0xD, pout->woof_g);
sdvx_io_set_pwm_light(0xE, pout->woof_b);
sdvx_io_set_pwm_light(0xF, pout->controller[0]);
sdvx_io_set_pwm_light(0x10, pout->controller[1]);
sdvx_io_set_pwm_light(0x11, pout->controller[2]);
sdvx_io_write_output();
sdvx_io_read_input();
uint8_t sys = sdvx_io_get_input_gpio_sys();
uint16_t gpio0 = sdvx_io_get_input_gpio(0);
uint16_t gpio1 = sdvx_io_get_input_gpio(1);
// TODO: Make a counter or smth to counteract the accuracy lost in *4
pin->ANALOGS[0].a_val = sdvx_io_get_spinner_pos(0);
pin->ANALOGS[1].a_val = sdvx_io_get_spinner_pos(1);
pin->ANALOGS[0].a_coin = check_pin(sys, SDVX_IO_IN_GPIO_SYS_COIN);
pin->ANALOGS[0].a_test = check_pin(sys, SDVX_IO_IN_GPIO_SYS_TEST);
pin->ANALOGS[0].a_service = check_pin(sys, SDVX_IO_IN_GPIO_SYS_SERVICE) ||
check_pin(sys, SDVX_IO_IN_GPIO_SYS_COIN);
pin->raw[0] = ac_io_u16(pin->raw[0]);
pin->raw[1] = ac_io_u16(pin->raw[1]);
pin->BUTTONS1.b_start = check_pin(gpio0, SDVX_IO_IN_GPIO_0_START);
pin->BUTTONS1.b_headphone = check_pin(gpio0, SDVX_IO_IN_GPIO_0_HEADPHONE);
pin->BUTTONS1.b_a = check_pin(gpio0, SDVX_IO_IN_GPIO_0_A);
pin->BUTTONS1.b_b = check_pin(gpio0, SDVX_IO_IN_GPIO_0_B);
pin->BUTTONS1.b_c = check_pin(gpio0, SDVX_IO_IN_GPIO_0_C);
pin->BUTTONS1.b_d = check_pin(gpio1, SDVX_IO_IN_GPIO_1_D);
pin->BUTTONS1.b_fxl = check_pin(gpio1, SDVX_IO_IN_GPIO_1_FX_L);
pin->BUTTONS2.b_fxr = check_pin(gpio1, SDVX_IO_IN_GPIO_1_FX_R);
ac_io_emu_response_push(emu, &resp, 0);
}

90
src/main/sdvxhook2/bi2a.h Normal file
View File

@ -0,0 +1,90 @@
#ifndef SDVXHOOK2_BI2A_H
#define SDVXHOOK2_BI2A_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "bio2emu/emu.h"
enum bio2_bi2a_cmd {
// Custom Stuff
BIO2_BI2A_CMD_UNK_0100 = 0x0100,
BIO2_BI2A_CMD_UNK_0120 = 0x0120,
BIO2_BI2A_CMD_POLL = 0x0152,
};
#pragma pack(push, 1)
struct bi2a_sdvx_analog {
uint16_t unk1 : 1;
uint16_t a_coin : 1;
uint16_t a_service : 1;
uint16_t a_test : 1;
uint16_t unk2 : 2;
uint16_t a_val : 10;
};
struct bi2a_sdvx_buttons1 {
uint8_t b_fxl : 1;
uint8_t b_d : 1;
uint8_t b_c : 1;
uint8_t b_b : 1;
uint8_t b_a : 1;
uint8_t b_start : 1;
uint8_t b_recorder : 1;
uint8_t b_headphone : 1;
};
struct bi2a_sdvx_buttons2 {
uint8_t unk : 5;
uint8_t b_ex2 : 1;
uint8_t b_ex1 : 1;
uint8_t b_fxr : 1;
};
struct bio2_bi2a_state {
union {
uint16_t raw[8];
struct {
struct bi2a_sdvx_analog ANALOGS[4];
uint8_t UNK; // coin mech?
struct bi2a_sdvx_buttons1 BUTTONS1;
struct bi2a_sdvx_buttons2 BUTTONS2;
uint8_t UNK2[5];
};
};
};
struct bio2_bi2a_state_out {
uint8_t unk1[2];
uint8_t c_block;
uint8_t woof_r;
uint8_t woof_g;
uint8_t unk2;
uint8_t woof_b;
uint8_t controller[3];
uint8_t unk3;
uint8_t gpio[7]; // START, ABCD, FXL, FXR
uint8_t unk4[3];
uint8_t generator[3];
uint8_t unk5[3];
uint8_t gpio2[3]; // pop, titleL, titleR
uint8_t unk6;
uint8_t wingUpper[3];
uint8_t wingLower[3];
uint8_t unk7[3];
};
_Static_assert(
sizeof(struct bio2_bi2a_state) == 16,
"bio2_bi2a_state_in is the wrong size");
_Static_assert(
sizeof(struct bio2_bi2a_state_out) == 40,
"bio2_bi2a_state_out is the wrong size");
#pragma pack(pop)
void bio2_emu_bi2a_init(struct bio2emu_port *in, bool disable_poll_limiter);
void bio2_emu_bi2a_dispatch_request(
struct bio2emu_port *bio2port, const struct ac_io_message *req);
#endif

View File

@ -0,0 +1,139 @@
#include <string.h>
#include "cconfig/cconfig-util.h"
#include "sdvxhook2/config-gfx.h"
#include "util/log.h"
#define SDVXHOOK2_CONFIG_GFX_FRAMED_KEY "gfx.framed"
#define SDVXHOOK2_CONFIG_GFX_PCI_ID_KEY "gfx.pci_id"
#define SDVXHOOK2_CONFIG_GFX_WINDOWED_KEY "gfx.windowed"
#define SDVXHOOK2_CONFIG_GFX_WINDOW_WIDTH_KEY "gfx.window_width"
#define SDVXHOOK2_CONFIG_GFX_WINDOW_HEIGHT_KEY "gfx.window_height"
#define SDVXHOOK2_CONFIG_GFX_DEFAULT_FRAMED_VALUE false
#define SDVXHOOK2_CONFIG_GFX_DEFAULT_PCI_ID_VALUE "1002:7146"
#define SDVXHOOK2_CONFIG_GFX_DEFAULT_WINDOWED_VALUE false
#define SDVXHOOK2_CONFIG_GFX_DEFAULT_WINDOW_WIDTH_VALUE -1
#define SDVXHOOK2_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE -1
void sdvxhook2_config_gfx_init(struct cconfig *config)
{
cconfig_util_set_bool(
config,
SDVXHOOK2_CONFIG_GFX_FRAMED_KEY,
SDVXHOOK2_CONFIG_GFX_DEFAULT_FRAMED_VALUE,
"Run the game in a framed window (requires windowed option)");
cconfig_util_set_str(
config,
SDVXHOOK2_CONFIG_GFX_PCI_ID_KEY,
SDVXHOOK2_CONFIG_GFX_DEFAULT_PCI_ID_VALUE,
"Patch the GPU device ID detection (leave empty to"
" disable), format XXXX:YYYY, two 4 digit hex numbers (vid:pid)."
" Examples: 1002:7146 (RV515, Radeon X1300), 1002:95C5 (RV620 LE,"
" Radeon HD3450)");
cconfig_util_set_bool(
config,
SDVXHOOK2_CONFIG_GFX_WINDOWED_KEY,
SDVXHOOK2_CONFIG_GFX_DEFAULT_WINDOWED_VALUE,
"Run the game windowed");
cconfig_util_set_int(
config,
SDVXHOOK2_CONFIG_GFX_WINDOW_WIDTH_KEY,
SDVXHOOK2_CONFIG_GFX_DEFAULT_WINDOW_WIDTH_VALUE,
"Windowed width, -1 for default size");
cconfig_util_set_int(
config,
SDVXHOOK2_CONFIG_GFX_WINDOW_HEIGHT_KEY,
SDVXHOOK2_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE,
"Windowed height, -1 for default size");
}
void sdvxhook2_config_gfx_get(
struct sdvxhook2_config_gfx *config_gfx, struct cconfig *config)
{
char tmp[10];
char *vid;
char *pid;
if (!cconfig_util_get_bool(
config,
SDVXHOOK2_CONFIG_GFX_FRAMED_KEY,
&config_gfx->framed,
SDVXHOOK2_CONFIG_GFX_DEFAULT_FRAMED_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
SDVXHOOK2_CONFIG_GFX_FRAMED_KEY,
SDVXHOOK2_CONFIG_GFX_DEFAULT_FRAMED_VALUE);
}
if (!cconfig_util_get_str(
config,
SDVXHOOK2_CONFIG_GFX_PCI_ID_KEY,
tmp,
sizeof(tmp) - 1,
SDVXHOOK2_CONFIG_GFX_DEFAULT_PCI_ID_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%s'",
SDVXHOOK2_CONFIG_GFX_PCI_ID_KEY,
SDVXHOOK2_CONFIG_GFX_DEFAULT_PCI_ID_VALUE);
}
if (tmp[4] != ':') {
log_warning(
"Invalid format for value for key '%s' specified, fallback "
"to default '%s'",
SDVXHOOK2_CONFIG_GFX_PCI_ID_KEY,
SDVXHOOK2_CONFIG_GFX_DEFAULT_PCI_ID_VALUE);
strcpy(tmp, SDVXHOOK2_CONFIG_GFX_DEFAULT_PCI_ID_VALUE);
}
tmp[4] = '\0';
vid = tmp;
pid = &tmp[5];
config_gfx->pci_id_vid = strtol(vid, NULL, 16);
config_gfx->pci_id_pid = strtol(pid, NULL, 16);
if (!cconfig_util_get_bool(
config,
SDVXHOOK2_CONFIG_GFX_WINDOWED_KEY,
&config_gfx->windowed,
SDVXHOOK2_CONFIG_GFX_DEFAULT_WINDOWED_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
SDVXHOOK2_CONFIG_GFX_WINDOWED_KEY,
SDVXHOOK2_CONFIG_GFX_DEFAULT_WINDOWED_VALUE);
}
if (!cconfig_util_get_int(
config,
SDVXHOOK2_CONFIG_GFX_WINDOW_WIDTH_KEY,
&config_gfx->window_width,
SDVXHOOK2_CONFIG_GFX_DEFAULT_WINDOW_WIDTH_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
SDVXHOOK2_CONFIG_GFX_WINDOW_WIDTH_KEY,
SDVXHOOK2_CONFIG_GFX_DEFAULT_WINDOW_WIDTH_VALUE);
}
if (!cconfig_util_get_int(
config,
SDVXHOOK2_CONFIG_GFX_WINDOW_HEIGHT_KEY,
&config_gfx->window_height,
SDVXHOOK2_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
SDVXHOOK2_CONFIG_GFX_WINDOW_HEIGHT_KEY,
SDVXHOOK2_CONFIG_GFX_DEFAULT_WINDOW_HEIGHT_VALUE);
}
}

View File

@ -0,0 +1,20 @@
#ifndef SDVXHOOK2_CONFIG_GFX_H
#define SDVXHOOK2_CONFIG_GFX_H
#include "cconfig/cconfig.h"
struct sdvxhook2_config_gfx {
bool framed;
uint16_t pci_id_vid;
uint16_t pci_id_pid;
bool windowed;
int32_t window_width;
int32_t window_height;
};
void sdvxhook2_config_gfx_init(struct cconfig *config);
void sdvxhook2_config_gfx_get(
struct sdvxhook2_config_gfx *config_gfx, struct cconfig *config);
#endif

View File

@ -0,0 +1,76 @@
#include "cconfig/cconfig-util.h"
#include "sdvxhook2/config-io.h"
#include "util/log.h"
#define SDVXHOOK2_CONFIG_IO_DISABLE_CARD_READER_EMU_KEY \
"io.disable_card_reader_emu"
#define SDVXHOOK2_CONFIG_IO_DISABLE_BIO2_EMU_KEY "io.disable_bio2_emu"
#define SDVXHOOK2_CONFIG_IO_DISABLE_POLL_LIMITER_KEY "io.disable_poll_limiter"
#define SDVXHOOK2_CONFIG_IO_DEFAULT_DISABLE_CARD_READER_EMU_VALUE false
#define SDVXHOOK2_CONFIG_IO_DEFAULT_DISABLE_BIO2_EMU_VALUE false
#define SDVXHOOK2_CONFIG_IO_DEFAULT_DISABLE_POLL_LIMITER_VALUE false
void sdvxhook2_config_io_init(struct cconfig *config)
{
cconfig_util_set_bool(
config,
SDVXHOOK2_CONFIG_IO_DISABLE_CARD_READER_EMU_KEY,
SDVXHOOK2_CONFIG_IO_DEFAULT_DISABLE_CARD_READER_EMU_VALUE,
"Disable card reader emulation and enable usage of real card reader "
"hardware on COM0 (for games supporting slotted readers)");
cconfig_util_set_bool(
config,
SDVXHOOK2_CONFIG_IO_DISABLE_BIO2_EMU_KEY,
SDVXHOOK2_CONFIG_IO_DEFAULT_DISABLE_BIO2_EMU_VALUE,
"Disable BIO2 emulation and enable usage of real BIO2 hardware");
cconfig_util_set_bool(
config,
SDVXHOOK2_CONFIG_IO_DISABLE_POLL_LIMITER_KEY,
SDVXHOOK2_CONFIG_IO_DEFAULT_DISABLE_POLL_LIMITER_VALUE,
"Disables the poll limiter, warning very high CPU usage may arise");
}
void sdvxhook2_config_io_get(
struct sdvxhook2_config_io *config_io, struct cconfig *config)
{
if (!cconfig_util_get_bool(
config,
SDVXHOOK2_CONFIG_IO_DISABLE_CARD_READER_EMU_KEY,
&config_io->disable_card_reader_emu,
SDVXHOOK2_CONFIG_IO_DEFAULT_DISABLE_CARD_READER_EMU_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
SDVXHOOK2_CONFIG_IO_DISABLE_CARD_READER_EMU_KEY,
SDVXHOOK2_CONFIG_IO_DEFAULT_DISABLE_CARD_READER_EMU_VALUE);
}
if (!cconfig_util_get_bool(
config,
SDVXHOOK2_CONFIG_IO_DISABLE_BIO2_EMU_KEY,
&config_io->disable_bio2_emu,
SDVXHOOK2_CONFIG_IO_DEFAULT_DISABLE_BIO2_EMU_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
SDVXHOOK2_CONFIG_IO_DISABLE_BIO2_EMU_KEY,
SDVXHOOK2_CONFIG_IO_DEFAULT_DISABLE_BIO2_EMU_VALUE);
}
if (!cconfig_util_get_bool(
config,
SDVXHOOK2_CONFIG_IO_DISABLE_POLL_LIMITER_KEY,
&config_io->disable_poll_limiter,
SDVXHOOK2_CONFIG_IO_DEFAULT_DISABLE_POLL_LIMITER_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
SDVXHOOK2_CONFIG_IO_DISABLE_POLL_LIMITER_KEY,
SDVXHOOK2_CONFIG_IO_DEFAULT_DISABLE_POLL_LIMITER_VALUE);
}
}

View File

@ -0,0 +1,19 @@
#ifndef SDVXHOOK2_CONFIG_IO_H
#define SDVXHOOK2_CONFIG_IO_H
#include <windows.h>
#include "cconfig/cconfig.h"
struct sdvxhook2_config_io {
bool disable_card_reader_emu;
bool disable_bio2_emu;
bool disable_poll_limiter;
};
void sdvxhook2_config_io_init(struct cconfig *config);
void sdvxhook2_config_io_get(
struct sdvxhook2_config_io *config_io, struct cconfig *config);
#endif

319
src/main/sdvxhook2/d3d9.c Normal file
View File

@ -0,0 +1,319 @@
#define LOG_MODULE "d3d9-hook"
#include <d3d9.h>
#include <d3dx9core.h>
#include <windows.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "hook/com-proxy.h"
#include "hook/table.h"
#include "sdvxhook2/d3d9.h"
#include "util/defs.h"
#include "util/log.h"
#include "util/str.h"
#include "util/time.h"
/* ------------------------------------------------------------------------- */
// thanks to Felix for reminding Xyen to hook 9Ex instead of 9
static HWND STDCALL my_CreateWindowExA(
DWORD dwExStyle,
LPCSTR lpClassName,
LPCSTR lpWindowName,
DWORD dwStyle,
int X,
int Y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam);
static HRESULT STDCALL my_CreateDeviceEx(
IDirect3D9Ex *self,
UINT adapter,
D3DDEVTYPE type,
HWND hwnd,
DWORD flags,
D3DPRESENT_PARAMETERS *pp,
D3DDISPLAYMODEEX *fdm,
IDirect3DDevice9Ex **pdev);
static HRESULT STDCALL my_Direct3DCreate9Ex(UINT sdk_ver, IDirect3D9Ex **api);
static BOOL STDCALL my_EnumDisplayDevicesA(
const char *dev_name, DWORD dev_num, DISPLAY_DEVICEA *info, DWORD flags);
static BOOL STDCALL
my_MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint);
static void calc_win_size_with_framed(
HWND hwnd, DWORD x, DWORD y, DWORD width, DWORD height, LPWINDOWPOS wp);
static HWND(STDCALL *real_CreateWindowExA)(
DWORD dwExStyle,
LPCSTR lpClassName,
LPCSTR lpWindowName,
DWORD dwStyle,
int X,
int Y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam);
static HRESULT(STDCALL *real_Direct3DCreate9Ex)(
UINT sdk_ver, IDirect3D9Ex **api);
static BOOL(STDCALL *real_EnumDisplayDevicesA)(
const char *dev_name, DWORD dev_num, DISPLAY_DEVICEA *info, DWORD flags);
static BOOL(STDCALL *real_MoveWindow)(
HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint);
/* ------------------------------------------------------------------------- */
static char d3d9_pci_id[32];
static bool d3d9_windowed;
static int32_t d3d9_window_width = -1;
static int32_t d3d9_window_height = -1;
static bool d3d9_window_framed;
/* ------------------------------------------------------------------------- */
static const struct hook_symbol d3d9_hook_syms[] = {
{.name = "Direct3DCreate9Ex",
.patch = my_Direct3DCreate9Ex,
.link = (void **) &real_Direct3DCreate9Ex},
};
static const struct hook_symbol d3d9_hook_user32_syms[] = {
{.name = "EnumDisplayDevicesA",
.patch = my_EnumDisplayDevicesA,
.link = (void **) &real_EnumDisplayDevicesA},
{.name = "CreateWindowExA",
.patch = my_CreateWindowExA,
.link = (void **) &real_CreateWindowExA},
{.name = "MoveWindow",
.patch = my_MoveWindow,
.link = (void **) &real_MoveWindow},
};
/* ------------------------------------------------------------------------- */
static HWND STDCALL my_CreateWindowExA(
DWORD dwExStyle,
LPCSTR lpClassName,
LPCSTR lpWindowName,
DWORD dwStyle,
int X,
int Y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam)
{
if (d3d9_windowed && d3d9_window_framed) {
/* use a different style */
dwStyle |= WS_OVERLAPPEDWINDOW;
/* also show mouse cursor */
ShowCursor(TRUE);
}
HWND hwnd = real_CreateWindowExA(
dwExStyle,
lpClassName,
lpWindowName,
dwStyle,
X,
Y,
nWidth,
nHeight,
hWndParent,
hMenu,
hInstance,
lpParam);
return hwnd;
}
static BOOL STDCALL
my_MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint)
{
if (d3d9_windowed && d3d9_window_framed) {
/* we have to adjust the window size, because the window needs to be a
slightly bigger than the rendering resolution (window caption and
stuff is included in the window size) */
if (d3d9_window_width != -1 && d3d9_window_height != -1) {
log_misc(
"Overriding window size from %dx%d with %dx%d",
nWidth,
nHeight,
d3d9_window_width,
d3d9_window_height);
nWidth = d3d9_window_width;
nHeight = d3d9_window_height;
}
WINDOWPOS wp;
calc_win_size_with_framed(hWnd, X, Y, nWidth, nHeight, &wp);
SetWindowPos(hWnd, 0, wp.x, wp.y, wp.cx, wp.cy, 0);
X = wp.x;
Y = wp.y;
nWidth = wp.cx;
nHeight = wp.cy;
}
BOOL result = real_MoveWindow(hWnd, X, Y, nWidth, nHeight, bRepaint);
return result;
}
static HRESULT STDCALL my_CreateDeviceEx(
IDirect3D9Ex *self,
UINT adapter,
D3DDEVTYPE type,
HWND hwnd,
DWORD flags,
D3DPRESENT_PARAMETERS *pp,
D3DDISPLAYMODEEX *fdm,
IDirect3DDevice9Ex **pdev)
{
IDirect3D9Ex *real = COM_PROXY_UNWRAP(self);
HRESULT hr;
if (d3d9_windowed) {
fdm = NULL;
pp->Windowed = TRUE;
pp->FullScreen_RefreshRateInHz = 0;
}
hr = IDirect3D9Ex_CreateDeviceEx(
real, adapter, type, hwnd, flags, pp, fdm, pdev);
// TODO stuff
return hr;
}
static HRESULT STDCALL my_Direct3DCreate9Ex(UINT sdk_ver, IDirect3D9Ex **api)
{
HRESULT hr;
IDirect3D9ExVtbl *api_vtbl;
struct com_proxy *api_proxy;
IDirect3D9Ex *api_;
log_info("Direct3DCreate9Ex hook hit");
hr = real_Direct3DCreate9Ex(sdk_ver, api);
api_ = *api;
api_proxy = com_proxy_wrap(api_, sizeof(*api_->lpVtbl));
api_vtbl = api_proxy->vptr;
api_vtbl->CreateDeviceEx = my_CreateDeviceEx;
*api = (IDirect3D9Ex *) api_proxy;
return hr;
}
static BOOL STDCALL my_EnumDisplayDevicesA(
const char *dev_name, DWORD dev_num, DISPLAY_DEVICEA *info, DWORD flags)
{
BOOL ok;
ok = real_EnumDisplayDevicesA(dev_name, dev_num, info, flags);
if (ok && d3d9_pci_id[0] != '\0') {
/* Apparently Konami didn't read the "Not Used" message in the MSDN
docs for DISPLAY_DEVICE */
log_misc("Replacing device ID %s with %s", info->DeviceID, d3d9_pci_id);
str_cpy(info->DeviceID, sizeof(info->DeviceID), d3d9_pci_id);
}
return ok;
}
void d3d9_hook_init(void)
{
hook_table_apply(
NULL, "d3d9.dll", d3d9_hook_syms, lengthof(d3d9_hook_syms));
hook_table_apply(
NULL,
"user32.dll",
d3d9_hook_user32_syms,
lengthof(d3d9_hook_user32_syms));
log_info("Inserted graphics hooks");
}
void d3d9_set_windowed(bool framed, int32_t width, int32_t height)
{
d3d9_windowed = true;
d3d9_window_framed = framed;
d3d9_window_width = width;
d3d9_window_height = height;
}
void d3d9_set_pci_id(uint16_t vid, uint16_t pid)
{
str_format(
d3d9_pci_id, sizeof(d3d9_pci_id), "PCI\\VEN_%04X&DEV_%04X", vid, pid);
}
/* ------------------------------------------------------------------------- */
static void calc_win_size_with_framed(
HWND hwnd, DWORD x, DWORD y, DWORD width, DWORD height, LPWINDOWPOS wp)
{
/* taken from dxwnd */
RECT rect;
DWORD style;
int max_x, max_y;
HMENU menu;
rect.left = x;
rect.top = y;
max_x = width;
max_y = height;
rect.right = x + max_x;
rect.bottom = y + max_y;
style = GetWindowLong(hwnd, GWL_STYLE);
menu = GetMenu(hwnd);
AdjustWindowRect(&rect, style, (menu != NULL));
/* shift down-right so that the border is visible
and also update the iPosX,iPosY upper-left coordinates
of the client area */
if (rect.left < 0) {
rect.right -= rect.left;
rect.left = 0;
}
if (rect.top < 0) {
rect.bottom -= rect.top;
rect.top = 0;
}
wp->x = rect.left;
wp->y = rect.top;
wp->cx = rect.right - rect.left;
wp->cy = rect.bottom - rect.top;
}

38
src/main/sdvxhook2/d3d9.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef SDVXHOOK2_D3D9_H
#define SDVXHOOK2_D3D9_H
#include <stdint.h>
/**
* Hook some d3d9 functions to patch gfx related stuff
* like enabling window mode.
*/
void d3d9_hook_init(void);
/**
* Set the game to window mode.
*
* @param framed True to add a window frame and make the window
* movable, resizable, minizable. False for no frame.
*/
void d3d9_set_windowed(bool framed, int32_t width, int32_t height);
/**
* Patch the GPU device ID detection to allow running the game with
* other GPUs than the ones it is locked to.
*
* @param vid Vendor ID to patch.
* @param pid Product ID to patch.
*/
void d3d9_set_pci_id(uint16_t vid, uint16_t pid);
/**
* Set a framerate limit for the rendering loop.
*
* Use this if the game won't sync up properly with vsync enabled.
*
* @limit Number of frames to limit the rendering loop to
*/
void d3d9_set_frame_rate_limit(int limit);
#endif

View File

@ -0,0 +1,184 @@
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "bemanitools/eamio.h"
#include "bemanitools/sdvxio.h"
#include "cconfig/cconfig-hook.h"
#include "hooklib/acp.h"
#include "hooklib/adapter.h"
#include "hooklib/app.h"
#include "hooklib/rs232.h"
#include "bio2emu/emu.h"
#include "sdvxhook2/bi2a.h"
#include "sdvxhook2/acio.h"
#include "sdvxhook2/d3d9.h"
#include "sdvxhook2/config-gfx.h"
#include "sdvxhook2/config-io.h"
#include "camhook/cam.h"
#include "camhook/config-cam.h"
#include "imports/avs.h"
#include "util/log.h"
#include "util/str.h"
#include "util/thread.h"
#define SDVXHOOK2_INFO_HEADER \
"sdvxhook for VW" \
", build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY(GITREV) "\n"
#define SDVXHOOK2_CMD_USAGE \
"Usage: launcher.exe -K sdvxhook2.dll <soundvoltex.dll> [options...]"
static const irp_handler_t sdvxhook_handlers[] = {
ac_io_port_dispatch_irp,
bio2emu_port_dispatch_irp,
};
struct sdvxhook2_config_io config_io;
struct camhook_config_cam config_cam;
struct sdvxhook2_config_gfx config_gfx;
static struct bio2emu_port bio2_emu = {
.port = "COM4",
.wport = L"\\\\.\\COM4",
.dispatcher = bio2_emu_bi2a_dispatch_request,
};
static bool my_dll_entry_init(char *sidcode, struct property_node *param)
{
struct cconfig *config;
log_info("--- Begin sdvxhook dll_entry_init ---");
config = cconfig_init();
sdvxhook2_config_io_init(config);
sdvxhook2_config_gfx_init(config);
camhook_config_cam_init(config, 1);
if (!cconfig_hook_config_init(
config,
SDVXHOOK2_INFO_HEADER "\n" SDVXHOOK2_CMD_USAGE,
CCONFIG_CMD_USAGE_OUT_STDOUT)) {
cconfig_finit(config);
exit(EXIT_FAILURE);
}
sdvxhook2_config_io_get(&config_io, config);
sdvxhook2_config_gfx_get(&config_gfx, config);
camhook_config_cam_get(&config_cam, config, 1);
cconfig_finit(config);
log_info(SDVXHOOK2_INFO_HEADER);
log_info("Initializing sdvxhook2...");
if (config_gfx.windowed) {
d3d9_set_windowed(
config_gfx.framed,
config_gfx.window_width,
config_gfx.window_height);
}
if (config_gfx.pci_id_pid != 0 && config_gfx.pci_id_vid != 0) {
d3d9_set_pci_id(config_gfx.pci_id_pid, config_gfx.pci_id_vid);
}
/* Start up sdvxio.DLL */
if (!config_io.disable_bio2_emu) {
log_info("Starting sdvx IO backend");
sdvx_io_set_loggers(
log_impl_misc, log_impl_info, log_impl_warning, log_impl_fatal);
if (!sdvx_io_init(
avs_thread_create, avs_thread_join, avs_thread_destroy)) {
log_fatal("Initializing sdvx IO backend failed");
}
}
/* Start up EAMIO.DLL */
if (!config_io.disable_card_reader_emu) {
log_misc("Initializing card reader backend");
eam_io_set_loggers(
log_impl_misc, log_impl_info, log_impl_warning, log_impl_fatal);
if (!eam_io_init(
avs_thread_create, avs_thread_join, avs_thread_destroy)) {
log_fatal("Initializing card reader backend failed");
}
}
/* iohooks are okay, even if emu is diabled since the fake handlers won't be
* used */
iohook_init(sdvxhook_handlers, lengthof(sdvxhook_handlers));
rs232_hook_init();
rs232_hook_limit_hooks();
if (!config_io.disable_bio2_emu) {
bio2emu_init();
bio2_emu_bi2a_init(&bio2_emu, config_io.disable_poll_limiter);
}
if (!config_io.disable_card_reader_emu) {
ac_io_port_init();
}
// camera hooks
if (!config_cam.disable_emu) {
camhook_init(&config_cam);
}
log_info("--- End sdvxhook dll_entry_init ---");
return app_hook_invoke_init(sidcode, param);
}
static bool my_dll_entry_main(void)
{
bool result;
result = app_hook_invoke_main();
if (!config_io.disable_card_reader_emu) {
log_misc("Shutting down card reader backend");
eam_io_fini();
}
if (!config_io.disable_bio2_emu) {
log_misc("Shutting down sdvx IO backend");
sdvx_io_fini();
}
return result;
}
/**
* Hook library Resort Anthem onwards
*/
BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx)
{
if (reason != DLL_PROCESS_ATTACH) {
goto end;
}
log_to_external(
log_body_misc, log_body_info, log_body_warning, log_body_fatal);
app_hook_init(my_dll_entry_init, my_dll_entry_main);
acp_hook_init();
adapter_hook_init();
d3d9_hook_init();
end:
return TRUE;
}

View File

@ -0,0 +1,4 @@
LIBRARY sdvxhook2
EXPORTS
DllMain@12 @1 NONAME