From e6fd5e058321b260fbe3c923e356f72d1e052f86 Mon Sep 17 00:00:00 2001 From: = <=> Date: Tue, 20 Aug 2024 22:18:44 +0200 Subject: [PATCH] Added apm3 hook and io --- Package.mk | 16 +++++ apm3hook/apm3-dll.c | 106 +++++++++++++++++++++++++++++ apm3hook/apm3-dll.h | 20 ++++++ apm3hook/apm3hook.def | 73 ++++++++++++++++++++ apm3hook/config.c | 44 ++++++++++++ apm3hook/config.h | 34 ++++++++++ apm3hook/dllmain.c | 133 +++++++++++++++++++++++++++++++++++++ apm3hook/io4.c | 69 +++++++++++++++++++ apm3hook/io4.h | 7 ++ apm3hook/meson.build | 31 +++++++++ apm3io/apm3io.c | 54 +++++++++++++++ apm3io/apm3io.h | 44 ++++++++++++ apm3io/config.c | 22 ++++++ apm3io/config.h | 16 +++++ apm3io/meson.build | 13 ++++ dist/apm3/config_hook.json | 9 +++ dist/apm3/segatools.ini | 103 ++++++++++++++++++++++++++++ dist/apm3/start.bat | 12 ++++ meson.build | 2 + 19 files changed, 808 insertions(+) create mode 100644 apm3hook/apm3-dll.c create mode 100644 apm3hook/apm3-dll.h create mode 100644 apm3hook/apm3hook.def create mode 100644 apm3hook/config.c create mode 100644 apm3hook/config.h create mode 100644 apm3hook/dllmain.c create mode 100644 apm3hook/io4.c create mode 100644 apm3hook/io4.h create mode 100644 apm3hook/meson.build create mode 100644 apm3io/apm3io.c create mode 100644 apm3io/apm3io.h create mode 100644 apm3io/config.c create mode 100644 apm3io/config.h create mode 100644 apm3io/meson.build create mode 100644 dist/apm3/config_hook.json create mode 100644 dist/apm3/segatools.ini create mode 100644 dist/apm3/start.bat diff --git a/Package.mk b/Package.mk index f85d86f..36fcc19 100644 --- a/Package.mk +++ b/Package.mk @@ -203,6 +203,22 @@ $(BUILD_DIR_ZIP)/cm.zip: $(V)strip $(BUILD_DIR_ZIP)/cm/*.{exe,dll} $(V)cd $(BUILD_DIR_ZIP)/cm ; zip -r ../cm.zip * +$(BUILD_DIR_ZIP)/apm3.zip: + $(V)echo ... $@ + $(V)mkdir -p $(BUILD_DIR_ZIP)/apm3 + $(V)mkdir -p $(BUILD_DIR_ZIP)/apm3/DEVICE + $(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \ + $(BUILD_DIR_64)/apm3hook/apm3hook.dll \ + $(DIST_DIR)/apm3/config_hook.json \ + $(DIST_DIR)/apm3/segatools.ini \ + $(DIST_DIR)/apm3/start.bat \ + $(BUILD_DIR_ZIP)/apm3 + $(V)cp pki/billing.pub \ + pki/ca.crt \ + $(BUILD_DIR_ZIP)/apm3/DEVICE + $(V)strip $(BUILD_DIR_ZIP)/apm3/*.{exe,dll} + $(V)cd $(BUILD_DIR_ZIP)/apm3 ; zip -r ../apm3.zip * + $(BUILD_DIR_ZIP)/tokyo.zip: $(V)echo ... $@ $(V)mkdir -p $(BUILD_DIR_ZIP)/tokyo diff --git a/apm3hook/apm3-dll.c b/apm3hook/apm3-dll.c new file mode 100644 index 0000000..28cde29 --- /dev/null +++ b/apm3hook/apm3-dll.c @@ -0,0 +1,106 @@ +#include + +#include +#include + +#include "apm3hook/apm3-dll.h" + +#include "util/dll-bind.h" +#include "util/dprintf.h" + +const struct dll_bind_sym apm3_dll_syms[] = { + { + .sym = "apm3_io_init", + .off = offsetof(struct apm3_dll, init), + }, { + .sym = "apm3_io_poll", + .off = offsetof(struct apm3_dll, poll), + }, { + .sym = "apm3_io_get_opbtns", + .off = offsetof(struct apm3_dll, get_opbtns), + } +}; + +struct apm3_dll apm3_dll; + +// Copypasta DLL binding and diagnostic message boilerplate. +// Not much of this lends itself to being easily factored out. Also there +// will be a lot of API-specific branching code here eventually as new API +// versions get defined, so even though these functions all look the same +// now this won't remain the case forever. + +HRESULT apm3_dll_init(const struct apm3_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("CardMaker IO: Failed to load IO DLL: %lx: %S\n", + hr, + cfg->path); + + goto end; + } + + dprintf("CardMaker IO: Using custom IO DLL: %S\n", cfg->path); + src = owned; + } else { + owned = NULL; + src = self; + } + + get_api_version = (void *) GetProcAddress(src, "apm3_io_get_api_version"); + + if (get_api_version != NULL) { + apm3_dll.api_version = get_api_version(); + } else { + apm3_dll.api_version = 0x0100; + dprintf("Custom IO DLL does not expose apm3_io_get_api_version, " + "assuming API version 1.0.\n" + "Please ask the developer to update their DLL.\n"); + } + + if (apm3_dll.api_version >= 0x0200) { + hr = E_NOTIMPL; + dprintf("CardMaker IO: Custom IO DLL implements an unsupported " + "API version (%#04x). Please update Segatools.\n", + apm3_dll.api_version); + + goto end; + } + + sym = apm3_dll_syms; + hr = dll_bind(&apm3_dll, src, &sym, _countof(apm3_dll_syms)); + + if (FAILED(hr)) { + if (src != self) { + dprintf("CardMaker 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; +} diff --git a/apm3hook/apm3-dll.h b/apm3hook/apm3-dll.h new file mode 100644 index 0000000..792faca --- /dev/null +++ b/apm3hook/apm3-dll.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "apm3io/apm3io.h" + +struct apm3_dll { + uint16_t api_version; + HRESULT (*init)(void); + HRESULT (*poll)(void); + void (*get_opbtns)(uint8_t *opbtn); +}; + +struct apm3_dll_config { + wchar_t path[MAX_PATH]; +}; + +extern struct apm3_dll apm3_dll; + +HRESULT apm3_dll_init(const struct apm3_dll_config *cfg, HINSTANCE self); diff --git a/apm3hook/apm3hook.def b/apm3hook/apm3hook.def new file mode 100644 index 0000000..d677365 --- /dev/null +++ b/apm3hook/apm3hook.def @@ -0,0 +1,73 @@ +LIBRARY apm3hook + +EXPORTS + aime_io_get_api_version + aime_io_init + aime_io_led_set_color + aime_io_nfc_get_aime_id + aime_io_nfc_get_felica_id + aime_io_nfc_poll + amDllVideoClose @2 + amDllVideoGetVBiosVersion @4 + amDllVideoOpen @1 + amDllVideoSetResolution @3 + apm3_io_get_api_version + apm3_io_get_opbtns + apm3_io_init + apm3_io_poll + CFW_init + CFW_term + CFW_open + CFW_close + CFW_listupPrinter + CFW_listupPrinterSN + CFW_selectPrinter + CFW_selectPrinterSN + CFW_getPrinterInfo + CFW_status + CFW_statusAll + CFW_resetPrinter + CFW_updateFirmware + CFW_getFirmwareInfo + CHCUSB_init + CHCUSB_term + CHCUSB_MakeThread + CHCUSB_open + CHCUSB_close + CHCUSB_ReleaseThread + CHCUSB_listupPrinter + CHCUSB_listupPrinterSN + CHCUSB_selectPrinter + CHCUSB_selectPrinterSN + CHCUSB_getPrinterInfo + CHCUSB_imageformat + CHCUSB_setmtf + CHCUSB_makeGamma + CHCUSB_setIcctableProfile + CHCUSB_setIcctable + CHCUSB_copies + CHCUSB_status + CHCUSB_statusAll + CHCUSB_startpage + CHCUSB_endpage + CHCUSB_write + CHCUSB_writeLaminate + CHCUSB_writeHolo + CHCUSB_setPrinterInfo + CHCUSB_setPrinterToneCurve + CHCUSB_getGamma + CHCUSB_getMtf + CHCUSB_cancelCopies + CHCUSB_getPrinterToneCurve + CHCUSB_blinkLED + CHCUSB_resetPrinter + CHCUSB_AttachThreadCount + CHCUSB_getPrintIDStatus + CHCUSB_setPrintStandby + CHCUSB_testCardFeed + CHCUSB_exitCard + CHCUSB_getCardRfidTID + CHCUSB_commCardRfidReader + CHCUSB_updateCardRfidReader + CHCUSB_getErrorLog + CHCUSB_getErrorStatus diff --git a/apm3hook/config.c b/apm3hook/config.c new file mode 100644 index 0000000..b6ffc83 --- /dev/null +++ b/apm3hook/config.c @@ -0,0 +1,44 @@ +#include +#include + +#include "board/config.h" + +#include "hooklib/config.h" +#include "hooklib/dvd.h" + +#include "apm3hook/config.h" + +#include "platform/config.h" + +void apm3_dll_config_load( + struct apm3_dll_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + GetPrivateProfileStringW( + L"apm3io", + L"path", + L"", + cfg->path, + _countof(cfg->path), + filename); +} + +void apm3_hook_config_load( + struct apm3_hook_config *cfg, + const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + platform_config_load(&cfg->platform, filename); + aime_config_load(&cfg->aime, filename); + dvd_config_load(&cfg->dvd, filename); + io4_config_load(&cfg->io4, filename); + vfd_config_load(&cfg->vfd, filename); + touch_screen_config_load(&cfg->touch, filename); + apm3_dll_config_load(&cfg->dll, filename); + unity_config_load(&cfg->unity, filename); +} diff --git a/apm3hook/config.h b/apm3hook/config.h new file mode 100644 index 0000000..69020c4 --- /dev/null +++ b/apm3hook/config.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "board/config.h" + +#include "hooklib/dvd.h" +#include "hooklib/touch.h" +#include "hooklib/printer.h" + +#include "apm3hook/apm3-dll.h" + +#include "platform/config.h" + +#include "unityhook/config.h" + +struct apm3_hook_config { + struct platform_config platform; + struct aime_config aime; + struct dvd_config dvd; + struct io4_config io4; + struct vfd_config vfd; + struct apm3_dll_config dll; + struct touch_screen_config touch; + struct unity_config unity; +}; + +void apm3_dll_config_load( + struct apm3_dll_config *cfg, + const wchar_t *filename); + +void apm3_hook_config_load( + struct apm3_hook_config *cfg, + const wchar_t *filename); diff --git a/apm3hook/dllmain.c b/apm3hook/dllmain.c new file mode 100644 index 0000000..f9a3ed7 --- /dev/null +++ b/apm3hook/dllmain.c @@ -0,0 +1,133 @@ +/* + "Card Maker" (apm3) hook + + Devices + + USB: 837-15257-01 "Type 4" I/O Board + USB: 838-20006 "WinTouch" Controller Board + USB: 630-00009 Sinfonia CHC-C310 Printer + COM1: 837-15396 "Gen 3" Aime Reader + COM2: 200-6275 VFD GP1232A02A FUTABA Board + COM3: 220-5872 AS-6DB Coin Selector +*/ + +#include + +#include + +#include "board/io4.h" +#include "board/sg-reader.h" +#include "board/vfd.h" + +#include "hook/process.h" + +#include "hooklib/dvd.h" +#include "hooklib/touch.h" +#include "hooklib/serial.h" +#include "hooklib/spike.h" + +#include "apm3hook/config.h" +#include "apm3hook/io4.h" +#include "apm3hook/apm3-dll.h" + +#include "platform/platform.h" + +#include "unityhook/hook.h" + +#include "util/dprintf.h" + +static HMODULE apm3_hook_mod; +static process_entry_t apm3_startup; +static struct apm3_hook_config apm3_hook_cfg; + +static DWORD CALLBACK apm3_pre_startup(void) +{ + HRESULT hr; + + dprintf("--- Begin apm3_pre_startup ---\n"); + + /* Load config */ + + apm3_hook_config_load(&apm3_hook_cfg, L".\\segatools.ini"); + + /* Hook Win32 APIs */ + + dvd_hook_init(&apm3_hook_cfg.dvd, apm3_hook_mod); + touch_screen_hook_init(&apm3_hook_cfg.touch, apm3_hook_mod); + serial_hook_init(); + + /* Initialize emulation hooks */ + + hr = platform_hook_init( + &apm3_hook_cfg.platform, + "SDEM", + "ACA1", + apm3_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = apm3_dll_init(&apm3_hook_cfg.dll, apm3_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = sg_reader_hook_init(&apm3_hook_cfg.aime, 1, 1, apm3_hook_mod); + + if (FAILED(hr)) { + goto fail; + } + + hr = vfd_hook_init(&apm3_hook_cfg.vfd, 2); + + if (FAILED(hr)) { + goto fail; + } + + hr = apm3_io4_hook_init(&apm3_hook_cfg.io4); + + if (FAILED(hr)) { + goto fail; + } + + /* Initialize Unity native plugin DLL hooks + + There seems to be an issue with other DLL hooks if `LoadLibraryW` is + hooked earlier in the `apm3hook` initialization. */ + + unity_hook_init(&apm3_hook_cfg.unity, apm3_hook_mod); + + /* Initialize debug helpers */ + + spike_hook_init(L".\\segatools.ini"); + + dprintf("--- End apm3_pre_startup ---\n"); + + /* Jump to EXE start address */ + + return apm3_startup(); + +fail: + ExitProcess(EXIT_FAILURE); +} + +BOOL WINAPI DllMain(HMODULE mod, DWORD cause, void *ctx) +{ + HRESULT hr; + + if (cause != DLL_PROCESS_ATTACH) { + return TRUE; + } + + apm3_hook_mod = mod; + + hr = process_hijack_startup(apm3_pre_startup, &apm3_startup); + + if (!SUCCEEDED(hr)) { + dprintf("Failed to hijack process startup: %x\n", (int) hr); + } + + return SUCCEEDED(hr); +} diff --git a/apm3hook/io4.c b/apm3hook/io4.c new file mode 100644 index 0000000..a84dd33 --- /dev/null +++ b/apm3hook/io4.c @@ -0,0 +1,69 @@ +#include + +#include +#include +#include + +#include "board/io4.h" + +#include "apm3hook/apm3-dll.h" + +#include "util/dprintf.h" + +static HRESULT apm3_io4_poll(void *ctx, struct io4_state *state); +static uint16_t coins; + +static const struct io4_ops apm3_io4_ops = { + .poll = apm3_io4_poll, +}; + +HRESULT apm3_io4_hook_init(const struct io4_config *cfg) +{ + HRESULT hr; + + assert(apm3_dll.init != NULL); + + hr = io4_hook_init(cfg, &apm3_io4_ops, NULL); + + if (FAILED(hr)) { + return hr; + } + + return apm3_dll.init(); +} + +static HRESULT apm3_io4_poll(void *ctx, struct io4_state *state) +{ + uint8_t opbtn; + HRESULT hr; + + assert(apm3_dll.poll != NULL); + assert(apm3_dll.get_opbtns != NULL); + + memset(state, 0, sizeof(*state)); + + hr = apm3_dll.poll(); + + if (FAILED(hr)) { + return hr; + } + + opbtn = 0; + + apm3_dll.get_opbtns(&opbtn); + + if (opbtn & apm3_IO_OPBTN_TEST) { + state->buttons[0] |= IO4_BUTTON_TEST; + } + + if (opbtn & apm3_IO_OPBTN_SERVICE) { + state->buttons[0] |= IO4_BUTTON_SERVICE; + } + + if (opbtn & apm3_IO_OPBTN_COIN) { + coins++; + } + state->chutes[0] = coins << 8; + + return S_OK; +} diff --git a/apm3hook/io4.h b/apm3hook/io4.h new file mode 100644 index 0000000..4f52503 --- /dev/null +++ b/apm3hook/io4.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "board/io4.h" + +HRESULT apm3_io4_hook_init(const struct io4_config *cfg); diff --git a/apm3hook/meson.build b/apm3hook/meson.build new file mode 100644 index 0000000..c5efca6 --- /dev/null +++ b/apm3hook/meson.build @@ -0,0 +1,31 @@ +shared_library( + 'apm3hook', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + vs_module_defs : 'apm3hook.def', + c_pch : '../precompiled.h', + dependencies : [ + capnhook.get_variable('hook_dep'), + capnhook.get_variable('hooklib_dep'), + xinput_lib, + ], + link_with : [ + aimeio_lib, + board_lib, + hooklib_lib, + apm3io_lib, + platform_lib, + unityhook_lib, + util_lib, + ], + sources : [ + 'config.c', + 'config.h', + 'dllmain.c', + 'io4.c', + 'io4.h', + 'apm3-dll.c', + 'apm3-dll.h', + ], +) diff --git a/apm3io/apm3io.c b/apm3io/apm3io.c new file mode 100644 index 0000000..02a2114 --- /dev/null +++ b/apm3io/apm3io.c @@ -0,0 +1,54 @@ +#include +#include + +#include +#include + +#include "apm3io/apm3io.h" +#include "apm3io/config.h" + +static uint8_t apm3_opbtn; +static struct apm3_io_config apm3_io_cfg; +static bool apm3_io_coin; + +uint16_t apm3_io_get_api_version(void) +{ + return 0x0100; +} + +HRESULT apm3_io_init(void) +{ + apm3_io_config_load(&apm3_io_cfg, L".\\segatools.ini"); + return S_OK; +} + +HRESULT apm3_io_poll(void) +{ + apm3_opbtn = 0; + + if (GetAsyncKeyState(apm3_io_cfg.vk_test) & 0x8000) { + apm3_opbtn |= apm3_IO_OPBTN_TEST; + } + + if (GetAsyncKeyState(apm3_io_cfg.vk_service) & 0x8000) { + apm3_opbtn |= apm3_IO_OPBTN_SERVICE; + } + + if (GetAsyncKeyState(apm3_io_cfg.vk_coin) & 0x8000) { + if (!apm3_io_coin) { + apm3_io_coin = true; + apm3_opbtn |= apm3_IO_OPBTN_COIN; + } + } else { + apm3_io_coin = false; + } + + return S_OK; +} + +void apm3_io_get_opbtns(uint8_t *opbtn) +{ + if (opbtn != NULL) { + *opbtn = apm3_opbtn; + } +} diff --git a/apm3io/apm3io.h b/apm3io/apm3io.h new file mode 100644 index 0000000..ebf35a3 --- /dev/null +++ b/apm3io/apm3io.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include + +enum { + apm3_IO_OPBTN_TEST = 0x01, + apm3_IO_OPBTN_SERVICE = 0x02, + apm3_IO_OPBTN_COIN = 0x04, +}; + +/* Get the version of the AllS.Net PRAS Multi 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 apm3_io_get_api_version(void); + +/* Initialize the IO DLL. This is the second function that will be called on + your DLL, after apm3_io_get_api_version. + + All subsequent calls to this API may originate from arbitrary threads. + + Minimum API version: 0x0100 */ + +HRESULT apm3_io_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 apm3_io_poll(void); + +/* Get the state of the cabinet's operator buttons as of the last poll. See + apm3_IO_OPBTN enum above: this contains bit mask definitions for button + states returned in *opbtn. All buttons are active-high. + + Minimum API version: 0x0100 */ + +void apm3_io_get_opbtns(uint8_t *opbtn); diff --git a/apm3io/config.c b/apm3io/config.c new file mode 100644 index 0000000..82bba50 --- /dev/null +++ b/apm3io/config.c @@ -0,0 +1,22 @@ +#include + +#include +#include +#include + +#include "apm3io/config.h" + +void apm3_io_config_load( + struct apm3_io_config *cfg, + const wchar_t *filename) +{ + wchar_t key[16]; + int i; + + assert(cfg != NULL); + assert(filename != NULL); + + 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); +} diff --git a/apm3io/config.h b/apm3io/config.h new file mode 100644 index 0000000..93395ac --- /dev/null +++ b/apm3io/config.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#include + +struct apm3_io_config { + uint8_t vk_test; + uint8_t vk_service; + uint8_t vk_coin; +}; + +void apm3_io_config_load( + struct apm3_io_config *cfg, + const wchar_t *filename); diff --git a/apm3io/meson.build b/apm3io/meson.build new file mode 100644 index 0000000..02fd480 --- /dev/null +++ b/apm3io/meson.build @@ -0,0 +1,13 @@ +apm3io_lib = static_library( + 'apm3io', + name_prefix : '', + include_directories : inc, + implicit_include_directories : false, + c_pch : '../precompiled.h', + sources : [ + 'apm3io.c', + 'apm3io.h', + 'config.c', + 'config.h', + ], +) diff --git a/dist/apm3/config_hook.json b/dist/apm3/config_hook.json new file mode 100644 index 0000000..5723db7 --- /dev/null +++ b/dist/apm3/config_hook.json @@ -0,0 +1,9 @@ +{ + "credit" : + { + "coin_selector_AS6DB" : + { + "enable" : false + } + } +} diff --git a/dist/apm3/segatools.ini b/dist/apm3/segatools.ini new file mode 100644 index 0000000..c3152ee --- /dev/null +++ b/dist/apm3/segatools.ini @@ -0,0 +1,103 @@ +; ----------------------------------------------------------------------------- +; Path settings +; ----------------------------------------------------------------------------- + +[vfs] +; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) +amfs= +; Insert the path to the game Option directory here (contains Axxx directories) +option= +; Create an empty directory somewhere and insert the path here. +; This directory may be shared between multiple SEGA games. +; NOTE: This has nothing to do with Windows %APPDATA%. +appdata= + +; ----------------------------------------------------------------------------- +; Device settings +; ----------------------------------------------------------------------------- + +[aime] +; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime +; reader. +enable=1 +aimePath=DEVICE\aime.txt + +[vfd] +; Enable VFD emulation (currently just stubbed). Disable to use a real VFD +; GP1232A02A FUTABA assembly. +enable=1 + +; ----------------------------------------------------------------------------- +; Network settings +; ----------------------------------------------------------------------------- + +[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. +default=127.0.0.1 + +[netenv] +; Simulate an ideal LAN environment. This may interfere with head-to-head play. +; SEGA games are somewhat picky about their LAN environment, so leaving this +; setting enabled is recommended. +enable=1 + +; ----------------------------------------------------------------------------- +; Board settings +; ----------------------------------------------------------------------------- + +[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. +subnet=192.168.165.0 + +[system] +; Enable ALLS system settings. +enable=1 + +; LAN Install: If multiple machines are present on the same LAN then set +; this to 0 on exactly one machine and set this to 1 on all others. +dipsw1=0 + +; ----------------------------------------------------------------------------- +; Misc. hooks settings +; ----------------------------------------------------------------------------- + +[touch] +; Enable/Disable WinTouch emulation +enable=1 + +[unity] +; Path to a .NET DLL that should run before the game. Useful for loading +; modding frameworks such as BepInEx. +targetAssembly= + +; ----------------------------------------------------------------------------- +; 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= + +; ----------------------------------------------------------------------------- +; Input settings +; ----------------------------------------------------------------------------- + +; Keyboard bindings are as hexadecimal (prefixed with 0x) or decimal +; (not prefixed with 0x) virtual-key codes, a list of which can be found here: +; +; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +; +; This is, admittedly, not the most user-friendly configuration method in the +; world. An improved solution will be provided later. + +[io4] +; Test button virtual-key code. Default is the F1 key. +test=0x70 +; Service button virtual-key code. Default is the F2 key. +service=0x71 +; Keyboard button to increment coin counter. Default is the F3 key. +coin=0x72 diff --git a/dist/apm3/start.bat b/dist/apm3/start.bat new file mode 100644 index 0000000..570fb9c --- /dev/null +++ b/dist/apm3/start.bat @@ -0,0 +1,12 @@ +@echo off + +pushd %~dp0 + +start "AM Daemon" /min inject -d -k cmhook.dll amdaemon.exe -c config_common.json config_server.json config_client.json config_hook.json +inject -d -k cmhook.dll CardMaker.exe -screen-fullscreen 0 -popupwindow -screen-width 1080 -screen-height 1920 + +taskkill /f /im amdaemon.exe > nul 2>&1 + +echo. +echo Game processes have terminated +pause \ No newline at end of file diff --git a/meson.build b/meson.build index c5b3d40..ca5bc66 100644 --- a/meson.build +++ b/meson.build @@ -106,6 +106,7 @@ subdir('swdcio') subdir('mu3io') subdir('mai2io') subdir('cmio') +subdir('apm3io') subdir('mercuryio') subdir('cxbio') subdir('tokyoio') @@ -122,6 +123,7 @@ subdir('chusanhook') subdir('mu3hook') subdir('mai2hook') subdir('cmhook') +subdir('apm3hook') subdir('mercuryhook') subdir('cxbhook') subdir('tokyohook')