WIP: Kemono Friends support / 32-bit CHC300 support #36

Draft
Haruka wants to merge 12 commits from Haruka/segatools:kemonofr into develop
Contributor

This PR adds support for Kemono Friends 3: Planet Tours.

The only thing that does not work is LED support (however, implemented), as the game seems to be loading that DLL twice/threaded which causes an instant crash on appling the file hooks. (See the FIXME comment)

Notable design choices or changes:

  • For all chcusb_/fwdlusb_ functions, I've added __stdcall (and a few __fastcall) calling conventions. This is only necessary for 32-bit DLLs. 64-bit builds ignore these statements. I am not aware of any other 32-bit games that use a printer that have support currently which would need testing in that regard. (most likely not breaking)
  • A few functions have different signatures on the CHC300, they have fixed duplicates added named "chcusb_*_300".
  • On getPrinterInfo, tag 8, this game requires a return value of 1 after setPrintStandby (possibly breaking?)
  • setIcctable is called with null, so a null check has been added.
  • CHC300 does not have an exitCard method, so status and awaitingCardExit are reset upon another call of setPrintStandby (most likely not breaking)
  • This game in particular does NOT call imageformat, so a function printer_set_dimensions was added to set the image size from the hook directly.
  • This game checks if it should run with amdaemon by calling GetVersionExW and checking for Windows 6.2/6.3 via Unity. Since not all Unity games will require this, unity_hook_init now has an optional parameter of type unity_hook_callback_func that is called with the DLL handle and name when a DLL is loaded in Unity to apply hooks that aren't needed in all cases, DLLs or games.
  • The VFS hooks for amdaemon_api.dll had a __thiscall declaration added, otherwise the game would randomly crash upon startup.

https://puu.sh/KeKge/f5b59939c9.png

This PR adds support for Kemono Friends 3: Planet Tours. The only thing that does not work is LED support (however, implemented), as the game seems to be loading that DLL twice/threaded which causes an instant crash on appling the file hooks. (See the FIXME comment) Notable design choices or changes: * For all chcusb_*/fwdlusb_* functions, I've added __stdcall (and a few __fastcall) calling conventions. This is only necessary for 32-bit DLLs. 64-bit builds ignore these statements. I am not aware of any other 32-bit games that use a printer that have support currently which would need testing in that regard. (most likely not breaking) * A few functions have different signatures on the CHC300, they have fixed duplicates added named "chcusb_*_300". * On getPrinterInfo, tag 8, this game requires a return value of 1 after setPrintStandby (possibly breaking?) * setIcctable is called with null, so a null check has been added. * CHC300 does not have an exitCard method, so status and awaitingCardExit are reset upon another call of setPrintStandby (most likely not breaking) * This game in particular does NOT call imageformat, so a function printer_set_dimensions was added to set the image size from the hook directly. * This game checks if it should run with amdaemon by calling GetVersionExW and checking for Windows 6.2/6.3 via Unity. Since not all Unity games will require this, unity_hook_init now has an optional parameter of type unity_hook_callback_func that is called with the DLL handle and name when a DLL is loaded in Unity to apply hooks that aren't needed in all cases, DLLs or games. * The VFS hooks for amdaemon_api.dll had a __thiscall declaration added, otherwise the game would randomly crash upon startup. ![https://puu.sh/KeKge/f5b59939c9.png](https://puu.sh/KeKge/f5b59939c9.png)
Haruka added 1 commit 2024-09-11 11:45:59 +00:00
Dniel97 requested changes 2024-09-12 05:27:30 +00:00
Dismissed
Dniel97 left a comment
Owner

Hey,

thanks again for your awesome PR. I just reviewed it and noticed seome improvements and some missing parts. Please make sure to add kemono also to the Package.mk file otherwise it won't get published inside the segatools.zip.

So the only QoL features which are still missing are:

  • 1: Proper hook for the username env variable
  • 2: Working LED support with documentation of the layout

Not sure if 2. is easily doable as I also struggled with that on my local kemono version, which is not that polsihed so I would prefer your PR ;)

