Compare commits

...

16 Commits

Author SHA1 Message Date
bicarus-dev 61c97ccaab net: ignore -ea if -url is set (#430)
## Link to GitHub Issue, if one exists
#345 

## Description of change
Ignore -ea if -url is provided

## Testing
2025-12-01 16:04:32 -08:00
bicarus-dev 12d6a88c60 iidx: turn off camera access by default (#428)
## Link to GitHub Issue, if one exists
For #345 
Similar idea as https://github.com/spice2x/spice2x.github.io/pull/350

## Description of change
Disable camera access by default by setting `CONNECT_CAMERA` environment
var to 0 before launching. This was one of those "required" things
people clicked on, but now it's done automatically to reduce friction
for new users.

On cab setups (i.e., running without -iidx module), cameras will remain
on, unless user overrides it.

On franken setups (partial I/O) - user will need to specify what they
want via the new option, we can't guess correctly.

## Testing
2025-11-30 16:13:34 -08:00
bicarus-dev 984b41a1ae cfg: fix combo boxes (#429)
## Link to GitHub Issue, if one exists
n/a

## Description of change
Combo boxes for options were not highlighting the currently selected
item. Also, when there were no description provided for an option, it
was still showing the empty `()` in the selected value.

## Testing
2025-11-30 01:59:25 -08:00
duel0213 d06b8bd731 mfc: fix 2025 version touch (#426)
## Link to GitHub Issue, if one exists
n/a

## Description of change
HG cabinet uses wintouch and it requires TOUCHEVENTF_PRIMARY flag in
order to accept touch inputs.
Added wintouchemu on game hook and TOUCHEVENTF_PRIMARY flag on
wintouchemu.
 
## Testing
The game boots into test menu, touch now works. (tested in I/O TEST ->
TOUCH PANEL CHECK with '-s' flag)
TDJ subscreen overlay and nostalgia seems works fine regardless added
TOUCHEVENTF_PRIMARY flag but more testing required.
2025-11-25 17:14:07 -08:00
bicarus-dev 0dad96b876 check for standalone cfg for fatal options 2025-11-23 09:36:38 -08:00
bicarus-dev def296095b reword log message to avoid confusion 2025-11-22 16:45:27 -08:00
bicarus-dev 750b1fea80 patches: disable patches tab for unity games (#425)
## Description of change
To redirect confused users why no one is developing a remote patch
server for PolCho

## Testing
checked spicecfg in working vs non-working games
2025-11-17 19:16:19 -08:00
aixxe 4c87078807 Refactor IIDX camhook texture replacement (#424)
## Link to GitHub Issue, if one exists
Fixes #393 

## Description of change
- Fixes compatibility with IIDX 33
- Adjusts the pattern scan for "hook A" to be compatible with IIDX 27
- Refactors texture replacement to use Camera::CCameraManager2, removing
the need for a second hook

Related: https://github.com/aixxe/2dxcamhook/compare/0.4.0.0...0.5.0.0

## Testing
Booted with `-iidxcamhook` on IIDX 27, 28, 29, 30, 31, 32 & 33
Confirmed both cameras were visible in I/O test, music select settings &
gameplay
2025-11-17 01:21:39 -08:00
bicarus-dev 052698afa3 rawinput: use UTF-8 for device descriptor (#422)
## Link to GitHub Issue, if one exists
n/a

## Description of change
For HID device descriptor, use the "W" version of Windows API, and make
sure UTF-8 is being used throughout since that's the only format IMGUI
supports.

Before this change, non-Latin characters would have shown up as `HID ???
?????` for a mouse, for example.

Due to the way ImGui loads fonts, only the following languages are
supported:

* Simplified Chinese
* Cyrillic
* Japanese
* Korean
* Thai
* Vietnamese

## Testing
Tested various combination of Windows UI language and non-Unicode
language.
2025-11-16 00:08:30 -08:00
bicarus-dev 9e2b04d5db troubleshooter: update link for vcredist (#423)
## Description of change
RIP abbodi1406
2025-11-16 00:07:36 -08:00
bicarus-dev 5641e06a19 iidx: fix kana input broken in subscreen when system language is not Japanese (#421)
## Link to GitHub Issue, if one exists
user-reported

## Description of change
When the system non-Unicode language is not set to Japanese, TDJ
subscreen katakana keyboard was broken (weird behavior with characters
not erasing, ending with corrupt characters, etc)

To fix this, add a hook for `IsDBCSLeadByte`. `IsDBCSLeadByte` assumes
system ACP (which may not be SHIFT_JIS). Instead, redirect bm2dx.dll to
use `IsDBCSLeadByteEx` instead with SHIFT_JIS explicitly specified as a
parameter.

Presumably the game was using IsDBCSLeadByte to manage the keyboard
typing logic.... which is weird because SDVX doesn't do the same.

## Testing
Tested iidx 31 and tried to do searches.
2025-11-10 11:35:46 -08:00
bicarus-dev 88ec6dbcee launcher: hide pcbid when -cmdoverride specified (#420)
## Link to GitHub Issue, if one exists
Fixes #419 

## Description of change
-cmdoverride caused pcbid to be logged in plain text

## Testing
2025-11-07 14:20:37 -08:00
bicarus-dev 1b614c94a7 mfc: remove log spam (#418)
## Link to GitHub Issue, if one exists
n/a

## Description of change
Remove mutex lock/unlock log spam

Are they important? Idk

## Testing
2025-11-06 17:51:39 -08:00
bicarus-dev 37c5913f69 mfc: detect 2025 version (#416)
## Link to GitHub Issue, if one exists
n/a

## Description of change
They moved some DLLs around so MFC wasn't being auto-detected, and I/O
hooks were not being performed. Fix that.

## Testing
The game boots into test menu, some i/o works, touch doesn't, not
playable yet.
2025-11-05 19:23:10 -08:00
wrigglebug 2eca668593 update readme.txt (#415)
please merge this important code
2025-11-02 23:29:48 -08:00
bicarus-dev aec1da9d16 troubleshooter: detect ea3_report_posev error (#413)
## Link to GitHub Issue, if one exists
#345 

## Description of change
When `ea3-pos: ea3_report_posev: no such node:` is detected, add a
deferred error message and guide user to the FAQ.

## Testing
Tested SDVX with the missing XML node.
2025-11-02 14:13:04 -08:00
23 changed files with 339 additions and 142 deletions
+72 -70
View File
@@ -22,35 +22,31 @@
static std::filesystem::path dll_path; static std::filesystem::path dll_path;
static HMODULE iidx_module; static HMODULE iidx_module;
static uintptr_t addr_hook_a = 0; static uintptr_t addr_hook_a = 0;
static uintptr_t addr_hook_b = 0;
static uintptr_t addr_textures = 0; static uintptr_t addr_textures = 0;
static uintptr_t addr_camera_manager = 0;
static uintptr_t addr_device_offset = 0; static uintptr_t addr_device_offset = 0;
static uintptr_t addr_afp_texture_offset = 0;
typedef void **(__fastcall *camera_hook_a_t)(PBYTE); typedef void **(__fastcall *camera_hook_a_t)(PBYTE);
typedef LPDIRECT3DTEXTURE9 (*camera_hook_b_t)(void*, int);
static camera_hook_a_t camera_hook_a_orig = nullptr; static camera_hook_a_t camera_hook_a_orig = nullptr;
static camera_hook_b_t camera_hook_b_orig = nullptr;
auto static hook_a_init = std::once_flag {}; auto static hook_a_init = std::once_flag {};
static LPDIRECT3DDEVICE9EX device; static LPDIRECT3DDEVICE9EX device;
static LPDIRECT3DTEXTURE9 *texture_a = nullptr; static LPDIRECT3DTEXTURE9 *camera_texture_a = nullptr;
static LPDIRECT3DTEXTURE9 *texture_b = nullptr; static LPDIRECT3DTEXTURE9 *camera_texture_b = nullptr;
static LPDIRECT3DTEXTURE9 *preview_texture_a = nullptr;
static LPDIRECT3DTEXTURE9 *preview_texture_b = nullptr;
struct PredefinedHook { struct PredefinedHook {
std::string pe_identifier; std::string pe_identifier;
uintptr_t hook_a; uintptr_t hook_a;
uintptr_t hook_b;
uintptr_t hook_textures; uintptr_t hook_textures;
uintptr_t hook_camera_manager;
uintptr_t hook_device_offset; uintptr_t hook_device_offset;
uintptr_t hook_afp_texture_offset;
}; };
PredefinedHook g_predefinedHooks[] = PredefinedHook g_predefinedHooks[] = {};
{
// 27 003
{ "5f713b52_6d4090", 0x005971b0, 0x005fb2c0, 0x04e49898, 0x000000d0 },
// 27 010
{ "5f713946_7f52b0", 0x006b89e0, 0x0071c950, 0x04fd08b8, 0x000000d0 },
};
const DWORD g_predefinedHooksLength = ARRAYSIZE(g_predefinedHooks); const DWORD g_predefinedHooksLength = ARRAYSIZE(g_predefinedHooks);
@@ -75,8 +71,8 @@ namespace games::iidx {
if (sscanf( if (sscanf(
s.c_str(), s.c_str(),
"%i,%i,%i,%i", "%i,%i,%i,%i,%i",
(int*)&addr_hook_a, (int*)&addr_hook_b, (int*)&addr_textures, (int*)&addr_device_offset) == 4) { (int*)&addr_hook_a, (int*)&addr_textures, (int*)&addr_camera_manager, (int*)&addr_device_offset, (int*)&addr_afp_texture_offset) == 5) {
return true; return true;
@@ -101,8 +97,8 @@ namespace games::iidx {
// there are three different ways we try to hook the camera entry points // there are three different ways we try to hook the camera entry points
// 1) user-provided override via cmd line // 1) user-provided override via cmd line
// 2) predefined offsets using PE header matching (needed for iidx27 and few others) // 2) predefined offsets using PE header matching
// 3) signature match (should work for most iidx28-31) // 3) signature match (should work for most iidx27-33)
// method 1: user provided // method 1: user provided
if (TDJ_CAMERA_OVERRIDE.has_value() && parse_cmd_params()) { if (TDJ_CAMERA_OVERRIDE.has_value() && parse_cmd_params()) {
@@ -117,10 +113,11 @@ namespace games::iidx {
for (DWORD i = 0; i < g_predefinedHooksLength; i++) { for (DWORD i = 0; i < g_predefinedHooksLength; i++) {
if (pe.compare(g_predefinedHooks[i].pe_identifier) == 0) { if (pe.compare(g_predefinedHooks[i].pe_identifier) == 0) {
log_misc("iidx:camhook", "Found predefined addresses"); log_misc("iidx:camhook", "Found predefined addresses");
addr_hook_a = g_predefinedHooks[i].hook_a; addr_hook_a = g_predefinedHooks[i].hook_a;
addr_hook_b = g_predefinedHooks[i].hook_b; addr_textures = g_predefinedHooks[i].hook_textures;
addr_textures = g_predefinedHooks[i].hook_textures; addr_camera_manager = g_predefinedHooks[i].hook_camera_manager;
addr_device_offset = g_predefinedHooks[i].hook_device_offset; addr_device_offset = g_predefinedHooks[i].hook_device_offset;
addr_afp_texture_offset = g_predefinedHooks[i].hook_afp_texture_offset;
return TRUE; return TRUE;
} }
} }
@@ -131,8 +128,8 @@ namespace games::iidx {
// --- addr_hook_a --- // --- addr_hook_a ---
uint8_t *addr_hook_a_ptr = reinterpret_cast<uint8_t *>(find_pattern( uint8_t *addr_hook_a_ptr = reinterpret_cast<uint8_t *>(find_pattern(
iidx_module, iidx_module,
"488BC4565741564883EC5048C740D8FEFFFFFF", "E800000000488B8F0000000048894D",
"XXXXXXXXXXXXXXXXXXX", "X????XXX????XXX",
0, 0)); 0, 0));
if (addr_hook_a_ptr == nullptr) { if (addr_hook_a_ptr == nullptr) {
@@ -141,24 +138,10 @@ namespace games::iidx {
return FALSE; return FALSE;
} }
addr_hook_a = (uint64_t) (addr_hook_a_ptr - (uint8_t*) iidx_module);
// addr_hook_b
uint8_t* addr_hook_b_ptr = reinterpret_cast<uint8_t *>(find_pattern(
iidx_module,
"E8000000004885C07439E8",
"X????XXXXXX",
0, 0));
if (addr_hook_b_ptr == nullptr) {
log_warning("iidx:camhook", "failed to find hook: addr_hook_b");
return FALSE;
}
// displace with the content of wildcard bytes // displace with the content of wildcard bytes
int32_t disp_b = *((int32_t *) (addr_hook_b_ptr + 1)); int32_t disp_a = *((int32_t *) (addr_hook_a_ptr + 1));
addr_hook_b = (addr_hook_b_ptr - (uint8_t*) iidx_module) + disp_b + 5; addr_hook_a = (addr_hook_a_ptr - (uint8_t*) iidx_module) + disp_a + 5;
// --- addr_textures --- // --- addr_textures ---
uint8_t* addr_textures_ptr = reinterpret_cast<uint8_t *>(find_pattern( uint8_t* addr_textures_ptr = reinterpret_cast<uint8_t *>(find_pattern(
@@ -194,6 +177,28 @@ namespace games::iidx {
addr_textures = (addr_textures_ptr - (uint8_t*) iidx_module) + disp_textures + 7; addr_textures = (addr_textures_ptr - (uint8_t*) iidx_module) + disp_textures + 7;
// --- addr_camera_manager ---
uint8_t *addr_camera_manager_ptr = reinterpret_cast<uint8_t *>(find_pattern(
iidx_module,
"E80000000033FF488B58",
"X????XXXXX",
0, 0));
if (addr_camera_manager_ptr == nullptr) {
log_warning("iidx:camhook", "failed to find hook: addr_get_camera_manager");
return FALSE;
}
// displace with the content of wildcard bytes
int32_t disp_camera_manager = *((int32_t *) (addr_camera_manager_ptr + 1));
addr_camera_manager_ptr = addr_camera_manager_ptr + disp_camera_manager + 5;
// once more to get the final address
disp_camera_manager = *((int32_t *) (addr_camera_manager_ptr + 3));
addr_camera_manager = (addr_camera_manager_ptr - (uint8_t*) iidx_module) + disp_camera_manager + 7;
// addr_device_offset // addr_device_offset
search_from = (addr_hook_a_ptr - (uint8_t*) iidx_module); search_from = (addr_hook_a_ptr - (uint8_t*) iidx_module);
uint8_t *addr_device_ptr = reinterpret_cast<uint8_t *>(find_pattern_from( uint8_t *addr_device_ptr = reinterpret_cast<uint8_t *>(find_pattern_from(
@@ -201,39 +206,47 @@ namespace games::iidx {
"488B89", "488B89",
"XXX", "XXX",
3, 0, search_from)); 3, 0, search_from));
addr_device_offset = *addr_device_ptr;
if (addr_textures_ptr == nullptr) { if (addr_device_ptr == nullptr) {
log_warning("iidx:camhook", "failed to find hook: addr_textures (part 3)"); log_warning("iidx:camhook", "failed to find hook: addr_device_ptr");
return FALSE; return FALSE;
} }
addr_device_offset = *addr_device_ptr;
// --- addr_afp_texture_offset ---
uint8_t *addr_afp_texture_ptr = reinterpret_cast<uint8_t *>(find_pattern(
iidx_module,
"488B41004885C07400488D5424",
"XXX?XXXX?XXXX",
0, 0));
if (addr_afp_texture_ptr == nullptr) {
log_warning("iidx:camhook", "failed to find hook: addr_afp_texture_offset");
return FALSE;
}
addr_afp_texture_offset = *(addr_afp_texture_ptr + 3);
return TRUE; return TRUE;
} }
static void **__fastcall camera_hook_a(PBYTE a1) { static void **__fastcall camera_hook_a(PBYTE a1) {
std::call_once(hook_a_init, [&]{ std::call_once(hook_a_init, [&]{
device = *reinterpret_cast<LPDIRECT3DDEVICE9EX*>(a1 + addr_device_offset); device = *reinterpret_cast<LPDIRECT3DDEVICE9EX*>(a1 + addr_device_offset);
auto const textures = *reinterpret_cast<LPDIRECT3DTEXTURE9**>((uint8_t*)iidx_module + addr_textures); auto const preview = *reinterpret_cast<LPDIRECT3DTEXTURE9**>((uint8_t*)iidx_module + addr_textures);
auto const manager = reinterpret_cast<Camera::CCameraManager2*>((uint8_t*)iidx_module + addr_camera_manager);
texture_a = textures; camera_texture_a = manager->cameras->a->d3d9_texture(addr_afp_texture_offset);
texture_b = textures + 2; camera_texture_b = manager->cameras->b->d3d9_texture(addr_afp_texture_offset);
preview_texture_a = preview;
preview_texture_b = preview + 2;
init_local_camera(); init_local_camera();
}); });
return camera_hook_a_orig(a1); return camera_hook_a_orig(a1);
} }
static LPDIRECT3DTEXTURE9 camera_hook_b(void* a1, int idx) {
if (idx == 0 && top_camera) {
return top_camera->GetTexture();
}
if (idx == 1 && front_camera) {
return front_camera->GetTexture();
}
return camera_hook_b_orig(a1, idx);
}
bool create_hooks() { bool create_hooks() {
auto *hook_a_ptr = reinterpret_cast<uint16_t *>( auto *hook_a_ptr = reinterpret_cast<uint16_t *>(
reinterpret_cast<intptr_t>(iidx_module) + addr_hook_a); reinterpret_cast<intptr_t>(iidx_module) + addr_hook_a);
@@ -246,17 +259,6 @@ namespace games::iidx {
return FALSE; return FALSE;
} }
auto *hook_b_ptr = reinterpret_cast<uint16_t *>(
reinterpret_cast<intptr_t>(iidx_module) + addr_hook_b);
if (!detour::trampoline(
reinterpret_cast<camera_hook_b_t>(hook_b_ptr),
camera_hook_b,
&camera_hook_b_orig)) {
log_warning("iidx:camhook", "failed to trampoline hook_b");
return FALSE;
}
return TRUE; return TRUE;
} }
@@ -443,7 +445,7 @@ namespace games::iidx {
} }
IIDXLocalCamera* add_top_camera(IMFActivate* pActivate) { IIDXLocalCamera* add_top_camera(IMFActivate* pActivate) {
auto top_camera = new IIDXLocalCamera("top", TDJ_CAMERA_PREFER_16_9, pActivate, s_pD3DManager, device, texture_a); auto top_camera = new IIDXLocalCamera("top", TDJ_CAMERA_PREFER_16_9, pActivate, s_pD3DManager, device, camera_texture_a, preview_texture_a);
if (top_camera->m_initialized) { if (top_camera->m_initialized) {
LOCAL_CAMERA_LIST.push_back(top_camera); LOCAL_CAMERA_LIST.push_back(top_camera);
} else { } else {
@@ -454,7 +456,7 @@ namespace games::iidx {
} }
IIDXLocalCamera* add_front_camera(IMFActivate* pActivate) { IIDXLocalCamera* add_front_camera(IMFActivate* pActivate) {
auto front_camera = new IIDXLocalCamera("front", TDJ_CAMERA_PREFER_16_9, pActivate, s_pD3DManager, device, texture_b); auto front_camera = new IIDXLocalCamera("front", TDJ_CAMERA_PREFER_16_9, pActivate, s_pD3DManager, device, camera_texture_b, preview_texture_b);
if (front_camera->m_initialized) { if (front_camera->m_initialized) {
LOCAL_CAMERA_LIST.push_back(front_camera); LOCAL_CAMERA_LIST.push_back(front_camera);
} else { } else {
@@ -469,8 +471,8 @@ namespace games::iidx {
if (result) { if (result) {
log_misc( log_misc(
"iidx:camhook", "iidx:camhook",
"found hooks:\n hook_a 0x{:x}\n hook_b 0x{:x}\n textures 0x{:x}\n device_offset 0x{:x}", "found hooks:\n hook_a 0x{:x}\n textures 0x{:x}\n camera_manager 0x{:x}\n device_offset 0x{:x}\n afp_texture_offset 0x{:x}",
addr_hook_a, addr_hook_b, addr_textures, addr_device_offset); addr_hook_a, addr_textures, addr_camera_manager, addr_device_offset, addr_afp_texture_offset);
result = create_hooks(); result = create_hooks();
if (result) { if (result) {
init_mf_library(); init_mf_library();
+22 -8
View File
@@ -53,7 +53,7 @@ namespace games::iidx {
// settings // settings
bool FLIP_CAMS = false; bool FLIP_CAMS = false;
bool DISABLE_CAMS = false; std::optional<bool> DISABLE_CAMS;
bool TDJ_CAMERA = false; bool TDJ_CAMERA = false;
bool TDJ_CAMERA_PREFER_16_9 = true; bool TDJ_CAMERA_PREFER_16_9 = true;
bool TDJ_MODE = false; bool TDJ_MODE = false;
@@ -334,11 +334,6 @@ namespace games::iidx {
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true; wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
wintouchemu::hook_title_ends("beatmania IIDX", "main", avs::game::DLL_INSTANCE); wintouchemu::hook_title_ends("beatmania IIDX", "main", avs::game::DLL_INSTANCE);
} }
// prevent crash on TDJ mode without correct DLL
if (!GetModuleHandle("nvcuda.dll")) {
DISABLE_CAMS = true;
}
} }
// insert BI2X hooks // insert BI2X hooks
@@ -399,7 +394,10 @@ namespace games::iidx {
"RegQueryValueExA", RegQueryValueExA_hook, avs::game::DLL_INSTANCE); "RegQueryValueExA", RegQueryValueExA_hook, avs::game::DLL_INSTANCE);
// check if cam hook should be enabled // check if cam hook should be enabled
if (!DISABLE_CAMS) { if (!DISABLE_CAMS.has_value()) {
log_fatal("iidx", "assertion failure - DISABLE_CAMS not set during attach");
}
if (!DISABLE_CAMS.value()) {
init_legacy_camera_hook(FLIP_CAMS); init_legacy_camera_hook(FLIP_CAMS);
} }
@@ -409,15 +407,31 @@ namespace games::iidx {
void IIDXGame::pre_attach() { void IIDXGame::pre_attach() {
Game::pre_attach(); Game::pre_attach();
auto options = games::get_options(eamuse_get_game());
// environment variables must be set before the DLL is loaded as the VC++ runtime copies all // environment variables must be set before the DLL is loaded as the VC++ runtime copies all
// environment variables at startup // environment variables at startup
if (SCREEN_MODE.has_value()) { if (SCREEN_MODE.has_value()) {
log_misc("iidx", "SCREEN_MODE env var set to {}", SCREEN_MODE.value().c_str());
SetEnvironmentVariable("SCREEN_MODE", SCREEN_MODE.value().c_str()); SetEnvironmentVariable("SCREEN_MODE", SCREEN_MODE.value().c_str());
} }
// check for cab camera access for the second time (first time was in launcher.cpp)
// this time, we are inside -iidx module hook, which means the user is likely NOT on a cab
// therefore, start with cams OFF by default, and allow user to forcibly override to ON
if (!games::iidx::DISABLE_CAMS.has_value()) {
games::iidx::DISABLE_CAMS = true;
if (options->at(launcher::Options::IIDXCabCamAccess).is_active() &&
options->at(launcher::Options::IIDXCabCamAccess).value_text() == "on") {
games::iidx::DISABLE_CAMS = false;
}
if (games::iidx::DISABLE_CAMS.value()) {
log_misc("iidx", "CONNECT_CAMERA env var set to 0");
SetEnvironmentVariable("CONNECT_CAMERA", "0");
}
}
// windowed subscreen, enabled by default, unless turned off by user // windowed subscreen, enabled by default, unless turned off by user
auto options = games::get_options(eamuse_get_game());
if (GRAPHICS_WINDOWED && !options->at(launcher::Options::spice2x_IIDXNoSub).value_bool()) { if (GRAPHICS_WINDOWED && !options->at(launcher::Options::spice2x_IIDXNoSub).value_bool()) {
GRAPHICS_IIDX_WSUB = true; GRAPHICS_IIDX_WSUB = true;
} }
+1 -1
View File
@@ -14,7 +14,7 @@ namespace games::iidx {
// settings // settings
extern bool FLIP_CAMS; extern bool FLIP_CAMS;
extern bool DISABLE_CAMS; extern std::optional<bool> DISABLE_CAMS;
extern bool TDJ_CAMERA; extern bool TDJ_CAMERA;
extern bool TDJ_CAMERA_PREFER_16_9; extern bool TDJ_CAMERA_PREFER_16_9;
extern std::optional<std::string> TDJ_CAMERA_OVERRIDE; extern std::optional<std::string> TDJ_CAMERA_OVERRIDE;
+2
View File
@@ -213,6 +213,8 @@ namespace games::iidx {
} }
void init_legacy_camera_hook(bool flip_cams) { void init_legacy_camera_hook(bool flip_cams) {
log_info("iidx::cam", "initializing legacy camera hook");
should_flip_cams = flip_cams; should_flip_cams = flip_cams;
// camera media framework hook // camera media framework hook
+10 -5
View File
@@ -46,14 +46,17 @@ namespace games::iidx {
IMFActivate *pActivate, IMFActivate *pActivate,
IDirect3DDeviceManager9 *pD3DManager, IDirect3DDeviceManager9 *pD3DManager,
LPDIRECT3DDEVICE9EX device, LPDIRECT3DDEVICE9EX device,
LPDIRECT3DTEXTURE9 *texture_target LPDIRECT3DTEXTURE9 *camera_texture_target,
LPDIRECT3DTEXTURE9 *preview_texture_target
): ):
m_nRefCount(1), m_nRefCount(1),
m_name(name), m_name(name),
m_prefer_16_by_9(prefer_16_by_9), m_prefer_16_by_9(prefer_16_by_9),
m_device(device), m_device(device),
m_texture_target(texture_target), m_camera_texture_target(camera_texture_target),
m_texture_original(*texture_target) m_preview_texture_target(preview_texture_target),
m_camera_texture_original(*camera_texture_target),
m_preview_texture_original(*preview_texture_target)
{ {
InitializeCriticalSection(&m_critsec); InitializeCriticalSection(&m_critsec);
@@ -691,7 +694,8 @@ namespace games::iidx {
if (FAILED(hr)) { goto done; } if (FAILED(hr)) { goto done; }
// Make the game use this new texture as camera stream source // Make the game use this new texture as camera stream source
*m_texture_target = m_texture; *m_camera_texture_target = m_texture;
*m_preview_texture_target = m_texture;
m_active = TRUE; m_active = TRUE;
// Create texture for colour conversion // Create texture for colour conversion
@@ -860,7 +864,8 @@ namespace games::iidx {
ULONG uCount = InterlockedDecrement(&m_nRefCount); ULONG uCount = InterlockedDecrement(&m_nRefCount);
*m_texture_target = m_texture_original; *m_camera_texture_target = m_camera_texture_original;
*m_preview_texture_target = m_preview_texture_original;
for (size_t i = 0; i < m_mediaTypeInfos.size(); i++) { for (size_t i = 0; i < m_mediaTypeInfos.size(); i++) {
SafeRelease(&(m_mediaTypeInfos.at(i).p_mediaType)); SafeRelease(&(m_mediaTypeInfos.at(i).p_mediaType));
+27 -5
View File
@@ -66,6 +66,25 @@ extern std::string CAMERA_CONTROL_LABELS[];
extern std::string DRAW_MODE_LABELS[]; extern std::string DRAW_MODE_LABELS[];
namespace games::iidx { namespace games::iidx {
namespace Camera {
struct PlayVideoCamera {
IDirect3DTexture9** d3d9_texture(const uintptr_t offset) {
auto const afp_texture = *reinterpret_cast<uint8_t**>
(reinterpret_cast<uint8_t*>(this) + offset);
return reinterpret_cast<IDirect3DTexture9**>(afp_texture + 0x8);
}
};
struct CCameraManager2 {
using camera_pointers = struct {
PlayVideoCamera* a;
PlayVideoCamera* b;
};
void* vftbl;
camera_pointers* cameras;
};
}
class IIDXLocalCamera { class IIDXLocalCamera {
protected: protected:
virtual ~IIDXLocalCamera() {}; virtual ~IIDXLocalCamera() {};
@@ -98,8 +117,9 @@ namespace games::iidx {
// DirectX9 DeviceEx // DirectX9 DeviceEx
LPDIRECT3DDEVICE9EX m_device; LPDIRECT3DDEVICE9EX m_device;
// Address to hook camera texture onto the game // Address to hook camera textures onto the game
LPDIRECT3DTEXTURE9 *m_texture_target = nullptr; LPDIRECT3DTEXTURE9 *m_camera_texture_target = nullptr;
LPDIRECT3DTEXTURE9 *m_preview_texture_target = nullptr;
// Target texture (to be shown in the game) // Target texture (to be shown in the game)
LPDIRECT3DTEXTURE9 m_texture = nullptr; LPDIRECT3DTEXTURE9 m_texture = nullptr;
@@ -117,8 +137,9 @@ namespace games::iidx {
LPDIRECT3DTEXTURE9 m_transformResultTexture = nullptr; LPDIRECT3DTEXTURE9 m_transformResultTexture = nullptr;
IDirect3DSurface9 *m_pTransformResultSurf = nullptr; IDirect3DSurface9 *m_pTransformResultSurf = nullptr;
// Storing original texture for clean up // Storing original textures for clean up
LPDIRECT3DTEXTURE9 m_texture_original = nullptr; LPDIRECT3DTEXTURE9 m_camera_texture_original = nullptr;
LPDIRECT3DTEXTURE9 m_preview_texture_original = nullptr;
IAMCameraControl *m_pCameraControl = nullptr; IAMCameraControl *m_pCameraControl = nullptr;
@@ -154,7 +175,8 @@ namespace games::iidx {
IMFActivate *pActivate, IMFActivate *pActivate,
IDirect3DDeviceManager9 *pD3DManager, IDirect3DDeviceManager9 *pD3DManager,
LPDIRECT3DDEVICE9EX device, LPDIRECT3DDEVICE9EX device,
LPDIRECT3DTEXTURE9 *texture_target LPDIRECT3DTEXTURE9 *camera_texture_target,
LPDIRECT3DTEXTURE9 *preview_texture_target
); );
LPDIRECT3DTEXTURE9 GetTexture(); LPDIRECT3DTEXTURE9 GetTexture();
ULONG Release(); ULONG Release();
+35 -2
View File
@@ -4,6 +4,7 @@
#include "avs/game.h" #include "avs/game.h"
#include "hooks/graphics/graphics.h" #include "hooks/graphics/graphics.h"
#include "misc/eamuse.h" #include "misc/eamuse.h"
#include "misc/wintouchemu.h"
#include "touch/touch.h" #include "touch/touch.h"
#include "util/detour.h" #include "util/detour.h"
#include "util/libutils.h" #include "util/libutils.h"
@@ -32,6 +33,8 @@ namespace games::mfc {
static uint8_t CARD_TYPE = 0; static uint8_t CARD_TYPE = 0;
static uint8_t CARD_UID[8]; static uint8_t CARD_UID[8];
bool HG_MODE = false;
typedef int (__cdecl *inifile_param_num_t)(const char *, int *); typedef int (__cdecl *inifile_param_num_t)(const char *, int *);
static inifile_param_num_t inifile_param_num_real; static inifile_param_num_t inifile_param_num_real;
@@ -50,8 +53,10 @@ namespace games::mfc {
static void __cdecl touch_init(int width, int height) { static void __cdecl touch_init(int width, int height) {
log_info("mfc", "call touch_init(width: {}, height: {})", width, height); log_info("mfc", "call touch_init(width: {}, height: {})", width, height);
// attach touch module if (HG_MODE) {
if (!TOUCH_ATTACHED) { wintouchemu::ADD_TOUCH_FLAG_PRIMARY = true;
wintouchemu::hook("MFC9", avs::game::DLL_INSTANCE);
} else if (!TOUCH_ATTACHED) { // attach touch module
// store touch size specification // store touch size specification
TOUCH_MAX_X = width; TOUCH_MAX_X = width;
@@ -288,6 +293,21 @@ namespace games::mfc {
MFCGame::MFCGame() : Game("Mahjong Fight Club") { MFCGame::MFCGame() : Game("Mahjong Fight Club") {
} }
static bool spam_remover(void *user, const std::string &data, logger::Style style, std::string &out) {
if (data.empty() || data[0] != '[') {
return false;
}
if (data.find("W:mutex: lock: mid 00000000 != AVS_DTYPE_MUTEX") != std::string::npos) {
out = "";
return true;
}
if (data.find("W:mutex: unlock: mid 00000000 != AVS_DTYPE_MUTEX") != std::string::npos) {
out = "";
return true;
}
return false;
}
void MFCGame::attach() { void MFCGame::attach() {
Game::attach(); Game::attach();
@@ -308,6 +328,17 @@ namespace games::mfc {
auto allinone_module = libutils::try_module("allinone.dll"); auto allinone_module = libutils::try_module("allinone.dll");
auto system_module = libutils::try_module("system.dll"); auto system_module = libutils::try_module("system.dll");
// Mahjong Fight Club - 2025?
// they removed allinone.dll and moved i/o into system.dll
if (allinone_module == nullptr) {
log_misc("mfc", "using system.dll instead of allinone.dll for i/o hooks");
allinone_module = system_module;
if (avs::game::SPEC[0] == 'F') {
HG_MODE = true;
}
}
// network fix // network fix
detour::iat_try("?nic_dhcp_maybe_exist@@YAEXZ", nic_dhcp_maybe_exist, system_module); detour::iat_try("?nic_dhcp_maybe_exist@@YAEXZ", nic_dhcp_maybe_exist, system_module);
@@ -378,5 +409,7 @@ namespace games::mfc {
detour::inline_hook((void *) mouse_utl_step, libutils::try_proc( detour::inline_hook((void *) mouse_utl_step, libutils::try_proc(
allinone_module, "?mouse_utl_step@@YAXXZ")); allinone_module, "?mouse_utl_step@@YAXXZ"));
} }
logger::hook_add(spam_remover, nullptr);
} }
} }
+2
View File
@@ -4,6 +4,8 @@
namespace games::mfc { namespace games::mfc {
extern bool HG_MODE;
struct joystick_state { struct joystick_state {
bool up = false; bool up = false;
bool down = false; bool down = false;
+11 -2
View File
@@ -106,8 +106,8 @@ namespace games::sdvx {
if (ENABLE_COM_PORT_SCAN_HOOK && if (ENABLE_COM_PORT_SCAN_HOOK &&
lpSubKey != nullptr && phkResult != nullptr && lpSubKey != nullptr && phkResult != nullptr &&
_stricmp(lpSubKey, "HARDWARE\\DEVICEMAP\\SERIALCOMM") == 0) { _stricmp(lpSubKey, "HARDWARE\\DEVICEMAP\\SERIALCOMM") == 0) {
log_info("sdvx::io", "failing HKLM\\HARDWARE\\DEVICEMAP\\SERIALCOMM to force COM1 ICCA"); log_info("sdvx::io", "hook access to HKLM\\HARDWARE\\DEVICEMAP\\SERIALCOMM to force COM1 ICCA");
return 2; //ERROR_FILE_NOT_FOUND return 2; // ERROR_FILE_NOT_FOUND
} }
return RegOpenKeyExA_orig(hKey, lpSubKey, ulOptions, samDesired, phkResult); return RegOpenKeyExA_orig(hKey, lpSubKey, ulOptions, samDesired, phkResult);
@@ -215,6 +215,15 @@ namespace games::sdvx {
deferredlogs::defer_error_messages(deferredlogs::SUPERSTEP_SOUND_ERROR_MESSAGE); deferredlogs::defer_error_messages(deferredlogs::SUPERSTEP_SOUND_ERROR_MESSAGE);
return false; return false;
} }
if (data.find("W:ea3-pos: ea3_report_posev: no such node:") != std::string::npos) {
deferredlogs::defer_error_messages({
"bad prop\\ea3-config.xml detected by game",
std::string(" ") + data,
" this will most likely cause Server Busy errors in certain conditions",
" follow the FAQ to fix your ea3-config.xml and try again"
});
return false;
}
return false; return false;
} }
@@ -15,6 +15,7 @@
#include "cfg/screen_resize.h" #include "cfg/screen_resize.h"
#include "games/iidx/iidx.h" #include "games/iidx/iidx.h"
#include "games/sdvx/sdvx.h" #include "games/sdvx/sdvx.h"
#include "games/mfc/mfc.h"
#include "games/io.h" #include "games/io.h"
#include "hooks/graphics/graphics.h" #include "hooks/graphics/graphics.h"
#include "launcher/launcher.h" #include "launcher/launcher.h"
@@ -1360,6 +1361,11 @@ void graphics_d3d9_on_present(
graphics_d3d9_ldj_on_present(wrapped_device); graphics_d3d9_ldj_on_present(wrapped_device);
} }
const bool is_mfc = avs::game::is_model("KK9") && games::mfc::HG_MODE;
if (is_mfc) {
wintouchemu::update();
}
// check screenshot key // check screenshot key
static bool trigger_last = false; static bool trigger_last = false;
auto buttons = games::get_buttons_overlay(eamuse_get_game()); auto buttons = games::get_buttons_overlay(eamuse_get_game());
+26
View File
@@ -8,6 +8,7 @@
#include <ntstatus.h> #include <ntstatus.h>
#include "avs/game.h" #include "avs/game.h"
#include "games/iidx/iidx.h"
#include "util/detour.h" #include "util/detour.h"
#include "util/logging.h" #include "util/logging.h"
#include "util/utils.h" #include "util/utils.h"
@@ -22,6 +23,7 @@ static decltype(GetLocaleInfoEx) *GetLocaleInfoEx_orig = nullptr;
#ifdef SPICE64 #ifdef SPICE64
static decltype(GetSystemDefaultLCID) *GetSystemDefaultLCID_orig = nullptr; static decltype(GetSystemDefaultLCID) *GetSystemDefaultLCID_orig = nullptr;
static decltype(IsDBCSLeadByte) *IsDBCSLeadByte_orig = nullptr;
#endif #endif
static NTSTATUS NTAPI RtlMultiByteToUnicodeN_hook( static NTSTATUS NTAPI RtlMultiByteToUnicodeN_hook(
@@ -162,6 +164,17 @@ static int WINAPI GetLocaleInfoEx_hook (
return GetLocaleInfoEx_orig(lpLocaleName, LCType, lpLCData, cchData); return GetLocaleInfoEx_orig(lpLocaleName, LCType, lpLCData, cchData);
} }
#ifdef SPICE64
static BOOL WINAPI IsDBCSLeadByte_hook (
BYTE TestChar
)
{
return IsDBCSLeadByteEx(CODEPAGE_SHIFT_JIS, TestChar);
}
#endif
void hooks::lang::early_init() { void hooks::lang::early_init() {
log_info("hooks::lang", "early initialization"); log_info("hooks::lang", "early initialization");
@@ -189,6 +202,19 @@ void hooks::lang::early_init() {
GetLocaleInfoEx_hook, GetLocaleInfoEx_hook,
&GetLocaleInfoEx_orig); &GetLocaleInfoEx_orig);
} }
#ifdef SPICE64
// for TDJ subscreen search keyboard
if (avs::game::is_model("LDJ") && games::iidx::TDJ_MODE) {
log_info("hooks::lang", "hooking IsDBCSLeadByte");
detour::trampoline_try(
"kernel32.dll",
"IsDBCSLeadByte",
IsDBCSLeadByte_hook,
&IsDBCSLeadByte_orig);
}
#endif
} }
void hooks::lang::init() { void hooks::lang::init() {
+38 -27
View File
@@ -3,6 +3,7 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <assert.h>
#include <shlwapi.h> #include <shlwapi.h>
#include <cfg/configurator.h> #include <cfg/configurator.h>
@@ -299,10 +300,14 @@ int main_implementation(int argc, char *argv[]) {
cfg::CONFIGURATOR_TYPE = cfg::ConfigType::Config; cfg::CONFIGURATOR_TYPE = cfg::ConfigType::Config;
cfg_run = true; cfg_run = true;
} }
if (options[launcher::Options::EAmusementEmulation].value_bool()) {
// -ea, but ignored if -url is set
if (options[launcher::Options::EAmusementEmulation].value_bool() &&
!options[launcher::Options::ServiceURL].is_active()) {
avs::ea3::URL_SLASH = 1; avs::ea3::URL_SLASH = 1;
easrv_port = 8080; easrv_port = 8080;
} }
if (options[launcher::Options::SmartEAmusement].value_bool()) { if (options[launcher::Options::SmartEAmusement].value_bool()) {
easrv_smart = true; easrv_smart = true;
} }
@@ -458,17 +463,26 @@ int main_implementation(int argc, char *argv[]) {
if (options[launcher::Options::IIDXCameraOrderFlip].value_bool()) { if (options[launcher::Options::IIDXCameraOrderFlip].value_bool()) {
games::iidx::FLIP_CAMS = true; games::iidx::FLIP_CAMS = true;
} }
// IIDX CONNECT_CAMERA logic here for cases where user is running without -iidx module
// for now, we assume that user may be running on a cab
// (games::iidx::DISABLE_CAMS starts out as false unless user overrides)
// we will check again in IIDX module with a different default
assert(!games::iidx::DISABLE_CAMS.has_value());
if (options[launcher::Options::IIDXDisableCameras].value_bool()) { if (options[launcher::Options::IIDXDisableCameras].value_bool()) {
games::iidx::DISABLE_CAMS = true; games::iidx::DISABLE_CAMS = true;
} }
if (options[launcher::Options::IIDXCabCamAccess].is_active() &&
options[launcher::Options::IIDXCabCamAccess].value_text() == "off") {
games::iidx::DISABLE_CAMS = true;
}
if (options[launcher::Options::IIDXCamHook].value_bool()) { if (options[launcher::Options::IIDXCamHook].value_bool()) {
games::iidx::TDJ_CAMERA = true; games::iidx::TDJ_CAMERA = true;
// Disable legacy behaviour to avoid conflict // Disable legacy behaviour to avoid conflict
games::iidx::DISABLE_CAMS = true; games::iidx::DISABLE_CAMS = true;
} }
if (games::iidx::DISABLE_CAMS) { // CONNECT_CAMERA env var will be set once logging is enabled
SetEnvironmentVariable("CONNECT_CAMERA", "0");
}
if (options[launcher::Options::IIDXCamHookOverride].is_active()) { if (options[launcher::Options::IIDXCamHookOverride].is_active()) {
games::iidx::TDJ_CAMERA_OVERRIDE = options[launcher::Options::IIDXCamHookOverride].value_text(); games::iidx::TDJ_CAMERA_OVERRIDE = options[launcher::Options::IIDXCamHookOverride].value_text();
} }
@@ -1262,18 +1276,19 @@ int main_implementation(int argc, char *argv[]) {
for (const auto &option : options) { for (const auto &option : options) {
if (option.conflicting && option.get_definition().type != OptionType::Bool) { if (option.conflicting && option.get_definition().type != OptionType::Bool) {
conflicts += 1; conflicts += 1;
const auto& value = option.get_definition().sensitive ? "*****" : option.value;
if (launcher::USE_CMD_OVERRIDE) { if (launcher::USE_CMD_OVERRIDE) {
log_warning( log_warning(
"launcher", "launcher",
"multiple values for -{}, command line args take precedence: {}", "multiple values for -{}, command line args take precedence: {}",
option.get_definition().name, option.get_definition().name,
option.value); value);
} else { } else {
log_warning( log_warning(
"launcher", "launcher",
"multiple values for -{}, spicecfg values take precedence: {}", "multiple values for -{}, spicecfg values take precedence: {}",
option.get_definition().name, option.get_definition().name,
option.value); value);
} }
} }
} }
@@ -1302,25 +1317,6 @@ int main_implementation(int argc, char *argv[]) {
); );
} }
if (options[launcher::Options::EAmusementEmulation].value_bool() &&
options[launcher::Options::ServiceURL].is_active() &&
!cfg::CONFIGURATOR_STANDALONE) {
log_warning(
"launcher",
"BAD EAMUSE SETTINGS ERROR\n\n\n"
"-------------------------------------------------------------------\n"
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
"A service URL is set **AND** E-Amusement emulation is enabled.\n"
"Either remove the service URL, or disable E-Amusement emulation.\n"
"Otherwise you may experience problems logging in.\n"
"-------------------------------------------------------------------\n\n\n"
);
log_fatal(
"launcher",
"BAD EAMUSE SETTINGS ERROR: both -ea and -url are set");
}
if (options[launcher::Options::FullscreenResolution].is_active()) { if (options[launcher::Options::FullscreenResolution].is_active()) {
std::pair<uint32_t, uint32_t> result; std::pair<uint32_t, uint32_t> result;
if (parse_width_height(options[launcher::Options::FullscreenResolution].value_text(), result)) { if (parse_width_height(options[launcher::Options::FullscreenResolution].value_text(), result)) {
@@ -1332,7 +1328,7 @@ int main_implementation(int argc, char *argv[]) {
// SDVXFullscreenLandscape disabled due to it messing with in-game camera angle // SDVXFullscreenLandscape disabled due to it messing with in-game camera angle
// FullscreenOrientationFlip continues to live on, however. // FullscreenOrientationFlip continues to live on, however.
if (options[launcher::Options::SDVXFullscreenLandscape].value_bool()) { if (options[launcher::Options::SDVXFullscreenLandscape].value_bool() && !cfg::CONFIGURATOR_STANDALONE) {
log_fatal("launcher", "-sdvxlandscape removed due to a camera bug in SDVX!"); log_fatal("launcher", "-sdvxlandscape removed due to a camera bug in SDVX!");
} }
// if (options[launcher::Options::SDVXFullscreenLandscape].value_bool() && !GRAPHICS_WINDOWED) { // if (options[launcher::Options::SDVXFullscreenLandscape].value_bool() && !GRAPHICS_WINDOWED) {
@@ -1347,8 +1343,15 @@ int main_implementation(int argc, char *argv[]) {
GRAPHICS_FS_ORIENTATION_SWAP = true; GRAPHICS_FS_ORIENTATION_SWAP = true;
} }
if (games::iidx::DISABLE_CAMS.has_value() &&
games::iidx::DISABLE_CAMS.value() &&
!cfg::CONFIGURATOR_STANDALONE) {
log_misc("launcher", "CONNECT_CAMERA env var set to 0");
SetEnvironmentVariable("CONNECT_CAMERA", "0");
}
// deleted options // deleted options
if (options[launcher::Options::OpenKFControl].value_bool()) { if (options[launcher::Options::OpenKFControl].value_bool() && !cfg::CONFIGURATOR_STANDALONE) {
log_fatal("launcher", "KFControl has been removed from spice2x; please use an older version."); log_fatal("launcher", "KFControl has been removed from spice2x; please use an older version.");
} }
if (options[launcher::Options::VREnable].value_bool()) { if (options[launcher::Options::VREnable].value_bool()) {
@@ -1676,6 +1679,14 @@ int main_implementation(int argc, char *argv[]) {
attach_io = true; attach_io = true;
attach_mfc = true; attach_mfc = true;
break; break;
// Mahjong Fight Club - 2025?
// they removed allinone.dll and moved i/o into system.dll
} else if (check_dll("system.dll") && fileutils::file_exists("data/mfc.ini")) {
avs::game::DLL_NAME = "system.dll";
attach_io = true;
attach_mfc = true;
break;
} }
// FutureTomTom // FutureTomTom
+21 -4
View File
@@ -456,13 +456,30 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.category = "Game Options (Advanced)", .category = "Game Options (Advanced)",
}, },
{ {
.title = "IIDX Disable Cameras", // IIDXDisableCameras
.title = "IIDX Disable Cameras (DEPRECATED - no longer needed)",
.name = "iidxdisablecams", .name = "iidxdisablecams",
.desc = "Disables cameras", .desc = "Disables cameras",
.type = OptionType::Bool, .type = OptionType::Bool,
.hidden = true,
.game_name = "Beatmania IIDX", .game_name = "Beatmania IIDX",
.category = "Game Options", .category = "Game Options",
}, },
{
// IIDXCabCamAccess
.title = "IIDX Use Official AC Cams",
.name = "iidxcabcams",
.desc = "For IIDX25+, allow direct access to cameras from real arcade cabinets. "
"Only turn this on if you have OFFICIAL arcade cameras connected to the correct USB ports. Default: auto",
.type = OptionType::Enum,
.game_name = "Beatmania IIDX",
.category = "Game Options (Advanced)",
.elements = {
{"auto", ""},
{"off", ""},
{"on", ""}
},
},
{ {
// IIDXCamHook // IIDXCamHook
.title = "IIDX Cam Hook", .title = "IIDX Cam Hook",
@@ -497,10 +514,10 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.display_name = "iidxcamhookoffset", .display_name = "iidxcamhookoffset",
.aliases = "iidxcamhookoffset", .aliases = "iidxcamhookoffset",
.desc = "Override DLL offsets for camera hook; " .desc = "Override DLL offsets for camera hook; "
"format: 4 hex values separated by commas " "format: 5 hex values separated by commas "
"(offset_hook_a, offset_hook_b, offset_textures, offset_d3d_device)", "(offset_hook_a, offset_textures, offset_camera_manager, offset_d3d_device, offset_afp_texture)",
.type = OptionType::Text, .type = OptionType::Text,
.setting_name = "0x5817a0,0x5ea3b0,0x6fffbd8,0xe0", .setting_name = "0x5817a0,0x6fffbd8,0xbbae40,0xe0,0x30",
.game_name = "Beatmania IIDX", .game_name = "Beatmania IIDX",
.category = "Game Options (Advanced)", .category = "Game Options (Advanced)",
}, },
+1
View File
@@ -55,6 +55,7 @@ namespace launcher {
LoadIIDXModule, LoadIIDXModule,
IIDXCameraOrderFlip, IIDXCameraOrderFlip,
IIDXDisableCameras, IIDXDisableCameras,
IIDXCabCamAccess,
IIDXCamHook, IIDXCamHook,
IIDXCamHookRatio, IIDXCamHookRatio,
IIDXCamHookOverride, IIDXCamHookOverride,
+25
View File
@@ -34,6 +34,7 @@ namespace wintouchemu {
bool FORCE = false; bool FORCE = false;
bool INJECT_MOUSE_AS_WM_TOUCH = false; bool INJECT_MOUSE_AS_WM_TOUCH = false;
bool LOG_FPS = false; bool LOG_FPS = false;
bool ADD_TOUCH_FLAG_PRIMARY = false;
static inline bool is_emu_enabled() { static inline bool is_emu_enabled() {
return FORCE || !is_touch_available("wintouchemu::is_emu_enabled") || GRAPHICS_SHOW_CURSOR; return FORCE || !is_touch_available("wintouchemu::is_emu_enabled") || GRAPHICS_SHOW_CURSOR;
@@ -187,16 +188,28 @@ namespace wintouchemu {
switch (touch_event->type) { switch (touch_event->type) {
case TOUCH_DOWN: case TOUCH_DOWN:
if (valid) { if (valid) {
if (ADD_TOUCH_FLAG_PRIMARY) {
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
}
touch_input->dwFlags |= TOUCHEVENTF_DOWN; touch_input->dwFlags |= TOUCHEVENTF_DOWN;
} }
break; break;
case TOUCH_MOVE: case TOUCH_MOVE:
if (valid) { if (valid) {
if (ADD_TOUCH_FLAG_PRIMARY) {
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
}
touch_input->dwFlags |= TOUCHEVENTF_MOVE; touch_input->dwFlags |= TOUCHEVENTF_MOVE;
} }
break; break;
case TOUCH_UP: case TOUCH_UP:
// don't check valid so that this touch ID can be released // don't check valid so that this touch ID can be released
if (ADD_TOUCH_FLAG_PRIMARY) {
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
}
touch_input->dwFlags |= TOUCHEVENTF_UP; touch_input->dwFlags |= TOUCHEVENTF_UP;
break; break;
} }
@@ -238,16 +251,28 @@ namespace wintouchemu {
switch (mouse_state.touch_event) { switch (mouse_state.touch_event) {
case TOUCHEVENTF_DOWN: case TOUCHEVENTF_DOWN:
if (valid) { if (valid) {
if (ADD_TOUCH_FLAG_PRIMARY) {
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
}
touch_input->dwFlags |= TOUCHEVENTF_DOWN; touch_input->dwFlags |= TOUCHEVENTF_DOWN;
} }
break; break;
case TOUCHEVENTF_MOVE: case TOUCHEVENTF_MOVE:
if (valid) { if (valid) {
if (ADD_TOUCH_FLAG_PRIMARY) {
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
}
touch_input->dwFlags |= TOUCHEVENTF_MOVE; touch_input->dwFlags |= TOUCHEVENTF_MOVE;
} }
break; break;
case TOUCHEVENTF_UP: case TOUCHEVENTF_UP:
// don't check valid so that this touch ID can be released // don't check valid so that this touch ID can be released
if (ADD_TOUCH_FLAG_PRIMARY) {
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
}
touch_input->dwFlags |= TOUCHEVENTF_UP; touch_input->dwFlags |= TOUCHEVENTF_UP;
break; break;
} }
+1
View File
@@ -8,6 +8,7 @@ namespace wintouchemu {
extern bool FORCE; extern bool FORCE;
extern bool INJECT_MOUSE_AS_WM_TOUCH; extern bool INJECT_MOUSE_AS_WM_TOUCH;
extern bool LOG_FPS; extern bool LOG_FPS;
extern bool ADD_TOUCH_FLAG_PRIMARY;
void hook(const char *window_title, HMODULE module = nullptr, int delay_in_s=0); void hook(const char *window_title, HMODULE module = nullptr, int delay_in_s=0);
void hook_title_ends( void hook_title_ends(
+6 -2
View File
@@ -2828,7 +2828,10 @@ namespace overlay::windows {
std::string current_item = option.value_text(); std::string current_item = option.value_text();
for (auto &element : definition.elements) { for (auto &element : definition.elements) {
if (element.first == current_item) { if (element.first == current_item) {
current_item += fmt::format(" ({})", element.second); if (!element.second.empty()) {
current_item += fmt::format(" ({})", element.second);
}
break;
} }
} }
if (current_item.empty()) { if (current_item.empty()) {
@@ -2836,11 +2839,12 @@ namespace overlay::windows {
} }
if (ImGui::BeginCombo("##combo", current_item.c_str(), 0)) { if (ImGui::BeginCombo("##combo", current_item.c_str(), 0)) {
for (auto &element : definition.elements) { for (auto &element : definition.elements) {
bool selected = current_item == element.first;
std::string label = element.first; std::string label = element.first;
if (!element.second.empty()) { if (!element.second.empty()) {
label += fmt::format(" ({})", element.second); label += fmt::format(" ({})", element.second);
} }
bool selected = current_item == label;
if (ImGui::Selectable(label.c_str(), selected)) { if (ImGui::Selectable(label.c_str(), selected)) {
this->options_dirty = true; this->options_dirty = true;
option.value = element.first; option.value = element.first;
@@ -288,6 +288,12 @@ namespace overlay::windows {
this->reload_local_patches(); this->reload_local_patches();
} }
if (avs::game::DLL_NAME == "kamunity.dll") {
ImGui::TextColored(ImVec4(1.f, 0.f, 0.f, 1.f), "Patches are not supported for Unity-based games.");
ImGui::TextColored(ImVec4(1.f, 0.f, 0.f, 1.f), "Instead, look for downloads of pre-patched DLLs.");
return;
}
// game code info // game code info
std::string identifiers; std::string identifiers;
identifiers += avs::game::get_identifier() + "\n\n"; identifiers += avs::game::get_identifier() + "\n\n";
+11 -13
View File
@@ -347,40 +347,38 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
if (hid_handle != INVALID_HANDLE_VALUE) { if (hid_handle != INVALID_HANDLE_VALUE) {
// check manufacturer string // check manufacturer string
std::wstring man_ws; std::string man_ws;
wchar_t man_str_buffer[256] {}; wchar_t man_str_buffer[256] {};
if (HidD_GetManufacturerString(hid_handle, man_str_buffer, sizeof(man_str_buffer))) { if (HidD_GetManufacturerString(hid_handle, man_str_buffer, sizeof(man_str_buffer))) {
man_ws = std::wstring(man_str_buffer); man_ws = wchar_to_u8(man_str_buffer);
} }
// get product string // get product string
std::wstring prod_ws; std::string prod_ws;
wchar_t prod_str_buffer[256] {}; wchar_t prod_str_buffer[256] {};
if (HidD_GetProductString(hid_handle, prod_str_buffer, sizeof(prod_str_buffer))) { if (HidD_GetProductString(hid_handle, prod_str_buffer, sizeof(prod_str_buffer))) {
prod_ws = std::wstring(prod_str_buffer); prod_ws = wchar_to_u8(prod_str_buffer);
} }
// For Bluetooth LE HID devices (e.g., newer Xbox controllers) HidD_GetProductString // For Bluetooth LE HID devices (e.g., newer Xbox controllers) HidD_GetProductString
// and HidD_GetManufacturerString will return blank strings. // and HidD_GetManufacturerString will return blank strings.
// https://docs.microsoft.com/en-us/answers/questions/401236/hidd-getproductstring-with-ble-hid-device.html // https://docs.microsoft.com/en-us/answers/questions/401236/hidd-getproductstring-with-ble-hid-device.html
if (man_ws.empty() && prod_ws.empty()) { if (man_ws.empty() && prod_ws.empty()) {
prod_ws = s2ws(device_description); prod_ws = device_description;
} }
// build desc string // build desc string
std::wstring desc_ws; std::string desc_ws;
if (string_begins_with(prod_ws, man_ws)) { if (string_begins_with(prod_ws, man_ws)) {
desc_ws = prod_ws; desc_ws = prod_ws;
} else { } else {
desc_ws = man_ws; desc_ws = man_ws;
if (!man_ws.empty() && !prod_ws.empty()) { if (!man_ws.empty() && !prod_ws.empty()) {
desc_ws += L" "; desc_ws += " ";
} }
desc_ws += prod_ws; desc_ws += prod_ws;
} }
new_device.desc = desc_ws;
// convert to normal string
new_device.desc = ws2s(desc_ws);
// get attributes // get attributes
if (!HidD_GetAttributes(hid_handle, &hid_attributes)) { if (!HidD_GetAttributes(hid_handle, &hid_attributes)) {
@@ -1148,7 +1146,7 @@ std::string rawinput::RawInputManager::rawinput_get_device_description(const raw
// get property // get property
DWORD desc_size = 0; DWORD desc_size = 0;
if (SetupDiGetDeviceRegistryProperty( if (SetupDiGetDeviceRegistryPropertyW(
devinfo, &devinfo_data, SPDRP_DEVICEDESC, nullptr, nullptr, 0, &desc_size)) devinfo, &devinfo_data, SPDRP_DEVICEDESC, nullptr, nullptr, 0, &desc_size))
{ {
continue; continue;
@@ -1160,14 +1158,14 @@ std::string rawinput::RawInputManager::rawinput_get_device_description(const raw
// allocate buffer // allocate buffer
auto desc_data = std::make_unique<BYTE[]>(desc_size); auto desc_data = std::make_unique<BYTE[]>(desc_size);
if (!SetupDiGetDeviceRegistryProperty( if (!SetupDiGetDeviceRegistryPropertyW(
devinfo, &devinfo_data, SPDRP_DEVICEDESC, nullptr, desc_data.get(), desc_size, nullptr)) devinfo, &devinfo_data, SPDRP_DEVICEDESC, nullptr, desc_data.get(), desc_size, nullptr))
{ {
continue; continue;
} }
// kthxbye // kthxbye
device_description = std::string(reinterpret_cast<char *>(desc_data.get())); device_description = wchar_to_u8(reinterpret_cast<PWCHAR>(desc_data.get()));
} }
} }
} }
+1
View File
@@ -3,6 +3,7 @@ developers when you can. Sources should be included, have fun!
spice2x fork maintainers: spice2x fork maintainers:
* sp2xdev team * sp2xdev team
* the lab
SpiceTools original contributors: SpiceTools original contributors:
* cube, felix, dinsfire, nolm, s2, crazyredmachine (jotaro44), mon, nibs * cube, felix, dinsfire, nolm, s2, crazyredmachine (jotaro44), mon, nibs
+4 -2
View File
@@ -49,8 +49,10 @@ namespace deferredlogs {
if (is_crash) { if (is_crash) {
msg += " the game has crashed\n"; msg += " the game has crashed\n";
msg += " share this entire log file with someone for troubleshooting (log.txt)\n"; msg += " * share this entire log file with someone for troubleshooting (log.txt)\n";
msg += " spice will also attempt to create a minidump (minidump.dmp)\n"; msg += " * spice will also attempt to create a minidump (minidump.dmp)\n";
msg += " minidump should only be shared with people you trust as it may contain\n";
msg += " sensitive data (PCBID, card ID, etc)\n";
msg += "\n"; msg += "\n";
} }
+1 -1
View File
@@ -12,7 +12,7 @@ namespace {
{ {
"msvcr100.dll", "msvcr100.dll",
"Visual Studio 2010 (VC++ 10.0) SP1 Redistributable", "Visual Studio 2010 (VC++ 10.0) SP1 Redistributable",
"Download and install VisualCppRedist_AIO_x86_x64.exe from https://github.com/abbodi1406/vcredist/releases/latest", "Download and install from https://github.com/spice2x/spice2x.github.io/wiki/Visual-Cpp-Redistributable-Runtimes",
}, },
{ {
"d3dx9_43.dll", "d3dx9_43.dll",
+10
View File
@@ -339,4 +339,14 @@ static inline bool parse_width_height(const std::string wh, std::pair<uint32_t,
} else { } else {
return false; return false;
} }
}
static inline std::string wchar_to_u8(const wchar_t* wstr) {
int size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
if (size <= 1) {
return "";
}
std::string out(size - 1, 0);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, out.data(), size - 1, nullptr, nullptr);
return out;
} }