Compare commits

6 Commits

Author SHA1 Message Date
201f54ae36 Formatting 2024-04-16 01:28:29 +07:00
3c2609798b Add option to enable/disable hook 2024-04-16 01:27:48 +07:00
c895c275cf CRLF -> LF 2024-04-15 20:34:30 +07:00
1eceba427e re-enable LTO
it has weird build issues on my machine, so I turned it off.
2024-04-15 20:27:45 +07:00
ecfc104f0f Migrate cm/mai2/mu3 to unityhook 2024-04-15 20:27:04 +07:00
49f7189d35 unityhook: managing VFS redirection and loading assemblies 2024-04-15 20:26:25 +07:00
53 changed files with 279 additions and 1271 deletions

View File

@ -79,11 +79,6 @@ static HRESULT io3_cmd_read_analogs(
struct const_iobuf *req_buf,
struct iobuf *resp_buf);
static HRESULT io3_cmd_read_rotarys(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf);
static HRESULT io3_cmd_write_gpio(
struct io3 *io3,
struct const_iobuf *req_buf,
@ -121,13 +116,6 @@ static uint8_t io3_features[] = {
0x03, 8, 10, 0,
/* Feature : 0x04 : Rotary inputs
Param1 : 4 : Number of rotary channels
Param2 : 0 : N/A
Param3 : 0 : N/A */
0x04, 4, 0, 0,
/* Feature : 0x12 : GPIO outputs
Param1 : 3 : Number of ports (8 bits per port)
Param2 : 0 : N/A
@ -230,9 +218,6 @@ static HRESULT io3_cmd(
case JVS_CMD_READ_ANALOGS:
return io3_cmd_read_analogs(io3, req, resp);
case JVS_CMD_READ_ROTARYS:
return io3_cmd_read_rotarys(io3, req, resp);
case JVS_CMD_WRITE_GPIO:
return io3_cmd_write_gpio(io3, req, resp);
@ -551,60 +536,6 @@ static HRESULT io3_cmd_read_analogs(
}
static HRESULT io3_cmd_read_rotarys(
struct io3 *io3,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
struct jvs_req_read_rotarys req;
uint16_t rotarys[4];
uint8_t i;
HRESULT hr;
/* Read req */
hr = iobuf_read(req_buf, &req, sizeof(req));
if (FAILED(hr)) {
return hr;
}
if (req.nrotarys > _countof(rotarys)) {
dprintf("JVS I/O: Invalid analog count %i\n", req.nrotarys);
return E_FAIL;
}
//dprintf("JVS I/O: Read rotarys, nrotarys=%i\n", req.nrotarys);
/* Write report byte */
hr = iobuf_write_8(resp_buf, 0x01);
if (FAILED(hr)) {
return hr;
}
/* Write analogs */
memset(rotarys, 0, sizeof(rotarys));
if (io3->ops->read_rotarys != NULL) {
io3->ops->read_rotarys(io3->ops_ctx, rotarys, req.nrotarys);
}
for (i = 0 ; i < req.nrotarys ; i++) {
hr = iobuf_write_be16(resp_buf, rotarys[i]);
if (FAILED(hr)) {
return hr;
}
}
return hr;
}
static HRESULT io3_cmd_write_gpio(
struct io3 *io3,
struct const_iobuf *req_buf,

View File

@ -18,7 +18,6 @@ struct io3_ops {
void (*write_gpio)(void *ctx, uint32_t state);
void (*read_switches)(void *ctx, struct io3_switch_state *out);
void (*read_analogs)(void *ctx, uint16_t *analogs, uint8_t nanalogs);
void (*read_rotarys)(void *ctx, uint16_t *rotaries, uint8_t nrotaries);
void (*read_coin_counter)(void *ctx, uint8_t slot_no, uint16_t *out);
};

View File

@ -48,7 +48,7 @@ static_assert(sizeof(struct io4_report_in) == 0x40, "IO4 IN report size");
struct io4_report_out {
uint8_t report_id;
uint8_t cmd;
uint8_t payload[IO4_REPORT_OUT_PAYLOAD_LEN];
uint8_t payload[62];
};
static_assert(sizeof(struct io4_report_out) == 0x40, "IO4 OUT report size");
@ -223,11 +223,7 @@ static HRESULT io4_handle_write(struct irp *irp)
return S_OK;
case IO4_CMD_SET_GENERAL_OUTPUT:
// dprintf("USB I/O: GPIO Out\n");
if (io4_ops->write_gpio != NULL) {
return io4_ops->write_gpio(out.payload, IO4_REPORT_OUT_PAYLOAD_LEN);
}
dprintf("USB I/O: GPIO Out\n");
return S_OK;

View File

@ -4,8 +4,6 @@
#include <stdint.h>
#define IO4_REPORT_OUT_PAYLOAD_LEN 62
enum {
/* System buttons in button[0] */
@ -26,7 +24,6 @@ struct io4_state {
struct io4_ops {
HRESULT (*poll)(void *ctx, struct io4_state *state);
HRESULT (*write_gpio)(uint8_t* payload, size_t len);
};
HRESULT io4_hook_init(

View File

@ -26,7 +26,6 @@ static HRESULT vfd_handle_irp(struct irp *irp);
static struct uart vfd_uart;
static uint8_t vfd_written[512];
static uint8_t vfd_readable[512];
UINT codepage;
HRESULT vfd_hook_init(const struct vfd_config *cfg, unsigned int port_no)
{
@ -42,7 +41,6 @@ HRESULT vfd_hook_init(const struct vfd_config *cfg, unsigned int port_no)
vfd_uart.readable.bytes = vfd_readable;
vfd_uart.readable.nbytes = sizeof(vfd_readable);
codepage = GetACP();
dprintf("VFD: hook enabled.\n");
return iohook_push_handler(vfd_handle_irp);
@ -64,60 +62,8 @@ static HRESULT vfd_handle_irp(struct irp *irp)
return hr;
}
uint8_t cmd = 0;
uint8_t str_1[512];
uint8_t str_2[512];
uint8_t str_1_len = 0;
uint8_t str_2_len = 0;
for (size_t i = 0; i < vfd_uart.written.pos; i++) {
if (vfd_uart.written.bytes[i] == 0x1B) {
i++;
cmd = vfd_uart.written.bytes[i];
if (cmd == 0x30) {
i += 3;
}
else if (cmd == 0x50) {
i++;
}
continue;
}
if (cmd == 0x30) {
str_1[str_1_len++] = vfd_uart.written.bytes[i];
}
else if (cmd == 0x50) {
str_2[str_2_len++] = vfd_uart.written.bytes[i];
}
}
if (str_1_len) {
str_1[str_1_len++] = '\0';
if (codepage != 932) {
WCHAR buffer[512];
MultiByteToWideChar(932, 0, (LPCSTR)str_1, str_1_len, buffer, str_1_len);
char str_recode[str_1_len * 3];
WideCharToMultiByte(codepage, 0, buffer, str_1_len, str_recode, str_1_len * 3, NULL, NULL);
dprintf("VFD: %s\n", str_recode);
}
else {
dprintf("VFD: %s\n", str_1);
}
}
if (str_2_len) {
str_2[str_2_len++] = '\0';
if (codepage != 932) {
WCHAR buffer[512];
MultiByteToWideChar(932, 0, (LPCSTR)str_2, str_2_len, buffer, str_2_len);
char str_recode[str_2_len * 3];
WideCharToMultiByte(codepage, 0, buffer, str_2_len, str_recode, str_2_len * 3, NULL, NULL);
dprintf("VFD: %s\n", str_recode);
} else {
dprintf("VFD: %s\n", str_2);
}
}
// dprintf("VFD TX:\n");
// dump_iobuf(&vfd_uart.written);
dprintf("VFD TX:\n");
dump_iobuf(&vfd_uart.written);
vfd_uart.written.pos = 0;
return hr;

View File

@ -57,11 +57,11 @@ void chuni_io_config_load(
filename);
}
cfg->cab_led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename);
cfg->cab_led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename);
cfg->led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename);
cfg->led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename);
cfg->controller_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename);
cfg->controller_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename);
cfg->slider_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename);
cfg->slider_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename);
cfg->led_serial_baud = GetPrivateProfileIntW(L"led", L"serialBaud", 921600, filename);
@ -70,7 +70,7 @@ void chuni_io_config_load(
L"serialPort",
L"COM5",
port_input,
_countof(port_input),
6,
filename);
// Sanitize the output path. If it's a serial COM port, it needs to be prefixed