Also don't forget to update the readme.md to list support for Kemono Friends 3 ;)

Hey, thanks again for your awesome PR. I just reviewed it and noticed seome improvements and some missing parts. Please make sure to add kemono also to the `Package.mk` file otherwise it won't get published inside the segatools.zip. So the only QoL features which are still missing are: - 1: Proper hook for the username env variable - 2: Working LED support with documentation of the layout Not sure if 2. is easily doable as I also struggled with that on my local kemono version, which is not that polsihed so I would prefer your PR ;) Also don't forget to update the readme.md to list support for Kemono Friends 3 ;)
@ -0,0 +54,4 @@
; 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.172.0
Owner

The real keychip subnet for this game is 192.168.179.0.

The real keychip subnet for this game is `192.168.179.0`.
Author
Contributor

woops, copy-paste

woops, copy-paste
Haruka marked this conversation as resolved
@ -0,0 +2,4 @@
pushd %~dp0
start "AM Daemon" /min cmd /C timeout 10 ^& inject_x64 -d -k kemonohook_x64.dll ../amdaemon.exe -f -c ../config.json"
Owner

Ok that is a really cursed way of avoiding AM Daemon from closing due to a missing hook :D

Ok that is a really cursed way of avoiding AM Daemon from closing due to a missing hook :D
Author
Contributor

oh my god lmao I totally forgot to update that, yeah that was while the hook was broken

oh my god lmao I totally forgot to update that, yeah that was while the hook was broken
Owner

It should be kemonohook_x64.dll and also please remove -f as it is not needed.

On the other hand, is it needed to actually excecute the game inside the folder UnityApp? I would prefer to set all scripts so that you can launch the game from the normal folder instead of UnityApp.

@echo off

pushd %~dp0

start "AM Daemon" /min inject_x64 -d -k kemonohook_x64.dll amdaemon.exe -c config.json
inject_x86 -d -k kemonohook_x86.dll UnityApp\Parade -screen-fullscreen 0 -popupwindow -screen-width 720 -screen-height 1280 -silent-crashes

taskkill /f /im amdaemon.exe > nul 2>&1

echo.
echo Game processes have terminated
pause
It should be `kemonohook_x64.dll` and also please remove `-f` as it is not needed. On the other hand, is it needed to actually excecute the game inside the folder `UnityApp`? I would prefer to set all scripts so that you can launch the game from the normal folder instead of `UnityApp`. ```c @echo off pushd %~dp0 start "AM Daemon" /min inject_x64 -d -k kemonohook_x64.dll amdaemon.exe -c config.json inject_x86 -d -k kemonohook_x86.dll UnityApp\Parade -screen-fullscreen 0 -popupwindow -screen-width 720 -screen-height 1280 -silent-crashes taskkill /f /im amdaemon.exe > nul 2>&1 echo. echo Game processes have terminated pause ```
Author
Contributor

Fixed. I had issues getting BepInEx to run from the root folder, but eventually that resolved by placing BepInEx inside the root folder instead of UnityApp, so I added a note to the ini file about that.

Fixed. I had issues getting BepInEx to run from the root folder, but eventually that resolved by placing BepInEx inside the root folder instead of UnityApp, so I added a note to the ini file about that.
Haruka marked this conversation as resolved
@ -76,3 +64,1 @@
int fwdlusb_ReleaseThread(uint16_t *rResult);
int fwdlusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount);
int fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult);
__stdcall int fwdlusb_open(uint16_t *rResult);
Owner

I would actually prefer WINAPI instead of __stdcall, looks nicer to read ;)

I would actually prefer `WINAPI` instead of `__stdcall`, looks nicer to read ;)
Author
Contributor

Fixed

Fixed
Owner

Ah and it should be int WINAPI instead of WINAPI int ;)

