1
0
mirror of synced 2024-11-23 21:40:58 +01:00

add exvs2hook

This commit is contained in:
Kevin Trocolli 2023-10-09 09:25:30 -04:00
parent f3171fbdfc
commit 97b17a0844
25 changed files with 812 additions and 6 deletions

View File

@ -20,9 +20,21 @@ $(BUILD_DIR_ZIP)/taiko.zip:
$(V)strip $(BUILD_DIR_ZIP)/taiko/*.{exe,dll} $(V)strip $(BUILD_DIR_ZIP)/taiko/*.{exe,dll}
$(V)cd $(BUILD_DIR_ZIP)/taiko ; zip -r ../taiko.zip * $(V)cd $(BUILD_DIR_ZIP)/taiko ; zip -r ../taiko.zip *
$(BUILD_DIR_ZIP)/exvs2.zip:
$(V)echo ... $@
$(V)mkdir -p $(BUILD_DIR_ZIP)/exvs2
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
$(BUILD_DIR_64)/exvs2hook/exvs2hook.dll \
$(DIST_DIR)/exvs2/bananatools.ini \
$(DIST_DIR)/exvs2/start.bat \
$(BUILD_DIR_ZIP)/exvs2
$(V)strip $(BUILD_DIR_ZIP)/exvs2/*.{exe,dll}
$(V)cd $(BUILD_DIR_ZIP)/exvs2 ; zip -r ../exvs2.zip *
$(BUILD_DIR_ZIP)/doc.zip: \ $(BUILD_DIR_ZIP)/doc.zip: \
$(DOC_DIR)/ferrumhook.md \ $(DOC_DIR)/ferrumhook.md \
$(DOC_DIR)/taikohook.md \ $(DOC_DIR)/taikohook.md \
$(DOC_DIR)/exvs2hook.md \
| $(zipdir)/ | $(zipdir)/
$(V)echo ... $@ $(V)echo ... $@
$(V)zip -r $@ $^ $(V)zip -r $@ $^
@ -30,6 +42,7 @@ $(BUILD_DIR_ZIP)/doc.zip: \
$(BUILD_DIR_ZIP)/bananatools.zip: \ $(BUILD_DIR_ZIP)/bananatools.zip: \
$(BUILD_DIR_ZIP)/ferrum.zip \ $(BUILD_DIR_ZIP)/ferrum.zip \
$(BUILD_DIR_ZIP)/taiko.zip \ $(BUILD_DIR_ZIP)/taiko.zip \
$(BUILD_DIR_ZIP)/exvs2.zip \
$(BUILD_DIR_ZIP)/doc.zip \ $(BUILD_DIR_ZIP)/doc.zip \
README.md \ README.md \

86
dist/exvs2/bananatools.ini vendored Normal file
View File

@ -0,0 +1,86 @@
; Controls the virtual file system hooks. These redirect file i/o
; requests to a folder specified below, instead of the drive.
; These are all required, even if the game doesn't use one of them.
[vfs]
path=
[dns]
default=localhost
; Security dongle emulation, disable if you have a
; real dongle connected that you want to use
[dongle]
enable=1
; XBoost
serial=284313110001
; EXVS2
; serial=281131010001
; For LM, change the 5th digit to a 1
; Set the network environment. Most games seem to want 192.168.123.X
[netenv]
enable=1
subnet=192.168.85.0
[misc]
systemVersion=GX2100-1-NA-SYS0-A06
; Graphics hook, may cause crashes in some games
[gfx]
enable=1
windowed=1
framed=0
monitor=0
; Control the AMCUS replacement class
[amcus]
enable=1
game_id=SBUZ
game_cd=GX21
am_game_ver=4.00
cacfg_game_ver=29.31
server_uri=localhost
server_host=localhost
; Controlls the xinput hooks
[xinput]
enable=1
[reader]
enable=1
; "Enter" key
insert_card=0x0D
access_code=00000000000000000000
; JVS config
[jvs]
enable=1
port=3
; Mappings for the najv4 IO board. To disable JVS emulation and use
; a real board, set enable to 0 in the "jvs" section.
[najv4]
; "Home" key
test=0x24
; "Insert" key
coin=0x2D
; "Delete" key
service=0x2E
; Up arrow
up=0x26
; Down arrow
down=0x28
; Left arrow
left=0x25
; Right arrow
right=0x27
; Spacebar
start=0x20
; 1
btn1=0x31
; 2
btn2=0x32
; 3
btn3=0x33
; 4
btn4=0x34

11
dist/exvs2/start.bat vendored Normal file
View File

@ -0,0 +1,11 @@
@echo off
pushd %~dp0
REM Comment out this line if you intend to use the AMCUS emulator
start inject.exe -d -k exvs2hook.dll AMCUS\AMAuthd.exe
inject.exe -d -k exvs2hook.dll exvs2_exe_Release.exe
echo.
echo The game process has terminated
pause

View File

@ -20,7 +20,7 @@ subnet=192.168.123.0
; Graphics hook, may cause crashes in some games ; Graphics hook, may cause crashes in some games
[gfx] [gfx]
enable=1 enable=0
windowed=1 windowed=1
framed=0 framed=0
monitor=0 monitor=0

13
doc/exvs2hook.md Normal file
View File

@ -0,0 +1,13 @@
# exvs2hook
# Supported games
* Extreme Vs 2 (all versions)
* Extreme Vs 2 XBoost (All Versions)
## General remarks
* Game requires both at least 1 game clinet and a "Live Monitor" server
* 2 game clients are required for the Live Monitor to function properly. 1 will still work for the game client, but the LM will throw an error.
* AMCUS hook is required to run on Windows 11 from my testing.
* XBoost requires the final octet of it's IP to be between 64 and 90 inclusive.
* Any XInput controller should work, but is untested with these tools.

View File

@ -2,7 +2,7 @@
# Supported games # Supported games
* Pokken Tournamen A** * Pokken Tournamen (All versions)
## General remarks ## General remarks
@ -14,4 +14,3 @@
## Known issues ## Known issues
* gfxhook doesn't work as the dxgi/dx11 hooks are currently non-functional. * gfxhook doesn't work as the dxgi/dx11 hooks are currently non-functional.
* Networking functionality is untested

0
exvs2hook/bngrw.c Normal file
View File

0
exvs2hook/bngrw.h Normal file
View File

36
exvs2hook/config.c Normal file
View File

@ -0,0 +1,36 @@
#include <assert.h>
#include <stddef.h>
#include "exvs2hook/config.h"
#include "platform/config.h"
void exvs2_dll_config_load(
struct exvs2_dll_config *cfg,
const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
GetPrivateProfileStringW(
L"exvs2io",
L"path",
L"",
cfg->path,
_countof(cfg->path),
filename);
}
void exvs2_hook_config_load(
struct exvs2_hook_config *cfg,
const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
platform_config_load(&cfg->platform, filename);
exvs2_dll_config_load(&cfg->dll, filename);
gfx_config_load(&cfg->gfx, filename);
qr_config_load(&cfg->qr, filename);
bpreader_config_load(&cfg->reader, filename);
}

28
exvs2hook/config.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include <stddef.h>
#include "exvs2hook/exvs2-dll.h"
#include "platform/config.h"
#include "gfxhook/config.h"
#include "amcus/config.h"
#include "board/config.h"
struct exvs2_hook_config {
struct platform_config platform;
struct exvs2_dll_config dll;
struct gfx_config gfx;
struct amcus_config amcus;
struct qr_config qr;
struct bpreader_config reader;
};
void exvs2_dll_config_load(
struct exvs2_dll_config *cfg,
const wchar_t *filename);
void exvs2_hook_config_load(
struct exvs2_hook_config *cfg,
const wchar_t *filename);

93
exvs2hook/dllmain.c Normal file
View File

@ -0,0 +1,93 @@
#include <windows.h>
#include <stdlib.h>
#include "exvs2hook/config.h"
#include "exvs2hook/exvs2-dll.h"
#include "exvs2hook/jvs.h"
#include "amcus/amcus.h"
#include "hook/process.h"
#include "hooklib/serial.h"
#include "board/bpreader.h"
#include "board/qr.h"
#include "platform/platform.h"
#include "gfxhook/gfx.h"
#include "gfxhook/dxgi.h"
#include "util/dprintf.h"
static HMODULE exvs2_hook_mod;
static process_entry_t exvs2_startup;
static struct exvs2_hook_config exvs2_hook_cfg;
static DWORD CALLBACK exvs2_pre_startup(void)
{
HRESULT hr;
dprintf("--- Begin exvs2_pre_startup ---\n");
exvs2_hook_config_load(&exvs2_hook_cfg, L".\\bananatools.ini");
serial_hook_init();
struct dongle_info dinfo;
dinfo.vid = 0x0B9A;
dinfo.pid = 0x0C20;
wcscpy_s(dinfo.manufacturer, _countof(dinfo.manufacturer), L"UFD 3.0");
wcscpy_s(dinfo.product, _countof(dinfo.product), L"Silicon-Power8G");
hr = platform_hook_init(&exvs2_hook_cfg.platform, PLATFORM_BNA1, exvs2_jvs_init, exvs2_hook_mod, dinfo);
if (FAILED(hr)) {
ExitProcess(EXIT_FAILURE);
}
hr = exvs2_dll_init(&exvs2_hook_cfg.dll, exvs2_hook_mod);
if (FAILED(hr)) {
ExitProcess(EXIT_FAILURE);
}
hr = bpreader_init(&exvs2_hook_cfg.reader, 4);
if (FAILED(hr)) {
ExitProcess(EXIT_FAILURE);
}
hr = amcus_hook_init(&exvs2_hook_cfg.amcus);
if (FAILED(hr)) {
ExitProcess(EXIT_FAILURE);
}
gfx_hook_init(&exvs2_hook_cfg.gfx);
gfx_dxgi_hook_init(&exvs2_hook_cfg.gfx, exvs2_hook_mod);
dprintf("--- End exvs2_pre_startup ---\n");
return exvs2_startup();
}
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
{
HRESULT hr;
if (cause != DLL_PROCESS_ATTACH) {
return TRUE;
}
exvs2_hook_mod = mod;
hr = process_hijack_startup(exvs2_pre_startup, &exvs2_startup);
if (!SUCCEEDED(hr)) {
dprintf("Failed to hijack process startup: %x\n", (int) hr);
}
return SUCCEEDED(hr);
}

100
exvs2hook/exvs2-dll.c Normal file
View File

@ -0,0 +1,100 @@
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include "exvs2hook/exvs2-dll.h"
#include "util/dll-bind.h"
#include "util/dprintf.h"
const struct dll_bind_sym exvs2_dll_syms[] = {
{
.sym = "exvs2_io_jvs_init",
.off = offsetof(struct exvs2_dll, jvs_init),
}, {
.sym = "exvs2_io_jvs_poll",
.off = offsetof(struct exvs2_dll, jvs_poll),
}, {
.sym = "exvs2_io_jvs_read_coin_counter",
.off = offsetof(struct exvs2_dll, jvs_read_coin_counter),
}
};
struct exvs2_dll exvs2_dll;
HRESULT exvs2_dll_init(const struct exvs2_dll_config *cfg, HINSTANCE self)
{
uint16_t (*get_api_version)(void);
const struct dll_bind_sym *sym;
HINSTANCE owned;
HINSTANCE src;
HRESULT hr;
assert(cfg != NULL);
assert(self != NULL);
if (cfg->path[0] != L'\0') {
owned = LoadLibraryW(cfg->path);
if (owned == NULL) {
hr = HRESULT_FROM_WIN32(GetLastError());
dprintf("exvs2 IO: Failed to load IO DLL: %lx: %S\n",
hr,
cfg->path);
goto end;
}
dprintf("exvs2 IO: Using custom IO DLL: %S\n", cfg->path);
src = owned;
} else {
owned = NULL;
src = self;
}
get_api_version = (void *) GetProcAddress(src, "exvs2_io_get_api_version");
if (get_api_version != NULL) {
exvs2_dll.api_version = get_api_version();
} else {
exvs2_dll.api_version = 0x0100;
dprintf("Custom IO DLL does not expose exvs2_io_get_api_version, "
"assuming API version 1.0.\n"
"Please ask the developer to update their DLL.\n");
}
if (exvs2_dll.api_version >= 0x0200) {
hr = E_NOTIMPL;
dprintf("exvs2 IO: Custom IO DLL implements an unsupported "
"API version (%#04x). Please update Segatools.\n",
exvs2_dll.api_version);
goto end;
}
sym = exvs2_dll_syms;
hr = dll_bind(&exvs2_dll, src, &sym, _countof(exvs2_dll_syms));
if (FAILED(hr)) {
if (src != self) {
dprintf("exvs2 IO: Custom IO DLL does not provide function "
"\"%s\". Please contact your IO DLL's developer for "
"further assistance.\n",
sym->sym);
goto end;
} else {
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
}
}
owned = NULL;
end:
if (owned != NULL) {
FreeLibrary(owned);
}
return hr;
}

20
exvs2hook/exvs2-dll.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include <windows.h>
#include "exvs2io/exvs2io.h"
struct exvs2_dll {
uint16_t api_version;
HRESULT (*jvs_init)(void);
HRESULT (*jvs_poll)(uint8_t *opbtn, uint16_t *gamepad);
void (*jvs_read_coin_counter)(uint16_t *coins);
};
struct exvs2_dll_config {
wchar_t path[MAX_PATH];
};
extern struct exvs2_dll exvs2_dll;
HRESULT exvs2_dll_init(const struct exvs2_dll_config *cfg, HINSTANCE self);

7
exvs2hook/exvs2hook.def Normal file
View File

@ -0,0 +1,7 @@
LIBRARY exvs2hook
EXPORTS
exvs2_io_get_api_version
exvs2_io_jvs_init
exvs2_io_jvs_poll
exvs2_io_jvs_read_coin_counter

125
exvs2hook/jvs.c Normal file
View File

@ -0,0 +1,125 @@
#include <windows.h>
#include <assert.h>
#include <process.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "hook/iobuf.h"
#include "hook/iohook.h"
#include "hooklib/uart.h"
#include "hooklib/fdshark.h"
#include "util/dprintf.h"
#include "util/dump.h"
#include "board/najv4.h"
#include "exvs2hook/jvs.h"
#include "exvs2hook/exvs2-dll.h"
static void exvs2_jvs_read_switches(void *ctx, struct najv4_switch_state *out);
static void exvs2_jvs_read_coin_counter(void *ctx, uint8_t slot_no, uint16_t *out);
static const struct najv4_ops exvs2_jvs_najv4_ops = {
.read_switches = exvs2_jvs_read_switches,
.read_coin_counter = exvs2_jvs_read_coin_counter,
};
static struct najv4 exvs2_jvs_najv4;
HRESULT exvs2_jvs_init(struct jvs_node **out)
{
HRESULT hr;
assert(out != NULL);
assert(exvs2_dll.jvs_init != NULL);
dprintf("exvs2 JVS: Starting IO backend\n");
hr = exvs2_dll.jvs_init();
if (FAILED(hr)) {
dprintf("exvs2 JVS: Backend error, I/O disconnected: %x\n", (int) hr);
return hr;
}
najv4_init(&exvs2_jvs_najv4, NULL, &exvs2_jvs_najv4_ops, NULL);
*out = najv4_to_jvs_node(&exvs2_jvs_najv4);
return S_OK;
}
static void exvs2_jvs_read_switches(void *ctx, struct najv4_switch_state *out)
{
uint8_t opbtn = 0;
uint16_t gamebtn = 0;
assert(out != NULL);
assert(exvs2_dll.jvs_poll != NULL);
exvs2_dll.jvs_poll(&opbtn, &gamebtn);
out->system = 0;
out->p1 = 0;
out->p2 = 0;
if (opbtn & EXVS2_IO_OPBTN_TEST) { // Test
out->system = 0x80;
}
if (gamebtn & EXVS2_IO_GAMEBTN_4) { // Btn4
out->p1 |= 0x40;
}
if (gamebtn & EXVS2_IO_GAMEBTN_3) { // Btn3
out->p1 |= 0x80;
}
if (gamebtn & EXVS2_IO_GAMEBTN_2) { // Btn2
out->p1 |= 0x100;
}
if (gamebtn & EXVS2_IO_GAMEBTN_1) { // Btn1
out->p1 |= 0x200;
}
if (gamebtn & EXVS2_IO_GAMEBTN_RIGHT) { // Right
out->p1 |= 0x400;
}
if (gamebtn & EXVS2_IO_GAMEBTN_LEFT) { // Left
out->p1 |= 0x800;
}
if (gamebtn & EXVS2_IO_GAMEBTN_DOWN) { // Down
out->p1 |= 0x1000;
}
if (gamebtn & EXVS2_IO_GAMEBTN_UP) { // Up
out->p1 |= 0x2000;
}
if (opbtn & EXVS2_IO_OPBTN_SERVICE) { // Service
out->p1 |= 0x4000;
}
if (gamebtn & EXVS2_IO_GAMEBTN_START) { // Start
out->p1 = 0x8000;
}
}
static void exvs2_jvs_read_coin_counter(void *ctx, uint8_t slot_no, uint16_t *out)
{
assert(out != NULL);
assert(exvs2_dll.jvs_read_coin_counter != NULL);
if (slot_no > 0) {
return;
}
exvs2_dll.jvs_read_coin_counter(out);
}

8
exvs2hook/jvs.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "jvs/jvs-bus.h"
HRESULT exvs2_jvs_init(struct jvs_node **root);

33
exvs2hook/meson.build Normal file
View File

@ -0,0 +1,33 @@
shared_library(
'exvs2hook',
name_prefix : '',
include_directories : inc,
implicit_include_directories : false,
vs_module_defs : 'exvs2hook.def',
c_pch : '../precompiled.h',
dependencies : [
capnhook.get_variable('hook_dep'),
capnhook.get_variable('hooklib_dep'),
],
link_with : [
exvs2io_lib,
amcus_lib,
platform_lib,
util_lib,
hooklib_lib,
gfxhook_lib,
jvs_lib,
board_lib
],
sources : [
'dllmain.c',
'config.c',
'config.h',
'exvs2-dll.c',
'exvs2-dll.h',
'jvs.c',
'jvs.h',
'bngrw.c',
'bngrw.h',
],
)

23
exvs2io/config.c Normal file
View File

@ -0,0 +1,23 @@
#include <windows.h>
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include "exvs2io/config.h"
void exvs2_io_najv4_config_load(struct exvs2_najv4_config *cfg, const wchar_t *filename)
{
cfg->test = GetPrivateProfileIntW(L"najv4", L"test", VK_HOME, filename);
cfg->service = GetPrivateProfileIntW(L"najv4", L"service", VK_DELETE, filename);
cfg->coin = GetPrivateProfileIntW(L"najv4", L"coin", VK_INSERT, filename);
cfg->up = GetPrivateProfileIntW(L"najv4", L"up", VK_UP, filename);
cfg->down = GetPrivateProfileIntW(L"najv4", L"down", VK_DOWN, filename);
cfg->left = GetPrivateProfileIntW(L"najv4", L"left", VK_LEFT, filename);
cfg->right = GetPrivateProfileIntW(L"najv4", L"right", VK_RIGHT, filename);
cfg->start = GetPrivateProfileIntW(L"najv4", L"start", VK_SPACE, filename);
cfg->btn1 = GetPrivateProfileIntW(L"najv4", L"btn1", '1', filename);
cfg->btn2 = GetPrivateProfileIntW(L"najv4", L"btn2", '2', filename);
cfg->btn3 = GetPrivateProfileIntW(L"najv4", L"btn3", '3', filename);
cfg->btn4 = GetPrivateProfileIntW(L"najv4", L"btn4", '4', filename);
}

21
exvs2io/config.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
struct exvs2_najv4_config {
uint8_t test;
uint8_t service;
uint8_t coin;
uint8_t up;
uint8_t down;
uint8_t left;
uint8_t right;
uint8_t start;
uint8_t btn1;
uint8_t btn2;
uint8_t btn3;
uint8_t btn4;
};
void exvs2_io_najv4_config_load(struct exvs2_najv4_config *cfg, const wchar_t *filename);

93
exvs2io/exvs2io.c Normal file
View File

@ -0,0 +1,93 @@
#include <windows.h>
#include <xinput.h>
#include <limits.h>
#include <stdint.h>
#include <stdbool.h>
#include "exvs2io/exvs2io.h"
#include "exvs2io/config.h"
#include "util/dprintf.h"
static bool exvs2_io_coin = false;
static uint16_t exvs2_coin_ct = 0;
static struct exvs2_najv4_config najv4_cfg;
uint16_t exvs2_io_get_api_version(void)
{
return 0x0100;
}
HRESULT exvs2_io_jvs_init(void)
{
dprintf("exvs2 IO: JVS Init\n");
exvs2_io_najv4_config_load(&najv4_cfg, L".\\bananatools.ini");
return S_OK;
}
HRESULT exvs2_io_jvs_poll(uint8_t *opbtn, uint16_t *gamepad)
{
*opbtn = 0;
*gamepad = 0;
if ((GetAsyncKeyState(najv4_cfg.test) & 0x8000)) {
*opbtn |= EXVS2_IO_OPBTN_TEST;
}
if (GetAsyncKeyState(najv4_cfg.service) & 0x8000) {
*opbtn |= EXVS2_IO_OPBTN_SERVICE;
}
if (GetAsyncKeyState(najv4_cfg.up) & 0x8000) {
*gamepad |= EXVS2_IO_GAMEBTN_UP;
}
if (GetAsyncKeyState(najv4_cfg.down) & 0x8000) {
*gamepad |= EXVS2_IO_GAMEBTN_DOWN;
}
if (GetAsyncKeyState(najv4_cfg.left) & 0x8000) {
*gamepad |= EXVS2_IO_GAMEBTN_LEFT;
}
if (GetAsyncKeyState(najv4_cfg.right) & 0x8000) {
*gamepad |= EXVS2_IO_GAMEBTN_RIGHT;
}
if (GetAsyncKeyState(najv4_cfg.start) & 0x8000) {
*gamepad |= EXVS2_IO_GAMEBTN_START;
}
if (GetAsyncKeyState(najv4_cfg.btn1) & 0x8000) {
*gamepad |= EXVS2_IO_GAMEBTN_1;
}
if (GetAsyncKeyState(najv4_cfg.btn2) & 0x8000) {
*gamepad |= EXVS2_IO_GAMEBTN_2;
}
if (GetAsyncKeyState(najv4_cfg.btn3) & 0x8000) {
*gamepad |= EXVS2_IO_GAMEBTN_3;
}
if (GetAsyncKeyState(najv4_cfg.btn4) & 0x8000) {
*gamepad |= EXVS2_IO_GAMEBTN_4;
}
return S_OK;
}
void exvs2_io_jvs_read_coin_counter(uint16_t *coins)
{
if (GetAsyncKeyState(najv4_cfg.coin) & 0x8000) {
if (!exvs2_io_coin) {
exvs2_io_coin = true;
exvs2_coin_ct++;
}
} else {
exvs2_io_coin = false;
}
*coins = exvs2_coin_ct;
}

7
exvs2io/exvs2io.def Normal file
View File

@ -0,0 +1,7 @@
LIBRARY exvs2hook
EXPORTS
exvs2_io_get_api_version
exvs2_io_jvs_init
exvs2_io_jvs_poll
exvs2_io_read_coin_counter

51
exvs2io/exvs2io.h Normal file
View File

@ -0,0 +1,51 @@
#pragma once
#include <windows.h>
#include <stdint.h>
#include "exvs2io/config.h"
enum {
EXVS2_IO_OPBTN_TEST = 0x01,
EXVS2_IO_OPBTN_SERVICE = 0x02,
EXVS2_IO_OPBTN_COIN = 0x20,
};
enum {
EXVS2_IO_GAMEBTN_1 = 0x1,
EXVS2_IO_GAMEBTN_2 = 0x2,
EXVS2_IO_GAMEBTN_3 = 0x4,
EXVS2_IO_GAMEBTN_4 = 0x8,
EXVS2_IO_GAMEBTN_UP = 0x10,
EXVS2_IO_GAMEBTN_DOWN = 0x20,
EXVS2_IO_GAMEBTN_LEFT = 0x40,
EXVS2_IO_GAMEBTN_RIGHT = 0x80,
EXVS2_IO_GAMEBTN_START = 0x100,
};
/* Get the version of the Pokken IO API that this DLL supports. This
function should return a positive 16-bit integer, where the high byte is
the major version and the low byte is the minor version (as defined by the
Semantic Versioning standard).
The latest API version as of this writing is 0x0100. */
uint16_t exvs2_io_get_api_version(void);
/* Initialize the IO DLL. This is the second function that will be called on
your DLL, after exvs2_io_get_api_version.
All subsequent calls to this API may originate from arbitrary threads.
Minimum API version: 0x0100 */
HRESULT exvs2_io_jvs_init(void);
/* Send any queued outputs (of which there are currently none, though this may
change in subsequent API versions) and retrieve any new inputs.
Minimum API version: 0x0100 */
HRESULT exvs2_io_jvs_poll(uint8_t *opbtn, uint16_t *gamepad);
void exvs2_io_jvs_read_coin_counter(uint16_t *coins);

