add tekken
This commit is contained in:
parent
8ff356b84c
commit
ea60cc4a18
12
Package.mk
12
Package.mk
@ -53,6 +53,17 @@ $(BUILD_DIR_ZIP)/mkac.zip:
|
|||||||
$(V)strip $(BUILD_DIR_ZIP)/mkac/*.{exe,dll}
|
$(V)strip $(BUILD_DIR_ZIP)/mkac/*.{exe,dll}
|
||||||
$(V)cd $(BUILD_DIR_ZIP)/mkac ; zip -r ../mkac.zip *
|
$(V)cd $(BUILD_DIR_ZIP)/mkac ; zip -r ../mkac.zip *
|
||||||
|
|
||||||
|
$(BUILD_DIR_ZIP)/tekken.zip:
|
||||||
|
$(V)echo ... $@
|
||||||
|
$(V)mkdir -p $(BUILD_DIR_ZIP)/tekken
|
||||||
|
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||||
|
$(BUILD_DIR_64)/tekkenhook/tekkenhook.dll \
|
||||||
|
$(DIST_DIR)/tekken/bananatools.ini \
|
||||||
|
$(DIST_DIR)/tekken/start.bat \
|
||||||
|
$(BUILD_DIR_ZIP)/tekken
|
||||||
|
$(V)strip $(BUILD_DIR_ZIP)/tekken/*.{exe,dll}
|
||||||
|
$(V)cd $(BUILD_DIR_ZIP)/tekken ; zip -r ../tekken.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 \
|
||||||
@ -68,6 +79,7 @@ $(BUILD_DIR_ZIP)/bananatools.zip: \
|
|||||||
$(BUILD_DIR_ZIP)/exvs2.zip \
|
$(BUILD_DIR_ZIP)/exvs2.zip \
|
||||||
$(BUILD_DIR_ZIP)/sao.zip \
|
$(BUILD_DIR_ZIP)/sao.zip \
|
||||||
$(BUILD_DIR_ZIP)/mkac.zip \
|
$(BUILD_DIR_ZIP)/mkac.zip \
|
||||||
|
$(BUILD_DIR_ZIP)/tekken.zip \
|
||||||
$(BUILD_DIR_ZIP)/doc.zip \
|
$(BUILD_DIR_ZIP)/doc.zip \
|
||||||
README.md \
|
README.md \
|
||||||
|
|
||||||
|
58
dist/tekken/bananatools.ini
vendored
Normal file
58
dist/tekken/bananatools.ini
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
; 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
|
||||||
|
serial=282814450001
|
||||||
|
|
||||||
|
; Set the network environment. Most games seem to want 192.168.123.X
|
||||||
|
[netenv]
|
||||||
|
enable=1
|
||||||
|
subnet=192.168.123.0
|
||||||
|
|
||||||
|
; Graphics hook, may cause crashes in some games
|
||||||
|
[gfx]
|
||||||
|
enable=1
|
||||||
|
windowed=1
|
||||||
|
framed=0
|
||||||
|
monitor=0
|
||||||
|
|
||||||
|
[misc]
|
||||||
|
systemVersion=TE7100-1-NA-SYS0-A03
|
||||||
|
|
||||||
|
; Control the AMCUS replacement class
|
||||||
|
[amcus]
|
||||||
|
enable=1
|
||||||
|
game_id=SDBS
|
||||||
|
game_cd=TR21
|
||||||
|
am_game_ver=1.80
|
||||||
|
cacfg_game_ver=10.03
|
||||||
|
server_uri=localhost
|
||||||
|
server_host=localhost
|
||||||
|
|
||||||
|
[reader]
|
||||||
|
enable=1
|
||||||
|
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]
|
||||||
|
test=0x24 ; "Home" key
|
||||||
|
coin=0x2D ; "Insert" key
|
||||||
|
service=0x2E ; "Delete" key
|
||||||
|
up=0x26 ; Up arrow
|
||||||
|
down=0x28 ; Down arrow
|
||||||
|
enter=0x0D ; "Enter" key
|
10
dist/tekken/start.bat
vendored
Normal file
10
dist/tekken/start.bat
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
pushd %~dp0
|
||||||
|
|
||||||
|
start inject.exe -d -k tekkenhook.dll AMCUS\AMAuthd.exe
|
||||||
|
inject.exe -d -k tekkenhook.dll TekkenGame\Binaries\Win64\TekkenGame-Win64-Shipping.exe
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo The game process has terminated
|
||||||
|
pause
|
@ -59,9 +59,11 @@ subdir('taikoio')
|
|||||||
subdir('exvs2io')
|
subdir('exvs2io')
|
||||||
subdir('saoio')
|
subdir('saoio')
|
||||||
subdir('mkacio')
|
subdir('mkacio')
|
||||||
|
subdir('tekkenio')
|
||||||
|
|
||||||
subdir('taikohook')
|
subdir('taikohook')
|
||||||
subdir('ferrumhook')
|
subdir('ferrumhook')
|
||||||
subdir('exvs2hook')
|
subdir('exvs2hook')
|
||||||
subdir('saohook')
|
subdir('saohook')
|
||||||
subdir('mkachook')
|
subdir('mkachook')
|
||||||
|
subdir('tekkenhook')
|
35
tekkenhook/config.c
Normal file
35
tekkenhook/config.c
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "tekkenhook/config.h"
|
||||||
|
|
||||||
|
#include "platform/config.h"
|
||||||
|
|
||||||
|
void tekken_dll_config_load(
|
||||||
|
struct tekken_dll_config *cfg,
|
||||||
|
const wchar_t *filename)
|
||||||
|
{
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(filename != NULL);
|
||||||
|
|
||||||
|
GetPrivateProfileStringW(
|
||||||
|
L"tekkenio",
|
||||||
|
L"path",
|
||||||
|
L"",
|
||||||
|
cfg->path,
|
||||||
|
_countof(cfg->path),
|
||||||
|
filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tekken_hook_config_load(
|
||||||
|
struct tekken_hook_config *cfg,
|
||||||
|
const wchar_t *filename)
|
||||||
|
{
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(filename != NULL);
|
||||||
|
|
||||||
|
platform_config_load(&cfg->platform, filename);
|
||||||
|
tekken_dll_config_load(&cfg->dll, filename);
|
||||||
|
gfx_config_load(&cfg->gfx, filename);
|
||||||
|
bpreader_config_load(&cfg->reader, filename);
|
||||||
|
}
|
28
tekkenhook/config.h
Normal file
28
tekkenhook/config.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "tekkenhook/tekken-dll.h"
|
||||||
|
#include "tekkenhook/jvs.h"
|
||||||
|
#include "board/config.h"
|
||||||
|
|
||||||
|
#include "platform/config.h"
|
||||||
|
#include "gfxhook/config.h"
|
||||||
|
#include "amcus/config.h"
|
||||||
|
|
||||||
|
struct tekken_hook_config {
|
||||||
|
struct platform_config platform;
|
||||||
|
struct tekken_dll_config dll;
|
||||||
|
struct gfx_config gfx;
|
||||||
|
struct amcus_config amcus;
|
||||||
|
struct bpreader_config reader;
|
||||||
|
};
|
||||||
|
|
||||||
|
void tekken_dll_config_load(
|
||||||
|
struct tekken_dll_config *cfg,
|
||||||
|
const wchar_t *filename);
|
||||||
|
|
||||||
|
void tekken_hook_config_load(
|
||||||
|
struct tekken_hook_config *cfg,
|
||||||
|
const wchar_t *filename);
|
||||||
|
|
96
tekkenhook/dllmain.c
Normal file
96
tekkenhook/dllmain.c
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "tekkenhook/config.h"
|
||||||
|
#include "tekkenhook/tekken-dll.h"
|
||||||
|
#include "tekkenhook/jvs.h"
|
||||||
|
|
||||||
|
#include "amcus/amcus.h"
|
||||||
|
|
||||||
|
#include "hook/process.h"
|
||||||
|
|
||||||
|
#include "hooklib/serial.h"
|
||||||
|
#include "hooklib/debug.h"
|
||||||
|
|
||||||
|
#include "platform/platform.h"
|
||||||
|
#include "gfxhook/gfx.h"
|
||||||
|
#include "gfxhook/dxgi.h"
|
||||||
|
#include "gfxhook/d3d11.h"
|
||||||
|
#include "board/bpreader.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
static HMODULE tekken_hook_mod;
|
||||||
|
static process_entry_t tekken_startup;
|
||||||
|
static struct tekken_hook_config tekken_hook_cfg;
|
||||||
|
|
||||||
|
static DWORD CALLBACK tekken_pre_startup(void)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
dprintf("--- Begin tekken_pre_startup ---\n");
|
||||||
|
|
||||||
|
tekken_hook_config_load(&tekken_hook_cfg, L".\\bananatools.ini");
|
||||||
|
|
||||||
|
serial_hook_init();
|
||||||
|
|
||||||
|
struct dongle_info dinfo;
|
||||||
|
dinfo.vid = 0x0B9A;
|
||||||
|
dinfo.pid = 0x0C10;
|
||||||
|
wcscpy_s(dinfo.manufacturer, _countof(dinfo.manufacturer), L"BM");
|
||||||
|
wcscpy_s(dinfo.product, _countof(dinfo.product), L"RUDI04GBN-274713");
|
||||||
|
|
||||||
|
hr = platform_hook_init(&tekken_hook_cfg.platform, PLATFORM_ES3, tekken_jvs_init, tekken_hook_mod, dinfo);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
ExitProcess(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = tekken_dll_init(&tekken_hook_cfg.dll, tekken_hook_mod);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
ExitProcess(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = amcus_hook_init(&tekken_hook_cfg.amcus);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
ExitProcess(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = bpreader_init(&tekken_hook_cfg.reader, 4);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
ExitProcess(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_hook_init();
|
||||||
|
|
||||||
|
gfx_hook_init(&tekken_hook_cfg.gfx);
|
||||||
|
gfx_d3d11_hook_init(&tekken_hook_cfg.gfx, tekken_hook_mod);
|
||||||
|
gfx_dxgi_hook_init(&tekken_hook_cfg.gfx, tekken_hook_mod);
|
||||||
|
|
||||||
|
dprintf("--- End tekken_pre_startup ---\n");
|
||||||
|
|
||||||
|
return tekken_startup();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
if (cause != DLL_PROCESS_ATTACH) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
tekken_hook_mod = mod;
|
||||||
|
|
||||||
|
hr = process_hijack_startup(tekken_pre_startup, &tekken_startup);
|
||||||
|
|
||||||
|
if (!SUCCEEDED(hr)) {
|
||||||
|
dprintf("Failed to hijack process startup: %x\n", (int) hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCEEDED(hr);
|
||||||
|
}
|
100
tekkenhook/jvs.c
Normal file
100
tekkenhook/jvs.c
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#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 "tekkenhook/jvs.h"
|
||||||
|
#include "tekkenhook/tekken-dll.h"
|
||||||
|
|
||||||
|
static void tekken_jvs_read_switches(void *ctx, struct najv4_switch_state *out);
|
||||||
|
static void tekken_jvs_read_coin_counter(void *ctx, uint8_t slot_no, uint16_t *out);
|
||||||
|
|
||||||
|
static const struct najv4_ops tekken_jvs_najv4_ops = {
|
||||||
|
.read_switches = tekken_jvs_read_switches,
|
||||||
|
.read_coin_counter = tekken_jvs_read_coin_counter,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct najv4 tekken_jvs_najv4;
|
||||||
|
|
||||||
|
HRESULT tekken_jvs_init(struct jvs_node **out)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(out != NULL);
|
||||||
|
assert(tekken_dll.jvs_init != NULL);
|
||||||
|
|
||||||
|
dprintf("Tekken JVS: Starting IO backend\n");
|
||||||
|
hr = tekken_dll.jvs_init();
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
dprintf("Tekken JVS: Backend error, I/O disconnected: %x\n", (int) hr);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
najv4_init(&tekken_jvs_najv4, NULL, &tekken_jvs_najv4_ops, NULL);
|
||||||
|
*out = najv4_to_jvs_node(&tekken_jvs_najv4);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tekken_jvs_read_switches(void *ctx, struct najv4_switch_state *out)
|
||||||
|
{
|
||||||
|
uint8_t opbtn = 0;
|
||||||
|
|
||||||
|
//dprintf("Tekken JVS: Read Switches\n");
|
||||||
|
|
||||||
|
assert(out != NULL);
|
||||||
|
assert(tekken_dll.jvs_poll != NULL);
|
||||||
|
|
||||||
|
tekken_dll.jvs_poll(&opbtn);
|
||||||
|
|
||||||
|
out->system = 0;
|
||||||
|
out->p1 = 0;
|
||||||
|
out->p2 = 0;
|
||||||
|
|
||||||
|
if (opbtn & 0x01) { // Test
|
||||||
|
out->system = 0x80;
|
||||||
|
}
|
||||||
|
if (opbtn & 0x02) { // Service
|
||||||
|
out->p1 |= 0x4000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opbtn & 0x04) { // Up
|
||||||
|
out->p1 |= 0x2000;
|
||||||
|
}
|
||||||
|
if (opbtn & 0x08) { // Down
|
||||||
|
out->p1 |= 0x1000;
|
||||||
|
}
|
||||||
|
if (opbtn & 0x10) { // Enter
|
||||||
|
out->p1 |= 0x0200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tekken_jvs_read_coin_counter(void *ctx, uint8_t slot_no, uint16_t *out)
|
||||||
|
{
|
||||||
|
//dprintf("Tekken JVS: Read coin counter\n");
|
||||||
|
|
||||||
|
assert(out != NULL);
|
||||||
|
assert(tekken_dll.jvs_read_coin_counter != NULL);
|
||||||
|
|
||||||
|
if (slot_no > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tekken_dll.jvs_read_coin_counter(out);
|
||||||
|
}
|
8
tekkenhook/jvs.h
Normal file
8
tekkenhook/jvs.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "jvs/jvs-bus.h"
|
||||||
|
|
||||||
|
HRESULT tekken_jvs_init(struct jvs_node **root);
|
31
tekkenhook/meson.build
Normal file
31
tekkenhook/meson.build
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
shared_library(
|
||||||
|
'tekkenhook',
|
||||||
|
name_prefix : '',
|
||||||
|
include_directories : inc,
|
||||||
|
implicit_include_directories : false,
|
||||||
|
vs_module_defs : 'tekkenhook.def',
|
||||||
|
c_pch : '../precompiled.h',
|
||||||
|
dependencies : [
|
||||||
|
capnhook.get_variable('hook_dep'),
|
||||||
|
capnhook.get_variable('hooklib_dep'),
|
||||||
|
],
|
||||||
|
link_with : [
|
||||||
|
tekkenio_lib,
|
||||||
|
amcus_lib,
|
||||||
|
platform_lib,
|
||||||
|
util_lib,
|
||||||
|
hooklib_lib,
|
||||||
|
gfxhook_lib,
|
||||||
|
jvs_lib,
|
||||||
|
board_lib,
|
||||||
|
],
|
||||||
|
sources : [
|
||||||
|
'dllmain.c',
|
||||||
|
'config.c',
|
||||||
|
'config.h',
|
||||||
|
'tekken-dll.c',
|
||||||
|
'tekken-dll.h',
|
||||||
|
'jvs.c',
|
||||||
|
'jvs.h',
|
||||||
|
],
|
||||||
|
)
|
100
tekkenhook/tekken-dll.c
Normal file
100
tekkenhook/tekken-dll.c
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "tekkenhook/tekken-dll.h"
|
||||||
|
|
||||||
|
#include "util/dll-bind.h"
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
const struct dll_bind_sym tekken_dll_syms[] = {
|
||||||
|
{
|
||||||
|
.sym = "tekken_io_jvs_init",
|
||||||
|
.off = offsetof(struct tekken_dll, jvs_init),
|
||||||
|
}, {
|
||||||
|
.sym = "tekken_io_jvs_poll",
|
||||||
|
.off = offsetof(struct tekken_dll, jvs_poll),
|
||||||
|
}, {
|
||||||
|
.sym = "tekken_io_jvs_read_coin_counter",
|
||||||
|
.off = offsetof(struct tekken_dll, jvs_read_coin_counter),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tekken_dll tekken_dll;
|
||||||
|
|
||||||
|
HRESULT tekken_dll_init(const struct tekken_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("Tekken IO: Failed to load IO DLL: %lx: %S\n",
|
||||||
|
hr,
|
||||||
|
cfg->path);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("Tekken IO: Using custom IO DLL: %S\n", cfg->path);
|
||||||
|
src = owned;
|
||||||
|
} else {
|
||||||
|
owned = NULL;
|
||||||
|
src = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_api_version = (void *) GetProcAddress(src, "tekken_io_get_api_version");
|
||||||
|
|
||||||
|
if (get_api_version != NULL) {
|
||||||
|
tekken_dll.api_version = get_api_version();
|
||||||
|
} else {
|
||||||
|
tekken_dll.api_version = 0x0100;
|
||||||
|
dprintf("Custom IO DLL does not expose tekken_io_get_api_version, "
|
||||||
|
"assuming API version 1.0.\n"
|
||||||
|
"Please ask the developer to update their DLL.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tekken_dll.api_version >= 0x0200) {
|
||||||
|
hr = E_NOTIMPL;
|
||||||
|
dprintf("Tekken IO: Custom IO DLL implements an unsupported "
|
||||||
|
"API version (%#04x). Please update Segatools.\n",
|
||||||
|
tekken_dll.api_version);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
sym = tekken_dll_syms;
|
||||||
|
hr = dll_bind(&tekken_dll, src, &sym, _countof(tekken_dll_syms));
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
if (src != self) {
|
||||||
|
dprintf("Tekken 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
tekkenhook/tekken-dll.h
Normal file
20
tekkenhook/tekken-dll.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "tekkenio/tekkenio.h"
|
||||||
|
|
||||||
|
struct tekken_dll {
|
||||||
|
uint16_t api_version;
|
||||||
|
HRESULT (*jvs_init)(void);
|
||||||
|
HRESULT (*jvs_poll)(uint8_t *opbtn);
|
||||||
|
void (*jvs_read_coin_counter)(uint16_t *coins);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tekken_dll_config {
|
||||||
|
wchar_t path[MAX_PATH];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct tekken_dll tekken_dll;
|
||||||
|
|
||||||
|
HRESULT tekken_dll_init(const struct tekken_dll_config *cfg, HINSTANCE self);
|
7
tekkenhook/tekkenhook.def
Normal file
7
tekkenhook/tekkenhook.def
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
LIBRARY tekkenhook
|
||||||
|
|
||||||
|
EXPORTS
|
||||||
|
tekken_io_get_api_version
|
||||||
|
tekken_io_jvs_init
|
||||||
|
tekken_io_jvs_poll
|
||||||
|
tekken_io_jvs_read_coin_counter
|
17
tekkenio/config.c
Normal file
17
tekkenio/config.c
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "tekkenio/config.h"
|
||||||
|
|
||||||
|
void tekken_io_najv4_config_load(struct tekken_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->enter = GetPrivateProfileIntW(L"najv4", L"enter", VK_RETURN, filename);
|
||||||
|
}
|
15
tekkenio/config.h
Normal file
15
tekkenio/config.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct tekken_najv4_config {
|
||||||
|
uint8_t test;
|
||||||
|
uint8_t service;
|
||||||
|
uint8_t up;
|
||||||
|
uint8_t down;
|
||||||
|
uint8_t enter;
|
||||||
|
uint8_t coin;
|
||||||
|
};
|
||||||
|
|
||||||
|
void tekken_io_najv4_config_load(struct tekken_najv4_config *cfg, const wchar_t *filename);
|
13
tekkenio/meson.build
Normal file
13
tekkenio/meson.build
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
tekkenio_lib = static_library(
|
||||||
|
'tekkenio',
|
||||||
|
name_prefix : '',
|
||||||
|
include_directories : inc,
|
||||||
|
implicit_include_directories : false,
|
||||||
|
c_pch : '../precompiled.h',
|
||||||
|
sources : [
|
||||||
|
'tekkenio.c',
|
||||||
|
'tekkenio.h',
|
||||||
|
'config.c',
|
||||||
|
'config.h',
|
||||||
|
],
|
||||||
|
)
|
69
tekkenio/tekkenio.c
Normal file
69
tekkenio/tekkenio.c
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <xinput.h>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "tekkenio/tekkenio.h"
|
||||||
|
#include "tekkenio/config.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
static bool tekken_io_coin = false;
|
||||||
|
static bool tekken_test_toggle = false;
|
||||||
|
static uint16_t tekken_coin_ct = 0;
|
||||||
|
static struct tekken_najv4_config najv4_cfg;
|
||||||
|
|
||||||
|
uint16_t tekken_io_get_api_version(void)
|
||||||
|
{
|
||||||
|
return 0x0100;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT tekken_io_jvs_init(void)
|
||||||
|
{
|
||||||
|
dprintf("Tekken IO: JVS Init\n");
|
||||||
|
tekken_io_najv4_config_load(&najv4_cfg, L".\\bananatools.ini");
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT tekken_io_jvs_poll(uint8_t *opbtn)
|
||||||
|
{
|
||||||
|
*opbtn = 0;
|
||||||
|
|
||||||
|
if ((GetAsyncKeyState(najv4_cfg.test) & 0x8000)) {
|
||||||
|
*opbtn |= TEKKEN_IO_OPBTN_TEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.service) & 0x8000) {
|
||||||
|
*opbtn |= TEKKEN_IO_OPBTN_SERVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.up) & 0x8000) {
|
||||||
|
*opbtn |= TEKKEN_IO_OPBTN_UP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.down) & 0x8000) {
|
||||||
|
*opbtn |= TEKKEN_IO_OPBTN_DOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(najv4_cfg.enter) & 0x8000) {
|
||||||
|
*opbtn |= TEKKEN_IO_OPBTN_ENTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tekken_io_jvs_read_coin_counter(uint16_t *coins)
|
||||||
|
{
|
||||||
|
if (GetAsyncKeyState(VK_INSERT) & 0x8000) {
|
||||||
|
if (!tekken_io_coin) {
|
||||||
|
tekken_io_coin = true;
|
||||||
|
tekken_coin_ct++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tekken_io_coin = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*coins = tekken_coin_ct;
|
||||||
|
}
|
7
tekkenio/tekkenio.def
Normal file
7
tekkenio/tekkenio.def
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
LIBRARY tekkenhook
|
||||||
|
|
||||||
|
EXPORTS
|
||||||
|
tekken_io_get_api_version
|
||||||
|
tekken_io_jvs_init
|
||||||
|
tekken_io_jvs_poll
|
||||||
|
tekken_io_read_coin_counter
|
43
tekkenio/tekkenio.h
Normal file
43
tekkenio/tekkenio.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "tekkenio/config.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TEKKEN_IO_OPBTN_TEST = 0x01,
|
||||||
|
TEKKEN_IO_OPBTN_SERVICE = 0x02,
|
||||||
|
TEKKEN_IO_OPBTN_UP = 0x04,
|
||||||
|
TEKKEN_IO_OPBTN_DOWN = 0x08,
|
||||||
|
TEKKEN_IO_OPBTN_ENTER = 0x10,
|
||||||
|
TEKKEN_IO_OPBTN_COIN = 0x20,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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 tekken_io_get_api_version(void);
|
||||||
|
|
||||||
|
/* Initialize the IO DLL. This is the second function that will be called on
|
||||||
|
your DLL, after tekken_io_get_api_version.
|
||||||
|
|
||||||
|
All subsequent calls to this API may originate from arbitrary threads.
|
||||||
|
|
||||||
|
Minimum API version: 0x0100 */
|
||||||
|
|
||||||
|
HRESULT tekken_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 tekken_io_jvs_poll(uint8_t *opbtn);
|
||||||
|
|
||||||
|
void tekken_io_jvs_read_coin_counter(uint16_t *coins);
|
Loading…
Reference in New Issue
Block a user