Ah and it should be `int WINAPI` instead of `WINAPI int` ;)
Haruka marked this conversation as resolved
@ -0,0 +13,4 @@
assert(cfg != NULL);
assert(filename != NULL);
cfg->vk_test = GetPrivateProfileIntW(L"io3", L"test", '1', filename);
Owner

Maybe also change this to 0x71, 0x72 and 0x73 (F1, F2, F3) so it matches all other segatools games. (And you won't accidentally enter test menu while typing numbers lol)

Maybe also change this to 0x71, 0x72 and 0x73 (F1, F2, F3) so it matches all other segatools games. (And you won't accidentally enter test menu while typing numbers lol)
Author
Contributor

The reason I intentionally changed this is that the Configuration Manager for BepInEx takes F1, so I got really annoyed always getting kicked out of the session to test menu if I just wanted to flip a mod setting.

I have absolutely no issues with reverting for consistency sake

The reason I intentionally changed this is that the Configuration Manager for BepInEx takes F1, so I got really annoyed always getting kicked out of the session to test menu if I just wanted to flip a mod setting. I have absolutely no issues with reverting for consistency sake
Dniel97 marked this conversation as resolved
@ -0,0 +50,4 @@
need to persist beyond the lifetime of the process.
Minimum API version: 0x0100 */
void kemono_io_jvs_read_coin_counter(uint16_t *out);
Owner

You missed the deinition of

kemono_io_led_init
kemono_io_led_set_colors
You missed the deinition of ``` kemono_io_led_init kemono_io_led_set_colors ```
Author
Contributor

fixed

fixed
Haruka marked this conversation as resolved
@ -145,2 +149,4 @@
clock_hook_insert_hooks(result);
proc_addr_insert_hooks(result);
if (hook_load_callback != NULL){
hook_load_callback(result, target_module);
Owner

That's a nice idea! I like it!

That's a nice idea! I like it!
Haruka marked this conversation as resolved
Dniel97 requested changes 2024-09-12 05:27:42 +00:00
Haruka added 3 commits 2024-09-12 10:42:32 +00:00
Owner

Awesome, you still missed the part where you have to add the zip file to the segatools.zip file:

Package.mk Line 266 in 96bdacfa7c
$(BUILD_DIR_ZIP)/fgo.zip \
;)

Awesome, you still missed the part where you have to add the zip file to the `segatools.zip` file: https://gitea.tendokyu.moe/Haruka/segatools/src/commit/96bdacfa7c598e1bb4c7e22bec6ac433ddee3660/Package.mk#L266 ;)
Haruka added 4 commits 2024-09-12 11:25:48 +00:00
Author
Contributor

Hey,

thanks again for your awesome PR. I just reviewed it and noticed seome improvements and some missing parts. Please make sure to add kemono also to the Package.mk file otherwise it won't get published inside the segatools.zip.

So the only QoL features which are still missing are:

  • 1: Proper hook for the username env variable
  • 2: Working LED support with documentation of the layout

Not sure if 2. is easily doable as I also struggled with that on my local kemono version, which is not that polsihed so I would prefer your PR ;)

Also don't forget to update the readme.md to list support for Kemono Friends 3 ;)

I actually fixed LEDs by just pre-loading the SerialPortAPI.dll lmao

https://puu.sh/KeO6G/2575d64b8e.png

The LED mappings have been added, plus another function for the button LEDs that I missed.

About the environment variable, sure can just hook the entirety of GetEnvironmentVariableA/W but since they're per process anyways I would personally think it's fine but /shrug

Rest is done.

> Hey, > > thanks again for your awesome PR. I just reviewed it and noticed seome improvements and some missing parts. Please make sure to add kemono also to the `Package.mk` file otherwise it won't get published inside the segatools.zip. > > So the only QoL features which are still missing are: > - 1: Proper hook for the username env variable > - 2: Working LED support with documentation of the layout > > Not sure if 2. is easily doable as I also struggled with that on my local kemono version, which is not that polsihed so I would prefer your PR ;) > > Also don't forget to update the readme.md to list support for Kemono Friends 3 ;) I actually fixed LEDs by just pre-loading the SerialPortAPI.dll lmao ![https://puu.sh/KeO6G/2575d64b8e.png](https://puu.sh/KeO6G/2575d64b8e.png) The LED mappings have been added, plus another function for the button LEDs that I missed. About the environment variable, sure can just hook the entirety of GetEnvironmentVariableA/W but since they're per process anyways I would personally think it's fine but /shrug Rest is done.
Author
Contributor

Also, I am not sure if 3eef5dd209 is breaking, because that was definetly wrong, compared with the official definition, it's supposed to be a ushort:

					[FixedBuffer(typeof(byte), 8)]
					public LedBoardCtrl.Packet.Report.Data.BoardInfo.<bdno>__FixedBuffer14 bdno;

					public byte lf;

					[FixedBuffer(typeof(byte), 5)]
					public LedBoardCtrl.Packet.Report.Data.BoardInfo.<chipno>__FixedBuffer15 chipno;

					public byte endcode;

					public byte rev;

					public ushort sz_rxbuf;
Also, I am not sure if 3eef5dd209 is breaking, because that was definetly wrong, compared with the official definition, it's supposed to be a ushort: ``` [FixedBuffer(typeof(byte), 8)] public LedBoardCtrl.Packet.Report.Data.BoardInfo.<bdno>__FixedBuffer14 bdno; public byte lf; [FixedBuffer(typeof(byte), 5)] public LedBoardCtrl.Packet.Report.Data.BoardInfo.<chipno>__FixedBuffer15 chipno; public byte endcode; public byte rev; public ushort sz_rxbuf; ```
Author
Contributor

Awesome, you still missed the part where you have to add the zip file to the segatools.zip file:

Package.mk Line 266 in 96bdacfa7c
$(BUILD_DIR_ZIP)/fgo.zip \
;)