16
exvs2io/meson.build Normal file
View File

@ -0,0 +1,16 @@
exvs2io_lib = static_library(
'exvs2io',
name_prefix : '',
include_directories : inc,
implicit_include_directories : false,
c_pch : '../precompiled.h',
dependencies : [
xinput_lib,
],
sources : [
'exvs2io.c',
'exvs2io.h',
'config.c',
'config.h',
],
)

View File

@ -73,6 +73,7 @@ void gfx_dxgi_hook_init(const struct gfx_config *cfg, HINSTANCE self)
memcpy(&gfx_config, cfg, sizeof(*cfg)); memcpy(&gfx_config, cfg, sizeof(*cfg));
hook_table_apply(NULL, "dxgi.dll", dxgi_hooks, _countof(dxgi_hooks)); hook_table_apply(NULL, "dxgi.dll", dxgi_hooks, _countof(dxgi_hooks));
hook_table_apply(NULL, "dxgi", dxgi_hooks, _countof(dxgi_hooks));
if (next_CreateDXGIFactory == NULL || next_CreateDXGIFactory1 == NULL) { if (next_CreateDXGIFactory == NULL || next_CreateDXGIFactory1 == NULL) {
dxgi = LoadLibraryW(L"dxgi.dll"); dxgi = LoadLibraryW(L"dxgi.dll");
@ -110,14 +111,15 @@ void gfx_dxgi_hook_init(const struct gfx_config *cfg, HINSTANCE self)
goto fail; goto fail;
} }
/* `CreateDXGIFactory2` was introduced in Windows 8.1 and the original
* Nu runs Windows 8, so do not require it to exist */
} }
if (self != NULL) { if (self != NULL) {
dll_hook_push(self, L"dxgi.dll"); dll_hook_push(self, L"dxgi.dll");
dll_hook_push(self, L"dxgi");
} }
dprintf("DXGI: init\n");
return; return;
fail: fail:
@ -192,7 +194,7 @@ HRESULT WINAPI CreateDXGIFactory2(UINT flags, REFIID riid, void **factory)
return hr; return hr;
} }
//hr = hook_factory(riid, factory); hr = hook_factory(riid, factory);
if (FAILED(hr)) { if (FAILED(hr)) {
return hr; return hr;
@ -206,8 +208,10 @@ static HRESULT hook_factory(REFIID riid, void **factory)
struct com_proxy *proxy; struct com_proxy *proxy;
IDXGIFactory *api_0; IDXGIFactory *api_0;
IDXGIFactory1 *api_1; IDXGIFactory1 *api_1;
IDXGIFactory2 *api_2;
IDXGIFactoryVtbl *vtbl_0; IDXGIFactoryVtbl *vtbl_0;
IDXGIFactory1Vtbl *vtbl_1; IDXGIFactory1Vtbl *vtbl_1;
IDXGIFactory2Vtbl *vtbl_2;
HRESULT hr; HRESULT hr;
api_0 = NULL; api_0 = NULL;
@ -242,6 +246,20 @@ static HRESULT hook_factory(REFIID riid, void **factory)
vtbl_1 = proxy->vptr; vtbl_1 = proxy->vptr;
vtbl_1->CreateSwapChain = my_IDXGIFactory1_CreateSwapChain; vtbl_1->CreateSwapChain = my_IDXGIFactory1_CreateSwapChain;
*factory = proxy;
} else if (memcmp(riid, &IID_IDXGIFactory2, sizeof(*riid)) == 0) {
api_2 = *factory;
hr = com_proxy_wrap(&proxy, api_2, sizeof(*api_2->lpVtbl));
if (FAILED(hr)) {
dprintf("DXGI: com_proxy_wrap returned %x\n", (int) hr);
goto fail;
}
vtbl_2 = proxy->vptr;
vtbl_2->CreateSwapChain = my_IDXGIFactory2_CreateSwapChain;
*factory = proxy; *factory = proxy;
} }
@ -255,6 +273,9 @@ fail:
if (api_1 != NULL) { if (api_1 != NULL) {
IDXGIFactory1_Release(api_1); IDXGIFactory1_Release(api_1);
} }
if (api_2 != NULL) {
IDXGIFactory2_Release(api_2);
}
return hr; return hr;
} }

View File

@ -56,6 +56,8 @@ subdir('amcus')
subdir('ferrumio') subdir('ferrumio')
subdir('taikoio') subdir('taikoio')
subdir('exvs2io')
subdir('taikohook') subdir('taikohook')
subdir('ferrumhook') subdir('ferrumhook')
subdir('exvs2hook')