add tekken

This commit is contained in:
Hay1tsme 2023-09-18 04:15:27 -04:00
parent 8ff356b84c
commit ea60cc4a18
19 changed files with 672 additions and 1 deletions

View File

@ -53,6 +53,17 @@ $(BUILD_DIR_ZIP)/mkac.zip:
$(V)strip $(BUILD_DIR_ZIP)/mkac/*.{exe,dll}
$(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: \
$(DOC_DIR)/ferrumhook.md \
$(DOC_DIR)/taikohook.md \
@ -68,6 +79,7 @@ $(BUILD_DIR_ZIP)/bananatools.zip: \
$(BUILD_DIR_ZIP)/exvs2.zip \
$(BUILD_DIR_ZIP)/sao.zip \
$(BUILD_DIR_ZIP)/mkac.zip \
$(BUILD_DIR_ZIP)/tekken.zip \
$(BUILD_DIR_ZIP)/doc.zip \
README.md \

58
dist/tekken/bananatools.ini vendored Normal file
View 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
View 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

View File

@ -59,9 +59,11 @@ subdir('taikoio')
subdir('exvs2io')
subdir('saoio')
subdir('mkacio')
subdir('tekkenio')
subdir('taikohook')
subdir('ferrumhook')
subdir('exvs2hook')
subdir('saohook')
subdir('mkachook')
subdir('mkachook')
subdir('tekkenhook')

35
tekkenhook/config.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);

View 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
View 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
View 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
View 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
View 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
View 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
View 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);