woops, my bad, can't really test this, fixed

> Awesome, you still missed the part where you have to add the zip file to the `segatools.zip` file: https://gitea.tendokyu.moe/Haruka/segatools/src/commit/96bdacfa7c598e1bb4c7e22bec6ac433ddee3660/Package.mk#L266 ;) woops, my bad, can't really test this, fixed
Haruka added 1 commit 2024-09-12 11:29:27 +00:00
Dniel97 requested changes 2024-09-12 18:46:43 +00:00
@ -0,0 +124,4 @@
[io3]
; Test button virtual-key code. Default is the 1 key.
test=0x31
Owner

Would it be possible to set them as F1, F2 and F3 as well?

Would it be possible to set them as F1, F2 and F3 as well?
Author
Contributor

Hmm, wasn't that fine w.r.t. this?
#36 (comment)

Hmm, wasn't that fine w.r.t. this? https://gitea.tendokyu.moe/Dniel97/segatools/pulls/36#issuecomment-2106
Owner

Oh nice I was able to figure out how to correctly read the firmware version in game but I noticed that no FWDL function is being hooked, normally it should start updating the printer when the firmware version is 0.00:

Oh nice I was able to figure out how to correctly read the firmware version in game but I noticed that no FWDL function is being hooked, normally it should start updating the printer when the firmware version is `0.00`:
Author
Contributor

Either the data has been tampered with or SEGA disabled something via code, because in 2.02, it reads this:

