diff --git a/GNUmakefile b/GNUmakefile index 99cc225..12f0e06 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -226,7 +226,7 @@ $$(dll_$1_$2_$3) $$(implib_$1_$2_$3): $$(obj_$1_$2_$3) $$(abslib_$1_$2_$3) \ $(V)echo ... $$(dll_$1_$2_$3) $(V)$$(toolchain_$1)gcc -shared \ -o $$(dll_$1_$2_$3) -Wl,--out-implib,$$(implib_$1_$2_$3) \ - $$^ $$(ldflags_$3) + -Wl,--start-group $$^ -Wl,--end-group $$(ldflags_$3) $(V)$$(toolchain_$1)strip $$(dll_$1_$2_$3) $(V)$$(toolchain_$1)ranlib $$(implib_$1_$2_$3) diff --git a/Module.mk b/Module.mk index b3bbb90..e8732b4 100644 --- a/Module.mk +++ b/Module.mk @@ -26,7 +26,8 @@ # 8: Patch 3: beatmania IIDX 16 Empress # jubeat # -# 10: Patch 4: DanceDanceRevolution X2 +# 10: Patch 2: jubeat Knit +# Patch 4: DanceDanceRevolution X2 # # 11: Patch 1: beatmania IIDX 18 Resort Anthem # pop'n music 19 Tune Street @@ -71,7 +72,7 @@ cflags += \ # Each AVS-dependent project should consume the earliest AVS import definition # that is still ABI-compatible with the real build its target links against. -avsvers_32 := 1700 1603 1601 1508 1403 1304 1101 803 0 +avsvers_32 := 1700 1603 1601 1508 1403 1304 1101 1002 803 0 avsvers_64 := 1700 1603 1601 1509 1508 imps += avs avs-ea3 @@ -136,12 +137,14 @@ include src/main/iidxio-ezusb2/Module.mk include src/main/iidxio/Module.mk include src/main/iidxiotest/Module.mk include src/main/inject/Module.mk -include src/main/jbhook/Module.mk -include src/main/jbhook1/Module.mk include src/main/jbio-magicbox/Module.mk include src/main/jbio-p4io/Module.mk include src/main/jbio/Module.mk include src/main/jbiotest/Module.mk +include src/main/jbhook-util/Module.mk +include src/main/jbhook1/Module.mk +include src/main/jbhook2/Module.mk +include src/main/jbhook3/Module.mk include src/main/launcher/Module.mk include src/main/mempatch-hook/Module.mk include src/main/mm/Module.mk @@ -424,28 +427,68 @@ $(zipdir)/jb-01.zip: \ $(V)echo ... $@ $(V)zip -j $@ $^ +$(zipdir)/jb-02.zip: \ + build/bin/avs2_1002-32/jbhook1.dll \ + build/bin/indep-32/inject.exe \ + build/bin/indep-32/config.exe \ + build/bin/indep-32/eamio.dll \ + build/bin/indep-32/geninput.dll \ + build/bin/indep-32/jbio.dll \ + dist/jb/config.bat \ + dist/jb/gamestart-02.bat \ + dist/jb/jbhook-02.conf \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/jb-03.zip: \ + build/bin/avs2_1101-32/jbhook2.dll \ + build/bin/avs2_1101-32/launcher.exe \ + build/bin/indep-32/config.exe \ + build/bin/indep-32/eamio.dll \ + build/bin/indep-32/geninput.dll \ + build/bin/indep-32/jbio.dll \ + dist/jb/config.bat \ + dist/jb/gamestart-03.bat \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + +$(zipdir)/jb-04.zip: \ + build/bin/avs2_1304-32/jbhook2.dll \ + build/bin/avs2_1304-32/launcher.exe \ + build/bin/indep-32/config.exe \ + build/bin/indep-32/eamio.dll \ + build/bin/indep-32/geninput.dll \ + build/bin/indep-32/jbio.dll \ + dist/jb/config.bat \ + dist/jb/gamestart-03.bat \ + | $(zipdir)/ + $(V)echo ... $@ + $(V)zip -j $@ $^ + $(zipdir)/jb-05-to-07.zip: \ - build/bin/avs2_1508-32/jbhook.dll \ + build/bin/avs2_1508-32/jbhook3.dll \ build/bin/avs2_1508-32/launcher.exe \ build/bin/indep-32/config.exe \ build/bin/indep-32/eamio.dll \ build/bin/indep-32/geninput.dll \ build/bin/indep-32/jbio.dll \ dist/jb/config.bat \ - dist/jb/gamestart.bat \ + dist/jb/gamestart-04.bat \ | $(zipdir)/ $(V)echo ... $@ $(V)zip -j $@ $^ $(zipdir)/jb-08.zip: \ - build/bin/avs2_1700-32/jbhook.dll \ + build/bin/avs2_1700-32/jbhook3.dll \ build/bin/avs2_1700-32/launcher.exe \ build/bin/indep-32/config.exe \ build/bin/indep-32/eamio.dll \ build/bin/indep-32/geninput.dll \ build/bin/indep-32/jbio.dll \ dist/jb/config.bat \ - dist/jb/gamestart.bat \ + dist/jb/gamestart-04.bat \ | $(zipdir)/ $(V)echo ... $@ $(V)zip -j $@ $^ @@ -621,6 +664,9 @@ $(BUILDDIR)/bemanitools.zip: \ $(zipdir)/iidx-hwio-x86.zip \ $(zipdir)/iidx-hwio-x64.zip \ $(zipdir)/jb-01.zip \ + $(zipdir)/jb-02.zip \ + $(zipdir)/jb-03.zip \ + $(zipdir)/jb-04.zip \ $(zipdir)/jb-05-to-07.zip \ $(zipdir)/jb-08.zip \ $(zipdir)/jb-hwio.zip \ diff --git a/dist/jb/gamestart-02.bat b/dist/jb/gamestart-02.bat new file mode 100644 index 0000000..6f6fb5c --- /dev/null +++ b/dist/jb/gamestart-02.bat @@ -0,0 +1,5 @@ +@echo off + +cd /d %~dp0 + +inject jbhook1.dll jubeat.exe --config jbhook-02.conf %* diff --git a/dist/jb/gamestart.bat b/dist/jb/gamestart-03.bat similarity index 85% rename from dist/jb/gamestart.bat rename to dist/jb/gamestart-03.bat index 0352cce..a819020 100644 --- a/dist/jb/gamestart.bat +++ b/dist/jb/gamestart-03.bat @@ -7,4 +7,4 @@ if not exist dev\nvram\coin.xml copy prop\defaults\coin.xml dev\nvram\coin.xml if not exist dev\nvram\eacoin.xml copy prop\defaults\eacoin.xml dev\nvram\eacoin.xml if not exist dev\raw mkdir dev\raw -launcher -H 33554432 -K jbhook.dll jubeat.dll +launcher -K jbhook2.dll jubeat.dll diff --git a/dist/jb/gamestart-04.bat b/dist/jb/gamestart-04.bat new file mode 100644 index 0000000..b481b94 --- /dev/null +++ b/dist/jb/gamestart-04.bat @@ -0,0 +1,10 @@ +@echo off + +cd /d %~dp0 + +if not exist dev\nvram mkdir dev\nvram +if not exist dev\nvram\coin.xml copy prop\defaults\coin.xml dev\nvram\coin.xml +if not exist dev\nvram\eacoin.xml copy prop\defaults\eacoin.xml dev\nvram\eacoin.xml +if not exist dev\raw mkdir dev\raw + +launcher -K jbhook3.dll jubeat.dll diff --git a/dist/jb/jbhook-02.conf b/dist/jb/jbhook-02.conf new file mode 100644 index 0000000..fdb476f --- /dev/null +++ b/dist/jb/jbhook-02.conf @@ -0,0 +1,15 @@ +# Run the game windowed +gfx.windowed=false + +# URL (e.g. http://my.eamuse.server:80/whatever) or IPV4 (e.g. 127.0.0.1:80) of the target eamuse server. The port is optional but defaults to 80. +eamuse.server=localhost:80 + +# PCBID +eamuse.pcbid=0101020304050607086F + +# EAMID +eamuse.eamid=0101020304050607086F + +# Mcode of the game to run. +security.mcode=GCI44JAA + diff --git a/doc/iidxhook/README.md b/doc/iidxhook/README.md index 1a47b1f..1da6e57 100644 --- a/doc/iidxhook/README.md +++ b/doc/iidxhook/README.md @@ -23,14 +23,14 @@ games: * [iidxhook8](iidxhook8.md): CANNON BALLERS, Rootage * [iidxhook8](iidxhook9.md): Heroic Verse -When building kactools, independent packages are created for each set of games +When building bemanitools, independent packages are created for each set of games which are ready to be dropped on top of vanilla AC data dumps. We recommend -using prestine dumps to avoid any conflicts with other hardcoded hacks or +using pristine dumps to avoid any conflicts with other hardcoded hacks or binary patches. ## How to run To run your game with iidxhook, you have to use the inject tool to inject the -DLL to the game process. *dist/iidx* contains bat scripts with all the +DLL to the game process. `dist/iidx` contains bat scripts with all the important parameters configured. Further parameters can be added but might not be required to run the game with default settings. Further information on how to setup the data for each specific version are @@ -47,4 +47,4 @@ IO hardware you want to use: game controllers * [iidxio-bio2](iidxhook/iidxio-bio2.md): Support BIO2 hardware * [iidxio-ezusb](iidxhook/iidxio-ezusb.md): Support C02 ezusb FX hardware -* [iidxio-ezusb2](iidxhook/iidxio-ezusb2.md): Support IO2 ezusb FX2 hardware \ No newline at end of file +* [iidxio-ezusb2](iidxhook/iidxio-ezusb2.md): Support IO2 ezusb FX2 hardware diff --git a/doc/jbhook/README.md b/doc/jbhook/README.md new file mode 100644 index 0000000..432ce12 --- /dev/null +++ b/doc/jbhook/README.md @@ -0,0 +1,77 @@ +# jbhook + +jbhook is a collection of hook libraries for jubeat providing +emulation and various patches to run these games on non BemaniPC hardware and +newer Windows versions. + +The hook libraries must be bootstrapped either using [inject](../inject.md) or +[launcher](../launcher.md) depending on the version you want to run. Further +instructions are given in dedicated readme files for each jbhook version +(see below). + +# Versions + +jbhook comes in a few different flavors. The game and its engine changed over +the years. Some game versions might require patches/parameters enabled which +others don't need or have different AVS versions. Here is the list of supported +games: +* [jbhook1](jbhook1.md): jubeat, ripples +* [jbhook2](jbhook2.md): knit, copious +* [jbhook3](jbhook3.md): saucer, prop, qubell, clan, festo + +I sure have trouble remembering which jubeat version is which, here's a handy +guide: +* 01 - jubeat +* 02 - ripples +* 03 - knit +* 04 - copious +* 05 - saucer +* 06 - prop +* 07 - qubell +* 08 - clan +* 09 - festo + +When building bemanitools, independent packages are created for each set of games +which are ready to be dropped on top of vanilla AC data dumps. We recommend +using pristine dumps to avoid any conflicts with other hardcoded hacks or +binary patches. + +# How to run + +To run your game with jbhook, you have to use the inject tool to inject the +DLL to the game process. `dist/jb` contains bat scripts with all the +important parameters configured. Further parameters can be added but might not +be required to run the game with default settings. +Further information on how to setup the data for each specific version are +elaborated in their dedicated readme files. + +# Data setup and running the game + +Ensure your folder with your unpacked data looks like this: +- `data` +- `prop` +- Various dll files including `jubeat.dll` **OR** `jubeat.exe` + +Unpack the package containing jbhook into the folder containing the jubeat +binary file. + +Run the `gamestart-XX.bat` file where `XX` denotes the version of the game you want to run. + +# Eamuse network setup + +Running jubeat or ripples? Modify jbhook-01.conf or jbhook-02.conf. + +Running anything newer? +* Open the `prop/ea3-config.xml` +* Replace the `ea3/network/services` URL with network service URL of your +choice (for example http://my.eamuse.com) +* Edit the `ea3/id/pcbid` + +# Real hardware support + +Run the launcher without the hook dll: `launcher jubeat.dll` + +# Command line options + +Add the argument *-h* when running inject with jbhook to print help/usage +information with a list of parameters you can apply to tweak various things. diff --git a/doc/jbhook/jbhook.md b/doc/jbhook/jbhook.md deleted file mode 100644 index 9fe2252..0000000 --- a/doc/jbhook/jbhook.md +++ /dev/null @@ -1,31 +0,0 @@ -# Game list - -The following games are compatible with this version of jbhook: -* saucer -* prop -* qubell - -# Data setup and running the game - -Ensure your folder with your unpacked data looks like this: -- data -- prop -- Various dll files including jubeat.dll - -Unpack the package containing jbhook into the folder containing the jubeat.dll -file. - -Run the gamestart.bat file. - -# Eamuse network setup - -* Open the prop/ea3-config.xml -* Replace the *ea3/network/services* URL with network service URL of your -choice (for example http://my.eamuse.com) -* Edit the *ea3/id/pcbid* - -# Real hardware support - -Run the launcher without the hook dll: *launcher jubeat.dll* - -# Troubleshooting and FAQ \ No newline at end of file diff --git a/doc/jbhook/jbhook1.md b/doc/jbhook/jbhook1.md new file mode 100644 index 0000000..936d22d --- /dev/null +++ b/doc/jbhook/jbhook1.md @@ -0,0 +1,21 @@ +# Game list + +The following games are compatible with this version of jbhook: +* jubeat +* jubeat ripples + +The games must be bootstrapped using [inject](../inject.md). + +# Data setup and running the game + +Unpack the package containing jbhook1 into the revision folder of your choice. +Most likely, you want to target the latest revision you have to run the latest +binary of the game with any bugfixes by developers. + +Run the `gamestart-01.bat` file as admin. + +# Eamuse network setup + +If you want to run the games online, you have to set a valid PCBID in the +configuration file. You also have to set the url of the eamuse server you want +to connect to. diff --git a/doc/jbhook/jbhook2.md b/doc/jbhook/jbhook2.md new file mode 100644 index 0000000..20f636e --- /dev/null +++ b/doc/jbhook/jbhook2.md @@ -0,0 +1,21 @@ +# Game list + +The following games are compatible with this version of jbhook: +* jubeat knit +* jubeat copious + +The games must be bootstrapped using [launcher](../launcher.md). + +# Data setup and running the game + +Unpack the package containing jbhook2 into the revision folder of your choice. +Most likely, you want to target the latest revision you have to run the latest +binary of the game with any bugfixes by developers. + +Run the `gamestart-02.bat` file as admin. + +# Eamuse network setup + +If you want to run the games online, you have to set a valid PCBID in the +configuration file. You also have to set the url of the eamuse server you want +to connect to. diff --git a/doc/jbhook/jbhook3.md b/doc/jbhook/jbhook3.md new file mode 100644 index 0000000..6b858e3 --- /dev/null +++ b/doc/jbhook/jbhook3.md @@ -0,0 +1,18 @@ +# Game list + +The following games are compatible with this version of jbhook: +* jubeat saucer +* jubeat prop +* jubeat qubell +* jubeat clan +* jubeat festo + +The games must be bootstrapped using [launcher](../launcher.md). + +# Data setup and running the game + +Unpack the package containing jbhook3 into the revision folder of your choice. +Most likely, you want to target the latest revision you have to run the latest +binary of the game with any bugfixes by developers. + +Run the `gamestart-03.bat` file as admin. diff --git a/src/imports/glhelper.h b/src/imports/glhelper.h new file mode 100644 index 0000000..809b4ce --- /dev/null +++ b/src/imports/glhelper.h @@ -0,0 +1,10 @@ +#include + +void glFramebufferTexture2DEXT(GLenum target, + GLenum attachment, + GLenum textarget, + GLuint texture, + GLint level); + +void glGenFramebuffersEXT(GLsizei n, + GLuint *ids); diff --git a/src/imports/import_32_1002_avs-ea3.def b/src/imports/import_32_1002_avs-ea3.def new file mode 100644 index 0000000..577276d --- /dev/null +++ b/src/imports/import_32_1002_avs-ea3.def @@ -0,0 +1,5 @@ +LIBRARY libavs-win32-ea3 + +EXPORTS + ea3_boot + ea3_shutdown diff --git a/src/imports/import_32_1002_avs.def b/src/imports/import_32_1002_avs.def new file mode 100644 index 0000000..a7f59b5 --- /dev/null +++ b/src/imports/import_32_1002_avs.def @@ -0,0 +1,37 @@ +LIBRARY libavs-win32 + +EXPORTS + avs_boot + avs_net_ctrl + avs_shutdown + avs_thread_create + avs_thread_destroy + avs_thread_exit + avs_thread_join + log_body_fatal + log_body_info + log_body_misc + log_body_warning + log_boot + log_change_level + property_create + property_desc_to_buffer + property_destroy + property_file_write + property_insert_read + property_mem_write + property_read_query_memsize + property_search + property_set_flag + property_node_clone + property_node_create + property_node_datasize + property_node_name + property_node_refer + property_node_remove + property_node_type + property_node_traversal + property_node_refdata + std_getenv + std_setenv + diff --git a/src/imports/import_32_1002_glhelper.def b/src/imports/import_32_1002_glhelper.def new file mode 100644 index 0000000..1f220bd --- /dev/null +++ b/src/imports/import_32_1002_glhelper.def @@ -0,0 +1,6 @@ +LIBRARY glhelper + +EXPORTS + glBindFramebufferEXT + glFramebufferTexture2DEXT + glGenFramebuffersEXT diff --git a/src/imports/import_32_1101_glhelper.def b/src/imports/import_32_1101_glhelper.def new file mode 100644 index 0000000..1f220bd --- /dev/null +++ b/src/imports/import_32_1101_glhelper.def @@ -0,0 +1,6 @@ +LIBRARY glhelper + +EXPORTS + glBindFramebufferEXT + glFramebufferTexture2DEXT + glGenFramebuffersEXT diff --git a/src/imports/import_32_1304_glhelper.def b/src/imports/import_32_1304_glhelper.def new file mode 100644 index 0000000..1f220bd --- /dev/null +++ b/src/imports/import_32_1304_glhelper.def @@ -0,0 +1,6 @@ +LIBRARY glhelper + +EXPORTS + glBindFramebufferEXT + glFramebufferTexture2DEXT + glGenFramebuffersEXT diff --git a/src/imports/import_32_803_glhelper.def b/src/imports/import_32_803_glhelper.def new file mode 100644 index 0000000..1f220bd --- /dev/null +++ b/src/imports/import_32_803_glhelper.def @@ -0,0 +1,6 @@ +LIBRARY glhelper + +EXPORTS + glBindFramebufferEXT + glFramebufferTexture2DEXT + glGenFramebuffersEXT diff --git a/src/main/acio/icca.h b/src/main/acio/icca.h index 19b0e48..74b7d2c 100644 --- a/src/main/acio/icca.h +++ b/src/main/acio/icca.h @@ -4,6 +4,8 @@ #include enum ac_io_icca_cmd { + /* found on jubeat, sent right after queue loop start */ + AC_IO_ICCA_CMD_UNKN_0116 = 0x0116, /* Yet unknown command encountered first on jubeat (1) */ AC_IO_ICCA_CMD_UNKN_0120 = 0x0120, AC_IO_ICCA_CMD_QUEUE_LOOP_START = 0x0130, diff --git a/src/main/acio/iccb.h b/src/main/acio/iccb.h deleted file mode 100644 index 4928054..0000000 --- a/src/main/acio/iccb.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef AC_IO_ICCB_H -#define AC_IO_ICCB_H - -#include - -enum ac_io_iccb_cmd { - /* found on jubeat prop, sent after acio init req, maybe fw update? */ - AC_IO_ICCB_CMD_UNK_0100 = 0x0100, - /* found on jubeat prop, sent right after queue loop start */ - AC_IO_ICCB_CMD_UNK_0116 = 0x0116, - /* found on jubeat prop, sent after 0100 req */ - AC_IO_ICCB_CMD_UNK_0120 = 0x0120, - AC_IO_ICCB_CMD_QUEUE_LOOP_START = 0x0130, - AC_IO_ICCB_CMD_POLL = 0x0134, - AC_IO_ICCB_CMD_UNK_135 = 0x0135, - AC_IO_ICCB_CMD_SLEEP = 0x013A, - AC_IO_ICCB_CMD_READ_CARD = 0x0161 -}; - -enum ac_io_iccb_sensor_state { - AC_IO_ICCB_SENSOR_CARD = 0x02, - AC_IO_ICCB_SENSOR_NO_CARD = 0x04 -}; - -enum ac_io_iccb_card_type { - AC_IO_ICCB_CARD_TYPE_ISO15696 = 0x0, - AC_IO_ICCB_CARD_TYPE_FELICA = 0x1, -}; - -#pragma pack(push, 1) - -struct ac_io_iccb_misc { - uint8_t unknown; - uint8_t subcmd; -}; - -struct ac_io_iccb_state { - uint8_t sensor_state; - uint8_t card_type; - uint8_t uid[8]; - uint8_t unk2; - uint8_t unk3; - uint8_t unk4[4]; -}; - -#pragma pack(pop) - -#endif \ No newline at end of file diff --git a/src/main/acioemu/Module.mk b/src/main/acioemu/Module.mk index 29c8c81..671cc08 100644 --- a/src/main/acioemu/Module.mk +++ b/src/main/acioemu/Module.mk @@ -6,6 +6,5 @@ src_acioemu := \ h44b.c \ hdxs.c \ icca.c \ - iccb.c \ pipe.c \ diff --git a/src/main/acioemu/icca.c b/src/main/acioemu/icca.c index 24f2298..2371a17 100644 --- a/src/main/acioemu/icca.c +++ b/src/main/acioemu/icca.c @@ -63,6 +63,8 @@ void ac_io_emu_icca_init( // default to 1.6.0 icca->version = v160; + // default, most common code + ac_io_emu_icca_set_product_code(icca, AC_IO_EMU_PROD_CODE_ICCA); } void ac_io_emu_icca_set_version( @@ -71,6 +73,12 @@ void ac_io_emu_icca_set_version( icca->version = version; } +void ac_io_emu_icca_set_product_code( + struct ac_io_emu_icca *icca, const char product_code[4]) +{ + memcpy(icca->product_code, product_code, sizeof(icca->product_code)); +} + void ac_io_emu_icca_dispatch_request( struct ac_io_emu_icca *icca, const struct ac_io_message *req) { @@ -119,8 +127,9 @@ void ac_io_emu_icca_dispatch_request( break; + case AC_IO_ICCA_CMD_UNKN_0116: case AC_IO_ICCA_CMD_UNKN_0120: - log_misc("AC_IO_ICCA_CMD_UNKN_0120(%d)", req->addr); + log_misc("AC_IO_ICCA_CMD_UNK_%04X(%d)", cmd_code, req->addr); ac_io_emu_icca_send_status(icca, req, 0x00); break; @@ -138,48 +147,52 @@ void ac_io_emu_icca_dispatch_request( break; case AC_IO_ICCA_CMD_SET_SLOT_STATE: { - struct ac_io_icca_misc *misc = - (struct ac_io_icca_misc *) &req->cmd.raw; - uint8_t cmd; + if(icca->version == v150) { + ac_io_emu_icca_send_state(icca, req, 0, false); + } else { + struct ac_io_icca_misc *misc = + (struct ac_io_icca_misc *) &req->cmd.raw; + uint8_t cmd; - switch (misc->subcmd) { - case AC_IO_ICCA_SUBCMD_CARD_SLOT_CLOSE: - cmd = EAM_IO_CARD_SLOT_CMD_CLOSE; - break; + switch (misc->subcmd) { + case AC_IO_ICCA_SUBCMD_CARD_SLOT_CLOSE: + cmd = EAM_IO_CARD_SLOT_CMD_CLOSE; + break; - case AC_IO_ICCA_SUBCMD_CARD_SLOT_OPEN: - cmd = EAM_IO_CARD_SLOT_CMD_OPEN; - break; + case AC_IO_ICCA_SUBCMD_CARD_SLOT_OPEN: + cmd = EAM_IO_CARD_SLOT_CMD_OPEN; + break; - case AC_IO_ICCA_SUBCMD_CARD_SLOT_EJECT: - cmd = EAM_IO_CARD_SLOT_CMD_EJECT; - icca->engaged = false; - break; + case AC_IO_ICCA_SUBCMD_CARD_SLOT_EJECT: + cmd = EAM_IO_CARD_SLOT_CMD_EJECT; + icca->engaged = false; + break; - case 3: - cmd = EAM_IO_CARD_SLOT_CMD_READ; - break; + case 3: + cmd = EAM_IO_CARD_SLOT_CMD_READ; + break; - default: - cmd = 0xFF; - log_warning( - "Unhandled slot command %X, node %d", - misc->subcmd, - icca->unit_no); - break; - } - - if (cmd != 0xFF) { - if (!eam_io_card_slot_cmd(icca->unit_no, cmd)) { - log_warning( - "Eamio failed to handle slot cmd %d for node %d", - cmd, - icca->unit_no); + default: + cmd = 0xFF; + log_warning( + "Unhandled slot command %X, node %d", + misc->subcmd, + icca->unit_no); + break; } - } - /* response with current slot state */ - ac_io_emu_icca_send_status(icca, req, misc->subcmd); + if (cmd != 0xFF) { + if (!eam_io_card_slot_cmd(icca->unit_no, cmd)) { + log_warning( + "Eamio failed to handle slot cmd %d for node %d", + cmd, + icca->unit_no); + } + } + + /* response with current slot state */ + ac_io_emu_icca_send_status(icca, req, misc->subcmd); + } break; } @@ -202,12 +215,14 @@ void ac_io_emu_icca_dispatch_request( break; case AC_IO_ICCA_CMD_POLL_FELICA: - icca->detected_new_reader = true; - - if (icca->version == v170) { + if (icca->version == v150) { + ac_io_emu_icca_send_state(icca, req, 0, false); + } else if (icca->version == v170) { ac_io_emu_icca_send_empty(icca, req); + icca->detected_new_reader = true; } else { ac_io_emu_icca_send_status(icca, req, 0x01); + icca->detected_new_reader = true; } break; @@ -244,8 +259,6 @@ static void ac_io_emu_icca_cmd_send_version( resp.cmd.version.major = 0x01; if (icca->version == v150) { - log_warning( - "ICCA v1.5.0 emulation requested, please remove this log once implemented"); resp.cmd.version.minor = 0x05; } else if (icca->version == v160) { resp.cmd.version.minor = 0x06; @@ -262,7 +275,7 @@ static void ac_io_emu_icca_cmd_send_version( memcpy( resp.cmd.version.product_code, - "ICCA", + icca->product_code, sizeof(resp.cmd.version.product_code)); strncpy(resp.cmd.version.date, __DATE__, sizeof(resp.cmd.version.date)); strncpy(resp.cmd.version.time, __TIME__, sizeof(resp.cmd.version.time)); diff --git a/src/main/acioemu/icca.h b/src/main/acioemu/icca.h index e8b7b84..a182398 100644 --- a/src/main/acioemu/icca.h +++ b/src/main/acioemu/icca.h @@ -12,6 +12,11 @@ enum ac_io_emu_icca_version { v170 = 0x7, }; +// ICC product types for ac_io_emu_icca_set_product_code +#define AC_IO_EMU_PROD_CODE_ICCA "ICCA" +#define AC_IO_EMU_PROD_CODE_ICCB "ICCB" +#define AC_IO_EMU_PROD_CODE_ICCC "ICCC" + struct ac_io_emu_icca { struct ac_io_emu *emu; uint8_t unit_no; @@ -28,6 +33,7 @@ struct ac_io_emu_icca { uint64_t time_counter_last_poll; enum ac_io_emu_icca_version version; + char product_code[4]; bool cipher_started; uint32_t cipher_keys[4]; }; @@ -39,6 +45,12 @@ void ac_io_emu_icca_init( void ac_io_emu_icca_set_version( struct ac_io_emu_icca *icca, enum ac_io_emu_icca_version version); +// optional, call after init to override default "ICCA" product code. +// Some games may refuse to boot or expect a different packet format when using +// one of the alternative codes such as ICCB or ICCC +void ac_io_emu_icca_set_product_code( + struct ac_io_emu_icca *icca, const char product_code[4]); + void ac_io_emu_icca_dispatch_request( struct ac_io_emu_icca *icca, const struct ac_io_message *req); diff --git a/src/main/acioemu/iccb.c b/src/main/acioemu/iccb.c deleted file mode 100644 index d4cfb33..0000000 --- a/src/main/acioemu/iccb.c +++ /dev/null @@ -1,223 +0,0 @@ -#define LOG_MODULE "acioemu-iccb" - -#include "acioemu/iccb.h" - -#include /* for _BitScanForward */ - -#include -#include - -#include "acio/iccb.h" - -#include "acioemu/emu.h" - -#include "bemanitools/eamio.h" - -static void ac_io_emu_iccb_cmd_send_version( - struct ac_io_emu_iccb *iccb, const struct ac_io_message *req); - -static void ac_io_emu_iccb_send_state( - struct ac_io_emu_iccb *iccb, const struct ac_io_message *req); - -static void ac_io_emu_iccb_send_empty( - struct ac_io_emu_iccb *iccb, const struct ac_io_message *req); - -static void ac_io_emu_iccb_send_status( - struct ac_io_emu_iccb *iccb, - const struct ac_io_message *req, - uint8_t status); - -void ac_io_emu_iccb_init( - struct ac_io_emu_iccb *iccb, struct ac_io_emu *emu, uint8_t unit_no) -{ - memset(iccb, 0, sizeof(*iccb)); - iccb->emu = emu; - iccb->unit_no = unit_no; -} - -void ac_io_emu_iccb_dispatch_request( - struct ac_io_emu_iccb *iccb, const struct ac_io_message *req) -{ - uint16_t cmd_code; - - cmd_code = ac_io_u16(req->cmd.code); - - switch (cmd_code) { - case AC_IO_CMD_GET_VERSION: - log_misc("AC_IO_CMD_GET_VERSION(%d)", req->addr); - ac_io_emu_iccb_cmd_send_version(iccb, req); - - break; - - case AC_IO_CMD_START_UP: - log_misc("AC_IO_CMD_START_UP(%d)", req->addr); - ac_io_emu_iccb_send_status(iccb, req, 0x00); - - break; - - case AC_IO_CMD_KEEPALIVE: - ac_io_emu_iccb_send_empty(iccb, req); - - break; - - case AC_IO_ICCB_CMD_QUEUE_LOOP_START: - log_misc("AC_IO_CMD_QUEUE_LOOP_START(%d)", req->addr); - ac_io_emu_iccb_send_status(iccb, req, 0x00); - - break; - - case AC_IO_ICCB_CMD_UNK_0100: - case AC_IO_ICCB_CMD_UNK_0116: - case AC_IO_ICCB_CMD_UNK_0120: - log_misc("AC_IO_ICCB_CMD_UNK_%04X(%d)", cmd_code, req->addr); - ac_io_emu_iccb_send_status(iccb, req, 0x00); - - break; - - case AC_IO_ICCB_CMD_SLEEP: - ac_io_emu_iccb_send_status(iccb, req, 0x00); - - break; - - case AC_IO_ICCB_CMD_UNK_135: - /* log_misc("AC_IO_ICCB_CMD_UNK_135"); */ - ac_io_emu_iccb_send_state(iccb, req); - - break; - - case AC_IO_ICCB_CMD_POLL: - /* log_misc("AC_IO_ICCB_CMD_POLL"); */ - ac_io_emu_iccb_send_state(iccb, req); - - break; - - case AC_IO_ICCB_CMD_READ_CARD: - /* log_misc("AC_IO_ICCB_CMD_READ_CARD"); */ - ac_io_emu_iccb_send_state(iccb, req); - - break; - - default: - log_warning( - "Unknown ACIO message %04x on ICCB node, addr=%d", - cmd_code, - req->addr); - - break; - } -} - -static void ac_io_emu_iccb_cmd_send_version( - struct ac_io_emu_iccb *iccb, const struct ac_io_message *req) -{ - struct ac_io_message resp; - - resp.addr = req->addr | AC_IO_RESPONSE_FLAG; - resp.cmd.code = req->cmd.code; - resp.cmd.seq_no = req->cmd.seq_no; - resp.cmd.nbytes = sizeof(resp.cmd.version); - resp.cmd.version.type = ac_io_u32(AC_IO_NODE_TYPE_ICCB); - resp.cmd.version.flag = 0x00; - resp.cmd.version.major = 0x01; - resp.cmd.version.minor = 0x05; - resp.cmd.version.revision = 0x01; - memcpy( - resp.cmd.version.product_code, - "ICCB", - sizeof(resp.cmd.version.product_code)); - strncpy(resp.cmd.version.date, __DATE__, sizeof(resp.cmd.version.date)); - strncpy(resp.cmd.version.time, __TIME__, sizeof(resp.cmd.version.time)); - - ac_io_emu_response_push(iccb->emu, &resp, 0); -} - -static void ac_io_emu_iccb_send_empty( - struct ac_io_emu_iccb *iccb, const struct ac_io_message *req) -{ - struct ac_io_message resp; - - resp.addr = req->addr | AC_IO_RESPONSE_FLAG; - resp.cmd.code = req->cmd.code; - resp.cmd.seq_no = req->cmd.seq_no; - resp.cmd.nbytes = 0; - - ac_io_emu_response_push(iccb->emu, &resp, 0); -} - -static void ac_io_emu_iccb_send_status( - struct ac_io_emu_iccb *iccb, - const struct ac_io_message *req, - uint8_t status) -{ - struct ac_io_message resp; - - resp.addr = req->addr | AC_IO_RESPONSE_FLAG; - resp.cmd.code = req->cmd.code; - resp.cmd.seq_no = req->cmd.seq_no; - resp.cmd.nbytes = sizeof(resp.cmd.status); - resp.cmd.status = status; - - ac_io_emu_response_push(iccb->emu, &resp, 0); -} - -static void ac_io_emu_iccb_send_state( - struct ac_io_emu_iccb *iccb, const struct ac_io_message *req) -{ - struct ac_io_message resp; - struct ac_io_iccb_state *body; - bool sensor; - - /* state update */ - - if (!eam_io_poll(iccb->unit_no)) { - log_warning("Polling eamio failed"); - } - - sensor = eam_io_get_sensor_state(iccb->unit_no); - - if (sensor != iccb->last_sensor) { - if (sensor) { - iccb->card_result = - eam_io_read_card(iccb->unit_no, iccb->uid, sizeof(iccb->uid)); - - // fault if sensor says to read but we got no card - iccb->fault = (iccb->card_result == EAM_IO_CARD_NONE); - } else { - iccb->fault = false; - } - } - - iccb->last_sensor = sensor; - - if (iccb->fault) { - memset(iccb->uid, 0, sizeof(iccb->uid)); - } - - /* create response */ - - resp.addr = req->addr | AC_IO_RESPONSE_FLAG; - resp.cmd.code = req->cmd.code; - resp.cmd.seq_no = req->cmd.seq_no; - resp.cmd.nbytes = sizeof(struct ac_io_iccb_state); - - body = (struct ac_io_iccb_state *) &resp.cmd.raw; - - if (sensor) { - body->sensor_state = AC_IO_ICCB_SENSOR_CARD; - } else { - body->sensor_state = AC_IO_ICCB_SENSOR_NO_CARD; - } - - if (!iccb->fault) { - memcpy(body->uid, iccb->uid, sizeof(body->uid)); - } - - body->card_type = 0x30 | (iccb->card_result - 1); - body->unk2 = 0; - // this doesn't seem to be an error code. If this is not set to 0x03 - // on slotted readers (only?), the game throws an unknown status error - body->unk3 = 0x03; - memset(body->unk4, 0, sizeof(body->unk4)); - - ac_io_emu_response_push(iccb->emu, &resp, 0); -} diff --git a/src/main/acioemu/iccb.h b/src/main/acioemu/iccb.h deleted file mode 100644 index 762068f..0000000 --- a/src/main/acioemu/iccb.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef AC_IO_EMU_ICCB_H -#define AC_IO_EMU_ICCB_H - -#include -#include - -#include "acioemu/emu.h" - -struct ac_io_emu_iccb { - struct ac_io_emu *emu; - uint8_t unit_no; - bool fault; - bool last_sensor; - uint8_t uid[8]; - uint8_t card_result; -}; - -void ac_io_emu_iccb_init( - struct ac_io_emu_iccb *iccb, struct ac_io_emu *emu, uint8_t unit_no); - -void ac_io_emu_iccb_dispatch_request( - struct ac_io_emu_iccb *iccb, const struct ac_io_message *req); - -#endif diff --git a/src/main/jbhook-util/Module.mk b/src/main/jbhook-util/Module.mk new file mode 100644 index 0000000..c013e76 --- /dev/null +++ b/src/main/jbhook-util/Module.mk @@ -0,0 +1,13 @@ +libs += jbhook-util + +libs_jbhook-util := \ + acioemu \ + +src_jbhook-util := \ + acio.c \ + eamuse.c \ + gfx.c \ + mixer.c \ + locale.c \ + p3io.c \ + p4io.c \ diff --git a/src/main/jbhook1/acio.c b/src/main/jbhook-util/acio.c similarity index 82% rename from src/main/jbhook1/acio.c rename to src/main/jbhook-util/acio.c index ff05043..c5f0e3d 100644 --- a/src/main/jbhook1/acio.c +++ b/src/main/jbhook-util/acio.c @@ -18,7 +18,7 @@ #include "hook/iohook.h" -#include "jbhook/acio.h" +#include "jbhook-util/acio.h" #include "imports/avs.h" @@ -32,20 +32,25 @@ static struct ac_io_emu ac_io_emu; static struct ac_io_emu_icca ac_io_emu_icca; static struct ac_io_emu_h44b ac_io_emu_h44b; -void ac_io_port_init(void) +void jbhook_util_ac_io_port_init(const wchar_t *filename) { - ac_io_emu_init(&ac_io_emu, L"COM1"); + ac_io_emu_init(&ac_io_emu, filename); ac_io_emu_icca_init(&ac_io_emu_icca, &ac_io_emu, 0); ac_io_emu_h44b_init(&ac_io_emu_h44b, &ac_io_emu, 1); } -void ac_io_port_fini(void) +void jbhook_util_ac_io_port_fini(void) { ac_io_emu_fini(&ac_io_emu); } +void jbhook_util_ac_io_set_iccb(void) { + ac_io_emu_icca_set_version(&ac_io_emu_icca, v150); + ac_io_emu_icca_set_product_code(&ac_io_emu_icca, AC_IO_EMU_PROD_CODE_ICCB); +} + HRESULT -ac_io_port_dispatch_irp(struct irp *irp) +jbhook_util_ac_io_port_dispatch_irp(struct irp *irp) { const struct ac_io_message *msg; HRESULT hr; diff --git a/src/main/jbhook-util/acio.h b/src/main/jbhook-util/acio.h new file mode 100644 index 0000000..1a924ae --- /dev/null +++ b/src/main/jbhook-util/acio.h @@ -0,0 +1,28 @@ +#ifndef JBHOOK1_ACIO_H +#define JBHOOK1_ACIO_H + +#include "hook/iohook.h" + +/** + * Initialize the ACIO backend for jubeat on the specified COM port. + */ +void jbhook_util_ac_io_port_init(const wchar_t *filename); + +/** + * Shutdown the ACIO backend. + */ +void jbhook_util_ac_io_port_fini(void); + +/** + * ACIO backend dispatch irp function. This needs to be hooked up to the iohook + * module in order to receive system calls to dispatch for emulation. + */ +HRESULT jbhook_util_ac_io_port_dispatch_irp(struct irp *irp); + +/** + * Enable ICCB emulation instead of the default ICCA emulation - some jubeats + * will have IO errors unless explicitly set to ICCB mode. + */ +void jbhook_util_ac_io_set_iccb(void); + +#endif diff --git a/src/main/jbhook-util/eamuse.c b/src/main/jbhook-util/eamuse.c new file mode 100644 index 0000000..87ece98 --- /dev/null +++ b/src/main/jbhook-util/eamuse.c @@ -0,0 +1,144 @@ +#define LOG_MODULE "eamuse-hook" + +#include +#include +#include +#include + +#include +#include +#include + +#include "hook/table.h" + +#include "util/defs.h" +#include "util/log.h" +#include "util/net.h" +#include "util/str.h" + +static const char *jbhook_eamuse_konami_url = "eamuse.konami."; + +static int(STDCALL *real_getaddrinfo)( + PCSTR pNodeName, + PCSTR pServiceName, + const ADDRINFOA *pHints, + PADDRINFOA *ppResult); + +static int STDCALL my_getaddrinfo( + PCSTR pNodeName, + PCSTR pServiceName, + const ADDRINFOA *pHints, + PADDRINFOA *ppResult); + +static DWORD WINAPI my_GetIpAddrTable( + PMIB_IPADDRTABLE pIpAddrTable, + PULONG pdwSize, + BOOL bOrder +); + +static const struct hook_symbol eamuse_hook_syms[] = { + { + .name = "getaddrinfo", + .ordinal = 176, + .patch = my_getaddrinfo, + .link = (void **) &real_getaddrinfo, + }, +}; + +static const struct hook_symbol network_hook_syms[] = { + { + .name = "GetIpAddrTable", + .patch = my_GetIpAddrTable, + }, +}; + +static int STDCALL my_getaddrinfo( + PCSTR pNodeName, + PCSTR pServiceName, + const ADDRINFOA *pHints, + PADDRINFOA *ppResult) +{ + log_misc("my_getaddrinfo: %s, %s", pNodeName, pServiceName); + + /* resolve eamuse.konami.fun/com to 127.0.0.1 to avoid lag spikes every + 150 seconds which might happen in-game as well */ + if (!strncmp( + pNodeName, + jbhook_eamuse_konami_url, + strlen(jbhook_eamuse_konami_url))) { + log_info("Resolve konami.eamuse.XXX -> localhost"); + pNodeName = "localhost"; + } + + return real_getaddrinfo(pNodeName, pServiceName, pHints, ppResult); +} + +static DWORD get_best_ip(void) { + PIP_ADAPTER_INFO info = NULL; + struct net_addr addr; + // fallback to a very obviously wrong value + DWORD ret = (5 << 24) | (7 << 16) | (3 << 8) | (0 << 0); + ULONG sz = 0; + + // this uses our hooked GetAdaptersInfo from hooklib/adapter.c, thus using + // the preferred interface instead of the default order + log_assert(GetAdaptersInfo(info, &sz) == ERROR_BUFFER_OVERFLOW); + + info = malloc(sz); + + if(GetAdaptersInfo(info, &sz) != NO_ERROR) { + goto CLEANUP; + } + + if(!net_str_parse(info->IpAddressList.IpAddress.String, &addr)) { + goto CLEANUP; + } + + // MS docs say this should be in network byte order, but we need to return + // host byte order for the game to not throw the IP error + ret = addr.ipv4.addr; + +CLEANUP: + free(info); + + return ret; +} + +/** + * In new games via network.dll:network_addr_is_changed and in old games + * directly, this function is called to compare the current IP address vs the IP + * address when the game was first loaded. If the two are different, an error is + * printed. It can be dismissed but will show up every ~10 seconds, impeding + * gameplay. Because GetAdaptersInfo is hooked to return a (sometimes) different + * adapter, computers with multiple interfaces will often fail this comparison + * check. By also hooking this function, the IP addresses of the two calls will + * agree. + */ +static DWORD WINAPI my_GetIpAddrTable( + PMIB_IPADDRTABLE pIpAddrTable, + PULONG pdwSize, + BOOL bOrder +) { + ULONG in = *pdwSize; + // 1 element return table + *pdwSize = sizeof(MIB_IPADDRTABLE) + sizeof(MIB_IPADDRROW); + + if(in < *pdwSize) { + return ERROR_INSUFFICIENT_BUFFER; + } + + pIpAddrTable->dwNumEntries = 1; + pIpAddrTable->table[0].dwAddr = get_best_ip(); + + return NO_ERROR; +} + +void jbhook_util_eamuse_hook_init(void) +{ + hook_table_apply( + NULL, "ws2_32.dll", eamuse_hook_syms, lengthof(eamuse_hook_syms)); + hook_table_apply( + NULL, "iphlpapi.dll", network_hook_syms, lengthof(network_hook_syms)); + + log_info("Inserted eamuse hooks"); +} diff --git a/src/main/jbhook-util/eamuse.h b/src/main/jbhook-util/eamuse.h new file mode 100644 index 0000000..67aef0a --- /dev/null +++ b/src/main/jbhook-util/eamuse.h @@ -0,0 +1,6 @@ +#ifndef JBHOOK_UTIL_EAMUSE_H +#define JBHOOK_UTIL_EAMUSE_H + +void jbhook_util_eamuse_hook_init(void); + +#endif diff --git a/src/main/jbhook-util/gfx.c b/src/main/jbhook-util/gfx.c new file mode 100644 index 0000000..a22d65c --- /dev/null +++ b/src/main/jbhook-util/gfx.c @@ -0,0 +1,180 @@ +#define LOG_MODULE "jbhook-gfx" + +#include + +#include +#include +#include +#include +#include +#include + +#include "hook/com-proxy.h" +#include "hook/table.h" + +#include "imports/glhelper.h" + +#include "jbhook-util/gfx.h" + +#include "util/defs.h" +#include "util/log.h" +#include "util/str.h" +#include "util/time.h" + +static void __stdcall hook_glFlush(void); +static void (__stdcall *real_glFlush)(void); + +static void hook_glBindFramebufferEXT(GLenum target, GLuint framebuffer); +static void (*real_glBindFramebufferEXT)(GLenum target, GLuint framebuffer); + +static const struct hook_symbol jbhook1_opengl_hook_syms[] = { + {.name = "glFlush", + .patch = hook_glFlush, + .link = (void **) &real_glFlush}, +}; + +static const struct hook_symbol jbhook1_glhelper_hook_syms[] = { + {.name = "glBindFramebufferEXT", + .patch = hook_glBindFramebufferEXT, + .link = (void **) &real_glBindFramebufferEXT}, +}; + +static DWORD STDCALL my_GetGlyphOutline( + HDC hdc, + UINT uChar, + UINT uFormat, + LPGLYPHMETRICS lpgm, + DWORD cbBuffer, + LPVOID lpvBuffer, + const MAT2 *lpmat2); + +static DWORD(STDCALL *real_GetGlyphOutline)( + HDC hdc, + UINT uChar, + UINT uFormat, + LPGLYPHMETRICS lpgm, + DWORD cbBuffer, + LPVOID lpvBuffer, + const MAT2 *lpmat2); + +static const struct hook_symbol gfx_hook_syms[] = { + {.name = "GetGlyphOutlineA", + .patch = my_GetGlyphOutline, + .link = (void **) &real_GetGlyphOutline}, + { + .name = "IsDBCSLeadByteEx", + .patch = my_GetGlyphOutline, // !?? + .link = (void **) &real_GetGlyphOutline // !?? + }, +}; + +static DWORD STDCALL my_GetGlyphOutline( + HDC hdc, + UINT uChar, + UINT uFormat, + LPGLYPHMETRICS lpgm, + DWORD cbBuffer, + LPVOID lpvBuffer, + const MAT2 *lpmat2) +{ + if (IsDBCSLeadByteEx(CP_ACP, uChar & 0xFF)) { + log_warning("!!!!!!!!"); + + char tmp[2]; + + tmp[0] = uChar & 0xFF; + tmp[1] = (uChar >> 8) & 0xFF; + + MultiByteToWideChar( + CP_ACP, MB_USEGLYPHCHARS, tmp, 2, lpvBuffer, cbBuffer); + } + + return real_GetGlyphOutline( + hdc, uChar, uFormat, lpgm, cbBuffer, lpvBuffer, lpmat2); +} + +void jbhook_util_gfx_hook_init(void) +{ + hook_table_apply(NULL, "gdi32.dll", gfx_hook_syms, lengthof(gfx_hook_syms)); + + log_info("Inserted gfx hooks"); +} + +void jbhook_util_gfx_set_windowed(bool framed) +{ +} + +void jbhook_util_gfx_install_vertical_hooks(void) { + hook_table_apply( + NULL, + "opengl32.dll", + jbhook1_opengl_hook_syms, + lengthof(jbhook1_opengl_hook_syms)); + + hook_table_apply( + NULL, + "glhelper.dll", + jbhook1_glhelper_hook_syms, + lengthof(jbhook1_glhelper_hook_syms)); + + log_info("Inserted vertical display hooks"); +} + +// only jubeat uses openGL, let alone needs rotation at all, so hardcode for now +#define W 768 +#define H 1360 + +static GLuint fb; +static GLuint color; + +static void fb_init(void) { + static bool init_done = false; + + if(init_done) { + return; + } + + init_done = true; + + glGenFramebuffersEXT(1, &fb); + glGenTextures(1, &color); +} + +static uint8_t pixels_raw[W*H*3]; +static uint8_t pixels_rot[W*H*3]; + +static void __stdcall hook_glFlush(void) { + glReadPixels(0, 0, H, W, GL_RGB, GL_UNSIGNED_BYTE, pixels_raw); + + for(size_t x = 0; x < W; x++) { + for(size_t y = 0; y < H; y++) { + memcpy(&pixels_rot[3*(y*W + x)], &pixels_raw[3*((W-x)*H + y)], 3); + } + } + + real_glBindFramebufferEXT(GL_FRAMEBUFFER, 0); + + glDisable(GL_SCISSOR_TEST); + glDrawPixels(W, H, GL_RGB, GL_UNSIGNED_BYTE, pixels_rot); + + real_glFlush(); + + fb_init(); + real_glBindFramebufferEXT(GL_FRAMEBUFFER, fb); + glBindTexture(GL_TEXTURE_2D, color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, H, W, 0, GL_RGBA,GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); +} + +static void hook_glBindFramebufferEXT(GLenum target, GLuint framebuffer) { + fb_init(); + + if(target == GL_FRAMEBUFFER && framebuffer == 0) { + framebuffer = fb; + } + + return real_glBindFramebufferEXT(target, framebuffer); +} diff --git a/src/main/jbhook/gfx.h b/src/main/jbhook-util/gfx.h similarity index 62% rename from src/main/jbhook/gfx.h rename to src/main/jbhook-util/gfx.h index 0bd9123..4d4bb0b 100644 --- a/src/main/jbhook/gfx.h +++ b/src/main/jbhook-util/gfx.h @@ -7,7 +7,7 @@ * Hook some gfx related functions to patch gfx related stuff * like enabling window mode. */ -void gfx_hook_init(void); +void jbhook_util_gfx_hook_init(void); /** * Set the game to window mode. @@ -15,6 +15,11 @@ void gfx_hook_init(void); * @param framed True to add a window frame and make the window * movable, resizable, minizable. False for no frame. */ -void gfx_set_windowed(bool framed); +void jbhook_util_gfx_set_windowed(bool framed); + +/** + * Rotate a horizontal-by-default jubeat window to vertical + */ +void jbhook_util_gfx_install_vertical_hooks(void); #endif diff --git a/src/main/jbhook-util/locale.c b/src/main/jbhook-util/locale.c new file mode 100644 index 0000000..c1fa13d --- /dev/null +++ b/src/main/jbhook-util/locale.c @@ -0,0 +1,37 @@ +#define LOG_MODULE "jbhook-locale" + +#include + +#include "hook/table.h" + +#include "util/defs.h" +#include "util/log.h" + +// ANSI/OEM Japanese; Japanese (Shift-JIS) +#define CODEPAGE_SHIFT_JIS 932 + +static UINT WINAPI hook_GetACP(); +static UINT WINAPI hook_GetOEMCP(); + +static const struct hook_symbol locale_hook_syms[] = { + {.name = "GetOEMCP", + .patch = hook_GetACP}, + {.name = "GetOEMCP", + .patch = hook_GetOEMCP}, +}; + +static UINT WINAPI hook_GetACP() { + return CODEPAGE_SHIFT_JIS; +} + +static UINT WINAPI hook_GetOEMCP() { + return CODEPAGE_SHIFT_JIS; +} + + +void jbhook_util_locale_hook_init(void) +{ + hook_table_apply(NULL, "kernel32.dll", locale_hook_syms, lengthof(locale_hook_syms)); + + log_info("Inserted locale hooks"); +} diff --git a/src/main/jbhook-util/locale.h b/src/main/jbhook-util/locale.h new file mode 100644 index 0000000..543b019 --- /dev/null +++ b/src/main/jbhook-util/locale.h @@ -0,0 +1,6 @@ +#ifndef JBHOOK_LOCALE_H +#define JBHOOK_LOCALE_H + +void jbhook_util_locale_hook_init(void); + +#endif diff --git a/src/main/jbhook-util/mixer.c b/src/main/jbhook-util/mixer.c new file mode 100644 index 0000000..692a6d9 --- /dev/null +++ b/src/main/jbhook-util/mixer.c @@ -0,0 +1,79 @@ +#define LOG_MODULE "jbhook-mixer" + +#include +#include + +#include "hook/table.h" + +#include "util/defs.h" +#include "util/log.h" + +MMRESULT STDCALL hook_mixerGetLineControlsA(HMIXEROBJ hmxobj, LPMIXERLINECONTROLSA pmxlc, DWORD fdwControls); +MMRESULT STDCALL hook_mixerGetDevCapsA(UINT_PTR uMxId, LPMIXERCAPSA pmxcaps, UINT cbmxcaps); +MMRESULT STDCALL hook_mixerOpen(LPHMIXER phmx, UINT uMxId, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen); +MMRESULT STDCALL hook_mixerSetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails); +MMRESULT STDCALL hook_mixerGetControlDetailsA(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails); +MMRESULT STDCALL hook_mixerClose(HMIXER hmx); +MMRESULT STDCALL hook_mixerGetLineInfoA(HMIXEROBJ hmxobj, LPMIXERLINEA pmxl, DWORD fdwInfo); + +static const struct hook_symbol mixer_hook_syms[] = { + {.name = "mixerGetLineControlsA", + .patch = hook_mixerGetLineControlsA}, + {.name = "mixerGetDevCapsA", + .patch = hook_mixerGetDevCapsA}, + {.name = "mixerOpen", + .patch = hook_mixerOpen}, + {.name = "mixerSetControlDetails", + .patch = hook_mixerSetControlDetails}, + {.name = "mixerGetControlDetailsA", + .patch = hook_mixerGetControlDetailsA}, + {.name = "mixerClose", + .patch = hook_mixerClose}, + {.name = "mixerGetLineInfoA", + .patch = hook_mixerGetLineInfoA}, +}; + +/* + Some of these functions return values which are used as pointer offsets into + memory, but that doesn't matter because the game never *modifies* the + pointed-to value, only passes it to the other mixer functions. So it's safe + to not set any of the returning data. +*/ + +MMRESULT STDCALL hook_mixerOpen(LPHMIXER phmx, UINT uMxId, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen) { + *(DWORD*)phmx = 1234; // any non-zero value is fine + + return MMSYSERR_NOERROR; +} + +MMRESULT STDCALL hook_mixerClose(HMIXER hmx) { + return MMSYSERR_NOERROR; +} + +MMRESULT STDCALL hook_mixerGetLineControlsA(HMIXEROBJ hmxobj, LPMIXERLINECONTROLSA pmxlc, DWORD fdwControls) { + return MMSYSERR_NOERROR; +} + +MMRESULT STDCALL hook_mixerGetDevCapsA(UINT_PTR uMxId, LPMIXERCAPSA pmxcaps, UINT cbmxcaps) { + return MMSYSERR_NOERROR; +} + +MMRESULT STDCALL hook_mixerGetControlDetailsA(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) { + return MMSYSERR_NOERROR; +} + +MMRESULT STDCALL hook_mixerGetLineInfoA(HMIXEROBJ hmxobj, LPMIXERLINEA pmxl, DWORD fdwInfo) { + return MMSYSERR_NOERROR; +} + +MMRESULT STDCALL hook_mixerSetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) { + return MMSYSERR_NOERROR; +} + + +void jbhook_util_mixer_hook_init(void) +{ + hook_table_apply(NULL, "winmm.dll", mixer_hook_syms, lengthof(mixer_hook_syms)); + + log_info("Inserted mixer hooks"); +} diff --git a/src/main/jbhook-util/mixer.h b/src/main/jbhook-util/mixer.h new file mode 100644 index 0000000..b66d26f --- /dev/null +++ b/src/main/jbhook-util/mixer.h @@ -0,0 +1,11 @@ +#ifndef JBHOOK_MIXER_H +#define JBHOOK_MIXER_H + +/** + * Hook some mixer related functions and stub out attempts to change the volume. + * In addition to being annoying, this can fail on Vista+ on some outputs, + * despite not actually preventing sound from playing. + */ +void jbhook_util_mixer_hook_init(void); + +#endif diff --git a/src/main/jbhook-util/p3io.c b/src/main/jbhook-util/p3io.c new file mode 100644 index 0000000..95c8b92 --- /dev/null +++ b/src/main/jbhook-util/p3io.c @@ -0,0 +1,206 @@ +#include + +#include +#include + +#include "bemanitools/jbio.h" + +#include "jbhook-util/p3io.h" + +#include "p3ioemu/emu.h" +#include "p3ioemu/uart.h" + +#include "security/rp-sign-key.h" +#include "security/rp3.h" + +#include "util/log.h" + +static HRESULT jbhook_p3io_read_jamma(void *ctx, uint32_t *state); +static HRESULT jbhook_p3io_get_roundplug( + void *ctx, uint8_t plug_id, uint8_t *rom, uint8_t *eeprom); +static HRESULT jbhook_p3io_set_outputs(void *ctx, uint32_t state); + +/* + 0:0 b13 + 0:1 - + 0:2 b15 + 0:3 - + 0:4 test + 0:5 coin + 0:6 service + 0:7 - + + 1:0 - + 1:1 b4 + 1:2 b8 + 1:3 b12 + 1:4 b16 + 1:5 b3 + 1:6 b7 + 1:7 b11 + + 2:0 - + 2:1 b2 + 2:2 b6 + 2:3 b10 + 2:4 b14 + 2:5 b1 + 2:6 b5 + 2:7 b9 + + 3:0 - + 3:1 - + 3:2 - + 3:3 - + 3:4 - + 3:5 - + 3:6 - + 3:7 - +*/ +static const uint32_t jbhook_p3io_panel_mappings[] = { + (1 << 21), + (1 << 17), + (1 << 13), + (1 << 9), + (1 << 22), + (1 << 18), + (1 << 14), + (1 << 10), + (1 << 23), + (1 << 19), + (1 << 15), + (1 << 11), + (1 << 0), + (1 << 20), + (1 << 2), + (1 << 12), +}; + +static const uint32_t jbhook_p3io_sys_button_mappings[] = { + (1 << 4), + (1 << 6), + (1 << 5), +}; + +static struct security_mcode jbhook_p3io_mcode; +static struct security_id jbhook_p3io_pcbid; +static struct security_id jbhook_p3io_eamid; + +static const struct p3io_ops p3io_ddr_ops = { + .read_jamma = jbhook_p3io_read_jamma, + .get_roundplug = jbhook_p3io_get_roundplug, + .set_outputs = jbhook_p3io_set_outputs, +}; + +void jbhook_util_p3io_init( + const struct security_mcode *mcode, + const struct security_id *pcbid, + const struct security_id *eamid) +{ + memcpy(&jbhook_p3io_mcode, mcode, sizeof(struct security_mcode)); + memcpy(&jbhook_p3io_pcbid, pcbid, sizeof(struct security_id)); + memcpy(&jbhook_p3io_eamid, eamid, sizeof(struct security_id)); + + p3io_emu_init(&p3io_ddr_ops, NULL); +} + +void jbhook_util_p3io_fini(void) +{ + p3io_emu_fini(); +} + +static HRESULT jbhook_p3io_read_jamma(void *ctx, uint32_t *state) +{ + uint16_t panels; + uint8_t buttons; + + log_assert(state != NULL); + + *state = 0; + + if (!jb_io_read_inputs()) { + log_warning("Reading inputs from jbio failed"); + return E_FAIL; + } + + panels = jb_io_get_panel_inputs(); + buttons = jb_io_get_sys_inputs(); + + for (uint8_t i = 0; i < 16; i++) { + // panels are active-low + if ((panels & (1 << i)) == 0) { + *state |= jbhook_p3io_panel_mappings[i]; + } + } + + for (uint8_t i = 0; i < 2; i++) { + // sys buttons are active-high + if (buttons & (1 << i)) { + *state |= jbhook_p3io_sys_button_mappings[i]; + } + } + + return S_OK; +} + +static HRESULT jbhook_p3io_get_roundplug( + void *ctx, uint8_t plug_id, uint8_t *rom, uint8_t *eeprom) +{ + struct security_rp3_eeprom eeprom_out; + + if (plug_id == 0) { + /* black */ + memcpy(rom, jbhook_p3io_pcbid.id, sizeof(jbhook_p3io_pcbid.id)); + security_rp3_generate_signed_eeprom_data( + SECURITY_RP_UTIL_RP_TYPE_BLACK, + &security_rp_sign_key_black_gfdmv4, + &jbhook_p3io_mcode, + &jbhook_p3io_pcbid, + &eeprom_out); + } else { + /* white */ + memcpy(rom, jbhook_p3io_eamid.id, sizeof(jbhook_p3io_eamid.id)); + security_rp3_generate_signed_eeprom_data( + SECURITY_RP_UTIL_RP_TYPE_WHITE, + &security_rp_sign_key_white_eamuse, + &security_mcode_eamuse, + &jbhook_p3io_eamid, + &eeprom_out); + } + + memcpy(eeprom, &eeprom_out, sizeof(struct security_rp3_eeprom)); + + return S_OK; +} + +static HRESULT jbhook_p3io_set_outputs(void *ctx, uint32_t state) { + uint8_t p3io_panel = (state & 0x00FF00) >> 8; + uint8_t p3io_coinblocker = (state & 0xFF0000) >> 16; + + enum jb_io_panel_mode panel_mode; + + switch(p3io_panel) { + case 5: + panel_mode = JB_IO_PANEL_MODE_TOP_LEFT; + break; + case 4: + panel_mode = JB_IO_PANEL_MODE_TOP_RIGHT; + break; + case 6: + panel_mode = JB_IO_PANEL_MODE_BOTTOM_RIGHT; + break; + case 7: + panel_mode = JB_IO_PANEL_MODE_BOTTOM_LEFT; + break; + default: + panel_mode = JB_IO_PANEL_MODE_ALL; + break; + } + + jb_io_set_panel_mode(panel_mode); + + // 0x40 has been seen to unblock, no other values observed + jb_io_set_coin_blocker(p3io_coinblocker == 0x00); + + return S_OK; +} diff --git a/src/main/jbhook1/p3io.h b/src/main/jbhook-util/p3io.h similarity index 79% rename from src/main/jbhook1/p3io.h rename to src/main/jbhook-util/p3io.h index 3838969..152dbb2 100644 --- a/src/main/jbhook1/p3io.h +++ b/src/main/jbhook-util/p3io.h @@ -9,13 +9,13 @@ #include "security/mcode.h" /** - * Initialize the jbhook1 specific p3io emulation backend. + * Initialize the jb01-04 specific p3io emulation backend. * * @param mcode Mcode of the target game to run. Required for dongle emulation. * @param pcbid PCBDID * @param eamid EAMID */ -void jbhook1_p3io_init( +void jbhook_util_p3io_init( const struct security_mcode *mcode, const struct security_id *pcbid, const struct security_id *eamid); @@ -23,6 +23,6 @@ void jbhook1_p3io_init( /** * Shutdown the p3io emulation backend. */ -void jbhook1_p3io_fini(void); +void jbhook_util_p3io_fini(void); #endif diff --git a/src/main/jbhook/io.c b/src/main/jbhook-util/p4io.c similarity index 95% rename from src/main/jbhook/io.c rename to src/main/jbhook-util/p4io.c index dafdbe9..ee0d950 100644 --- a/src/main/jbhook/io.c +++ b/src/main/jbhook-util/p4io.c @@ -6,7 +6,7 @@ #include "imports/avs.h" -#include "jbhook/io.h" +#include "jbhook-util/p4io.h" #include "p4io/cmd.h" @@ -20,7 +20,7 @@ static uint32_t jbhook_command_handle( void *resp, uint32_t resp_max_len); -static const struct p4ioemu_device_msg_hook jbhook_io_msg = { +static const struct p4ioemu_device_msg_hook jbhook_p4io_msg = { .jamma2_read = jbhook_io_jamma2_read, .command_handle = jbhook_command_handle, .roundplug_read_id = NULL, @@ -181,7 +181,7 @@ static uint32_t jbhook_command_handle( } } -const struct p4ioemu_device_msg_hook *jbhook_io_init(void) +const struct p4ioemu_device_msg_hook *jbhook_p4io_init(void) { - return &jbhook_io_msg; + return &jbhook_p4io_msg; } diff --git a/src/main/jbhook/io.h b/src/main/jbhook-util/p4io.h similarity index 50% rename from src/main/jbhook/io.h rename to src/main/jbhook-util/p4io.h index 83e93f7..32091cf 100644 --- a/src/main/jbhook/io.h +++ b/src/main/jbhook-util/p4io.h @@ -3,6 +3,6 @@ #include "p4ioemu/device.h" -const struct p4ioemu_device_msg_hook *jbhook_io_init(void); +const struct p4ioemu_device_msg_hook *jbhook_p4io_init(void); -#endif \ No newline at end of file +#endif diff --git a/src/main/jbhook-util/security.h b/src/main/jbhook-util/security.h new file mode 100644 index 0000000..12b3651 --- /dev/null +++ b/src/main/jbhook-util/security.h @@ -0,0 +1,15 @@ +#ifndef JBHOOK_UTIL_SECURITY_H +#define JBHOOK_UTIL_SECURITY_H + +#include "security/mcode.h" + +static const struct security_mcode jbhook_util_security_default_mcode = { + .header = SECURITY_MCODE_HEADER, + .unkn = SECURITY_MCODE_UNKN_C, + .game = SECURITY_MCODE_GAME_JB_1, + .region = SECURITY_MCODE_REGION_JAPAN, + .cabinet = SECURITY_MCODE_CABINET_A, + .revision = SECURITY_MCODE_REVISION_B, +}; + +#endif diff --git a/src/main/jbhook/Module.mk b/src/main/jbhook/Module.mk deleted file mode 100644 index ef8c79e..0000000 --- a/src/main/jbhook/Module.mk +++ /dev/null @@ -1,25 +0,0 @@ -avsdlls += jbhook - -deplibs_jbhook := \ - avs \ - -ldflags_jbhook := \ - -lws2_32 \ - -liphlpapi \ - -libs_jbhook := \ - acioemu \ - eamio \ - jbio \ - p4ioemu \ - hook \ - hooklib \ - util \ - -src_jbhook := \ - acio.c \ - dllmain.c \ - eamuse.c \ - gfx.c \ - options.c \ - io.c diff --git a/src/main/jbhook/acio.c b/src/main/jbhook/acio.c deleted file mode 100644 index e3eb26a..0000000 --- a/src/main/jbhook/acio.c +++ /dev/null @@ -1,98 +0,0 @@ -// clang-format off -// Don't format because the order is important here -#include -#include -#include -#include -// clang-format on - -#include -#include -#include -#include - -#include "acioemu/addr.h" -#include "acioemu/emu.h" -#include "acioemu/h44b.h" -#include "acioemu/iccb.h" - -#include "hook/iohook.h" - -#include "jbhook/acio.h" - -#include "imports/avs.h" - -#include "util/defs.h" -#include "util/hex.h" -#include "util/iobuf.h" -#include "util/log.h" -#include "util/str.h" - -static struct ac_io_emu ac_io_emu; -static struct ac_io_emu_iccb ac_io_emu_iccb; -static struct ac_io_emu_h44b ac_io_emu_h44b; - -void ac_io_port_init(void) -{ - ac_io_emu_init(&ac_io_emu, L"COM2"); - ac_io_emu_iccb_init(&ac_io_emu_iccb, &ac_io_emu, 0); - ac_io_emu_h44b_init(&ac_io_emu_h44b, &ac_io_emu, 1); -} - -void ac_io_port_fini(void) -{ - ac_io_emu_fini(&ac_io_emu); -} - -HRESULT -ac_io_port_dispatch_irp(struct irp *irp) -{ - const struct ac_io_message *msg; - HRESULT hr; - - log_assert(irp != NULL); - - if (!ac_io_emu_match_irp(&ac_io_emu, irp)) { - return iohook_invoke_next(irp); - } - - for (;;) { - hr = ac_io_emu_dispatch_irp(&ac_io_emu, irp); - - if (hr != S_OK) { - return hr; - } - - msg = ac_io_emu_request_peek(&ac_io_emu); - - switch (msg->addr) { - case 0: - ac_io_emu_cmd_assign_addrs(&ac_io_emu, msg, 2); - - break; - - case 1: - ac_io_emu_iccb_dispatch_request(&ac_io_emu_iccb, msg); - - break; - - case 2: - ac_io_emu_h44b_dispatch_request(&ac_io_emu_h44b, msg); - - break; - - case AC_IO_BROADCAST: - log_warning("Broadcast(?) message on jubeat ACIO bus?"); - - break; - - default: - log_warning( - "ACIO message on unhandled bus address: %d", msg->addr); - - break; - } - - ac_io_emu_request_pop(&ac_io_emu); - } -} diff --git a/src/main/jbhook/acio.h b/src/main/jbhook/acio.h deleted file mode 100644 index c12fd37..0000000 --- a/src/main/jbhook/acio.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef JBHOOK_ACIO_H -#define JBHOOK_ACIO_H - -void ac_io_port_init(void); -void ac_io_port_fini(void); -HRESULT ac_io_port_dispatch_irp(struct irp *irp); - -#endif diff --git a/src/main/jbhook/eamuse.c b/src/main/jbhook/eamuse.c deleted file mode 100644 index 429c473..0000000 --- a/src/main/jbhook/eamuse.c +++ /dev/null @@ -1,67 +0,0 @@ -#define LOG_MODULE "eamuse-hook" - -#include -#include -#include - -#include -#include -#include - -#include "hook/table.h" - -#include "util/defs.h" -#include "util/log.h" -#include "util/str.h" - -static const char *jbhook_eamuse_konami_url = "eamuse.konami."; - -static int(STDCALL *real_getaddrinfo)( - PCSTR pNodeName, - PCSTR pServiceName, - const ADDRINFOA *pHints, - PADDRINFOA *ppResult); - -static int STDCALL my_getaddrinfo( - PCSTR pNodeName, - PCSTR pServiceName, - const ADDRINFOA *pHints, - PADDRINFOA *ppResult); - -static const struct hook_symbol eamuse_hook_syms[] = { - { - .name = "getaddrinfo", - .ordinal = 176, - .patch = my_getaddrinfo, - .link = (void **) &real_getaddrinfo, - }, -}; - -static int STDCALL my_getaddrinfo( - PCSTR pNodeName, - PCSTR pServiceName, - const ADDRINFOA *pHints, - PADDRINFOA *ppResult) -{ - log_misc("my_getaddrinfo: %s, %s", pNodeName, pServiceName); - - /* resolve eamuse.konami.fun/com to 127.0.0.1 to avoid lag spikes every - 150 seconds which might happen in-game as well */ - if (!strncmp( - pNodeName, - jbhook_eamuse_konami_url, - strlen(jbhook_eamuse_konami_url))) { - log_info("Resolve konami.eamuse.XXX -> localhost"); - pNodeName = "localhost"; - } - - return real_getaddrinfo(pNodeName, pServiceName, pHints, ppResult); -} - -void jbhook_eamuse_hook_init(void) -{ - hook_table_apply( - NULL, "ws2_32.dll", eamuse_hook_syms, lengthof(eamuse_hook_syms)); - - log_info("Inserted eamuse hooks"); -} diff --git a/src/main/jbhook/eamuse.h b/src/main/jbhook/eamuse.h deleted file mode 100644 index 5f4707e..0000000 --- a/src/main/jbhook/eamuse.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef JBHOOK_EAMUSE_H -#define JBHOOK_EAMUSE_H - -void jbhook_eamuse_hook_init(void); - -#endif diff --git a/src/main/jbhook/gfx.c b/src/main/jbhook/gfx.c deleted file mode 100644 index 270d947..0000000 --- a/src/main/jbhook/gfx.c +++ /dev/null @@ -1,83 +0,0 @@ -#define LOG_MODULE "jbhook-gfx" - -#include - -#include -#include -#include -#include - -#include "hook/com-proxy.h" -#include "hook/table.h" - -#include "jbhook/gfx.h" - -#include "util/defs.h" -#include "util/log.h" -#include "util/str.h" -#include "util/time.h" - -static DWORD STDCALL my_GetGlyphOutline( - HDC hdc, - UINT uChar, - UINT uFormat, - LPGLYPHMETRICS lpgm, - DWORD cbBuffer, - LPVOID lpvBuffer, - const MAT2 *lpmat2); - -static DWORD(STDCALL *real_GetGlyphOutline)( - HDC hdc, - UINT uChar, - UINT uFormat, - LPGLYPHMETRICS lpgm, - DWORD cbBuffer, - LPVOID lpvBuffer, - const MAT2 *lpmat2); - -static const struct hook_symbol gfx_hook_syms[] = { - {.name = "GetGlyphOutlineA", - .patch = my_GetGlyphOutline, - .link = (void **) &real_GetGlyphOutline}, - { - .name = "IsDBCSLeadByteEx", - .patch = my_GetGlyphOutline, // !?? - .link = (void **) &real_GetGlyphOutline // !?? - }, -}; - -static DWORD STDCALL my_GetGlyphOutline( - HDC hdc, - UINT uChar, - UINT uFormat, - LPGLYPHMETRICS lpgm, - DWORD cbBuffer, - LPVOID lpvBuffer, - const MAT2 *lpmat2) -{ - if (IsDBCSLeadByteEx(CP_ACP, uChar & 0xFF)) { - log_warning("!!!!!!!!"); - - char tmp[2]; - - tmp[0] = uChar & 0xFF; - tmp[1] = (uChar >> 8) & 0xFF; - - MultiByteToWideChar( - CP_ACP, MB_USEGLYPHCHARS, tmp, 2, lpvBuffer, cbBuffer); - } - - return real_GetGlyphOutline( - hdc, uChar, uFormat, lpgm, cbBuffer, lpvBuffer, lpmat2); -} - -void gfx_hook_init(void) -{ - hook_table_apply(NULL, "gdi32.dll", gfx_hook_syms, lengthof(gfx_hook_syms)); - - log_info("Inserted gfx hooks"); -} - -void gfx_set_windowed(bool framed) -{ -} diff --git a/src/main/jbhook1/Module.mk b/src/main/jbhook1/Module.mk index d76ab6e..f598045 100644 --- a/src/main/jbhook1/Module.mk +++ b/src/main/jbhook1/Module.mk @@ -1,17 +1,21 @@ avsdlls += jbhook1 +imps += glhelper deplibs_jbhook1 := \ avs \ + glhelper \ ldflags_jbhook1 := \ -lws2_32 \ -liphlpapi \ + -lopengl32 \ libs_jbhook1 := \ acioemu \ cconfig \ eamio \ jbio \ + jbhook-util \ p3ioemu \ p3io \ hook \ @@ -20,11 +24,9 @@ libs_jbhook1 := \ util \ src_jbhook1 := \ - acio.c \ avs-boot.c \ config-gfx.c \ config-eamuse.c \ config-security.c \ dllmain.c \ log-gftools.c \ - p3io.c \ diff --git a/src/main/jbhook1/acio.h b/src/main/jbhook1/acio.h deleted file mode 100644 index efbf7e0..0000000 --- a/src/main/jbhook1/acio.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef JBHOOK1_ACIO_H -#define JBHOOK1_ACIO_H - -#include "hook/iohook.h" - -/** - * Initialize the ACIO backend for jubeat. - */ -void ac_io_port_init(void); - -/** - * Shutdown the ACIO backend. - */ -void ac_io_port_fini(void); - -/** - * ACIO backend dispatch irp function. This needs to be hooked up to the iohook - * module in order to receive system calls to dispatch for emulation. - */ -HRESULT ac_io_port_dispatch_irp(struct irp *irp); - -#endif diff --git a/src/main/jbhook1/config-gfx.c b/src/main/jbhook1/config-gfx.c index cc426f2..5215659 100644 --- a/src/main/jbhook1/config-gfx.c +++ b/src/main/jbhook1/config-gfx.c @@ -7,8 +7,10 @@ #include "util/log.h" #define JBHOOK1_CONFIG_GFX_WINDOWED_KEY "gfx.windowed" +#define JBHOOK1_CONFIG_GFX_VERTICAL_KEY "gfx.vertical" #define JBHOOK1_CONFIG_GFX_DEFAULT_WINDOWED_VALUE false +#define JBHOOK1_CONFIG_GFX_DEFAULT_VERTICAL_VALUE true void jbhook1_config_gfx_init(struct cconfig *config) { @@ -17,6 +19,11 @@ void jbhook1_config_gfx_init(struct cconfig *config) JBHOOK1_CONFIG_GFX_WINDOWED_KEY, JBHOOK1_CONFIG_GFX_DEFAULT_WINDOWED_VALUE, "Run the game windowed"); + cconfig_util_set_bool( + config, + JBHOOK1_CONFIG_GFX_VERTICAL_KEY, + JBHOOK1_CONFIG_GFX_DEFAULT_VERTICAL_VALUE, + "Adjust the rotation of the game window so it runs vertically"); } void jbhook1_config_gfx_get( @@ -33,4 +40,15 @@ void jbhook1_config_gfx_get( JBHOOK1_CONFIG_GFX_WINDOWED_KEY, JBHOOK1_CONFIG_GFX_DEFAULT_WINDOWED_VALUE); } + if (!cconfig_util_get_bool( + config, + JBHOOK1_CONFIG_GFX_VERTICAL_KEY, + &config_gfx->vertical, + JBHOOK1_CONFIG_GFX_DEFAULT_VERTICAL_VALUE)) { + log_warning( + "Invalid value for key '%s' specified, fallback " + "to default '%d'", + JBHOOK1_CONFIG_GFX_VERTICAL_KEY, + JBHOOK1_CONFIG_GFX_DEFAULT_VERTICAL_VALUE); + } } diff --git a/src/main/jbhook1/config-gfx.h b/src/main/jbhook1/config-gfx.h index 73b27a8..e39aece 100644 --- a/src/main/jbhook1/config-gfx.h +++ b/src/main/jbhook1/config-gfx.h @@ -8,6 +8,7 @@ */ struct jbhook1_config_gfx { bool windowed; + bool vertical; }; /** @@ -27,4 +28,4 @@ void jbhook1_config_gfx_init(struct cconfig *config); void jbhook1_config_gfx_get( struct jbhook1_config_gfx *config_gfx, struct cconfig *config); -#endif \ No newline at end of file +#endif diff --git a/src/main/jbhook1/config-security.c b/src/main/jbhook1/config-security.c index 6e0123e..5d13447 100644 --- a/src/main/jbhook1/config-security.c +++ b/src/main/jbhook1/config-security.c @@ -4,6 +4,8 @@ #include "jbhook1/config-security.h" +#include "jbhook-util/security.h" + #include "security/mcode.h" #include "util/log.h" @@ -12,16 +14,7 @@ #define JBHOOK1_CONFIG_SECURITY_MCODE_KEY "security.mcode" #define JBHOOK1_CONFIG_SECURITY_DEFAULT_MCODE_VALUE \ - jbhook1_config_security_default_mcode - -static const struct security_mcode jbhook1_config_security_default_mcode = { - .header = SECURITY_MCODE_HEADER, - .unkn = SECURITY_MCODE_UNKN_C, - .game = SECURITY_MCODE_GAME_JB_1, - .region = SECURITY_MCODE_REGION_JAPAN, - .cabinet = SECURITY_MCODE_CABINET_A, - .revision = SECURITY_MCODE_REVISION_B, -}; + jbhook_util_security_default_mcode void jbhook1_config_security_init(struct cconfig *config) { diff --git a/src/main/jbhook1/dllmain.c b/src/main/jbhook1/dllmain.c index 1c58893..ad44eaa 100644 --- a/src/main/jbhook1/dllmain.c +++ b/src/main/jbhook1/dllmain.c @@ -16,13 +16,17 @@ #include "hooklib/adapter.h" #include "hooklib/rs232.h" -#include "jbhook1/acio.h" #include "jbhook1/avs-boot.h" #include "jbhook1/config-eamuse.h" #include "jbhook1/config-gfx.h" #include "jbhook1/config-security.h" #include "jbhook1/log-gftools.h" -#include "jbhook1/p3io.h" + +#include "jbhook-util/acio.h" +#include "jbhook-util/eamuse.h" +#include "jbhook-util/gfx.h" +#include "jbhook-util/mixer.h" +#include "jbhook-util/p3io.h" #include "p3ioemu/devmgr.h" #include "p3ioemu/emu.h" @@ -72,6 +76,8 @@ static HWND CDECL my_mwindow_create( log_info("---------------- Begin jbhook mwindow_create ----------------"); log_info("-------------------------------------------------------------"); + jbhook_util_mixer_hook_init(); + config = cconfig_init(); jbhook1_config_gfx_init(config); @@ -101,6 +107,14 @@ static HWND CDECL my_mwindow_create( fullscreen = !config_gfx.windowed; + if(config_gfx.vertical) { + DWORD tmp = window_width; + window_width = window_height; + window_height = tmp; + + jbhook_util_gfx_install_vertical_hooks(); + } + log_info("Starting up jubeat IO backend"); jb_io_set_loggers( @@ -119,14 +133,16 @@ static HWND CDECL my_mwindow_create( log_fatal("Initializing card reader backend failed"); } + jbhook_util_eamuse_hook_init(); + iohook_push_handler(p3io_emu_dispatch_irp); - iohook_push_handler(ac_io_port_dispatch_irp); + iohook_push_handler(jbhook_util_ac_io_port_dispatch_irp); rs232_hook_init(); - ac_io_port_init(); + jbhook_util_ac_io_port_init(L"COM1"); p3io_setupapi_insert_hooks(NULL); - jbhook1_p3io_init( + jbhook_util_p3io_init( &config_security.mcode, &config_eamuse.pcbid, &config_eamuse.eamid); log_info("-------------------------------------------------------------"); diff --git a/src/main/jbhook1/p3io.c b/src/main/jbhook1/p3io.c deleted file mode 100644 index 612732e..0000000 --- a/src/main/jbhook1/p3io.c +++ /dev/null @@ -1,171 +0,0 @@ -#include - -#include -#include - -#include "bemanitools/jbio.h" - -#include "jbhook1/p3io.h" - -#include "p3ioemu/emu.h" -#include "p3ioemu/uart.h" - -#include "security/rp-sign-key.h" -#include "security/rp3.h" - -#include "util/log.h" - -static HRESULT jbhook1_p3io_read_jamma(void *ctx, uint32_t *state); -static HRESULT jbhook1_p3io_get_roundplug( - void *ctx, uint8_t plug_id, uint8_t *rom, uint8_t *eeprom); - -/* - 0:0 b13 - 0:1 - - 0:2 b15 - 0:3 - - 0:4 test - 0:5 coin - 0:6 service - 0:7 - - - 1:0 - - 1:1 b4 - 1:2 b8 - 1:3 b12 - 1:4 b16 - 1:5 b3 - 1:6 b7 - 1:7 b11 - - 2:0 - - 2:1 b2 - 2:2 b6 - 2:3 b10 - 2:4 b14 - 2:5 b1 - 2:6 b5 - 2:7 b9 - - 3:0 - - 3:1 - - 3:2 - - 3:3 - - 3:4 - - 3:5 - - 3:6 - - 3:7 - -*/ -static const uint32_t jbhook1_p3io_panel_mappings[] = { - (1 << 21), - (1 << 17), - (1 << 13), - (1 << 9), - (1 << 22), - (1 << 18), - (1 << 14), - (1 << 10), - (1 << 23), - (1 << 19), - (1 << 15), - (1 << 11), - (1 << 0), - (1 << 20), - (1 << 2), - (1 << 12), -}; - -static const uint32_t jbhook1_p3io_sys_button_mappings[] = { - (1 << 4), - (1 << 6), - (1 << 5), -}; - -static struct security_mcode jbhook1_p3io_mcode; -static struct security_id jbhook1_p3io_pcbid; -static struct security_id jbhook1_p3io_eamid; - -static const struct p3io_ops p3io_ddr_ops = { - .read_jamma = jbhook1_p3io_read_jamma, - .get_roundplug = jbhook1_p3io_get_roundplug, -}; - -void jbhook1_p3io_init( - const struct security_mcode *mcode, - const struct security_id *pcbid, - const struct security_id *eamid) -{ - memcpy(&jbhook1_p3io_mcode, mcode, sizeof(struct security_mcode)); - memcpy(&jbhook1_p3io_pcbid, pcbid, sizeof(struct security_id)); - memcpy(&jbhook1_p3io_eamid, eamid, sizeof(struct security_id)); - - p3io_emu_init(&p3io_ddr_ops, NULL); -} - -void jbhook1_p3io_finit(void) -{ - p3io_emu_fini(); -} - -static HRESULT jbhook1_p3io_read_jamma(void *ctx, uint32_t *state) -{ - uint16_t panels; - uint8_t buttons; - - log_assert(state != NULL); - - /* lower three bytes low active, highest byte high active */ - *state = 0; - - if (!jb_io_read_inputs()) { - log_warning("Reading inputs from jbio failed"); - return E_FAIL; - } - - panels = jb_io_get_panel_inputs(); - buttons = jb_io_get_sys_inputs(); - - for (uint8_t i = 0; i < 16; i++) { - if (panels & (1 << i)) { - *state |= jbhook1_p3io_panel_mappings[i]; - } - } - - for (uint8_t i = 0; i < 2; i++) { - if (buttons & (1 << i)) { - *state |= jbhook1_p3io_sys_button_mappings[i]; - } - } - - return S_OK; -} - -static HRESULT jbhook1_p3io_get_roundplug( - void *ctx, uint8_t plug_id, uint8_t *rom, uint8_t *eeprom) -{ - struct security_rp3_eeprom eeprom_out; - - if (plug_id == 0) { - /* black */ - memcpy(rom, jbhook1_p3io_pcbid.id, sizeof(jbhook1_p3io_pcbid.id)); - security_rp3_generate_signed_eeprom_data( - SECURITY_RP_UTIL_RP_TYPE_BLACK, - &security_rp_sign_key_black_gfdmv4, - &jbhook1_p3io_mcode, - &jbhook1_p3io_pcbid, - &eeprom_out); - } else { - /* white */ - memcpy(rom, jbhook1_p3io_eamid.id, sizeof(jbhook1_p3io_eamid.id)); - security_rp3_generate_signed_eeprom_data( - SECURITY_RP_UTIL_RP_TYPE_WHITE, - &security_rp_sign_key_white_eamuse, - &security_mcode_eamuse, - &jbhook1_p3io_eamid, - &eeprom_out); - } - - memcpy(eeprom, &eeprom_out, sizeof(struct security_rp3_eeprom)); - - return S_OK; -} diff --git a/src/main/jbhook2/Module.mk b/src/main/jbhook2/Module.mk new file mode 100644 index 0000000..7961994 --- /dev/null +++ b/src/main/jbhook2/Module.mk @@ -0,0 +1,27 @@ +avsdlls += jbhook2 + +deplibs_jbhook2 := \ + avs \ + glhelper \ + +ldflags_jbhook2 := \ + -lws2_32 \ + -liphlpapi \ + -lopengl32 \ + +libs_jbhook2 := \ + acioemu \ + eamio \ + jbio \ + jbhook-util \ + p3ioemu \ + p3io \ + p4ioemu \ + hook \ + hooklib \ + security \ + util \ + +src_jbhook2 := \ + dllmain.c \ + options.c diff --git a/src/main/jbhook2/dllmain.c b/src/main/jbhook2/dllmain.c new file mode 100644 index 0000000..75a74a9 --- /dev/null +++ b/src/main/jbhook2/dllmain.c @@ -0,0 +1,209 @@ +#include + +#include +#include +#include +#include + +#include "bemanitools/eamio.h" +#include "bemanitools/jbio.h" + +#include "hook/iohook.h" +#include "hook/table.h" + +#include "hooklib/adapter.h" +#include "hooklib/app.h" +#include "hooklib/rs232.h" +#include "hooklib/setupapi.h" + +#include "imports/avs.h" + +#include "jbhook2/options.h" + +#include "jbhook-util/acio.h" +#include "jbhook-util/eamuse.h" +#include "jbhook-util/gfx.h" +#include "jbhook-util/p3io.h" +#include "jbhook-util/security.h" + +#include "p3ioemu/devmgr.h" +#include "p3ioemu/emu.h" + +#include "p4ioemu/device.h" +#include "p4ioemu/setupapi.h" + +#include "security/id.h" + +#include "util/defs.h" +#include "util/log.h" +#include "util/thread.h" + +static struct options options; + +static bool my_dll_entry_init(char *sidcode, struct property_node *param) +{ + jbhook_util_gfx_install_vertical_hooks(); + + bool eam_io_ok; + bool jb_io_ok; + + eam_io_ok = false; + jb_io_ok = false; + + log_info("--- Begin jbhook dll_entry_init ---"); + + if (!options.disable_p3ioemu) { + log_assert(sidcode != NULL); + // pcbid and eamid are only used here for sec check, the ones used for + // network access are taken from ea3-config.xml + jbhook_util_p3io_init( + &jbhook_util_security_default_mcode, + &security_id_default, &security_id_default); + + log_info("Starting up jubeat IO backend"); + + jb_io_set_loggers( + log_impl_misc, log_impl_info, log_impl_warning, log_impl_fatal); + + jb_io_ok = + jb_io_init(avs_thread_create, avs_thread_join, avs_thread_destroy); + + if (!jb_io_ok) { + goto fail; + } + } + + if (!options.disable_cardemu) { + jbhook_util_ac_io_port_init(L"COM1"); + + log_info("Starting up card reader backend"); + + eam_io_set_loggers( + log_impl_misc, log_impl_info, log_impl_warning, log_impl_fatal); + + eam_io_ok = + eam_io_init(avs_thread_create, avs_thread_join, avs_thread_destroy); + + if (!eam_io_ok) { + goto fail; + } + } + + log_info("--- End jbhook dll_entry_init ---"); + + bool ret = app_hook_invoke_init(sidcode, param); + + return ret; + +fail: + if (eam_io_ok) { + eam_io_fini(); + } + + if (jb_io_ok) { + jb_io_fini(); + } + + return false; +} + +static bool my_dll_entry_main(void) +{ + bool result; + + result = app_hook_invoke_main(); + + log_info("Shutting down card reader backend"); + eam_io_fini(); + + log_info("Shutting down Jubeat IO backend"); + jb_io_fini(); + + if (!options.disable_cardemu) { + jbhook_util_ac_io_port_fini(); + } + + if (!options.disable_p3ioemu) { + jbhook_util_p3io_fini(); + } + + options_fini(&options); + + return result; +} + +static HWND CDECL +my_mwindow_create(HINSTANCE, void *, const char *, DWORD, DWORD, BOOL); +static HWND(CDECL *real_mwindow_create)( + HINSTANCE, void *, const char *, DWORD, DWORD, BOOL); + +static const struct hook_symbol init_hook_syms[] = { + { + .name = "mwindow_create", + .patch = my_mwindow_create, + .link = (void **) &real_mwindow_create, + }, +}; + +static HWND CDECL my_mwindow_create( + HINSTANCE hinstance, + void *callback, + const char *window_title, + DWORD window_width, + DWORD window_height, + BOOL fullscreen) +{ + log_info("-------------------------------------------------------------"); + log_info("---------------- Begin jbhook mwindow_create ----------------"); + log_info("-------------------------------------------------------------"); + + DWORD tmp = window_width; + window_width = window_height; + window_height = tmp; + + return real_mwindow_create( + hinstance, + callback, + window_title, + window_width, + window_height, + 0); +} + +BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx) +{ + if (reason != DLL_PROCESS_ATTACH) { + return TRUE; + } + + log_to_external( + log_body_misc, log_body_info, log_body_warning, log_body_fatal); + + options_init_from_cmdline(&options); + + hook_table_apply( + NULL, "mwindow.dll", init_hook_syms, lengthof(init_hook_syms)); + + app_hook_init(my_dll_entry_init, my_dll_entry_main); + + iohook_push_handler(p3io_emu_dispatch_irp); + + iohook_push_handler(jbhook_util_ac_io_port_dispatch_irp); + + if (!options.disable_adapteremu) { + adapter_hook_init(); + } + + if (!options.disable_cardemu) { + rs232_hook_init(); + } + + if (!options.disable_p3ioemu) { + p3io_setupapi_insert_hooks(NULL); + } + + jbhook_util_gfx_hook_init(); + jbhook_util_eamuse_hook_init(); + + return TRUE; +} diff --git a/src/main/jbhook/jbhook.def b/src/main/jbhook2/jbhook2.def similarity index 68% rename from src/main/jbhook/jbhook.def rename to src/main/jbhook2/jbhook2.def index 2bb53a1..cccec24 100644 --- a/src/main/jbhook/jbhook.def +++ b/src/main/jbhook2/jbhook2.def @@ -1,4 +1,4 @@ -LIBRARY jbhook +LIBRARY jbhook2 EXPORTS DllMain@12 @1 NONAME diff --git a/src/main/jbhook2/options.c b/src/main/jbhook2/options.c new file mode 100644 index 0000000..4af7a6d --- /dev/null +++ b/src/main/jbhook2/options.c @@ -0,0 +1,108 @@ +#include "jbhook2/options.h" + +#include + +#include +#include +#include + +#include "util/cmdline.h" +#include "util/defs.h" +#include "util/hex.h" +#include "util/log.h" +#include "util/str.h" + +void options_init_from_cmdline(struct options *options) +{ + int argc; + char **argv; + bool ok; + + args_recover(&argc, &argv); + + options_init(options); + + ok = options_read_cmdline(options, argc, (const char **) argv); + + args_free(argc, argv); + + if (!ok) { + exit(0); + } +} + +void options_init(struct options *options) +{ + options->windowed = false; + options->window_framed = false; + options->disable_p3ioemu = false; + options->disable_cardemu = false; + options->disable_adapteremu = false; +} + +bool options_read_cmdline(struct options *options, int argc, const char **argv) +{ + int i; + + for (i = 0; i < argc; i++) { + if (argv[i][0] != '-') { + continue; + } + + switch (argv[i][1]) { + case 'h': { + options_print_usage(); + return false; + } + + case 'w': { + options->windowed = true; + break; + } + + case 'f': { + options->window_framed = true; + break; + } + + case 'a': { + options->disable_adapteremu = true; + break; + } + + case 'c': { + options->disable_cardemu = true; + break; + } + + case 'p': { + options->disable_p3ioemu = true; + break; + } + } + } + + return true; +} + +void options_print_usage(void) +{ + OutputDebugStringA("jbhook for jubeat, build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY( + GITREV) "\n" + "Usage: launcher.exe -K jbhook2.dll [game exec] \n" + "\n" + " The following options can be specified after the game exec path:\n" + "\n" + " -h Print this usage message\n" + " -w Run the game windowed\n" + " -f Run the game in a framed window (needs -w option)\n" + " -a Disable adapter hook\n" + " -c Disable card emulation (e.g. when running on a " + "real cab)\n" + " -p Disable p3io emulation (e.g. when running on a " + "real cab)\n"); +} + +void options_fini(struct options *options) +{ +} diff --git a/src/main/jbhook2/options.h b/src/main/jbhook2/options.h new file mode 100644 index 0000000..de4d259 --- /dev/null +++ b/src/main/jbhook2/options.h @@ -0,0 +1,22 @@ +#ifndef JBHOOK_OPTIONS_H +#define JBHOOK_OPTIONS_H + +#include +#include + +struct options { + bool windowed; + bool window_framed; + bool disable_p3ioemu; + bool disable_cardemu; + bool disable_adapteremu; +}; + +void options_init_from_cmdline(struct options *options); + +void options_init(struct options *options); +bool options_read_cmdline(struct options *options, int argc, const char **argv); +void options_print_usage(void); +void options_fini(struct options *options); + +#endif diff --git a/src/main/jbhook3/Module.mk b/src/main/jbhook3/Module.mk new file mode 100644 index 0000000..1f504e8 --- /dev/null +++ b/src/main/jbhook3/Module.mk @@ -0,0 +1,25 @@ +avsdlls += jbhook3 + +deplibs_jbhook3 := \ + avs \ + +ldflags_jbhook3 := \ + -lws2_32 \ + -liphlpapi \ + +libs_jbhook3 := \ + acioemu \ + eamio \ + jbio \ + jbhook-util \ + p3ioemu \ + p3io \ + p4ioemu \ + hook \ + hooklib \ + security \ + util \ + +src_jbhook3 := \ + dllmain.c \ + options.c diff --git a/src/main/jbhook/dllmain.c b/src/main/jbhook3/dllmain.c similarity index 81% rename from src/main/jbhook/dllmain.c rename to src/main/jbhook3/dllmain.c index 0136bf2..a210fd0 100644 --- a/src/main/jbhook/dllmain.c +++ b/src/main/jbhook3/dllmain.c @@ -17,15 +17,19 @@ #include "imports/avs.h" -#include "jbhook/acio.h" -#include "jbhook/eamuse.h" -#include "jbhook/gfx.h" -#include "jbhook/io.h" -#include "jbhook/options.h" +#include "jbhook3/options.h" + +#include "jbhook-util/acio.h" +#include "jbhook-util/eamuse.h" +#include "jbhook-util/gfx.h" +#include "jbhook-util/p4io.h" +#include "jbhook-util/security.h" #include "p4ioemu/device.h" #include "p4ioemu/setupapi.h" +#include "security/id.h" + #include "util/defs.h" #include "util/log.h" #include "util/thread.h" @@ -43,7 +47,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) log_info("--- Begin jbhook dll_entry_init ---"); iohook_push_handler(p4ioemu_dispatch_irp); - iohook_push_handler(ac_io_port_dispatch_irp); + iohook_push_handler(jbhook_util_ac_io_port_dispatch_irp); if (!options.disable_p4ioemu) { log_info("Starting up jubeat IO backend"); @@ -59,7 +63,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) } hook_setupapi_init(&p4ioemu_setupapi_data); - p4ioemu_init(jbhook_io_init()); + p4ioemu_init(jbhook_p4io_init()); } if (!options.disable_cardemu) { @@ -76,12 +80,15 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) } rs232_hook_init(); - ac_io_port_init(); + jbhook_util_ac_io_port_init(L"COM2"); + jbhook_util_ac_io_set_iccb(); } log_info("--- End jbhook dll_entry_init ---"); - return app_hook_invoke_init(sidcode, param); + bool ret = app_hook_invoke_init(sidcode, param); + + return ret; fail: if (eam_io_ok) { @@ -108,7 +115,7 @@ static bool my_dll_entry_main(void) jb_io_fini(); if (!options.disable_cardemu) { - ac_io_port_fini(); + jbhook_util_ac_io_port_fini(); } if (!options.disable_p4ioemu) { @@ -137,8 +144,8 @@ BOOL WINAPI DllMain(HMODULE mod, DWORD reason, void *ctx) adapter_hook_init(); } - gfx_hook_init(); - jbhook_eamuse_hook_init(); + jbhook_util_gfx_hook_init(); + jbhook_util_eamuse_hook_init(); return TRUE; } diff --git a/src/main/jbhook3/jbhook3.def b/src/main/jbhook3/jbhook3.def new file mode 100644 index 0000000..a1b99b7 --- /dev/null +++ b/src/main/jbhook3/jbhook3.def @@ -0,0 +1,4 @@ +LIBRARY jbhook3 + +EXPORTS + DllMain@12 @1 NONAME diff --git a/src/main/jbhook/options.c b/src/main/jbhook3/options.c similarity index 96% rename from src/main/jbhook/options.c rename to src/main/jbhook3/options.c index e384480..ff11021 100644 --- a/src/main/jbhook/options.c +++ b/src/main/jbhook3/options.c @@ -1,4 +1,4 @@ -#include "jbhook/options.h" +#include "jbhook3/options.h" #include @@ -89,7 +89,7 @@ void options_print_usage(void) { OutputDebugStringA("jbhook for jubeat, build " __DATE__ " " __TIME__ ", gitrev " STRINGIFY( GITREV) "\n" - "Usage: launcher.exe -K jbhook.dll [game exec] \n" + "Usage: launcher.exe -K jbhook3.dll [game exec] \n" "\n" " The following options can be specified after the game exec path:\n" "\n" diff --git a/src/main/jbhook/options.h b/src/main/jbhook3/options.h similarity index 100% rename from src/main/jbhook/options.h rename to src/main/jbhook3/options.h diff --git a/src/main/p3io/ioctl.h b/src/main/p3io/ioctl.h index b420fd1..39a9dbd 100644 --- a/src/main/p3io/ioctl.h +++ b/src/main/p3io/ioctl.h @@ -2,7 +2,9 @@ #define P3IO_IOCTL_H enum { - P3IO_IOCTL_READ_JAMMA = 0x00222068, + P3IO_IOCTL_GET_VERSION = 0x00222004, + P3IO_IOCTL_READ_JAMMA = 0x00222068, + P3IO_IOCTL_RESET_PIPE = 0x00222098, }; #endif diff --git a/src/main/p3ioemu/emu.c b/src/main/p3ioemu/emu.c index 62e74c7..49bf276 100644 --- a/src/main/p3ioemu/emu.c +++ b/src/main/p3ioemu/emu.c @@ -150,10 +150,34 @@ static HRESULT p3io_emu_handle_ioctl(struct irp *irp) uint32_t pad; HRESULT hr; - if (irp->ioctl != P3IO_IOCTL_READ_JAMMA) { - log_warning("Unknown ioctl: %x", irp->ioctl); + switch (irp->ioctl) { + case P3IO_IOCTL_GET_VERSION: { + const char dev_name[] = "bemanitools p3ioemu"; - return E_NOTIMPL; + if (irp->read.nbytes < strlen(dev_name)) { + log_fatal("Device name string does not fit into buffer"); + } + + memset(irp->read.bytes, 0, irp->read.nbytes); + memcpy(irp->read.bytes, dev_name, strlen(dev_name)); + irp->read.pos = strlen(dev_name); + + return S_OK; + } + + case P3IO_IOCTL_RESET_PIPE: + // does not expect a response + irp->read.pos = 0; + return S_OK; + + case P3IO_IOCTL_READ_JAMMA: + // handle it below + break; + + default: + log_warning("Unknown ioctl %08x", irp->ioctl); + + return E_NOTIMPL; } if (irp->read.nbytes < sizeof(uint32_t)) { diff --git a/src/main/security/id.c b/src/main/security/id.c index e9fc593..3dd1134 100644 --- a/src/main/security/id.c +++ b/src/main/security/id.c @@ -137,6 +137,19 @@ bool security_id_verify(const struct security_id *id) { log_assert(id); - return id->header == SECURITY_ID_HEADER && - id->checksum == security_id_checksum_buffer(id->id); + if(id->header != SECURITY_ID_HEADER) { + log_warning("PCBID header needs to be %02X but was %02X", + SECURITY_ID_HEADER, id->header); + return false; + } + + uint8_t check = id->checksum; + uint8_t need = security_id_checksum_buffer(id->id); + + if(check != need) { + log_warning("PCBID checksum should be %02X got %02X", need, check); + return false; + } + + return true; }