#include "sciunit.h" #include "acio/icca/icca.h" #include "avs/game.h" #include "eamuse.h" #include "games/jb/jb.h" #include "games/jb/io.h" #include "rawinput/rawinput.h" #include "util/detour.h" #include "util/libutils.h" #include "util/logging.h" #include "util/utils.h" // function definitions typedef int (__cdecl *cardunit_card_cardnumber_t)(const uint8_t *const, int, char *, int); static cardunit_card_cardnumber_t cardunit_card_cardnumber = nullptr; // state static HINSTANCE SCIUNIT_INSTANCE; static std::string SCIUNIT_INSTANCE_NAME = "sciunit.dll"; static bool SCIUNIT_INITIALIZED = false; static bool CARD_IN = false; static bool CARD_PRESSED = false; static uint8_t CARD_UID[8]; static int CARD_TYPE = 1; static char CARD_DISPLAY_ID[17]; static bool CARD_WAS_CONVERTED = false; static inline void update_card() { if (eamuse_card_insert_consume(1, 0)) { if (!CARD_PRESSED) { CARD_PRESSED = true; // get and check if valid card if (!eamuse_get_card(1, 0, CARD_UID)) { return; } CARD_IN = true; CARD_WAS_CONVERTED = false; CARD_TYPE = is_card_uid_felica(CARD_UID) ? 2 : 1; // convert the card UID into the Konami ID if the conversion method was found if (cardunit_card_cardnumber != nullptr) { auto ret = cardunit_card_cardnumber(CARD_UID, CARD_TYPE, CARD_DISPLAY_ID, sizeof(CARD_DISPLAY_ID)); CARD_DISPLAY_ID[16] = '\0'; CARD_WAS_CONVERTED = ret == 0; } } } else { CARD_PRESSED = false; } } static int __cdecl mng_card_check_removed(int /* a1 */) { return 0; } static int __cdecl mng_card_eject_init(int /* a1 */) { CARD_IN = false; return 0; } static int __cdecl mng_card_get_cardnumber(int a1, uint8_t *out) { if (CARD_WAS_CONVERTED) { // copy the display id to the output buffer memcpy(out, CARD_DISPLAY_ID, 16); } else { // fallback to displaying the card UID if the conversion method was not // found or the conversion to the Konami ID failed std::string konami_id = bin2hex(CARD_UID, sizeof(CARD_UID)); memcpy(out, konami_id.c_str(), 16); } // ensure the output is null-terminated out[16] = '\0'; return 0; } static int __cdecl mng_card_get_cardtype(int /* a1 */) { return CARD_TYPE; } static int __cdecl mng_card_get_stat(int /* a1 */) { return CARD_IN ? 2 : 1; } static int __cdecl mng_card_get_uid(int /* a1 */, uint8_t *uid) { memcpy(uid, CARD_UID, 8); return CARD_IN ? 0 : 1; } static int __cdecl mng_card_is_detected(int /* a1 */) { return static_cast(CARD_IN); } static int __cdecl mng_card_is_ejected(int /* a1 */) { return 1; } static int __cdecl mng_card_is_inserted(int /* a1 */) { update_card(); return static_cast(CARD_IN); } static bool __cdecl mng_card_is_invalid_unit(int /* a1 */) { return false; } static int __cdecl mng_card_is_read_done(int /* a1 */) { update_card(); return static_cast(CARD_IN); } static int __cdecl mng_card_is_ready(int /* a1 */) { return 1; } static int __cdecl mng_card_is_removed(int /* a1 */) { return 1; } static int __cdecl mng_card_is_valid_card(int /* a1 */) { return static_cast(CARD_IN); } static int __cdecl mng_card_read_init(int /* a1 */) { return 0; } static int __cdecl mng_card_sensor_raw(int /* a1 */) { update_card(); return CARD_IN ? 48 : 0; } static void __cdecl mng_card_sleep(int a1) { } static int __cdecl sciunit_finalize() { return 0; } static int __cdecl sciunit_get_errorunit() { return 0; } static int __cdecl sciunit_get_stat() { return 0; } static int __cdecl sciunit_get_version(int a1, int a2) { return 0; } static int __cdecl sciunit_initialize() { SCIUNIT_INITIALIZED = true; return 0; } static int __cdecl sciunit_is_initialized() { return SCIUNIT_INITIALIZED ? 1 : 0; } static int __cdecl sciunit_is_usable() { return 1; } static int __cdecl sciunit_led_set_color(uint8_t *led_field) { // Jubeat if (avs::game::is_model({ "J44", "K44", "L44" })) { // get lights auto &lights = games::jb::get_lights(); // control mapping // // The list in `Lamp Check` is not in the same order as the LED array passed to this // function. static size_t mapping[] = { games::jb::Lights::PANEL_FRONT_R, games::jb::Lights::PANEL_FRONT_G, games::jb::Lights::PANEL_FRONT_B, games::jb::Lights::PANEL_TOP_R, games::jb::Lights::PANEL_TOP_G, games::jb::Lights::PANEL_TOP_B, games::jb::Lights::PANEL_LEFT_R, games::jb::Lights::PANEL_LEFT_G, games::jb::Lights::PANEL_LEFT_B, games::jb::Lights::PANEL_RIGHT_R, games::jb::Lights::PANEL_RIGHT_G, games::jb::Lights::PANEL_RIGHT_B, games::jb::Lights::PANEL_TITLE_R, games::jb::Lights::PANEL_TITLE_G, games::jb::Lights::PANEL_TITLE_B, games::jb::Lights::PANEL_WOOFER_R, games::jb::Lights::PANEL_WOOFER_G, games::jb::Lights::PANEL_WOOFER_B, }; // write light for (size_t i = 0; i < std::size(mapping); i++) { GameAPI::Lights::writeLight(RI_MGR, lights.at(mapping[i]), led_field[i] / 255.f); } RI_MGR->devices_flush_output(); } return 0; } static int __cdecl sciunit_reset() { return 0; } static int __cdecl sciunit_update() { if (SCIUNIT_INITIALIZED) update_card(); return 0; } void sciunit_attach() { // get instance SCIUNIT_INSTANCE = libutils::try_module(SCIUNIT_INSTANCE_NAME); if (!SCIUNIT_INSTANCE) { log_info("sciunit", "skipping sciunit hooks"); return; } log_info("sciunit", "SpiceTools SCIUNIT"); // get functions if (cardunit_card_cardnumber == nullptr) { cardunit_card_cardnumber = libutils::try_proc_list( SCIUNIT_INSTANCE, {"cardunit_card_cardnumber", "?cardunit_card_cardnumber@@YAHQBEHPADH@Z"}); } // patch detour::inline_hook((void *) mng_card_check_removed, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_check_removed")); detour::inline_hook((void *) mng_card_eject_init, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_eject_init")); detour::inline_hook((void *) mng_card_get_cardnumber, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_get_cardnumber")); detour::inline_hook((void *) mng_card_get_cardtype, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_get_cardtype")); detour::inline_hook((void *) mng_card_get_stat, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_get_stat")); detour::inline_hook((void *) mng_card_get_uid, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_get_uid")); detour::inline_hook((void *) mng_card_is_detected, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_is_detected")); detour::inline_hook((void *) mng_card_is_ejected, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_is_ejected")); detour::inline_hook((void *) mng_card_is_inserted, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_is_inserted")); detour::inline_hook((void *) mng_card_is_invalid_unit, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_is_invalid_unit")); detour::inline_hook((void *) mng_card_is_read_done, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_is_read_done")); detour::inline_hook((void *) mng_card_is_ready, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_is_ready")); detour::inline_hook((void *) mng_card_is_removed, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_is_removed")); detour::inline_hook((void *) mng_card_is_valid_card, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_is_valid_card")); detour::inline_hook((void *) mng_card_read_init, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_read_init")); detour::inline_hook((void *) mng_card_sensor_raw, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_sensor_raw")); detour::inline_hook((void *) mng_card_sleep, libutils::try_proc( SCIUNIT_INSTANCE, "mng_card_sleep")); detour::inline_hook((void *) sciunit_finalize, libutils::try_proc( SCIUNIT_INSTANCE, "sciunit_finalize")); detour::inline_hook((void *) sciunit_get_errorunit, libutils::try_proc( SCIUNIT_INSTANCE, "sciunit_get_errorunit")); detour::inline_hook((void *) sciunit_get_stat, libutils::try_proc( SCIUNIT_INSTANCE, "sciunit_get_stat")); detour::inline_hook((void *) sciunit_get_version, libutils::try_proc( SCIUNIT_INSTANCE, "sciunit_get_version")); detour::inline_hook((void *) sciunit_initialize, libutils::try_proc( SCIUNIT_INSTANCE, "sciunit_initialize")); detour::inline_hook((void *) sciunit_is_initialized, libutils::try_proc( SCIUNIT_INSTANCE, "sciunit_is_initialized")); detour::inline_hook((void *) sciunit_is_usable, libutils::try_proc( SCIUNIT_INSTANCE, "sciunit_is_usable")); detour::inline_hook((void *) sciunit_led_set_color, libutils::try_proc( SCIUNIT_INSTANCE, "sciunit_led_set_color")); detour::inline_hook((void *) sciunit_reset, libutils::try_proc( SCIUNIT_INSTANCE, "sciunit_reset")); detour::inline_hook((void *) sciunit_update, libutils::try_proc( SCIUNIT_INSTANCE, "sciunit_update")); } void sciunit_detach() { // TODO }