View File

@ -12,15 +12,16 @@ struct chuni_io_config {
uint8_t vk_cell[32];
// Which ways to output LED information are enabled
bool cab_led_output_pipe;
bool cab_led_output_serial;
bool led_output_pipe;
bool led_output_serial;
bool controller_led_output_pipe;
bool controller_led_output_serial;
bool slider_led_output_pipe;
bool slider_led_output_serial;
// The name of a COM port to output LED data on, in serial mode
wchar_t led_serial_port[12];
int32_t led_serial_baud;
};
void chuni_io_config_load(

View File

@ -48,15 +48,15 @@ HRESULT led_output_init(struct chuni_io_config* const cfg)
led_escaped_buf[i].data_len = chuni_led_board_data_lens[i];
}
any_outputs_enabled = config->cab_led_output_pipe || config->controller_led_output_pipe
|| config->cab_led_output_serial || config->controller_led_output_serial;
any_outputs_enabled = config->led_output_pipe || config->slider_led_output_pipe
|| config->led_output_serial || config->slider_led_output_serial;
if (config->cab_led_output_pipe || config->controller_led_output_pipe)
if (config->led_output_pipe || config->slider_led_output_pipe)
{
led_pipe_init(); // don't really care about errors here tbh
}
if (config->cab_led_output_serial || config->controller_led_output_serial)
if (config->led_output_serial || config->slider_led_output_serial)
{
led_serial_init(config->led_serial_port, config->led_serial_baud);
}
@ -106,13 +106,13 @@ void led_output_update(uint8_t board, const byte* rgb)
if (board < 2)
{
// billboard (cab)
if (config->cab_led_output_pipe)
// billboard
if (config->led_output_pipe)
{
led_pipe_update(escaped_data);
}
if (config->cab_led_output_serial)
if (config->led_output_serial)
{
led_serial_update(escaped_data);
}
@ -120,12 +120,12 @@ void led_output_update(uint8_t board, const byte* rgb)
else
{
// slider
if (config->controller_led_output_pipe)
if (config->slider_led_output_pipe)
{
led_pipe_update(escaped_data);
}
if (config->controller_led_output_serial)
if (config->slider_led_output_serial)
{
led_serial_update(escaped_data);
}

View File

@ -4,7 +4,6 @@
Credits:
somewhatlurker, skogaby
*/
#pragma once
#include <windows.h>

View File

@ -5,7 +5,7 @@
#include "cxbhook/led.h"
#include "cxbhook/cxb-dll.h"
#include "hook/procaddr.h"
#include "hooklib/procaddr.h"
#include "hook/table.h"
@ -56,7 +56,7 @@ HRESULT led_hook_init(struct led_config *cfg)
}
dprintf("LED: Hook enabled.\n");
return proc_addr_table_push(NULL, "CommLamp.dll", lamp_syms, _countof(lamp_syms));
return proc_addr_table_push("CommLamp.dll", lamp_syms, _countof(lamp_syms));
}
static int my_cCommLamp_Open(char *port)

View File

@ -6,7 +6,7 @@
#include "cxbhook/revio.h"
#include "cxbhook/cxb-dll.h"
#include "hook/procaddr.h"
#include "hooklib/procaddr.h"
#include "hook/table.h"
@ -89,7 +89,7 @@ HRESULT revio_hook_init(struct revio_config *cfg)
}
dprintf("Revio: Hook enabled.\n");
return proc_addr_table_push(NULL, "CommIo.dll", revio_syms, _countof(revio_syms));
return proc_addr_table_push("CommIo.dll", revio_syms, _countof(revio_syms));
}
static int my_cCommIo_Open(char *port)

View File

@ -63,6 +63,20 @@ framed=1
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
monitor=0
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
[chuniio]
; To use a custom Chunithm IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
; -----------------------------------------------------------------------------
; LED settings
; -----------------------------------------------------------------------------
@ -108,20 +122,6 @@ controllerLedOutputSerial=0
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
[chuniio]
; To use a custom Chunithm IO DLL enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
; -----------------------------------------------------------------------------
; Input settings
; -----------------------------------------------------------------------------

View File

@ -88,6 +88,25 @@ framed=0
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
monitor=0
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL (x64) enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
[chuniio]
; Uncomment this if you have custom chuniio implementation comprised of a single 32bit DLL.
; (will use chu2to3 engine internally)
;path=
; Uncomment both of these if you have custom chuniio implementation comprised of two DLLs.
; x86 chuniio to path32, x64 to path64. Both are necessary.
;path32=
;path64=
; -----------------------------------------------------------------------------
; LED settings
; -----------------------------------------------------------------------------
@ -133,25 +152,6 @@ controllerLedOutputSerial=0
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------
[aimeio]
; To use a custom card reader IO DLL (x64) enter its path here.
; Leave empty if you want to use Segatools built-in keyboard input.
path=
[chuniio]
; Uncomment this if you have custom chuniio implementation comprised of a single 32bit DLL.
; (will use chu2to3 engine internally)
;path=
; Uncomment both of these if you have custom chuniio implementation comprised of two DLLs.
; x86 chuniio to path32, x64 to path64. Both are necessary.
;path32=
;path64=
; -----------------------------------------------------------------------------
; Input settings
; -----------------------------------------------------------------------------

View File

@ -128,6 +128,7 @@ path=
; world. An improved solution will be provided later.
[io4]
; Input API selection for JVS input emulator.
; Test button virtual-key code. Default is the F1 key.
test=0x70
; Service button virtual-key code. Default is the F2 key.

25
dist/idac/start.bat vendored
View File

@ -2,6 +2,20 @@
pushd %~dp0
REM set the APP_DIR to the Y drive
set APP_DIR=Y:\SDGT
REM create the APP_DIR if it doesn't exist and redirect it to the TEMP folder
if not exist "%APP_DIR%" (
subst Y: %TEMP%
REM timeout /t 1
if not exist "%APP_DIR%" (
mkdir "%APP_DIR%"
)
)
echo Mounted the Y:\ drive to the %TEMP%\SDGT folder
set AMDAEMON_CFG=config_common.json ^
config_ex.json ^
config_jp.json ^
@ -26,15 +40,12 @@ config_seat_single_jp.json ^
config_hook.json
start "AM Daemon" /min inject -d -k idachook.dll amdaemon.exe -c %AMDAEMON_CFG%
rem JP
rem inject -d -k idachook.dll ..\WindowsNoEditor\GameProject\Binaries\Win64\GameProject-Win64-Shipping.exe -culture=ja launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED
rem EXP
inject -d -k idachook.dll ..\WindowsNoEditor\GameProject\Binaries\Win64\GameProject-Win64-Shipping.exe -culture=en launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED
inject -d -k idachook.dll ..\WindowsNoEditor\GameProject.exe -culture=en launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED
taskkill /f /im amdaemon.exe > nul 2>&1
REM unmount the APP_DIR
subst Y: /d > nul 2>&1
echo.
echo Game processes have terminated
pause

View File

@ -73,61 +73,10 @@ dipsw1=1
enable=1
[unity]
; Enable Unity hook. This will allow you to run custom .NET code before the game
enable=1
; Path to a .NET DLL that should run before the game. Useful for loading
; modding frameworks such as BepInEx.
targetAssembly=
; -----------------------------------------------------------------------------
; LED settings
; -----------------------------------------------------------------------------
[led15093]
; Enable emulation of the 15093-06 controlled lights, which handle the air tower
; RGBs and the rear LED panel (billboard) on the cabinet.
enable=1
[led]
; Output billboard LED strip data to a named pipe called "\\.\pipe\ongeki_led"
cabLedOutputPipe=1
; Output billboard LED strip data to serial
cabLedOutputSerial=0
; Output slider LED data to the named pipe
controllerLedOutputPipe=1
; Output slider LED data to the serial port
controllerLedOutputSerial=0
; Serial port to send data to if using serial output. Default is COM5.
;serialPort=COM5
; Baud rate for serial data
;serialBaud=921600
; Data output a sequence of bytes, with JVS-like framing.
; Each "packet" starts with 0xE0 as a sync. To avoid E0 appearing elsewhere,
; 0xD0 is used as an escape character -- if you receive D0 in the output, ignore
; it and use the next sent byte plus one instead.
;
; After the sync is one byte for the board number that was updated, followed by
; the red, green and blue values for each LED.
;
; Board 0 has 61 LEDs:
; [0]-[1]: left side button
; [2]-[8]: left pillar lower LEDs
; [9]-[17]: left pillar center LEDs
; [18]-[24]: left pillar upper LEDs
; [25]-[35]: billboard LEDs
; [36]-[42]: right pillar upper LEDs
; [43]-[51]: right pillar center LEDs
; [52]-[58]: right pillar lower LEDs
; [59]-[60]: right side button
;
; Board 1 has 6 LEDs:
; [0]-[5]: 3 left and 3 right controller buttons
;
; -----------------------------------------------------------------------------
; Custom IO settings
; -----------------------------------------------------------------------------

