From c27ef9674d2f15f92b9bc3cd0d4f0e094daf55a0 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Fri, 14 Jul 2023 00:41:23 +0200 Subject: [PATCH] idac: added dipswitch support (beta) --- dist/idac/segatools.ini | 31 +++++++- dist/idac/start.bat | 22 +++++- idachook/dllmain.c | 8 --- idachook/meson.build | 1 - platform/config.c | 20 ++++++ platform/config.h | 2 + platform/dipsw.c | 153 ++++++++++++++++++++++++++++++++++++++++ platform/dipsw.h | 15 ++++ platform/dns.c | 8 +++ platform/meson.build | 2 + platform/platform.c | 7 ++ platform/platform.h | 2 + platform/vfs.c | 8 ++- 13 files changed, 263 insertions(+), 16 deletions(-) create mode 100644 platform/dipsw.c create mode 100644 platform/dipsw.h diff --git a/dist/idac/segatools.ini b/dist/idac/segatools.ini index aa408c5..c6660ca 100644 --- a/dist/idac/segatools.ini +++ b/dist/idac/segatools.ini @@ -8,6 +8,12 @@ option= ; NOTE: This has nothing to do with Windows %APPDATA%. appdata= +[aime] +; Controls emulation of the Aime card reader assembly. +enable=1 +aimePath=DEVICE\aime.txt +felicaGen=0 + [dns] ; Insert the hostname or IP address of the server you wish to use here. ; Note that 127.0.0.1, localhost etc are specifically rejected. @@ -22,9 +28,32 @@ enable=1 [keychip] ; The /24 LAN subnet that the emulated keychip will tell the game to expect. ; If you disable netenv then you must set this to your LAN's IP subnet, and -; that subnet must start with 192.168. +; that subnet must start with 192.168. Set it to your LAN's subnet if you +; want to play head-to-head using netenv=1. subnet=192.168.100.0 +; Override the keychip's region code. Most games seem to pay attention to the +; DS EEPROM region code and not the keychip region code, and this seems to be +; a bit mask that controls which Nu PCB region codes this keychip is authorized +; for. So it probably only affects the system software and not the game software. +; 1: JPN: Japan, 4: EXP: Export (for Asian markets) +region=4 + +[gpio] +; ALLS DIP switches. + +; If multiple machines are present on the same LAN then set this to 1 on +; exactly one machine and set this to 0 on all others. +dipsw1=1 +; 0 is the DZero CVT cab and 1 is the SWDC CVT cab. +dipsw2=0 +; Enable the Single Seat mode, always requires dipsw1=1. +dipsw3=0 +; The next two dip switches are the seat settings in bits, where +; 00 = Seat 1, 10 = Seat 2, 01 = Seat 3 and 11 = Seat 4 +dipsw4=0 +dipsw5=0 + [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. diff --git a/dist/idac/start.bat b/dist/idac/start.bat index 022d5ec..4b2d8e9 100644 --- a/dist/idac/start.bat +++ b/dist/idac/start.bat @@ -2,11 +2,27 @@ pushd %~dp0 -REM start /min inject.exe -d -k idachook.dll amdaemon.exe -f -c config_aime_high_ex.json config_aime_high_jp.json config_aime_normal_ex.json config_aime_normal_jp.json config_common.json config_ex.json config_jp.json config_laninstall_client_ex.json config_laninstall_client_jp.json config_laninstall_server_ex.json config_laninstall_server_jp.json config_seat_1_ex.json config_seat_1_jp.json config_seat_2_ex.json config_seat_2_jp.json config_seat_3_ex.json config_seat_3_jp.json config_seat_4_ex.json config_seat_4_jp.json config_seat_single_ex.json config_seat_single_jp.json -start /min inject -d -k idachook.dll amdaemon.exe -f -c config_aime_normal_jp.json config_common.json config_jp.json config_laninstall_server_jp.json config_seat_1_jp.json -inject -d -k idachook.dll ..\WindowsNoEditor\GameProject.exe -culture=ja launch=Cabinet ABSLOG="..\..\..\..\..\Userdata\GameProject.log" -Master -UserDir="..\..\..\Userdata" -NotInstalled -UNATTENDED +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 + +start /min inject -d -k idachook.dll amdaemon.exe -f -c config_aime_high_ex.json config_aime_high_jp.json config_aime_normal_ex.json config_aime_normal_jp.json config_common.json config_ex.json config_jp.json config_laninstall_client_ex.json config_laninstall_client_jp.json config_laninstall_server_ex.json config_laninstall_server_jp.json config_seat_1_ex.json config_seat_1_jp.json config_seat_2_ex.json config_seat_2_jp.json config_seat_3_ex.json config_seat_3_jp.json config_seat_4_ex.json config_seat_4_jp.json config_seat_single_ex.json config_seat_single_jp.json +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 \ No newline at end of file diff --git a/idachook/dllmain.c b/idachook/dllmain.c index ed64515..5d6f695 100644 --- a/idachook/dllmain.c +++ b/idachook/dllmain.c @@ -5,7 +5,6 @@ #include "board/sg-reader.h" #include "board/io4.h" -#include "board/vfd.h" #include "hook/process.h" @@ -60,13 +59,6 @@ static DWORD CALLBACK idac_pre_startup(void) goto fail; } - // Not needed? - hr = vfd_hook_init(4); - - if (FAILED(hr)) { - return hr; - } - hr = idac_dll_init(&idac_hook_cfg.dll, idac_hook_mod); if (FAILED(hr)) { diff --git a/idachook/meson.build b/idachook/meson.build index 81c2c7b..72214ac 100644 --- a/idachook/meson.build +++ b/idachook/meson.build @@ -8,7 +8,6 @@ shared_library( dependencies : [ capnhook.get_variable('hook_dep'), capnhook.get_variable('hooklib_dep'), - shlwapi_lib, xinput_lib, ], link_with : [ diff --git a/platform/config.c b/platform/config.c index 1c6be62..62f2707 100644 --- a/platform/config.c +++ b/platform/config.c @@ -21,6 +21,7 @@ #include "platform/pcbid.h" #include "platform/platform.h" #include "platform/vfs.h" +#include "platform/dipsw.h" void platform_config_load(struct platform_config *cfg, const wchar_t *filename) { @@ -37,6 +38,7 @@ void platform_config_load(struct platform_config *cfg, const wchar_t *filename) netenv_config_load(&cfg->netenv, filename); nusec_config_load(&cfg->nusec, filename); vfs_config_load(&cfg->vfs, filename); + dipsw_config_load(&cfg->dipsw, filename); } void amvideo_config_load(struct amvideo_config *cfg, const wchar_t *filename) @@ -317,3 +319,21 @@ void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename) filename); } +void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename) +{ + wchar_t name[7]; + size_t i; + + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"gpio", L"enable", 1, filename); + + wcscpy_s(name, _countof(name), L"dipsw0"); + + for (i = 0 ; i < 8 ; i++) { + name[5] = L'1' + i; + cfg->dipsw[i] = GetPrivateProfileIntW(L"gpio", name, 0, filename); + } +} + diff --git a/platform/config.h b/platform/config.h index 7ece41d..1e56d43 100644 --- a/platform/config.h +++ b/platform/config.h @@ -17,6 +17,7 @@ #include "platform/pcbid.h" #include "platform/platform.h" #include "platform/vfs.h" +#include "platform/dipsw.h" void platform_config_load( struct platform_config *cfg, @@ -32,3 +33,4 @@ void netenv_config_load(struct netenv_config *cfg, const wchar_t *filename); void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename); void pcbid_config_load(struct pcbid_config *cfg, const wchar_t *filename); void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename); +void dipsw_config_load(struct dipsw_config *cfg, const wchar_t *filename); diff --git a/platform/dipsw.c b/platform/dipsw.c new file mode 100644 index 0000000..e6af610 --- /dev/null +++ b/platform/dipsw.c @@ -0,0 +1,153 @@ +#include +#include + +#include +#include +// #include + +#include "platform/dipsw.h" +#include "platform/vfs.h" + +#include "util/dprintf.h" +#include "util/str.h" +#include "util/crc.h" + +#define DATA_SIZE 503 +#define BLOCK_SIZE (sizeof(uint32_t) + 4 + 1 + DATA_SIZE) + +#pragma pack(push, 1) + +typedef struct +{ + uint32_t checksum; + char padding_1[4]; + uint8_t dip_switches; + char data[DATA_SIZE]; +} DipSwitchBlock; + +typedef struct +{ + DipSwitchBlock dip_switch_block; + char *data; +} DipSwitches; + +#pragma pack(pop) + +static DipSwitches dip_switches; + +static struct dipsw_config dipsw_config; +static struct vfs_config vfs_config; + +static void dipsw_read_sysfile(const wchar_t *sys_file); +static void dipsw_save_sysfile(const wchar_t *sys_file); + +HRESULT dipsw_init(const struct dipsw_config *cfg, const struct vfs_config *vfs_cfg) +{ + HRESULT hr; + wchar_t sys_file_path[MAX_PATH]; + + assert(cfg != NULL); + assert(vfs_cfg != NULL); + + if (!cfg->enable) + { + return S_FALSE; + } + + memcpy(&dipsw_config, cfg, sizeof(*cfg)); + + sys_file_path[0] = L'\0'; + // concatenate vfs_config.amfs with L"sysfile.dat" + wcsncpy(sys_file_path, vfs_cfg->amfs, MAX_PATH); + wcsncat(sys_file_path, L"\\sysfile.dat", MAX_PATH); + + dipsw_read_sysfile(sys_file_path); + + // now write the dipsw_config.dipsw to the dip_switch_block + dipsw_save_sysfile(sys_file_path); + + return S_OK; +} + +static void dipsw_read_sysfile(const wchar_t *sys_file) +{ + FILE *f = _wfopen(sys_file, L"r"); + + if (f == NULL) + { + dprintf("First run detected, DipSw settings can only be applied AFTER the first run\n"); + return; + } + + fseek(f, 0, SEEK_END); + long file_size = ftell(f); + fseek(f, 0, SEEK_SET); + + if (file_size != 0x6000) + { + dprintf("Invalid sysfile.dat file size\n"); + fclose(f); + + return; + } + + dip_switches.data = malloc(file_size); + fread(dip_switches.data, 1, file_size, f); + fclose(f); + + // memcpy(dip_switches.dip_switch_block, dip_switches.data + 0x2800, BLOCK_SIZE); + memcpy(&dip_switches.dip_switch_block, dip_switches.data + 0x2800, BLOCK_SIZE); +} + +static void dipsw_save_sysfile(const wchar_t *sys_file) +{ + uint8_t dipsw = 0; + // open the sysfile.dat for writing in bytes mode + FILE *f = _wfopen(sys_file, L"rb+"); + + if (f == NULL) + { + return; + } + + // write the dipsw_config.dipsw to the dip_switch_block + for (int i = 0; i < 8; i++) + { + if (dipsw_config.dipsw[i]) + { + // print which dipsw is enabled + dprintf("DipSw: DipSw%d=1 set\n", i + 1); + dipsw |= (1 << i); + } + } + + dip_switches.dip_switch_block.dip_switches = dipsw; + + // calculate the new checksum, skip the old crc32 value + // which is at the beginning of the block, thats's why the +4 + // conver the struct to chars in order for the crc32 calculation to work + dip_switches.dip_switch_block.checksum = crc32( + (char *)&dip_switches.dip_switch_block + 4, BLOCK_SIZE - 4, 0); + + // build the new dip switch block + char block[BLOCK_SIZE]; + memcpy(block, (char *)&dip_switches.dip_switch_block, BLOCK_SIZE); + + // replace the old block with the new one + memcpy(dip_switches.data + 0x2800, block, BLOCK_SIZE); + memcpy(dip_switches.data + 0x5800, block, BLOCK_SIZE); + + // print the dip_switch_block in hex + /* + dprintf("DipSw Block: "); + for (size_t i = 0; i < BLOCK_SIZE; i++) + { + dprintf("%02X ", ((uint8_t *)&dip_switches.dip_switch_block)[i]); + } + dprintf("\n"); + */ + + fwrite(dip_switches.data, 1, 0x6000, f); + + fclose(f); +} diff --git a/platform/dipsw.h b/platform/dipsw.h new file mode 100644 index 0000000..a4bfdb2 --- /dev/null +++ b/platform/dipsw.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include +#include + +#include "platform/vfs.h" + +struct dipsw_config { + bool enable; + bool dipsw[8]; +}; + +HRESULT dipsw_init(const struct dipsw_config *cfg, const struct vfs_config *vfs_cfg); diff --git a/platform/dns.c b/platform/dns.c index 5486d42..e2c5905 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -79,5 +79,13 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) return hr; } + // Disable api/polling to the original servers + + hr = dns_hook_push(L"amlog.sys-all.net", NULL); + + if (FAILED(hr)) { + return hr; + } + return S_OK; } diff --git a/platform/meson.build b/platform/meson.build index 4f0fbc9..0de228c 100644 --- a/platform/meson.build +++ b/platform/meson.build @@ -32,5 +32,7 @@ platform_lib = static_library( 'platform.h', 'vfs.c', 'vfs.h', + 'dipsw.c', + 'dipsw.h', ], ) diff --git a/platform/platform.c b/platform/platform.c index 218204c..35d2ba7 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -12,6 +12,7 @@ #include "platform/pcbid.h" #include "platform/platform.h" #include "platform/vfs.h" +#include "platform/dipsw.h" HRESULT platform_hook_init( const struct platform_config *cfg, @@ -80,5 +81,11 @@ HRESULT platform_hook_init( return hr; } + hr = dipsw_init(&cfg->dipsw, &cfg->vfs); + + if (FAILED(hr)) { + return hr; + } + return S_OK; } diff --git a/platform/platform.h b/platform/platform.h index 69c65e2..ba06567 100644 --- a/platform/platform.h +++ b/platform/platform.h @@ -12,6 +12,7 @@ #include "platform/nusec.h" #include "platform/pcbid.h" #include "platform/vfs.h" +#include "platform/dipsw.h" struct platform_config { struct amvideo_config amvideo; @@ -24,6 +25,7 @@ struct platform_config { struct netenv_config netenv; struct nusec_config nusec; struct vfs_config vfs; + struct dipsw_config dipsw; }; HRESULT platform_hook_init( diff --git a/platform/vfs.c b/platform/vfs.c index 7bd2953..9f620d8 100644 --- a/platform/vfs.c +++ b/platform/vfs.c @@ -28,7 +28,9 @@ static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes); static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes); static wchar_t vfs_nthome_real[MAX_PATH]; -static const wchar_t vfs_nthome[] = L"C:\\Documents and Settings\\AppUser"; +// new home for ALLS +static const wchar_t vfs_nthome[] = L"C:\\Users\\AppUser"; +// static const wchar_t vfs_nthome[] = L"C:\\Documents and Settings\\AppUser"; static const size_t vfs_nthome_len = _countof(vfs_nthome) - 1; static const wchar_t vfs_option[] = L"C:\\Mount\\Option"; @@ -273,8 +275,8 @@ static HRESULT vfs_path_hook(const wchar_t *src, wchar_t *dest, size_t *count) } switch (src[0]) { - case L'D': // later AMDaemon versions default to D: for AMFS if it can't find it - case L'd': + // case L'D': // later AMDaemon versions default to D: for AMFS if it can't find it + // case L'd': case L'e': case L'E': redir = vfs_config.amfs;