mirror of
https://gitea.tendokyu.moe/TeamTofuShop/segatools.git
synced 2026-09-26 00:07:59 +03:00
Requires https://gitea.tendokyu.moe/TeamTofuShop/capnhook/pulls/8 This adds the following: 1. Fixes `am::abaas::FileSearchSuite::isAvailableAbsolutePath: Line259 ERROR: folder is unavailable (Y:\SDEM\log\\SDFU)` by hooking `DeviceIoControl` with `FSCTL_SET_REPARSE_POINT`. Sega decided to use the most bizzare way possible of creating symbolic links. These are created in the AbaaS log directory inside SDEM and point to the appdata directories for the sub-games. Magic numbers have been taken from amdaemon decompilation. That whole API is very sparsely documented on the Microsoft side. 2. Fixes distribution server settings not applying. Unlike most other games, the daemon config files do not have dipswitch filters in them. Instead the distribution setting is determined by running `hwvalue.exe` twice and checking it's exit code. This has been added to `launch.bat` and requires the linked addition for inject. 3. Implemented `get_opbtns` and added extra buttons for dinput. * `get_opbtns` existed but was never implemented. Added the ability to bind dinput buttons for test/service. * DirectInput is weird. The controller I'm using is sending directional keys as buttons rather than a D-Pad, so I was unable to bind it. These extra directional buttons can be bound in addition to the bindings that exist for a D-Pad. 4. Fixes audio in Rolling Gunner by setting the CWD to the root of the C:\ drive before starting a game. lol. lmao even. 5. Add a `DefineDosDevice` for Y:\ to fix Blazblue crashing They hardcoded the damn path to appdata instead of retrieving it from the apm.dll... Reviewed-on: https://gitea.tendokyu.moe/TeamTofuShop/segatools/pulls/123 Co-authored-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Co-committed-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com>
194 lines
5.0 KiB
C
194 lines
5.0 KiB
C
#include "board/aime-dll.h"
|
|
|
|
#include "config.h"
|
|
#include "mount.h"
|
|
|
|
#include <assert.h>
|
|
#include <pathcch.h>
|
|
#include <shlwapi.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "hooklib/path.h"
|
|
#include "hook/procaddr.h"
|
|
#include "hook/table.h"
|
|
|
|
#include "util/dprintf.h"
|
|
|
|
/* API hooks */
|
|
|
|
static bool hook_ApmSys_mountVhd(const wchar_t* vhdOriginalPath, const wchar_t* vhdPatchPath, char mountDriveLetter);
|
|
static bool hook_ApmSys_mountFscrypt(const wchar_t* fscryptImagePath, const wchar_t* mountFolderPath, const wchar_t* subGameId);
|
|
static bool hook_ApmSys_unmountVhd(char mountDriveLetter);
|
|
static bool hook_ApmSys_unmountFscrypt(const wchar_t* mountFolderPath);
|
|
|
|
static const struct hook_symbol mount_hooks[] = {
|
|
{
|
|
.name = "ApmSys_mountVhd",
|
|
.patch = hook_ApmSys_mountVhd,
|
|
.ordinal = 2,
|
|
},
|
|
{
|
|
.name = "ApmSys_unmountVhd",
|
|
.patch = hook_ApmSys_unmountVhd,
|
|
.ordinal = 4,
|
|
},
|
|
{
|
|
.name = "ApmSys_mountFscrypt",
|
|
.patch = hook_ApmSys_mountFscrypt,
|
|
.ordinal = 1,
|
|
},
|
|
{
|
|
.name = "ApmSys_unmountFscrypt",
|
|
.patch = hook_ApmSys_unmountFscrypt,
|
|
.ordinal = 3,
|
|
},
|
|
};
|
|
|
|
static struct vfs_config* vcfg;
|
|
static struct mount_config* mcfg;
|
|
|
|
static wchar_t game_directory[MAX_PATH];
|
|
|
|
void mount_hook_init(struct vfs_config* vfs_cfg, struct mount_config* mount_cfg) {
|
|
|
|
assert(vfs_cfg != NULL);
|
|
assert(mount_cfg != NULL);
|
|
|
|
vcfg = vfs_cfg;
|
|
mcfg = mount_cfg;
|
|
|
|
if (!mcfg->enable) {
|
|
return;
|
|
}
|
|
|
|
mount_hook_apply_hooks(NULL);
|
|
|
|
dprintf("Mount: hook enabled\n");
|
|
}
|
|
|
|
void mount_hook_apply_hooks(HMODULE target) {
|
|
proc_addr_table_push(
|
|
target,
|
|
"apmmount.dll",
|
|
mount_hooks,
|
|
_countof(mount_hooks));
|
|
}
|
|
|
|
|
|
bool hook_ApmSys_mountFscrypt(const wchar_t* fscryptImagePath, const wchar_t* mountFolderPath, const wchar_t* subGameId) {
|
|
dprintf("Mount: Mount FsCrypt (%ls, %ls, %ls)\n", fscryptImagePath, mountFolderPath, subGameId);
|
|
|
|
wcscpy_s(game_directory, MAX_PATH, fscryptImagePath);
|
|
PathCchRemoveFileSpec(game_directory, MAX_PATH);
|
|
wnsprintfW(game_directory, MAX_PATH, L"%s\\App", game_directory);
|
|
|
|
wchar_t *trans;
|
|
BOOL ok;
|
|
|
|
ok = path_transform_w(&trans, game_directory);
|
|
|
|
if (!ok) {
|
|
dprintf("Mount: Path transformation error\n");
|
|
return 1;
|
|
}
|
|
|
|
if (trans != NULL) {
|
|
wcscpy_s(game_directory, MAX_PATH, trans);
|
|
}
|
|
|
|
free(trans);
|
|
|
|
dprintf("Mount: Target Path: %ls\n", game_directory);
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool hook_ApmSys_mountVhd(const wchar_t* vhdOriginalPath, const wchar_t* vhdPatchPath, char mountDriveLetter) {
|
|
dprintf("Mount: Mount VHD (%ls, %ls, %c)\n", vhdOriginalPath, vhdPatchPath, mountDriveLetter);
|
|
|
|
if (game_directory[0] == '\0') {
|
|
dprintf("Mount: Target directory is unset!\n");
|
|
return 1;
|
|
}
|
|
|
|
// Game drive
|
|
wchar_t device[3];
|
|
device[0] = (unsigned char) mountDriveLetter;
|
|
device[1] = ':';
|
|
device[2] = '\0';
|
|
|
|
dprintf("Mount: Mapping %ls to %ls\n", device, game_directory);
|
|
if (!DefineDosDeviceW(0, device, game_directory)) {
|
|
dprintf("DefineDosDevice failed: %lx\n", GetLastError());
|
|
return 1;
|
|
}
|
|
|
|
// APM root drive
|
|
device[0] = 'X';
|
|
|
|
wchar_t self_directory[MAX_PATH];
|
|
GetCurrentDirectoryW(MAX_PATH, self_directory);
|
|
|
|
dprintf("Mount: Mapping %ls to %ls\n", device, self_directory);
|
|
if (!DefineDosDeviceW(0, device, self_directory)) {
|
|
dprintf("DefineDosDevice failed: %lx\n", GetLastError());
|
|
return 1;
|
|
}
|
|
|
|
// Appdata drive
|
|
device[0] = 'Y';
|
|
|
|
dprintf("Mount: Mapping %ls to %ls\n", device, vcfg->appdata);
|
|
if (!DefineDosDeviceW(0, device, vcfg->appdata)) {
|
|
dprintf("DefineDosDevice failed: %lx\n", GetLastError());
|
|
return 1;
|
|
}
|
|
|
|
if (mcfg->delay) {
|
|
Sleep(1500);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
bool hook_ApmSys_unmountVhd(char mountDriveLetter) {
|
|
dprintf("Mount: Unmount VHD (%c)\n", mountDriveLetter);
|
|
|
|
char device[3];
|
|
device[0] = mountDriveLetter;
|
|
device[1] = ':';
|
|
device[2] = '\0';
|
|
|
|
// Game drive
|
|
if (!DefineDosDevice(DDD_REMOVE_DEFINITION, device, NULL)) {
|
|
dprintf("DefineDosDevice failed: %lx\n", GetLastError());
|
|
return 1;
|
|
}
|
|
|
|
// APM root drive
|
|
device[0] = 'X';
|
|
if (!DefineDosDevice(DDD_REMOVE_DEFINITION, device, NULL)) {
|
|
dprintf("DefineDosDevice failed: %lx\n", GetLastError());
|
|
return 1;
|
|
}
|
|
|
|
// Appdata drive
|
|
device[0] = 'Y';
|
|
if (!DefineDosDevice(DDD_REMOVE_DEFINITION, device, NULL)) {
|
|
dprintf("DefineDosDevice failed: %lx\n", GetLastError());
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CALLBACK UnmountApmDrives(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) {
|
|
hook_ApmSys_unmountVhd('W');
|
|
hook_ApmSys_unmountVhd('X');
|
|
hook_ApmSys_unmountVhd('Y');
|
|
}
|
|
|
|
bool hook_ApmSys_unmountFscrypt(const wchar_t* mountFolderPath) {
|
|
dprintf("Mount: Unmount FsCrypt (%ls)\n", mountFolderPath);
|
|
memset(game_directory, 0, MAX_PATH * sizeof(wchar_t));
|
|
return 0;
|
|
} |