View File

@ -28,7 +28,7 @@ const struct dll_bind_sym fgo_dll_syms[] = {
.sym = "fgo_io_led_init",
.off = offsetof(struct fgo_dll, led_init),
}, {
.sym = "fgo_io_led_set_colors",
.sym = "fgo_io_led_set_leds",
.off = offsetof(struct fgo_dll, led_set_leds),
}
};

View File

@ -18,7 +18,7 @@ EXPORTS
fgo_io_init
fgo_io_poll
fgo_io_led_init
fgo_io_led_set_colors
fgo_io_led_set_leds
fwdlusb_open
fwdlusb_close
fwdlusb_listupPrinter

View File

@ -145,7 +145,7 @@ HRESULT fgo_io_led_init(void)
return S_OK;
}
void fgo_io_led_set_colors(uint8_t board, uint8_t *rgb)
void fgo_io_led_set_leds(uint8_t board, uint8_t *rgb)
{
return;
}
}

View File

@ -83,4 +83,4 @@ HRESULT fgo_io_led_init(void);
Exact layout is TBD. */
void fgo_io_led_set_colors(uint8_t board, uint8_t *rgb);
void fgo_io_led_set_leds(uint8_t board, uint8_t *rgb);

View File

@ -194,37 +194,6 @@ static void dns_hook_init(void)
_countof(dns_hook_syms_winhttp));
}
// This function match domain and subdomains like *.naominet.jp.
bool match_domain(const wchar_t* target, const wchar_t* pattern) {
if (_wcsicmp(pattern, target) == 0) {
return true;
}
int pattern_ptr_index = 0;
int target_ptr_index = 0;
while (pattern[pattern_ptr_index] != '\0' && target[target_ptr_index] != '\0') {
if (pattern[pattern_ptr_index] == '*') {
pattern_ptr_index++; // Check next character for wildcard match.
while (pattern[pattern_ptr_index] != target[target_ptr_index]) {
target_ptr_index++;
if (target[target_ptr_index] == '\0') return false;
}
}
else if (pattern[pattern_ptr_index] != target[target_ptr_index]) {
return false;
}
else {
pattern_ptr_index++;
target_ptr_index++;
}
}
return pattern[pattern_ptr_index] == '\0' && target[target_ptr_index] == '\0';
}
HRESULT dns_hook_push(const wchar_t *from_src, const wchar_t *to_src)
{
HRESULT hr;
@ -328,7 +297,7 @@ static DNS_STATUS WINAPI hook_DnsQuery_A(
for (i = 0 ; i < dns_hook_nentries ; i++) {
pos = &dns_hook_entries[i];
if (match_domain(wstr, pos->from)) {
if (_wcsicmp(wstr, pos->from) == 0) {
if(pos->to == NULL) {
LeaveCriticalSection(&dns_hook_lock);
hr = HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR);
@ -392,7 +361,7 @@ static DNS_STATUS WINAPI hook_DnsQuery_W(
for (i = 0 ; i < dns_hook_nentries ; i++) {
pos = &dns_hook_entries[i];
if (match_domain(pszName, pos->from)) {
if (_wcsicmp(pszName, pos->from) == 0) {
if(pos->to == NULL) {
LeaveCriticalSection(&dns_hook_lock);
return HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR);
@ -436,7 +405,7 @@ static DNS_STATUS WINAPI hook_DnsQueryEx(
for (i = 0 ; i < dns_hook_nentries ; i++) {
pos = &dns_hook_entries[i];
if (match_domain(pRequest->QueryName, pos->from)) {
if (_wcsicmp(pRequest->QueryName, pos->from) == 0) {
if(pos->to == NULL) {
LeaveCriticalSection(&dns_hook_lock);
return HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR);
@ -503,7 +472,7 @@ static int WSAAPI hook_getaddrinfo(
for (i = 0 ; i < dns_hook_nentries ; i++) {
pos = &dns_hook_entries[i];
if (match_domain(wstr, pos->from)) {
if (_wcsicmp(wstr, pos->from) == 0) {
if(pos->to == NULL) {
LeaveCriticalSection(&dns_hook_lock);
result = EAI_NONAME;
@ -557,7 +526,7 @@ static HINTERNET WINAPI hook_WinHttpConnect(
for (i = 0 ; i < dns_hook_nentries ; i++) {
pos = &dns_hook_entries[i];
if (match_domain(pwszServerName, pos->from)) {
if (_wcsicmp(pwszServerName, pos->from) == 0) {
if(pos->to == NULL) {
LeaveCriticalSection(&dns_hook_lock);
return NULL;
@ -589,7 +558,7 @@ static bool WINAPI hook_WinHttpCrackUrl(
for (i = 0 ; i < dns_hook_nentries ; i++) {
pos = &dns_hook_entries[i];
if (match_domain(pwszUrl, pos->from)) {
if (_wcsicmp(pwszUrl, pos->from) == 0) {
wchar_t* toAddr = pos->to;
wchar_t titleBuffer[255];

View File

@ -23,6 +23,8 @@ hooklib_lib = static_library(
'fdshark.h',
'path.c',
'path.h',
'procaddr.c',
'procaddr.h',
'reg.c',
'reg.h',
'setupapi.c',

125
hooklib/procaddr.c Normal file
View File

@ -0,0 +1,125 @@
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
#include <libgen.h>
#include "hooklib/procaddr.h"
#include "hook/table.h"
#include "util/dprintf.h"
static struct proc_addr_table *proc_addr_hook_list;
static size_t proc_addr_hook_count;
static CRITICAL_SECTION proc_addr_hook_lock;
static bool proc_addr_hook_initted;
static FARPROC WINAPI my_GetProcAddress(HMODULE hModule, const char *name);
static FARPROC (WINAPI *next_GetProcAddress)(HMODULE hModule, const char *name);
static void proc_addr_hook_init(void);
static const struct hook_symbol win32_hooks[] = {
{
.name = "GetProcAddress",
.patch = my_GetProcAddress,
.link = (void **) &next_GetProcAddress
}
};
HRESULT proc_addr_table_push(
const char *target,
struct hook_symbol *syms,
size_t nsyms
)
{
HRESULT hr;
struct proc_addr_table *new_item;
struct proc_addr_table *new_mem;
proc_addr_hook_init();
EnterCriticalSection(&proc_addr_hook_lock);
new_mem = realloc(
proc_addr_hook_list,
(proc_addr_hook_count + 1) * sizeof(struct proc_addr_table));
if (new_mem == NULL) {
hr = E_OUTOFMEMORY;
LeaveCriticalSection(&proc_addr_hook_lock);
return hr;
}
new_item = &new_mem[proc_addr_hook_count];
new_item->name = target;
new_item->nsyms = nsyms;
new_item->syms = syms;
proc_addr_hook_list = new_mem;
proc_addr_hook_count++;
hr = S_OK;
LeaveCriticalSection(&proc_addr_hook_lock);
return hr;
}
static void proc_addr_hook_init(void)
{
if (proc_addr_hook_initted) {
return;
}
dprintf("ProcAddr: Hook init\n");
proc_addr_hook_initted = true;
InitializeCriticalSection(&proc_addr_hook_lock);
hook_table_apply(
NULL,
"kernel32.dll",
win32_hooks,
_countof(win32_hooks));
}
FARPROC WINAPI my_GetProcAddress(HMODULE hModule, const char *name)
{
uintptr_t ordinal = (uintptr_t) name;
char mod_path[PATH_MAX];
char *mod_name;
const struct hook_symbol *sym;
FARPROC result = next_GetProcAddress(hModule, name);
GetModuleFileNameA(hModule, mod_path, PATH_MAX);
mod_name = basename(mod_path);
for (int i = 0; i < proc_addr_hook_count; i++) {
if (strcmp(proc_addr_hook_list[i].name, mod_name) == 0) {
for (int j = 0; j < proc_addr_hook_list[i].nsyms; j++) {
sym = &proc_addr_hook_list[i].syms[j];
if (ordinal > 0xFFFF) {
if (strcmp(sym->name, name) == 0) {
dprintf("ProcAddr: Hooking %s from %s\n", name, mod_name);
result = (FARPROC) sym->patch;
}
}
else {
if (sym->ordinal == ordinal) {
dprintf("ProcAddr: Hooking Ord %p from %s\n", (void *)ordinal, mod_name);
result = (FARPROC) sym->patch;
}
}
}
}
}
return result;
}

18
hooklib/procaddr.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
#include "hook/table.h"
struct proc_addr_table {
const char *name;
size_t nsyms;
struct hook_symbol *syms;
};
HRESULT proc_addr_table_push(
const char *target,
struct hook_symbol *syms,
size_t nsyms
);

View File

@ -7,7 +7,6 @@
#include "hook/table.h"
#include "hooklib/reg.h"
#include "hook/procaddr.h"
#include "util/dprintf.h"
#include "util/str.h"
@ -100,29 +99,6 @@ static LSTATUS WINAPI hook_RegGetValueW(
uint32_t *numData
);
static LSTATUS WINAPI hook_RegQueryInfoKeyW(
HKEY hKey,
LPWSTR lpClass,
LPDWORD lpcchClass,
LPDWORD lpReserved,
LPDWORD lpcSubKeys,
LPDWORD lpcbMaxSubKeyLen,
LPDWORD lpcbMaxClassLen,
LPDWORD lpcValues,
LPDWORD lpcbMaxValueNameLen,
LPDWORD lpcbMaxValueLen,
LPDWORD lpcbSecurityDescriptor,
PFILETIME lpftLastWriteTime);
static LSTATUS WINAPI hook_RegEnumValueW(
HKEY hkey,
DWORD dwIndex,
LPWSTR lpValueName,
LPDWORD lpcchValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData);
/* Link pointers */
static LSTATUS (WINAPI *next_RegOpenKeyExW)(
@ -179,30 +155,6 @@ static LSTATUS (WINAPI *next_RegGetValueW)(
uint32_t *numData
);
static LSTATUS (WINAPI *next_RegQueryInfoKeyW)(
HKEY hKey,
LPWSTR lpClass,
LPDWORD lpcchClass,
LPDWORD lpReserved,
LPDWORD lpcSubKeys,
LPDWORD lpcbMaxSubKeyLen,
LPDWORD lpcbMaxClassLen,
LPDWORD lpcValues,
LPDWORD lpcbMaxValueNameLen,
LPDWORD lpcbMaxValueLen,
LPDWORD lpcbSecurityDescriptor,
PFILETIME lpftLastWriteTime);
static LSTATUS (WINAPI *next_RegEnumValueW)(
HKEY hkey,
DWORD dwIndex,
LPWSTR lpValueName,
LPDWORD lpcchValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData);
static const struct hook_symbol reg_hook_syms[] = {
{
.name = "RegOpenKeyExW",
@ -232,14 +184,6 @@ static const struct hook_symbol reg_hook_syms[] = {
.name = "RegGetValueW",
.patch = hook_RegGetValueW,
.link = (void **) &next_RegGetValueW,
}, {
.name = "RegQueryInfoKeyW",
.patch = hook_RegQueryInfoKeyW,
.link = (void **) &next_RegQueryInfoKeyW,
}, {
.name = "RegEnumValueW",
.patch = hook_RegEnumValueW,
.link = (void **) &next_RegEnumValueW,
}
};
@ -310,24 +254,11 @@ static void reg_hook_init(void)
InitializeCriticalSection(&reg_hook_lock);
dprintf("Reg hook init\n");
reg_hook_insert_hooks(NULL);
proc_addr_table_push(
NULL,
"ADVAPI32.dll",
(struct hook_symbol *) reg_hook_syms,
_countof(reg_hook_syms));
}
void reg_hook_insert_hooks(HMODULE target)
{
hook_table_apply(
target,
NULL,
"advapi32.dll",
reg_hook_syms,
_countof(reg_hook_syms));
}
static LRESULT reg_hook_propagate_hr(HRESULT hr)
@ -400,7 +331,6 @@ static LSTATUS reg_hook_open_locked(
/* Assume reg keys are referenced from a root key and not from some
intermediary key */
key = &reg_hook_keys[i];
//dprintf("Reg: %ls vs %ls\n", name, key->name);
if (key->root == parent && wstr_ieq(key->name, name)) {
break;
@ -891,99 +821,6 @@ static LSTATUS WINAPI hook_RegGetValueW(
return err;
}
static LSTATUS WINAPI hook_RegQueryInfoKeyW(
HKEY hKey,
LPWSTR lpClass,
LPDWORD lpcchClass,
LPDWORD lpReserved,
LPDWORD lpcSubKeys,
LPDWORD lpcbMaxSubKeyLen,
LPDWORD lpcbMaxClassLen,
LPDWORD lpcValues,
LPDWORD lpcbMaxValueNameLen,
LPDWORD lpcbMaxValueLen,
LPDWORD lpcbSecurityDescriptor,
PFILETIME lpftLastWriteTime)
{
struct reg_hook_key *key;
LSTATUS err;
EnterCriticalSection(&reg_hook_lock);
key = reg_hook_match_key_locked(hKey);
/* Check if this is a virtualized registry key */
if (key == NULL) {
LeaveCriticalSection(&reg_hook_lock);
return next_RegQueryInfoKeyW(
hKey,
lpClass,
lpcchClass,
lpReserved,
lpcSubKeys,
lpcbMaxSubKeyLen,
lpcbMaxClassLen,
lpcValues,
lpcbMaxValueNameLen,
lpcbMaxValueLen,
lpcbSecurityDescriptor,
lpftLastWriteTime);
}
// This is the only one I've seen even be changed, so it's all I'm doing
// until I see otherwise.
*lpcValues = key->nvals;
LeaveCriticalSection(&reg_hook_lock);
return ERROR_SUCCESS;
}
static LSTATUS WINAPI hook_RegEnumValueW(
HKEY hkey,
DWORD dwIndex,
LPWSTR lpValueName,
LPDWORD lpcchValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData)
{
struct reg_hook_key *key;
HRESULT hr;
LSTATUS err;
EnterCriticalSection(&reg_hook_lock);
key = reg_hook_match_key_locked(hkey);
/* Check if this is a virtualized registry key */
if (key == NULL) {
LeaveCriticalSection(&reg_hook_lock);
return next_RegEnumValueW(
hkey,
dwIndex,
lpValueName,
lpcchValueName,
lpReserved,
lpType,
lpData,
lpcbData);
}
if (dwIndex >= key->nvals) {
LeaveCriticalSection(&reg_hook_lock);
return ERROR_NO_MORE_ITEMS; // Pretty sure this is what it actually returns here?
}
wcscpy_s(lpValueName, *lpcchValueName, key->vals[dwIndex].name);
*lpcchValueName = wcslen(key->vals[dwIndex].name);
LeaveCriticalSection(&reg_hook_lock);
return ERROR_SUCCESS;
}
HRESULT reg_hook_read_bin(
void *bytes,
uint32_t *nbytes,

View File

@ -12,8 +12,6 @@ struct reg_hook_val {
uint32_t type;
};
void reg_hook_insert_hooks(HMODULE target);
HRESULT reg_hook_push_key(
HKEY root,
const wchar_t *name,

View File

@ -119,19 +119,10 @@ void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE sel
defaultCursor = LoadCursorA(NULL, IDC_CROSS);
memcpy(&touch_config, cfg, sizeof(*cfg));
touch_hook_insert_hooks(NULL);
hook_table_apply(NULL, "user32.dll", touch_hooks, _countof(touch_hooks));
dprintf("TOUCH: hook enabled.\n");
}
void touch_hook_insert_hooks(HMODULE target)
{
hook_table_apply(
target,
"user32.dll",
touch_hooks,
_countof(touch_hooks));
}
static HCURSOR WINAPI hook_SetCursor(HCURSOR cursor) {
if (cursor == 0 && touch_config.cursor)
return next_SetCursor(defaultCursor);

View File

@ -14,4 +14,3 @@ struct touch_screen_config {
blah blah you know the drill by now. */
void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE self);
void touch_hook_insert_hooks(HMODULE target);

View File

@ -9,7 +9,6 @@ enum {
JVS_CMD_READ_SWITCHES = 0x20,
JVS_CMD_READ_COIN = 0x21,
JVS_CMD_READ_ANALOGS = 0x22,
JVS_CMD_READ_ROTARYS = 0x23,
JVS_CMD_WRITE_GPIO = 0x32,
JVS_CMD_RESET = 0xF0,
JVS_CMD_ASSIGN_ADDR = 0xF1,
@ -33,11 +32,6 @@ struct jvs_req_read_analogs {
uint8_t nanalogs;
};
struct jvs_req_read_rotarys {
uint8_t cmd;
uint8_t nrotarys;
};
struct jvs_req_reset {
uint8_t cmd;
uint8_t unknown;

View File

@ -14,7 +14,6 @@ add_project_arguments(
'-D_WIN32_WINNT=_WIN32_WINNT_WIN7',
'-DMINGW_HAS_SECURE_API=1',
'-Wno-unused',
# '-ggdb', # Add debug information
language: 'c',
)
@ -24,6 +23,7 @@ if cc.get_id() != 'msvc'
add_project_arguments(
'-ffunction-sections',
'-fdata-sections',
'-flto', # Enable Link-Time Optimization
language: 'c',
)
@ -32,9 +32,8 @@ if cc.get_id() != 'msvc'
'-Wl,--exclude-all-symbols',
'-Wl,--gc-sections',
'-static-libgcc',
# '-ggdb', # Add debug information
'-lcrypt32', # Bcrypt needed for prashook
# '-Wl,-s', # Strip debug symbols
'-flto', # Enable Link-Time Optimization
'-Wl,-s', # Strip debug symbols
language: 'c',
)
endif

View File

@ -28,66 +28,6 @@ void mu3_dll_config_load(
filename);
}
void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
wchar_t tmpstr[16];
memset(cfg->board_number, ' ', sizeof(cfg->board_number));
memset(cfg->chip_number, ' ', sizeof(cfg->chip_number));
memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number));
cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename);
cfg->port_no = GetPrivateProfileIntW(L"led15093", L"portNo", 0, filename);
cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaud", 0, filename);
cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename);
cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xAA53, filename);
GetPrivateProfileStringW(
L"led15093",
L"boardNumber",
L"15093-06",
tmpstr,
_countof(tmpstr),
filename);
size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number));
for (int i = n; i < sizeof(cfg->board_number); i++)
{
cfg->board_number[i] = ' ';
}
GetPrivateProfileStringW(
L"led15093",
L"chipNumber",
L"6710A",
tmpstr,
_countof(tmpstr),
filename);
n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number));
for (int i = n; i < sizeof(cfg->chip_number); i++)
{
cfg->chip_number[i] = ' ';
}
GetPrivateProfileStringW(
L"led15093",
L"bootChipNumber",
L"6709 ",
tmpstr,
_countof(tmpstr),
filename);
n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number));
for (int i = n; i < sizeof(cfg->boot_chip_number); i++)
{
cfg->boot_chip_number[i] = ' ';
}
}
void mu3_hook_config_load(
struct mu3_hook_config *cfg,
const wchar_t *filename)
@ -100,7 +40,6 @@ void mu3_hook_config_load(
dvd_config_load(&cfg->dvd, filename);
io4_config_load(&cfg->io4, filename);
gfx_config_load(&cfg->gfx, filename);
led15093_config_load(&cfg->led15093, filename);
vfd_config_load(&cfg->vfd, filename);
mu3_dll_config_load(&cfg->dll, filename);
unity_config_load(&cfg->unity, filename);

View File

@ -3,7 +3,7 @@
#include <stddef.h>
#include "board/config.h"
#include "board/led15093.h"
// #include "board/led15093.h"
#include "gfxhook/gfx.h"
@ -21,7 +21,7 @@ struct mu3_hook_config {
struct dvd_config dvd;
struct io4_config io4;
struct gfx_config gfx;
struct led15093_config led15093;
// struct led15093_config led15093;
struct vfd_config vfd;
struct mu3_dll_config dll;
struct unity_config unity;

View File

@ -62,18 +62,14 @@ static DWORD CALLBACK mu3_pre_startup(void)
goto fail;
}
hr = mu3_dll_init(&mu3_hook_cfg.dll, mu3_hook_mod);
if (FAILED(hr)) {
goto fail;
}
hr = led15093_hook_init(&mu3_hook_cfg.led15093,
mu3_dll.led_init, mu3_dll.led_set_leds, 3, 1, 1, 2);
/*
// Does not work, Unity moment
hr = led15093_hook_init(&mu3_hook_cfg.led15093, 3, 1, 1, 2);
if (FAILED(hr)) {
return hr;
}
*/
hr = sg_reader_hook_init(&mu3_hook_cfg.aime, 1, 1, mu3_hook_mod);
@ -87,6 +83,12 @@ static DWORD CALLBACK mu3_pre_startup(void)
goto fail;
}
hr = mu3_dll_init(&mu3_hook_cfg.dll, mu3_hook_mod);
if (FAILED(hr)) {
goto fail;
}
hr = mu3_io4_hook_init(&mu3_hook_cfg.io4);
if (FAILED(hr)) {

View File

@ -11,13 +11,10 @@
#include "util/dprintf.h"
static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state);
static HRESULT mu3_io4_write_gpio(uint8_t* payload, size_t len);
static uint16_t coins;
static const struct io4_ops mu3_io4_ops = {
.poll = mu3_io4_poll,
.write_gpio = mu3_io4_write_gpio,
};
HRESULT mu3_io4_hook_init(const struct io4_config *cfg)
@ -127,46 +124,3 @@ static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state)
return S_OK;
}
static HRESULT mu3_io4_write_gpio(uint8_t* payload, size_t len)
{
// Just fast fail if there aren't enough bytes in the payload
if (len < 3)
return S_OK;
// This command is used for lights in Ongeki, but it only contains button lights,
// and only in the first 3 bytes of the payload; everything else is padding to
// make the payload 62 bytes. The rest of the cabinet lights and the side button
// lights are handled separately, by the 15093 lights controller.
uint32_t lights_data = (uint32_t) ((uint8_t)(payload[0]) << 24 |
(uint8_t)(payload[1]) << 16 |
(uint8_t)(payload[2]) << 8);
// Since Sega uses an odd ordering for the first part of the bitfield,
// let's normalize the data and just send over bytes for the receiver
// to interpret as RGB values.
uint8_t rgb_out[6 * 3] = {
lights_data & MU3_IO_LED_L1_R ? 0xFF : 0x00,
lights_data & MU3_IO_LED_L1_G ? 0xFF : 0x00,
lights_data & MU3_IO_LED_L1_B ? 0xFF : 0x00,
lights_data & MU3_IO_LED_L2_R ? 0xFF : 0x00,
lights_data & MU3_IO_LED_L2_G ? 0xFF : 0x00,
lights_data & MU3_IO_LED_L2_B ? 0xFF : 0x00,
lights_data & MU3_IO_LED_L3_R ? 0xFF : 0x00,
lights_data & MU3_IO_LED_L3_G ? 0xFF : 0x00,
lights_data & MU3_IO_LED_L3_B ? 0xFF : 0x00,
lights_data & MU3_IO_LED_R1_R ? 0xFF : 0x00,
lights_data & MU3_IO_LED_R1_G ? 0xFF : 0x00,
lights_data & MU3_IO_LED_R1_B ? 0xFF : 0x00,
lights_data & MU3_IO_LED_R2_R ? 0xFF : 0x00,
lights_data & MU3_IO_LED_R2_G ? 0xFF : 0x00,
lights_data & MU3_IO_LED_R2_B ? 0xFF : 0x00,
lights_data & MU3_IO_LED_R3_R ? 0xFF : 0x00,
lights_data & MU3_IO_LED_R3_G ? 0xFF : 0x00,
lights_data & MU3_IO_LED_R3_B ? 0xFF : 0x00,
};
mu3_io_led_set_colors(1, rgb_out);
return S_OK;
}

View File

@ -24,28 +24,9 @@ const struct dll_bind_sym mu3_dll_syms[] = {
}, {
.sym = "mu3_io_get_lever",
.off = offsetof(struct mu3_dll, get_lever),
}, {
.sym = "mu3_io_led_init",
.off = offsetof(struct mu3_dll, led_init),
}, {
.sym = "mu3_io_led_set_colors",
.off = offsetof(struct mu3_dll, led_set_leds),
}
};
/* Helper function to determine upon dll_bind failure whether the required functions were found
NOTE: relies on symbols order declared above */
static HRESULT has_enough_symbols(uint16_t version, uint8_t count)
{
if ( version <= 0x0100 && count == 5 )
return S_OK;
if ( version >= 0x0101 && count == 7 )
return S_OK;
return E_FAIL;
}
struct mu3_dll mu3_dll;
// Copypasta DLL binding and diagnostic message boilerplate.
@ -105,25 +86,16 @@ HRESULT mu3_dll_init(const struct mu3_dll_config *cfg, HINSTANCE self)
}
sym = mu3_dll_syms;
const struct dll_bind_sym *init_sym = &sym[0];
hr = dll_bind(&mu3_dll, src, &sym, _countof(mu3_dll_syms));
if (FAILED(hr)) {
if (src != self) {
// Might still be ok depending on external dll API version
int bind_count = sym - init_sym;
if (has_enough_symbols(mu3_dll.api_version, bind_count) == S_OK)
{
hr = S_OK;
} else {
dprintf("Ongeki IO: Custom IO DLL does not provide function "
"\"%s\". Please contact your IO DLL's developer for "
"further assistance.\n",
sym->sym);
dprintf("Ongeki IO: Custom IO DLL does not provide function "
"\"%s\". Please contact your IO DLL's developer for "
"further assistance.\n",
sym->sym);
goto end;
}
goto end;
} else {
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
}

View File

@ -11,8 +11,6 @@ struct mu3_dll {
void (*get_opbtns)(uint8_t *opbtn);
void (*get_gamebtns)(uint8_t *left, uint8_t *right);
void (*get_lever)(int16_t *pos);
HRESULT (*led_init)(void);
void (*led_set_leds)(uint8_t board, uint8_t *rgb);
};
struct mu3_dll_config {

View File

@ -23,5 +23,3 @@ EXPORTS
mu3_io_get_opbtns
mu3_io_init
mu3_io_poll
mu3_io_led_init
mu3_io_led_set_colors

View File

@ -14,8 +14,6 @@ void mu3_io_config_load(
assert(cfg != NULL);
assert(filename != NULL);
wchar_t output_path_input[6];
cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename);
cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename);
cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename);
@ -32,25 +30,4 @@ void mu3_io_config_load(
cfg->vk_right_3 = GetPrivateProfileIntW(L"io4", L"right3", 'L', filename);
cfg->vk_left_menu = GetPrivateProfileIntW(L"io4", L"leftMenu", 'U', filename);
cfg->vk_right_menu = GetPrivateProfileIntW(L"io4", L"rightMenu", 'O', filename);
cfg->cab_led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename);
cfg->cab_led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename);
cfg->controller_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename);
cfg->controller_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename);
cfg->led_serial_baud = GetPrivateProfileIntW(L"led", L"serialBaud", 921600, filename);
GetPrivateProfileStringW(
L"led",
L"serialPort",
L"COM5",
output_path_input,
_countof(output_path_input),
filename);
// Sanitize the output path. If it's a serial COM port, it needs to be prefixed
// with `\\.\`.
wcsncpy(cfg->led_serial_port, L"\\\\.\\", 4);
wcsncat_s(cfg->led_serial_port, MAX_PATH, output_path_input, MAX_PATH);
}

View File

@ -22,17 +22,6 @@ struct mu3_io_config {
uint8_t vk_right_3;
uint8_t vk_left_menu;
uint8_t vk_right_menu;
// Which ways to output LED information are enabled
bool cab_led_output_pipe;
bool cab_led_output_serial;
bool controller_led_output_pipe;
bool controller_led_output_serial;
// The name of a COM port to output LED data on, in serial mode
wchar_t led_serial_port[12];
int32_t led_serial_baud;
};
void mu3_io_config_load(

View File

@ -1,23 +0,0 @@
#pragma once
#include <windows.h>
#include <stdint.h>
#define LED_PACKET_FRAMING 0xE0
#define LED_PACKET_ESCAPE 0xD0
#define LED_NUM_MAX 66
#define LED_BOARDS_TOTAL 2
#define LED_OUTPUT_HEADER_SIZE 2
#define LED_OUTPUT_DATA_SIZE_MAX LED_NUM_MAX * 3 * 2 // max if every byte's escaped
#define LED_OUTPUT_TOTAL_SIZE_MAX LED_OUTPUT_HEADER_SIZE + LED_OUTPUT_DATA_SIZE_MAX
// This struct is used to send data related to the button and cab LEDs
struct _ongeki_led_data_buf_t {
byte framing; // Sync byte
uint8_t board; // LED output the data is for (0: cab, 1: control deck)
byte data[LED_OUTPUT_DATA_SIZE_MAX]; // Buffer for LEDs
byte data_len; // How many bytes to output from the buffer
};
static byte ongeki_led_board_data_lens[LED_BOARDS_TOTAL] = {9*3, 6*3};

View File

@ -1,130 +0,0 @@
#include <windows.h>
#include <process.h>
#include <stdbool.h>
#include <stdint.h>
#include "mu3io/config.h"
#include "mu3io/leddata.h"
#include "mu3io/ledoutput.h"
#include "mu3io/pipeimpl.h"
#include "mu3io/serialimpl.h"
static struct _ongeki_led_data_buf_t mu3_led_unescaped_buf[LED_BOARDS_TOTAL];
static struct _ongeki_led_data_buf_t mu3_led_escaped_buf[LED_BOARDS_TOTAL];
static bool mu3_led_output_is_init = false;
static struct mu3_io_config* mu3_io_config;
static bool mu3_led_any_outputs_enabled;
HANDLE mu3_led_init_mutex;
HRESULT mu3_led_output_init(struct mu3_io_config* const cfg)
{
DWORD dwWaitResult = WaitForSingleObject(mu3_led_init_mutex, INFINITE);
if (dwWaitResult == WAIT_FAILED)
{
return HRESULT_FROM_WIN32(GetLastError());
}
else if (dwWaitResult != WAIT_OBJECT_0)
{
return E_FAIL;
}
if (!mu3_led_output_is_init)
{
mu3_io_config = cfg;
// Setup the framing bytes for the packets
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
mu3_led_unescaped_buf[i].framing = LED_PACKET_FRAMING;
mu3_led_unescaped_buf[i].board = i;
mu3_led_unescaped_buf[i].data_len = ongeki_led_board_data_lens[i];
mu3_led_escaped_buf[i].framing = LED_PACKET_FRAMING;
mu3_led_escaped_buf[i].board = i;
mu3_led_escaped_buf[i].data_len = ongeki_led_board_data_lens[i];
}
mu3_led_any_outputs_enabled = mu3_io_config->cab_led_output_pipe || mu3_io_config->controller_led_output_pipe
|| mu3_io_config->cab_led_output_serial || mu3_io_config->controller_led_output_serial;
if (mu3_io_config->cab_led_output_pipe || mu3_io_config->controller_led_output_pipe)
{
mu3_led_pipe_init(); // don't really care about errors here tbh
}
if (mu3_io_config->cab_led_output_serial || mu3_io_config->controller_led_output_serial)
{
mu3_led_serial_init(mu3_io_config->led_serial_port, mu3_io_config->led_serial_baud);
}
}
mu3_led_output_is_init = true;
ReleaseMutex(mu3_led_init_mutex);
return S_OK;
}
struct _ongeki_led_data_buf_t* escape_led_data(struct _ongeki_led_data_buf_t* unescaped)
{
struct _ongeki_led_data_buf_t* out_struct = &mu3_led_escaped_buf[unescaped->board];
byte* in_buf = unescaped->data;
byte* out_buf = out_struct->data;
int i = 0;
int o = 0;
while (i < unescaped->data_len)
{
byte b = in_buf[i++];
if (b == LED_PACKET_FRAMING || b == LED_PACKET_ESCAPE)
{
out_buf[o++] = LED_PACKET_ESCAPE;
b--;
}
out_buf[o++] = b;
}
out_struct->data_len = o;
return out_struct;
}
void mu3_led_output_update(int board, const byte* rgb)
{
if (board < 0 || board > 1 || !mu3_led_any_outputs_enabled)
{
return;
}
memcpy(mu3_led_unescaped_buf[board].data, rgb, mu3_led_unescaped_buf[board].data_len);
struct _ongeki_led_data_buf_t* escaped_data = escape_led_data(&mu3_led_unescaped_buf[board]);
if (board == 0)
{
// cab
if (mu3_io_config->cab_led_output_pipe)
{
mu3_led_pipe_update(escaped_data);
}
if (mu3_io_config->cab_led_output_serial)
{
mu3_led_serial_update(escaped_data);
}
}
else
{
// slider
if (mu3_io_config->controller_led_output_pipe)
{
mu3_led_pipe_update(escaped_data);
}
if (mu3_io_config->controller_led_output_serial)
{
mu3_led_serial_update(escaped_data);
}
}
}

View File

@ -1,20 +0,0 @@
/*
LED output functions
Credits:
somewhatlurker, skogaby
*/
#pragma once
#include <windows.h>
#include <stdbool.h>
#include <stdint.h>
#include "mu3io/config.h"
extern HANDLE mu3_led_init_mutex;
HRESULT mu3_led_output_init(struct mu3_io_config* const cfg);
void mu3_led_output_update(int board, const byte* rgb);

View File

@ -8,16 +8,9 @@ mu3io_lib = static_library(
xinput_lib,
],
sources : [
'config.c',
'config.h',
'leddata.h',
'ledoutput.c',
'ledoutput.h',
'mu3io.c',
'mu3io.h',
'pipeimpl.c',
'pipeimpl.h',
'serialimpl.c',
'serialimpl.h'
'config.c',
'config.h',
],
)

View File

@ -6,8 +6,6 @@
#include "mu3io/mu3io.h"
#include "mu3io/config.h"
#include "mu3io/ledoutput.h"
#include "util/dprintf.h"
static uint8_t mu3_opbtn;
@ -23,7 +21,7 @@ const double MOUSE_SENSITIVITY = 0.5;
uint16_t mu3_io_get_api_version(void)
{
return 0x0101;
return 0x0100;
}
HRESULT mu3_io_init(void)
@ -34,17 +32,7 @@ HRESULT mu3_io_init(void)
dprintf("XInput: Mouse lever emulation : %i\n", mu3_io_cfg.use_mouse);
dprintf("XInput: --- End configuration ---\n");
mu3_led_init_mutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
if (mu3_led_init_mutex == NULL)
{
return E_FAIL;
}
return mu3_led_output_init(&mu3_io_cfg);
return S_OK;
}
HRESULT mu3_io_poll(void)
@ -207,13 +195,3 @@ void mu3_io_get_lever(int16_t *pos)
*pos = mu3_lever_xpos;
}
}
HRESULT mu3_io_led_init(void)
{
return S_OK;
}
void mu3_io_led_set_colors(uint8_t board, uint8_t *rgb)
{
mu3_led_output_update(board, rgb);
}

View File

@ -1,15 +1,5 @@
#pragma once
/*
MU3 CUSTOM IO API
Changelog:
- 0x0100: Initial API version (assumed if chuni_io_get_api_version is not
exported)
- 0x0101: Added mu3_io_led_init and mu3_io_set_leds
*/
#include <windows.h>
#include <stdint.h>
@ -28,29 +18,6 @@ enum {
MU3_IO_GAMEBTN_MENU = 0x10,
};
enum {
/* These are the bitmasks to use when checking which
lights are triggered on incoming IO4 GPIO writes. */
MU3_IO_LED_L1_R = 1 << 31,
MU3_IO_LED_L1_G = 1 << 28,
MU3_IO_LED_L1_B = 1 << 30,
MU3_IO_LED_L2_R = 1 << 27,
MU3_IO_LED_L2_G = 1 << 29,
MU3_IO_LED_L2_B = 1 << 26,
MU3_IO_LED_L3_R = 1 << 25,
MU3_IO_LED_L3_G = 1 << 24,
MU3_IO_LED_L3_B = 1 << 23,
MU3_IO_LED_R1_R = 1 << 22,
MU3_IO_LED_R1_G = 1 << 21,
MU3_IO_LED_R1_B = 1 << 20,
MU3_IO_LED_R2_R = 1 << 19,
MU3_IO_LED_R2_G = 1 << 18,
MU3_IO_LED_R2_B = 1 << 17,
MU3_IO_LED_R3_R = 1 << 16,
MU3_IO_LED_R3_G = 1 << 15,
MU3_IO_LED_R3_B = 1 << 14,
};
/* Get the version of the Ongeki 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
@ -116,19 +83,3 @@ void mu3_io_get_gamebtns(uint8_t *left, uint8_t *right);
Minimum API version: 0x0100 */
void mu3_io_get_lever(int16_t *pos);
/* Initialize LED emulation. This function will be called before any
other mu3_io_led_*() function calls.
All subsequent calls may originate from arbitrary threads and some may
overlap with each other. Ensuring synchronization inside your IO DLL is
your responsibility. */
HRESULT mu3_io_led_init(void);
/* Update the RGB LEDs.
Exact layout is TBD. */
void mu3_io_led_set_colors(uint8_t board, uint8_t *rgb);

View File

@ -1,160 +0,0 @@
#include <windows.h>
#include <process.h>
#include <stdbool.h>
#include <stdint.h>
#include "mu3io/leddata.h"
#include "mu3io/pipeimpl.h"
static bool mu3_pipe_update[LED_BOARDS_TOTAL];
// incoming data is copied into these to ensure it isn't written during output
static struct _ongeki_led_data_buf_t mu3_pipe_write_buf[LED_BOARDS_TOTAL];
static HANDLE mu3_pipe_write_mutex;
static HRESULT mu3_pipe_create(LPHANDLE hPipe, LPCWSTR lpszPipename, DWORD dwBufSize)
{
*hPipe = INVALID_HANDLE_VALUE;
*hPipe = CreateNamedPipeW(
lpszPipename, // pipe name
PIPE_ACCESS_OUTBOUND, // read/write access
PIPE_TYPE_BYTE | // byte type pipe
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
dwBufSize, // output buffer size
0, // input buffer size
0, // client time-out
NULL); // default security attribute
if (*hPipe == INVALID_HANDLE_VALUE)
{
return E_FAIL;
}
return S_OK;
}
static HRESULT mu3_pipe_write(HANDLE hPipe, LPCVOID lpBuffer, DWORD dwSize)
{
DWORD cbWritten = 0;
bool fSuccess = WriteFile(
hPipe,
lpBuffer,
dwSize,
&cbWritten,
NULL);
if (!fSuccess || cbWritten != dwSize)
{
DWORD last_err = GetLastError();
return (last_err == ERROR_BROKEN_PIPE) ? E_ABORT : E_FAIL;
}
return S_OK;
}
static unsigned int __stdcall mu3_io_led_pipe_thread_proc(void *ctx)
{
HANDLE hPipe;
LPCWSTR lpszPipename = L"\\\\.\\pipe\\ongeki_led";
while (true)
{
hPipe = INVALID_HANDLE_VALUE;
if (mu3_pipe_create(&hPipe, lpszPipename, LED_OUTPUT_TOTAL_SIZE_MAX) != S_OK)
{
continue;
}
// wait for a connection to the pipe
bool fConnected = ConnectNamedPipe(hPipe, NULL) ?
true : (GetLastError() == ERROR_PIPE_CONNECTED);
while (fConnected)
{
if (WaitForSingleObject(mu3_pipe_write_mutex, INFINITE) != WAIT_OBJECT_0)
{
continue;
}
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
if (mu3_pipe_update[i])
{
HRESULT result = mu3_pipe_write(
hPipe,
&mu3_pipe_write_buf[i],
LED_OUTPUT_HEADER_SIZE + mu3_pipe_write_buf[i].data_len);
if (result != S_OK)
{
//if (result == E_ABORT)
//{
fConnected = false;
//}
break;
}
mu3_pipe_update[i] = false;
}
}
ReleaseMutex(mu3_pipe_write_mutex);
}
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
}
return 0;
}
HRESULT mu3_led_pipe_init()
{
mu3_pipe_write_mutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
if (mu3_pipe_write_mutex == NULL)
{
return E_FAIL;
}
// clear out update bools
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
mu3_pipe_update[i] = false;
}
_beginthreadex(
NULL,
0,
mu3_io_led_pipe_thread_proc,
0,
0,
NULL);
return S_OK;
}
void mu3_led_pipe_update(struct _ongeki_led_data_buf_t* data)
{
if (data->board > 1)
{
return;
}
if (WaitForSingleObject(mu3_pipe_write_mutex, INFINITE) != WAIT_OBJECT_0)
{
return;
}
memcpy(&mu3_pipe_write_buf[data->board], data, sizeof(struct _ongeki_led_data_buf_t));
mu3_pipe_update[data->board] = true;
ReleaseMutex(mu3_pipe_write_mutex);
}

View File

@ -1,15 +0,0 @@
/*
Pipe implementation for chuniio
Credits:
somewhatlurker, skogaby
*/
#pragma once
#include <windows.h>
#include "mu3io/leddata.h"
HRESULT mu3_led_pipe_init();
void mu3_led_pipe_update(struct _ongeki_led_data_buf_t* data);

View File

@ -1,88 +0,0 @@
#include <windows.h>
#include <process.h>
#include <stdbool.h>
#include <stdint.h>
#include "mu3io/leddata.h"
#include "mu3io/serialimpl.h"
#include "util/dprintf.h"
static HANDLE mu3_serial_port;
HRESULT mu3_led_serial_init(wchar_t led_com[12], DWORD baud)
{
// Setup the serial communications
BOOL status;
mu3_serial_port = CreateFileW(led_com,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (mu3_serial_port == INVALID_HANDLE_VALUE)
{
dprintf("Ongeki Serial LEDs: Failed to open COM port (attempted on %S)\n", led_com);
return E_FAIL;
}
DCB dcb_serial_params = { 0 };
dcb_serial_params.DCBlength = sizeof(dcb_serial_params);
status = GetCommState(mu3_serial_port, &dcb_serial_params);
dcb_serial_params.BaudRate = baud;
dcb_serial_params.ByteSize = 8;
dcb_serial_params.StopBits = ONESTOPBIT;
dcb_serial_params.Parity = NOPARITY;
SetCommState(mu3_serial_port, &dcb_serial_params);
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
SetCommTimeouts(mu3_serial_port, &timeouts);
if (!status)
{
return E_FAIL;
}
return S_OK;
}
void mu3_led_serial_update(struct _ongeki_led_data_buf_t* data)
{
if (data->board > 1)
{
return;
}
if (mu3_serial_port != INVALID_HANDLE_VALUE)
{
DWORD bytes_written = 0;
BOOL status = WriteFile(
mu3_serial_port,
data,
LED_OUTPUT_HEADER_SIZE + data->data_len,
&bytes_written,
NULL);
if (!status)
{
DWORD last_err = GetLastError();
dprintf("Ongeki Serial LEDs: Serial port write failed -- %d\n", (int) last_err);
}
}
else
{
dprintf("Ongeki Serial LEDs: Invalid serial port handle\n");
}
}

View File

@ -1,15 +0,0 @@
/*
Serial LED implementation for chuniio
Credits:
somewhatlurker, skogaby
*/
#pragma once
#include <windows.h>
#include "mu3io/leddata.h"
HRESULT mu3_led_serial_init(wchar_t led_com[12], DWORD baud);
void mu3_led_serial_update(struct _ongeki_led_data_buf_t* data);

View File

@ -126,13 +126,7 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg)
// Disable api/polling to the original servers
hr = dns_hook_push(L"*.amlog.sys-all.net", NULL);
if (FAILED(hr)) {
return hr;
}
hr = dns_hook_push(L"*.d-amlog.sys-all.net", NULL);
hr = dns_hook_push(L"amlog.sys-all.net", NULL);
if (FAILED(hr)) {
return hr;

View File

@ -1,4 +1,4 @@
[wrap-git]
directory = capnhook
url = https://github.com/Hay1tsme/capnhook
revision = 09306229f1fd09bae0e617865a26778d3537ff93
url = https://github.com/decafcode/capnhook
revision = 69f7e3b48c2e0ff5be1d7a83cdcc2597a458357b

View File

@ -8,7 +8,7 @@
#include <pathcch.h>
#include <psapi.h>
#include "hook/procaddr.h"
#include "hooklib/procaddr.h"
#include "util/dprintf.h"
#include "doorstop.h"
@ -37,7 +37,7 @@ void doorstop_mono_hook_init(const struct unity_config *cfg, HINSTANCE module) {
memcpy(&unity_config, cfg, sizeof(*cfg));
load_mono_functions(module);
proc_addr_table_push(NULL, module_name, unity_mono_syms, _countof(unity_mono_syms));
proc_addr_table_push(module_name, unity_mono_syms, _countof(unity_mono_syms));
doorstop_hook_initted = true;
}
@ -66,22 +66,21 @@ void doorstop_invoke(void* domain) {
if (mono_domain_set_config) {
#define CONFIG_EXT L".config"
wchar_t config_path[MAX_PATH];
size_t config_path_len = GetModuleFileNameW(NULL, config_path, MAX_PATH);
wchar_t *folder_name = wcsdup(config_path);
wchar_t exe_path[MAX_PATH];
size_t exe_path_len = GetModuleFileNameW(NULL, exe_path, MAX_PATH);
wchar_t *folder_name = wcsdup(exe_path);
PathCchRemoveFileSpec(folder_name, config_path_len + 1);
wmemcpy(config_path + config_path_len, CONFIG_EXT, sizeof(CONFIG_EXT) / sizeof(CONFIG_EXT[0]));
PathCchRemoveFileSpec(folder_name, exe_path_len + 1);
char *config_path_n = narrow(config_path);
char *exe_path_n = narrow(exe_path);
char *folder_name_n = narrow(folder_name);
dprintf("Unity: Setting config paths: base dir: %s; config path: %s\n", folder_name_n, config_path_n);
dprintf("Unity: Setting config paths: base dir: %s; config path: %s\n", folder_name_n, exe_path_n);
mono_domain_set_config(domain, folder_name_n, config_path_n);
mono_domain_set_config(domain, folder_name_n, exe_path_n);
free(folder_name);
free(config_path_n);
free(exe_path_n);
free(folder_name_n);
#undef CONFIG_EXT
@ -118,19 +117,9 @@ void doorstop_invoke(void* domain) {
return;
}
// BepInEx 5.4.23 has upgrade its doorstop version,
// which forces entrypoint to Doorstop.Entrypoint:Start
void *desc = mono_method_desc_new("Doorstop.Entrypoint:Start", TRUE);
void *desc = mono_method_desc_new("*:Main", FALSE);
void *method = mono_method_desc_search_in_image(desc, image);
if (!method) {
// Fallback to old entrypoint definition.
desc = mono_method_desc_new("*:Main", FALSE);
method = mono_method_desc_search_in_image(desc, image);
}
if (!method) {
dprintf("Unity: Assembly does not have a valid entrypoint.\n");
free(dll_path);

View File

@ -2,16 +2,7 @@
#include <stdbool.h>
#include "hook/table.h"
#include "hook/procaddr.h"
#include "hook/iohook.h"
#include "hooklib/dll.h"
#include "hooklib/path.h"
#include "hooklib/printer.h"
#include "hooklib/reg.h"
#include "hooklib/touch.h"
#include "hooklib/serial.h"
#include "util/dprintf.h"
#include "doorstop.h"
@ -24,35 +15,22 @@ static const wchar_t *target_modules[] = {
L"mono.dll",
L"mono-2.0-bdwgc.dll",
L"cri_ware_unity.dll",
L"SerialPortAPI.dll",
L"C300usb.dll",
L"C300FWDLusb.dll",
L"apmled.dll",
L"apmmount.dll",
};
static const size_t target_modules_len = _countof(target_modules);
static void dll_hook_insert_hooks(HMODULE target);
static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name);
static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name);
static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name);
static HMODULE WINAPI hook_LoadLibraryExW(const wchar_t *name, HANDLE hFile, DWORD dwFlags);
static HMODULE (WINAPI *next_LoadLibraryExW)(const wchar_t *name, HANDLE hFile, DWORD dwFlags);
static const struct hook_symbol unity_kernel32_syms[] = {
{
.name = "LoadLibraryW",
.patch = hook_LoadLibraryW,
.patch = my_LoadLibraryW,
.link = (void **) &next_LoadLibraryW,
}, {
.name = "LoadLibraryExW",
.patch = hook_LoadLibraryExW,
.link = (void **) &next_LoadLibraryExW,
}
},
};
void unity_hook_init(const struct unity_config *cfg, HINSTANCE self) {
assert(cfg != NULL);
@ -79,14 +57,7 @@ static void dll_hook_insert_hooks(HMODULE target) {
_countof(unity_kernel32_syms));
}
static HMODULE WINAPI hook_LoadLibraryExW(const wchar_t *name, HANDLE hFile, DWORD dwFlags)
{
// dprintf("Unity: LoadLibraryExW %ls\n", name);
return hook_LoadLibraryW(name);
}
static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name)
{
static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name) {
const wchar_t *name_end;
const wchar_t *target_module;
bool already_loaded;
@ -136,14 +107,6 @@ static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name)
dll_hook_insert_hooks(result);
path_hook_insert_hooks(result);
// printer_hook_insert_hooks(result);
reg_hook_insert_hooks(result);
proc_addr_insert_hooks(result);
serial_hook_apply_hooks(result);
iohook_apply_hooks(result);
}
}