private bool UpdateFirmwareProcess(ref PrinterInterface.PrnSeq inSequence, ref PrnStatus inStatus)
{
	bool flag = false;
	if (PrinterManager.WaitForExecution())
	{
		inSequence = PrinterInterface.PrnSeq.FINISH; 
		inStatus = PrnStatus.PRINTER_OK;
[...]

so the entire fwdlusb process is skipped and no functions are called to begin with.

Either the data has been tampered with or SEGA disabled something via code, because in 2.02, it reads this: ``` private bool UpdateFirmwareProcess(ref PrinterInterface.PrnSeq inSequence, ref PrnStatus inStatus) { bool flag = false; if (PrinterManager.WaitForExecution()) { inSequence = PrinterInterface.PrnSeq.FINISH; inStatus = PrnStatus.PRINTER_OK; [...] ``` so the entire fwdlusb process is skipped and no functions are called to begin with.
Haruka added 1 commit 2024-09-13 15:51:03 +00:00
Haruka added 1 commit 2024-09-16 12:30:05 +00:00
Owner

Either the data has been tampered with or SEGA disabled something via code, because in 2.02, it reads this:

private bool UpdateFirmwareProcess(ref PrinterInterface.PrnSeq inSequence, ref PrnStatus inStatus)
{
	bool flag = false;
	if (PrinterManager.WaitForExecution())
	{
		inSequence = PrinterInterface.PrnSeq.FINISH; 
		inStatus = PrnStatus.PRINTER_OK;
[...]

so the entire fwdlusb process is skipped and no functions are called to begin with.

Hmm I also see this check in my game data but still cannot figure out how to trigger the pinter update properly. Btw you have to define the number of firmwares correctly liek this:

        case 3:  // getFirmwareVersion
            if (*rLen != 0x99) *rLen = 0x99;
            if (rBuffer) {
                memset(rBuffer, 0, *rLen);
                // C300 has 4 firmwares
                // TODO: C310 and later only 3 firmwares
                rBuffer[0] = 0x04;
                // bootFirmware
                int i = 1;
                memcpy(rBuffer + i, mainFirmware, sizeof(mainFirmware));
                // mainFirmware
                i += 0x26;
                memcpy(rBuffer + i, mainFirmware, sizeof(mainFirmware));
                // printParameterTable
                i += 0x26;
                memcpy(rBuffer + i, paramFirmware, sizeof(paramFirmware));
                // dspFirmware (C300 only)
                i += 0x26;
                memcpy(rBuffer + i, dspFirmware, sizeof(dspFirmware));
> Either the data has been tampered with or SEGA disabled something via code, because in 2.02, it reads this: > > ``` > private bool UpdateFirmwareProcess(ref PrinterInterface.PrnSeq inSequence, ref PrnStatus inStatus) > { > bool flag = false; > if (PrinterManager.WaitForExecution()) > { > inSequence = PrinterInterface.PrnSeq.FINISH; > inStatus = PrnStatus.PRINTER_OK; > [...] > ``` > > so the entire fwdlusb process is skipped and no functions are called to begin with. Hmm I also see this check in my game data but still cannot figure out how to trigger the pinter update properly. Btw you have to define the number of firmwares correctly liek this: ```c case 3: // getFirmwareVersion if (*rLen != 0x99) *rLen = 0x99; if (rBuffer) { memset(rBuffer, 0, *rLen); // C300 has 4 firmwares // TODO: C310 and later only 3 firmwares rBuffer[0] = 0x04; // bootFirmware int i = 1; memcpy(rBuffer + i, mainFirmware, sizeof(mainFirmware)); // mainFirmware i += 0x26; memcpy(rBuffer + i, mainFirmware, sizeof(mainFirmware)); // printParameterTable i += 0x26; memcpy(rBuffer + i, paramFirmware, sizeof(paramFirmware)); // dspFirmware (C300 only) i += 0x26; memcpy(rBuffer + i, dspFirmware, sizeof(dspFirmware)); ```
Haruka added 1 commit 2024-09-19 11:46:57 +00:00
This pull request is marked as a work in progress.
This branch is out-of-date with the base branch

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u kemonofr:Haruka-kemonofr
git checkout Haruka-kemonofr
Sign in to join this conversation.
No reviewers
No Milestone
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: Dniel97/segatools#36
No description provided.