diff --git a/Module.mk b/Module.mk index b4e72c6..76aee1d 100644 --- a/Module.mk +++ b/Module.mk @@ -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 \ diff --git a/dist/sdvx5/config.bat b/dist/sdvx5/config.bat new file mode 100644 index 0000000..611e43c --- /dev/null +++ b/dist/sdvx5/config.bat @@ -0,0 +1 @@ +@start config.exe sdvx diff --git a/dist/sdvx5/gamestart.bat b/dist/sdvx5/gamestart.bat new file mode 100644 index 0000000..a6e2dfb --- /dev/null +++ b/dist/sdvx5/gamestart.bat @@ -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 %* diff --git a/dist/sdvx5/sdvxhook.conf b/dist/sdvx5/sdvxhook.conf new file mode 100644 index 0000000..63da5ae --- /dev/null +++ b/dist/sdvx5/sdvxhook.conf @@ -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= + diff --git a/src/main/sdvxhook2/Module.mk b/src/main/sdvxhook2/Module.mk new file mode 100644 index 0000000..ea05d43 --- /dev/null +++ b/src/main/sdvxhook2/Module.mk @@ -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 \ diff --git a/src/main/sdvxhook2/acio.c b/src/main/sdvxhook2/acio.c new file mode 100644 index 0000000..2dd34a8 --- /dev/null +++ b/src/main/sdvxhook2/acio.c @@ -0,0 +1,93 @@ +// clang-format off +// Don't format because the order is important here +#include +#include +#include +#include +// clang-format on + +#include +#include +#include +#include + +#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); + } +} diff --git a/src/main/sdvxhook2/acio.h b/src/main/sdvxhook2/acio.h new file mode 100644 index 0000000..5766a2f --- /dev/null +++ b/src/main/sdvxhook2/acio.h @@ -0,0 +1,14 @@ +#ifndef SDVXHOOK2_AC_IO_H +#define SDVXHOOK2_AC_IO_H + +#include + +#include + +#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 diff --git a/src/main/sdvxhook2/bi2a.c b/src/main/sdvxhook2/bi2a.c new file mode 100644 index 0000000..3be7a40 --- /dev/null +++ b/src/main/sdvxhook2/bi2a.c @@ -0,0 +1,251 @@ +#define LOG_MODULE "sdvxhook2-bi2a" + +#include "sdvxhook2/bi2a.h" +#include "bio2emu/emu.h" + +#include /* for _BitScanForward */ + +#include +#include +#include + +#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); +} diff --git a/src/main/sdvxhook2/bi2a.h b/src/main/sdvxhook2/bi2a.h new file mode 100644 index 0000000..50c011c --- /dev/null +++ b/src/main/sdvxhook2/bi2a.h @@ -0,0 +1,90 @@ +#ifndef SDVXHOOK2_BI2A_H +#define SDVXHOOK2_BI2A_H + +#include +#include +#include + +#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 diff --git a/src/main/sdvxhook2/config-gfx.c b/src/main/sdvxhook2/config-gfx.c new file mode 100644 index 0000000..6171170 --- /dev/null +++ b/src/main/sdvxhook2/config-gfx.c @@ -0,0 +1,139 @@ +#include + +#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); + } +} diff --git a/src/main/sdvxhook2/config-gfx.h b/src/main/sdvxhook2/config-gfx.h new file mode 100644 index 0000000..327fe17 --- /dev/null +++ b/src/main/sdvxhook2/config-gfx.h @@ -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 \ No newline at end of file diff --git a/src/main/sdvxhook2/config-io.c b/src/main/sdvxhook2/config-io.c new file mode 100644 index 0000000..704eb02 --- /dev/null +++ b/src/main/sdvxhook2/config-io.c @@ -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); + } +} diff --git a/src/main/sdvxhook2/config-io.h b/src/main/sdvxhook2/config-io.h new file mode 100644 index 0000000..610bd47 --- /dev/null +++ b/src/main/sdvxhook2/config-io.h @@ -0,0 +1,19 @@ +#ifndef SDVXHOOK2_CONFIG_IO_H +#define SDVXHOOK2_CONFIG_IO_H + +#include + +#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 \ No newline at end of file diff --git a/src/main/sdvxhook2/d3d9.c b/src/main/sdvxhook2/d3d9.c new file mode 100644 index 0000000..fcf9498 --- /dev/null +++ b/src/main/sdvxhook2/d3d9.c @@ -0,0 +1,319 @@ +#define LOG_MODULE "d3d9-hook" + +#include +#include +#include + +#include +#include +#include +#include + +#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; +} diff --git a/src/main/sdvxhook2/d3d9.h b/src/main/sdvxhook2/d3d9.h new file mode 100644 index 0000000..feeb474 --- /dev/null +++ b/src/main/sdvxhook2/d3d9.h @@ -0,0 +1,38 @@ +#ifndef SDVXHOOK2_D3D9_H +#define SDVXHOOK2_D3D9_H + +#include + +/** + * 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 diff --git a/src/main/sdvxhook2/dllmain.c b/src/main/sdvxhook2/dllmain.c new file mode 100644 index 0000000..1baa333 --- /dev/null +++ b/src/main/sdvxhook2/dllmain.c @@ -0,0 +1,184 @@ +#include + +#include +#include +#include +#include + +#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 [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; +} diff --git a/src/main/sdvxhook2/sdvxhook2.def b/src/main/sdvxhook2/sdvxhook2.def new file mode 100644 index 0000000..9da2aa6 --- /dev/null +++ b/src/main/sdvxhook2/sdvxhook2.def @@ -0,0 +1,4 @@ +LIBRARY sdvxhook2 + +EXPORTS + DllMain@12 @1 NONAME