mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3ef1b3ecaa | |||
| 931811da14 | |||
| 7624ded512 | |||
| a5252939dd | |||
| 808ac0c557 | |||
| 4e138b244e | |||
| 3fcd1bdbc9 | |||
| f857e63d5d | |||
| b462c838f6 | |||
| 4d658bf273 | |||
| 67721c416b | |||
| 0b5f7787be | |||
| a554c8f923 | |||
| 6592191624 | |||
| 164592b16d | |||
| 81f879e7ff | |||
| 1af8b3de61 | |||
| c33fef606f | |||
| a9fc6ef1b2 | |||
| d530bfcd65 | |||
| c96f4330d2 | |||
| 26a2a0f481 | |||
| 11b9790e6c | |||
| 1dfcf8c087 | |||
| 5c7ad0d51e | |||
| 587ae86341 | |||
| 926f2ef2a0 | |||
| d262e02f8c | |||
| f6b63473a0 | |||
| 1ad45edd6e | |||
| e79de3b117 | |||
| f783a5a1cd | |||
| 7848d5c237 | |||
| cec735a81b | |||
| 753702e32e | |||
| 7bd7503951 | |||
| d0c38956bf | |||
| 77bca2baee | |||
| 46e8c8a5a5 | |||
| 4d58e5d080 | |||
| 168084d672 | |||
| 740ed90d95 | |||
| 61c17f15b4 | |||
| 99035f312f | |||
| aafc916bb6 | |||
| c5eb1e999b | |||
| 7c15452c1e |
@@ -36,6 +36,7 @@ please do not ask for these, as it will never happen here.
|
|||||||
|
|
||||||
Rules for filing a new issue or adding comments to existing issues in the tracker:
|
Rules for filing a new issue or adding comments to existing issues in the tracker:
|
||||||
|
|
||||||
|
* Low effort submissions will be simply deleted, and repeated attempts will get you banned.
|
||||||
* Check the [known issues](https://github.com/spice2x/spice2x.github.io/wiki/Known-issues) page first before reporting a new issue. If you have some new information or workarounds for a known issue, you can file a documentation bug as well.
|
* Check the [known issues](https://github.com/spice2x/spice2x.github.io/wiki/Known-issues) page first before reporting a new issue. If you have some new information or workarounds for a known issue, you can file a documentation bug as well.
|
||||||
* Use the search function and see if there is an existing issue.
|
* Use the search function and see if there is an existing issue.
|
||||||
* This is not the place to obtain a guide or receive basic troubleshooting.
|
* This is not the place to obtain a guide or receive basic troubleshooting.
|
||||||
|
|||||||
@@ -19,3 +19,8 @@ dist/*
|
|||||||
external/cv2pdb/*
|
external/cv2pdb/*
|
||||||
|
|
||||||
.ccache/*
|
.ccache/*
|
||||||
|
|
||||||
|
# Visual Studio
|
||||||
|
.vs
|
||||||
|
out
|
||||||
|
CMakeSettings.json
|
||||||
|
|||||||
@@ -80,6 +80,25 @@ if(MSVC)
|
|||||||
|
|
||||||
# enable COMDAT folding for even smaller release builds
|
# enable COMDAT folding for even smaller release builds
|
||||||
add_link_options("$<$<CONFIG:RELEASE,MINSIZEREL>:/OPT:ICF>")
|
add_link_options("$<$<CONFIG:RELEASE,MINSIZEREL>:/OPT:ICF>")
|
||||||
|
|
||||||
|
# always use UTF-8 (fix 4819)
|
||||||
|
add_compile_options("/utf-8")
|
||||||
|
|
||||||
|
# spectre mitigation warning
|
||||||
|
add_compile_options("/wd5045")
|
||||||
|
|
||||||
|
# implicit type convert warnings
|
||||||
|
add_compile_options("/wd4244")
|
||||||
|
add_compile_options("/wd4267")
|
||||||
|
add_compile_options("/wd4305")
|
||||||
|
|
||||||
|
# unreferenced local variable
|
||||||
|
add_compile_options("/wd4101")
|
||||||
|
|
||||||
|
# warning in winbase.h??
|
||||||
|
add_compile_options("/wd5039")
|
||||||
|
|
||||||
|
|
||||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
# disable warnings about using non _s variants like strncpy
|
# disable warnings about using non _s variants like strncpy
|
||||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||||
@@ -443,6 +462,9 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
games/mfg/mfg.cpp
|
games/mfg/mfg.cpp
|
||||||
games/mfg/io.cpp
|
games/mfg/io.cpp
|
||||||
games/mfg/bi2a_hook.cpp
|
games/mfg/bi2a_hook.cpp
|
||||||
|
games/pc/pc.cpp
|
||||||
|
games/pc/io.cpp
|
||||||
|
games/pc/bi2x_hook.cpp
|
||||||
|
|
||||||
# hooks
|
# hooks
|
||||||
hooks/audio/audio.cpp
|
hooks/audio/audio.cpp
|
||||||
|
|||||||
@@ -247,6 +247,25 @@ which also means that your hex edits are applicable directly.
|
|||||||
- sets the contents of the 16 segment display and disables writes from game
|
- sets the contents of the 16 segment display and disables writes from game
|
||||||
- ticker_reset()
|
- ticker_reset()
|
||||||
- re-enables writes from game
|
- re-enables writes from game
|
||||||
|
- tapeled_get(name: str, ...)
|
||||||
|
- returns a list containing a dict of the current tape LED states. The dict keys are:
|
||||||
|
- `Stage Left`
|
||||||
|
- `Stage Right`
|
||||||
|
- `Cabinet Left`
|
||||||
|
- `Cabinet Right`
|
||||||
|
- `Control Panel Under`
|
||||||
|
- `Ceiling Left`
|
||||||
|
- `Title Left`
|
||||||
|
- `Title Right`
|
||||||
|
- `Ceiling Right`
|
||||||
|
- `Touch Panel Left`
|
||||||
|
- `Touch Panel Right`
|
||||||
|
- `Side Panel Left Inner`
|
||||||
|
- `Side Panel Left Outer`
|
||||||
|
- `Side Panel Left`
|
||||||
|
- `Side Panel Right Outer`
|
||||||
|
- `Side Panel Right Inner`
|
||||||
|
- `Side Panel Right`
|
||||||
|
|
||||||
#### LCD
|
#### LCD
|
||||||
- info()
|
- info()
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
namespace acio {
|
namespace acio {
|
||||||
HINSTANCE DLL_INSTANCE = nullptr;
|
HINSTANCE DLL_INSTANCE = nullptr;
|
||||||
std::vector<acio::ACIOModule *> MODULES;
|
std::vector<acio::ACIOModule *> MODULES;
|
||||||
|
std::atomic<bool> IO_INIT_IN_PROGRESS = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -58,6 +59,7 @@ static inline acio::HookMode get_hookmode() {
|
|||||||
|
|
||||||
void acio::attach() {
|
void acio::attach() {
|
||||||
log_info("acio", "SpiceTools ACIO");
|
log_info("acio", "SpiceTools ACIO");
|
||||||
|
IO_INIT_IN_PROGRESS = true;
|
||||||
|
|
||||||
// load settings and instance
|
// load settings and instance
|
||||||
acio::DLL_INSTANCE = LoadLibraryA("libacio.dll");
|
acio::DLL_INSTANCE = LoadLibraryA("libacio.dll");
|
||||||
@@ -111,6 +113,8 @@ void acio::attach() {
|
|||||||
for (auto &module : MODULES) {
|
for (auto &module : MODULES) {
|
||||||
module->attach();
|
module->attach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IO_INIT_IN_PROGRESS = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void acio::attach_icca() {
|
void acio::attach_icca() {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@@ -11,6 +12,7 @@ namespace acio {
|
|||||||
// globals
|
// globals
|
||||||
extern HINSTANCE DLL_INSTANCE;
|
extern HINSTANCE DLL_INSTANCE;
|
||||||
extern std::vector<acio::ACIOModule *> MODULES;
|
extern std::vector<acio::ACIOModule *> MODULES;
|
||||||
|
extern std::atomic<bool> IO_INIT_IN_PROGRESS;
|
||||||
|
|
||||||
void attach();
|
void attach();
|
||||||
void attach_icca();
|
void attach_icca();
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ bool ICCADevice::parse_msg(MessageData *msg_in,
|
|||||||
// send version data
|
// send version data
|
||||||
auto msg = this->create_msg(msg_in, MSG_VERSION_SIZE);
|
auto msg = this->create_msg(msg_in, MSG_VERSION_SIZE);
|
||||||
if (
|
if (
|
||||||
avs::game::is_model({"LDJ", "TBS", "UJK"}) ||
|
avs::game::is_model({"LDJ", "TBS", "UJK", "XIF"}) ||
|
||||||
// SDVX Valkyrie cabinet mode
|
// SDVX Valkyrie cabinet mode
|
||||||
(avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))
|
(avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))
|
||||||
) {
|
) {
|
||||||
@@ -373,7 +373,7 @@ void ICCADevice::update_card(int unit) {
|
|||||||
bool kb_insert_press = false;
|
bool kb_insert_press = false;
|
||||||
|
|
||||||
// eamio keypress
|
// eamio keypress
|
||||||
kb_insert_press |= eamuse_get_keypad_state((size_t) unit) & (1 << EAM_IO_INSERT);
|
kb_insert_press |= static_cast<bool>(eamuse_get_keypad_state((size_t) unit) & (1 << EAM_IO_INSERT));
|
||||||
|
|
||||||
// check for card
|
// check for card
|
||||||
if (this->cards[unit] == nullptr && (eamuse_card_insert_consume(this->node_count, unit) || kb_insert_press)) {
|
if (this->cards[unit] == nullptr && (eamuse_card_insert_consume(this->node_count, unit) || kb_insert_press)) {
|
||||||
@@ -521,7 +521,7 @@ void ICCADevice::update_status(int unit) {
|
|||||||
buffer[10] = felica ? 0x01 : 0x00;
|
buffer[10] = felica ? 0x01 : 0x00;
|
||||||
|
|
||||||
} else if (
|
} else if (
|
||||||
avs::game::is_model({"LDJ", "TBS"}) ||
|
avs::game::is_model({"LDJ", "TBS", "XIF"}) ||
|
||||||
// SDVX Valkyrie cabinet mode
|
// SDVX Valkyrie cabinet mode
|
||||||
(avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))) {
|
(avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))) {
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
#include "iidx.h"
|
#include "iidx.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <vector>
|
|
||||||
#include "games/iidx/iidx.h"
|
|
||||||
#include "external/rapidjson/document.h"
|
|
||||||
|
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
|
||||||
namespace api::modules {
|
namespace api::modules {
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
@@ -17,6 +13,11 @@ namespace api::modules {
|
|||||||
functions["ticker_get"] = std::bind(&IIDX::ticker_get, this, _1, _2);
|
functions["ticker_get"] = std::bind(&IIDX::ticker_get, this, _1, _2);
|
||||||
functions["ticker_set"] = std::bind(&IIDX::ticker_set, this, _1, _2);
|
functions["ticker_set"] = std::bind(&IIDX::ticker_set, this, _1, _2);
|
||||||
functions["ticker_reset"] = std::bind(&IIDX::ticker_reset, this, _1, _2);
|
functions["ticker_reset"] = std::bind(&IIDX::ticker_reset, this, _1, _2);
|
||||||
|
functions["tapeled_get"] = std::bind(&IIDX::tapeled_get, this, _1, _2);
|
||||||
|
|
||||||
|
for (auto &light : games::iidx::TAPELED_MAPPING) {
|
||||||
|
this->lights_by_names.emplace(light.lightName, light);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,4 +70,51 @@ namespace api::modules {
|
|||||||
// disable read only
|
// disable read only
|
||||||
games::iidx::IIDXIO_LED_TICKER_READONLY = false;
|
games::iidx::IIDXIO_LED_TICKER_READONLY = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tapeled_get()
|
||||||
|
* tapeled_get(name: str, ...)
|
||||||
|
*/
|
||||||
|
void IIDX::tapeled_get(Request &req, Response &res) {
|
||||||
|
Value response_object(kObjectType);
|
||||||
|
|
||||||
|
// all tape leds
|
||||||
|
if (req.params.Size() == 0) {
|
||||||
|
// Iterate through each device and dump its lights data into the response
|
||||||
|
for (const auto &mapping : games::iidx::TAPELED_MAPPING) {
|
||||||
|
copy_tapeled_data(res, response_object, mapping);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// specified light names
|
||||||
|
for (Value ¶m : req.params.GetArray()) {
|
||||||
|
// check params
|
||||||
|
if (!param.IsString()) {
|
||||||
|
error_type(res, "name", "string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto name = param.GetString();
|
||||||
|
if (const auto &it = lights_by_names.find(name); it != lights_by_names.end()) {
|
||||||
|
const auto mapping = it->second.get();
|
||||||
|
copy_tapeled_data(res, response_object, mapping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.add_data(response_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IIDX::copy_tapeled_data(Response &res, Value &response_object, const tapeledutils::tape_led &mapping) {
|
||||||
|
// Create an array for the light state
|
||||||
|
Value light_state(kArrayType);
|
||||||
|
light_state.Reserve(mapping.data.capacity() * 3, res.doc()->GetAllocator());
|
||||||
|
for (const auto [r, g, b] : mapping.data) {
|
||||||
|
light_state.PushBack(r, res.doc()->GetAllocator());
|
||||||
|
light_state.PushBack(g, res.doc()->GetAllocator());
|
||||||
|
light_state.PushBack(b, res.doc()->GetAllocator());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't use StringRef here, turns some strings partially into null bytes for some reason
|
||||||
|
Value light_name(mapping.lightName.c_str(), res.doc()->GetAllocator());
|
||||||
|
response_object.AddMember(light_name, light_state, res.doc()->GetAllocator());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "api/module.h"
|
#include "api/module.h"
|
||||||
#include "api/request.h"
|
#include "api/request.h"
|
||||||
|
#include "games/iidx/iidx.h"
|
||||||
|
|
||||||
namespace api::modules {
|
namespace api::modules {
|
||||||
|
|
||||||
@@ -10,10 +11,16 @@ namespace api::modules {
|
|||||||
IIDX();
|
IIDX();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// state
|
||||||
|
robin_hood::unordered_map<std::string, std::reference_wrapper<tapeledutils::tape_led>> lights_by_names;
|
||||||
|
|
||||||
// function definitions
|
// function definitions
|
||||||
void ticker_get(Request &req, Response &res);
|
void ticker_get(Request &req, Response &res);
|
||||||
void ticker_set(Request &req, Response &res);
|
void ticker_set(Request &req, Response &res);
|
||||||
void ticker_reset(Request &req, Response &res);
|
void ticker_reset(Request &req, Response &res);
|
||||||
|
void tapeled_get(Request &req, Response &res);
|
||||||
|
|
||||||
|
// helper
|
||||||
|
void copy_tapeled_data(Response &res, rapidjson::Value &response_object, const tapeledutils::tape_led &mapping);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,3 +16,13 @@ def iidx_ticker_set(con: Connection, text: str):
|
|||||||
def iidx_ticker_reset(con: Connection):
|
def iidx_ticker_reset(con: Connection):
|
||||||
req = Request("iidx", "ticker_reset")
|
req = Request("iidx", "ticker_reset")
|
||||||
con.request(req)
|
con.request(req)
|
||||||
|
|
||||||
|
|
||||||
|
def iidx_tapeled_get(con: Connection, *light_names):
|
||||||
|
req = Request("iidx", "tapeled_get")
|
||||||
|
|
||||||
|
for light_name in light_names:
|
||||||
|
req.add_param(light_name)
|
||||||
|
|
||||||
|
res = con.request(req)
|
||||||
|
return res.get_data()
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
namespace avs {
|
namespace avs {
|
||||||
namespace core {
|
namespace core {
|
||||||
|
|||||||
@@ -356,6 +356,12 @@ namespace avs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fall back to default PCBID if node is not found
|
||||||
|
if (!EA3_PCBID[0] && PCBID_CUSTOM.empty()) {
|
||||||
|
log_warning("avs-ea3", "no PCBID set, falling back to default PCBID value (04040000000000000000)");
|
||||||
|
PCBID_CUSTOM = "04040000000000000000";
|
||||||
|
}
|
||||||
|
|
||||||
// custom PCBID
|
// custom PCBID
|
||||||
if (!PCBID_CUSTOM.empty()) {
|
if (!PCBID_CUSTOM.empty()) {
|
||||||
|
|
||||||
@@ -399,7 +405,7 @@ namespace avs {
|
|||||||
avs::core::NODE_TYPE_str, "/ea3/id/accountid", &EA3_ACCOUNTID);
|
avs::core::NODE_TYPE_str, "/ea3/id/accountid", &EA3_ACCOUNTID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if PCBID is defined
|
// check if PCBID is defined - should never hit, left for sanity check only
|
||||||
if (avs::core::property_search(ea3_config, nullptr, "/ea3/id/pcbid") == nullptr) {
|
if (avs::core::property_search(ea3_config, nullptr, "/ea3/id/pcbid") == nullptr) {
|
||||||
log_fatal("avs-ea3", "node not found: /ea3/id/pcbid (try using -p to specify PCBID)");
|
log_fatal("avs-ea3", "node not found: /ea3/id/pcbid (try using -p to specify PCBID)");
|
||||||
} else if (strlen(EA3_PCBID) == 0) {
|
} else if (strlen(EA3_PCBID) == 0) {
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ namespace avs {
|
|||||||
if (130 <= dll_path_s.length()) {
|
if (130 <= dll_path_s.length()) {
|
||||||
log_warning(
|
log_warning(
|
||||||
"avs-game",
|
"avs-game",
|
||||||
"PATH TOO LONG WARNING\n\n\n"
|
"PATH TOO LONG WARNING\n\n"
|
||||||
"-------------------------------------------------------------------\n"
|
"-------------------------------------------------------------------\n"
|
||||||
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||||
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
|
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
|
||||||
@@ -95,10 +95,26 @@ namespace avs {
|
|||||||
"-------------------------------------------------------------------\n\n",
|
"-------------------------------------------------------------------\n\n",
|
||||||
dll_path_s, dll_path_s.length());
|
dll_path_s, dll_path_s.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ddr gamemdx.dll user error
|
||||||
|
if (avs::game::is_model("MDX") && DLL_NAME == "gamemdx.dll") {
|
||||||
|
log_fatal(
|
||||||
|
"ddr",
|
||||||
|
"BAD GAME DLL ERROR\n\n"
|
||||||
|
"!!! !!!\n"
|
||||||
|
"!!! -exec gamemdx.dll was specified !!!\n"
|
||||||
|
"!!! this is the wrong DLL; the game will not load !!!\n"
|
||||||
|
"!!! remove -exec argument and try again. !!!\n"
|
||||||
|
"!!! !!!\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// file not found on disk
|
||||||
if (!fileutils::file_exists(dll_path)) {
|
if (!fileutils::file_exists(dll_path)) {
|
||||||
log_warning("avs-game", "game DLL could not be found on disk: {}", dll_path.string().c_str());
|
log_warning("avs-game", "game DLL could not be found on disk: {}", dll_path.string().c_str());
|
||||||
log_warning("avs-game", "double check -exec and -modules parameters; unless you know what you're doing, leave them blank");
|
log_warning("avs-game", "double check -exec and -modules parameters; unless you know what you're doing, leave them blank");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileutils::verify_header_pe(dll_path)) {
|
if (fileutils::verify_header_pe(dll_path)) {
|
||||||
DLL_INSTANCE = libutils::load_library(dll_path);
|
DLL_INSTANCE = libutils::load_library(dll_path);
|
||||||
}
|
}
|
||||||
@@ -106,7 +122,7 @@ namespace avs {
|
|||||||
// load entry points
|
// load entry points
|
||||||
dll_entry_init = (ENTRY_INIT_T) libutils::get_proc(DLL_INSTANCE, ENTRY_INIT_NAME);
|
dll_entry_init = (ENTRY_INIT_T) libutils::get_proc(DLL_INSTANCE, ENTRY_INIT_NAME);
|
||||||
dll_entry_main = (ENTRY_MAIN_T) libutils::get_proc(DLL_INSTANCE, ENTRY_MAIN_NAME);
|
dll_entry_main = (ENTRY_MAIN_T) libutils::get_proc(DLL_INSTANCE, ENTRY_MAIN_NAME);
|
||||||
log_info("avs-game", "loaded successfully ({})", fmt::ptr(DLL_INSTANCE));
|
log_info("avs-game", "loaded {} successfully ({})", DLL_NAME, fmt::ptr(DLL_INSTANCE));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool entry_init(char *sid_code, void *app_param) {
|
bool entry_init(char *sid_code, void *app_param) {
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public:
|
|||||||
std::string value;
|
std::string value;
|
||||||
std::vector<Option> alternatives;
|
std::vector<Option> alternatives;
|
||||||
bool disabled = false;
|
bool disabled = false;
|
||||||
|
bool conflicting = false;
|
||||||
|
|
||||||
explicit Option(OptionDefinition definition, std::string value = "") :
|
explicit Option(OptionDefinition definition, std::string value = "") :
|
||||||
definition(std::move(definition)), value(std::move(value)) {
|
definition(std::move(definition)), value(std::move(value)) {
|
||||||
|
|||||||
@@ -1,3 +1,41 @@
|
|||||||
|
09/20/2025 [spice2x]
|
||||||
|
Polaris Chord support for knobs/turntables/mouse as fader input
|
||||||
|
Misc fixes
|
||||||
|
|
||||||
|
09/18/2025 [spice2x]
|
||||||
|
Polaris Chord windowed mode fixes
|
||||||
|
UI tweaks
|
||||||
|
|
||||||
|
09/17/2025 [spice2x]
|
||||||
|
Polaris Chord I/O fixes, language shim
|
||||||
|
|
||||||
|
09/16/2025 [spice2x]
|
||||||
|
Add Polaris Chord support
|
||||||
|
Tweak ImGUI theme
|
||||||
|
|
||||||
|
08/21/2025 [spice2x]
|
||||||
|
DDR: check for common DLL errors
|
||||||
|
Supply default PCBID if absent
|
||||||
|
Rearrange options
|
||||||
|
|
||||||
|
08/17/2025 [spice2x]
|
||||||
|
DDR: fix codec registration failure when path contains spaces
|
||||||
|
|
||||||
|
08/11/2025 [spice2x]
|
||||||
|
SDVX: fix camera hook, remove -sdvxdisablecams
|
||||||
|
DDR: automatically register codecs in com folder on boot
|
||||||
|
|
||||||
|
06/03/2025 [spice2x]
|
||||||
|
Add libshare-pj.dll to Gitadora patch import
|
||||||
|
Detect ACIO init failures
|
||||||
|
|
||||||
|
05/31/2025 [spice2x]
|
||||||
|
IIDX: fix windowed subscreen not accepting mouse clicks when
|
||||||
|
overlay is active
|
||||||
|
IIDX: tape LED over API
|
||||||
|
Option to make command line args take precedence
|
||||||
|
UI tweaks
|
||||||
|
|
||||||
05/09/2025 [spice2x]
|
05/09/2025 [spice2x]
|
||||||
Check for window focus when processing input (-inputfocus)
|
Check for window focus when processing input (-inputfocus)
|
||||||
More options for IIDX/SDVX windowed subscreen
|
More options for IIDX/SDVX windowed subscreen
|
||||||
|
|||||||
+4
@@ -1527,8 +1527,10 @@ FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context> {
|
|||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wdangling-reference"
|
#pragma GCC diagnostic ignored "-Wdangling-reference"
|
||||||
|
#endif
|
||||||
|
|
||||||
// The type template parameter is there to avoid an ODR violation when using
|
// The type template parameter is there to avoid an ODR violation when using
|
||||||
// a fallback formatter in one translation unit and an implicit conversion in
|
// a fallback formatter in one translation unit and an implicit conversion in
|
||||||
@@ -1544,7 +1546,9 @@ FMT_CONSTEXPR FMT_INLINE auto make_arg(const T& val) -> value<Context> {
|
|||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
template <bool IS_PACKED, typename Context, type, typename T,
|
template <bool IS_PACKED, typename Context, type, typename T,
|
||||||
FMT_ENABLE_IF(!IS_PACKED)>
|
FMT_ENABLE_IF(!IS_PACKED)>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace games::ccj {
|
|||||||
bool MOUSE_TRACKBALL_USE_TOGGLE = false;
|
bool MOUSE_TRACKBALL_USE_TOGGLE = false;
|
||||||
uint8_t TRACKBALL_SENSITIVITY = 10;
|
uint8_t TRACKBALL_SENSITIVITY = 10;
|
||||||
|
|
||||||
static HANDLE fakeHandle = (HANDLE)0xDEADBEEF;
|
static HANDLE fakeHandle = (HANDLE)0xDEADBEEFull;
|
||||||
static HWND hWnd = nullptr;
|
static HWND hWnd = nullptr;
|
||||||
static WNDPROC wndProc = nullptr;
|
static WNDPROC wndProc = nullptr;
|
||||||
static std::thread *tbThread = nullptr;
|
static std::thread *tbThread = nullptr;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ namespace games::ddr {
|
|||||||
|
|
||||||
// settings
|
// settings
|
||||||
bool SDMODE = false;
|
bool SDMODE = false;
|
||||||
|
bool NO_CODEC_REGISTRATION = false;
|
||||||
|
|
||||||
uint8_t DDR_TAPELEDS[TAPELED_DEVICE_COUNT][50][3] {};
|
uint8_t DDR_TAPELEDS[TAPELED_DEVICE_COUNT][50][3] {};
|
||||||
|
|
||||||
@@ -49,9 +50,79 @@ namespace games::ddr {
|
|||||||
return SendMessage_real(hWnd, Msg, wParam, lParam);
|
return SendMessage_real(hWnd, Msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool contains_only_ascii(const std::string& str) {
|
||||||
|
for (auto c: str) {
|
||||||
|
if (static_cast<unsigned char>(c) > 127) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
DDRGame::DDRGame() : Game("Dance Dance Revolution") {
|
DDRGame::DDRGame() : Game("Dance Dance Revolution") {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DDRGame::register_codecs() {
|
||||||
|
// find where spice.exe / spice64.exe is located
|
||||||
|
const auto &spice_bin_path = libutils::module_file_name(nullptr).parent_path();
|
||||||
|
|
||||||
|
// find the com directory
|
||||||
|
std::filesystem::path dir = "";
|
||||||
|
if (MODULE_PATH == spice_bin_path) {
|
||||||
|
// try: \com
|
||||||
|
dir = spice_bin_path / "com";
|
||||||
|
} else {
|
||||||
|
// try: modules\..\com
|
||||||
|
dir = MODULE_PATH / ".." / "com";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileutils::dir_exists(dir)) {
|
||||||
|
log_info("ddr", "looking for codecs in this directory: {}", dir.string());
|
||||||
|
} else {
|
||||||
|
log_info("ddr", "codecs directory not found: {}", dir.string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &file : std::filesystem::directory_iterator(dir)) {
|
||||||
|
const auto &filename = file.path().filename();
|
||||||
|
const auto extension = strtolower(filename.extension().string());
|
||||||
|
|
||||||
|
if (extension != ".dll") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("ddr", "found DLL: {}, size: {} bytes", filename.string(), file.file_size());
|
||||||
|
if (filename == "k-clvsd.dll" || filename.string().find("xactengine") == 0) {
|
||||||
|
const std::wstring wcmd = L"regsvr32.exe /s \"" + file.path().wstring() + L"\"";
|
||||||
|
const std::string cmd = "regsvr32.exe /s \"" + file.path().string() + "\"";
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
std::thread t([wcmd, &result]() {
|
||||||
|
result = _wsystem(wcmd.c_str());
|
||||||
|
});
|
||||||
|
t.join();
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
log_info("ddr", "`{}` returned {}", cmd, result);
|
||||||
|
} else {
|
||||||
|
log_warning("ddr", "`{}` failed, returned {}", cmd, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contains_only_ascii(file.path().string())) {
|
||||||
|
log_warning(
|
||||||
|
"ddr",
|
||||||
|
"BAD PATH ERROR\n\n\n"
|
||||||
|
"!!! !!!\n"
|
||||||
|
"!!! filesystem path to codec contains non-ASCII characters! !!!\n"
|
||||||
|
"!!! this may cause the game to crash! !!!\n"
|
||||||
|
"!!! !!!\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DDRGame::pre_attach() {
|
void DDRGame::pre_attach() {
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("TDX")) {
|
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("TDX")) {
|
||||||
log_fatal(
|
log_fatal(
|
||||||
@@ -87,6 +158,17 @@ namespace games::ddr {
|
|||||||
"!!! !!!\n\n\n"
|
"!!! !!!\n\n\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!cfg::CONFIGURATOR_STANDALONE) {
|
||||||
|
if (!NO_CODEC_REGISTRATION) {
|
||||||
|
this->register_codecs();
|
||||||
|
} else {
|
||||||
|
log_warning(
|
||||||
|
"ddr",
|
||||||
|
"skipping codec registration (-ddrnocodec), "
|
||||||
|
"game may crash if you didn't register codecs before launching the game");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DDRGame::attach() {
|
void DDRGame::attach() {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace games::ddr {
|
|||||||
|
|
||||||
// settings
|
// settings
|
||||||
extern bool SDMODE;
|
extern bool SDMODE;
|
||||||
|
extern bool NO_CODEC_REGISTRATION;
|
||||||
|
|
||||||
// Buffers to store RGB data for tape LEDs on gold cabinets
|
// Buffers to store RGB data for tape LEDs on gold cabinets
|
||||||
const size_t TAPELED_DEVICE_COUNT = 11;
|
const size_t TAPELED_DEVICE_COUNT = 11;
|
||||||
@@ -18,5 +19,8 @@ namespace games::ddr {
|
|||||||
virtual void pre_attach() override;
|
virtual void pre_attach() override;
|
||||||
virtual void attach() override;
|
virtual void attach() override;
|
||||||
virtual void detach() override;
|
virtual void detach() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void register_codecs();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -409,50 +409,27 @@ namespace games::iidx {
|
|||||||
* 16 - side panel right - 183 bytes - 61 colors
|
* 16 - side panel right - 183 bytes - 61 colors
|
||||||
*
|
*
|
||||||
* data is stored in RGB order, 3 bytes per color
|
* data is stored in RGB order, 3 bytes per color
|
||||||
*
|
|
||||||
* TODO: expose this data via API
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// data mapping
|
|
||||||
static struct TapeLedMapping {
|
|
||||||
size_t data_size;
|
|
||||||
int index_r, index_g, index_b;
|
|
||||||
|
|
||||||
TapeLedMapping(size_t data_size, int index_r, int index_g, int index_b)
|
|
||||||
: data_size(data_size), index_r(index_r), index_g(index_g), index_b(index_b) {}
|
|
||||||
|
|
||||||
} mapping[] = {
|
|
||||||
{ 19, Lights::StageLeftAvgR, Lights::StageLeftAvgG, Lights::StageLeftAvgB },
|
|
||||||
{ 19, Lights::StageRightAvgR, Lights::StageRightAvgG, Lights::StageRightAvgB },
|
|
||||||
{ 45, Lights::CabinetLeftAvgR, Lights::CabinetLeftAvgG, Lights::CabinetLeftAvgB },
|
|
||||||
{ 45, Lights::CabinetRightAvgR, Lights::CabinetRightAvgG, Lights::CabinetRightAvgB },
|
|
||||||
{ 21, Lights::ControlPanelUnderAvgR, Lights::ControlPanelUnderAvgG, Lights::ControlPanelUnderAvgB },
|
|
||||||
{ 54, Lights::CeilingLeftAvgR, Lights::CeilingLeftAvgG, Lights::CeilingLeftAvgB },
|
|
||||||
{ 11, Lights::TitleLeftAvgR, Lights::TitleLeftAvgG, Lights::TitleLeftAvgB },
|
|
||||||
{ 11, Lights::TitleRightAvgR, Lights::TitleRightAvgG, Lights::TitleRightAvgB },
|
|
||||||
{ 54, Lights::CeilingRightAvgR, Lights::CeilingRightAvgG, Lights::CeilingRightAvgB },
|
|
||||||
{ 17, Lights::TouchPanelLeftAvgR, Lights::TouchPanelLeftAvgG, Lights::TouchPanelLeftAvgB },
|
|
||||||
{ 17, Lights::TouchPanelRightAvgR, Lights::TouchPanelRightAvgG, Lights::TouchPanelRightAvgB },
|
|
||||||
{ 68, Lights::SidePanelLeftInnerAvgR, Lights::SidePanelLeftInnerAvgG, Lights::SidePanelLeftInnerAvgB },
|
|
||||||
{ 68, Lights::SidePanelLeftOuterAvgR, Lights::SidePanelLeftOuterAvgG, Lights::SidePanelLeftOuterAvgB },
|
|
||||||
{ 61, Lights::SidePanelLeftAvgR, Lights::SidePanelLeftAvgG, Lights::SidePanelLeftAvgB },
|
|
||||||
{ 68, Lights::SidePanelRightOuterAvgR, Lights::SidePanelRightOuterAvgG, Lights::SidePanelRightOuterAvgB },
|
|
||||||
{ 68, Lights::SidePanelRightInnerAvgR, Lights::SidePanelRightInnerAvgG, Lights::SidePanelRightInnerAvgB },
|
|
||||||
{ 61, Lights::SidePanelRightAvgR, Lights::SidePanelRightAvgG, Lights::SidePanelRightAvgB },
|
|
||||||
};
|
|
||||||
|
|
||||||
// check index bounds
|
// check index bounds
|
||||||
if (tapeledutils::is_enabled() && index < std::size(mapping)) {
|
if (tapeledutils::is_enabled() && index < std::size(TAPELED_MAPPING)) {
|
||||||
auto &map = mapping[index];
|
auto &map = TAPELED_MAPPING[index];
|
||||||
|
const auto data_size = map.data.capacity();
|
||||||
|
|
||||||
// pick a color to use
|
// pick a color to use
|
||||||
const auto rgb = tapeledutils::pick_color_from_led_tape(data, map.data_size);
|
const auto rgb = tapeledutils::pick_color_from_led_tape(data, data_size);
|
||||||
|
|
||||||
// program the lights into API
|
// program the lights into API
|
||||||
auto &lights = get_lights();
|
auto &lights = get_lights();
|
||||||
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_r], rgb.r);
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_r], rgb.r);
|
||||||
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_g], rgb.g);
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_g], rgb.g);
|
||||||
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_b], rgb.b);
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_b], rgb.b);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < data_size; ++i) {
|
||||||
|
map.data[i].r = data[i * 3];
|
||||||
|
map.data[i].g = data[i * 3 + 1];
|
||||||
|
map.data[i].b = data[i * 3 + 2];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (This != custom_node) {
|
if (This != custom_node) {
|
||||||
|
|||||||
@@ -27,6 +27,9 @@
|
|||||||
#include "util/memutils.h"
|
#include "util/memutils.h"
|
||||||
#include "util/sigscan.h"
|
#include "util/sigscan.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
|
#include "launcher/signal.h"
|
||||||
|
|
||||||
|
#include "external/robin_hood.h"
|
||||||
|
|
||||||
#include "bi2a.h"
|
#include "bi2a.h"
|
||||||
#include "bi2x_hook.h"
|
#include "bi2x_hook.h"
|
||||||
@@ -74,6 +77,26 @@ namespace games::iidx {
|
|||||||
bool IIDXIO_LED_TICKER_READONLY = false;
|
bool IIDXIO_LED_TICKER_READONLY = false;
|
||||||
std::mutex IIDX_LED_TICKER_LOCK;
|
std::mutex IIDX_LED_TICKER_LOCK;
|
||||||
|
|
||||||
|
tapeledutils::tape_led TAPELED_MAPPING[IIDX_TAPELED_TOTAL] = {
|
||||||
|
{ 19, Lights::StageLeftAvgR, Lights::StageLeftAvgG, Lights::StageLeftAvgB, "Stage Left" },
|
||||||
|
{ 19, Lights::StageRightAvgR, Lights::StageRightAvgG, Lights::StageRightAvgB, "Stage Right" },
|
||||||
|
{ 45, Lights::CabinetLeftAvgR, Lights::CabinetLeftAvgG, Lights::CabinetLeftAvgB, "Cabinet Left" },
|
||||||
|
{ 45, Lights::CabinetRightAvgR, Lights::CabinetRightAvgG, Lights::CabinetRightAvgB, "Cabinet Right" },
|
||||||
|
{ 21, Lights::ControlPanelUnderAvgR, Lights::ControlPanelUnderAvgG, Lights::ControlPanelUnderAvgB, "Control Panel Under" },
|
||||||
|
{ 54, Lights::CeilingLeftAvgR, Lights::CeilingLeftAvgG, Lights::CeilingLeftAvgB, "Ceiling Left" },
|
||||||
|
{ 11, Lights::TitleLeftAvgR, Lights::TitleLeftAvgG, Lights::TitleLeftAvgB, "Title Left" },
|
||||||
|
{ 11, Lights::TitleRightAvgR, Lights::TitleRightAvgG, Lights::TitleRightAvgB, "Title Right" },
|
||||||
|
{ 54, Lights::CeilingRightAvgR, Lights::CeilingRightAvgG, Lights::CeilingRightAvgB, "Ceiling Right" },
|
||||||
|
{ 17, Lights::TouchPanelLeftAvgR, Lights::TouchPanelLeftAvgG, Lights::TouchPanelLeftAvgB, "Touch Panel Left" },
|
||||||
|
{ 17, Lights::TouchPanelRightAvgR, Lights::TouchPanelRightAvgG, Lights::TouchPanelRightAvgB, "Touch Panel Right" },
|
||||||
|
{ 68, Lights::SidePanelLeftInnerAvgR, Lights::SidePanelLeftInnerAvgG, Lights::SidePanelLeftInnerAvgB, "Side Panel Left Inner" },
|
||||||
|
{ 68, Lights::SidePanelLeftOuterAvgR, Lights::SidePanelLeftOuterAvgG, Lights::SidePanelLeftOuterAvgB, "Side Panel Left Outer" },
|
||||||
|
{ 61, Lights::SidePanelLeftAvgR, Lights::SidePanelLeftAvgG, Lights::SidePanelLeftAvgB, "Side Panel Left" },
|
||||||
|
{ 68, Lights::SidePanelRightOuterAvgR, Lights::SidePanelRightOuterAvgG, Lights::SidePanelRightOuterAvgB, "Side Panel Right Outer" },
|
||||||
|
{ 68, Lights::SidePanelRightInnerAvgR, Lights::SidePanelRightInnerAvgG, Lights::SidePanelRightInnerAvgB, "Side Panel Right Inner" },
|
||||||
|
{ 61, Lights::SidePanelRightAvgR, Lights::SidePanelRightAvgG, Lights::SidePanelRightAvgB, "Side Panel Right" },
|
||||||
|
};
|
||||||
|
|
||||||
static LONG WINAPI RegOpenKeyA_hook(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult) {
|
static LONG WINAPI RegOpenKeyA_hook(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult) {
|
||||||
if (lpSubKey != nullptr && phkResult != nullptr) {
|
if (lpSubKey != nullptr && phkResult != nullptr) {
|
||||||
if (hKey == HKEY_LOCAL_MACHINE &&
|
if (hKey == HKEY_LOCAL_MACHINE &&
|
||||||
@@ -210,6 +233,9 @@ namespace games::iidx {
|
|||||||
} else if (data.find(" W:touch: missing trigger:") != std::string::npos) {
|
} else if (data.find(" W:touch: missing trigger:") != std::string::npos) {
|
||||||
out.clear();
|
out.clear();
|
||||||
return true;
|
return true;
|
||||||
|
} else if (data.find("SuperstepSound: Audio device is not available") != std::string::npos) {
|
||||||
|
launcher::signal::SUPERSTEP_SOUND_ERROR = TRUE;
|
||||||
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -759,7 +785,7 @@ namespace games::iidx {
|
|||||||
if (SOUND_OUTPUT_DEVICE_IN_EFFECT.has_value() && SOUND_OUTPUT_DEVICE_IN_EFFECT.value() == "wasapi") {
|
if (SOUND_OUTPUT_DEVICE_IN_EFFECT.has_value() && SOUND_OUTPUT_DEVICE_IN_EFFECT.value() == "wasapi") {
|
||||||
intptr_t result = replace_pattern(
|
intptr_t result = replace_pattern(
|
||||||
avs::game::DLL_INSTANCE,
|
avs::game::DLL_INSTANCE,
|
||||||
"FF5008E8????ECFF83780803740D",
|
"FF5008E8??????FF83780803740D",
|
||||||
"??????BB00000000EB169090????",
|
"??????BB00000000EB169090????",
|
||||||
0, 0);
|
0, 0);
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,13 @@
|
|||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "games/game.h"
|
#include "games/game.h"
|
||||||
|
|
||||||
|
#include "external/robin_hood.h"
|
||||||
|
#include "util/tapeled.h"
|
||||||
|
|
||||||
namespace games::iidx {
|
namespace games::iidx {
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
@@ -30,6 +34,10 @@ namespace games::iidx {
|
|||||||
extern bool IIDXIO_LED_TICKER_READONLY;
|
extern bool IIDXIO_LED_TICKER_READONLY;
|
||||||
extern std::mutex IIDX_LED_TICKER_LOCK;
|
extern std::mutex IIDX_LED_TICKER_LOCK;
|
||||||
|
|
||||||
|
constexpr int IIDX_TAPELED_TOTAL = 17;
|
||||||
|
// data mapping
|
||||||
|
extern tapeledutils::tape_led TAPELED_MAPPING[IIDX_TAPELED_TOTAL];
|
||||||
|
|
||||||
class IIDXGame : public games::Game {
|
class IIDXGame : public games::Game {
|
||||||
public:
|
public:
|
||||||
IIDXGame();
|
IIDXGame();
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
#include "ccj/io.h"
|
#include "ccj/io.h"
|
||||||
#include "qks/io.h"
|
#include "qks/io.h"
|
||||||
#include "mfg/io.h"
|
#include "mfg/io.h"
|
||||||
|
#include "pc/io.h"
|
||||||
|
|
||||||
namespace games {
|
namespace games {
|
||||||
|
|
||||||
@@ -313,6 +314,15 @@ namespace games {
|
|||||||
buttons.insert({ mfg, mfg::get_buttons() });
|
buttons.insert({ mfg, mfg::get_buttons() });
|
||||||
buttons_help.insert({ mfg, mfg::get_buttons_help() });
|
buttons_help.insert({ mfg, mfg::get_buttons_help() });
|
||||||
file_hints[mfg].emplace_back("game/MFGClient_Data");
|
file_hints[mfg].emplace_back("game/MFGClient_Data");
|
||||||
|
|
||||||
|
// Polaris Chord
|
||||||
|
const std::string pc("Polaris Chord");
|
||||||
|
games.push_back(pc);
|
||||||
|
buttons.insert({ pc, pc::get_buttons() });
|
||||||
|
buttons_help.insert({ pc, pc::get_buttons_help() });
|
||||||
|
analogs.insert({ pc, pc::get_analogs() });
|
||||||
|
lights.insert({ pc, pc::get_lights() });
|
||||||
|
file_hints[pc].emplace_back("game/svm_Data");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string> &get_games() {
|
const std::vector<std::string> &get_games() {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace games::mfg {
|
|||||||
SetEnvironmentVariableA("VFG_CABINET_TYPE", MFG_CABINET_TYPE.c_str());
|
SetEnvironmentVariableA("VFG_CABINET_TYPE", MFG_CABINET_TYPE.c_str());
|
||||||
|
|
||||||
// add card reader
|
// add card reader
|
||||||
portName = MFG_CABINET_TYPE == "UKS" ? L"\\\\.\\COM1" : L"\\\\.\\COM3";
|
portName = (MFG_CABINET_TYPE == "UKS") ? std::wstring(L"\\\\.\\COM1") : std::wstring(L"\\\\.\\COM3");
|
||||||
acioHandle = new acioemu::ACIOHandle(portName.c_str(), 1);
|
acioHandle = new acioemu::ACIOHandle(portName.c_str(), 1);
|
||||||
devicehook_init_trampoline();
|
devicehook_init_trampoline();
|
||||||
devicehook_add(acioHandle);
|
devicehook_add(acioHandle);
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ namespace games::otoca {
|
|||||||
bool kb_insert_press = false;
|
bool kb_insert_press = false;
|
||||||
|
|
||||||
// eamio keypress
|
// eamio keypress
|
||||||
kb_insert_press |= eamuse_get_keypad_state(0) & (1 << EAM_IO_INSERT);
|
kb_insert_press |= static_cast<bool>(eamuse_get_keypad_state(0) & (1 << EAM_IO_INSERT));
|
||||||
|
|
||||||
// check for card
|
// check for card
|
||||||
if (CARD_DATA == nullptr && (eamuse_card_insert_consume(1, 0) || kb_insert_press)) {
|
if (CARD_DATA == nullptr && (eamuse_card_insert_consume(1, 0) || kb_insert_press)) {
|
||||||
|
|||||||
@@ -0,0 +1,652 @@
|
|||||||
|
#include "bi2x_hook.h"
|
||||||
|
|
||||||
|
#include "util/execexe.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
#include "rawinput/rawinput.h"
|
||||||
|
#include "misc/eamuse.h"
|
||||||
|
#include "games/io.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "util/tapeled.h"
|
||||||
|
#include "pc.h"
|
||||||
|
#include "util/utils.h"
|
||||||
|
|
||||||
|
namespace games::pc {
|
||||||
|
bool PC_KNOB_MODE = false;
|
||||||
|
|
||||||
|
constexpr float RELATIVE_DECAY = 0.02f;
|
||||||
|
struct FADER_RELATIVE {
|
||||||
|
// ranges from 0.f to 1.f
|
||||||
|
float previous_raw = 0.5f;
|
||||||
|
|
||||||
|
// ranges from -1.f to +1.f
|
||||||
|
float effective_value = 0.f;
|
||||||
|
};
|
||||||
|
|
||||||
|
FADER_RELATIVE fader_l_relative;
|
||||||
|
FADER_RELATIVE fader_r_relative;
|
||||||
|
|
||||||
|
float calculate_analog_raw_delta(float old_value, float new_value) {
|
||||||
|
// assumed that values are between 0.f and 1.f
|
||||||
|
|
||||||
|
float delta = 0.f;
|
||||||
|
if ((old_value < 0.25f) && (0.75f < new_value)) {
|
||||||
|
// wrapped around: going left
|
||||||
|
delta = -((1.f - new_value) + old_value);
|
||||||
|
|
||||||
|
} else if ((new_value < 0.25f) && (0.75f < old_value)) {
|
||||||
|
// wrapped around: going right
|
||||||
|
delta = (1.f - old_value) + new_value;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
delta = new_value - old_value;
|
||||||
|
}
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
float apply_decay(float val) {
|
||||||
|
// return to center over time
|
||||||
|
if (RELATIVE_DECAY < val) {
|
||||||
|
return val - RELATIVE_DECAY;
|
||||||
|
} else if (val < -RELATIVE_DECAY) {
|
||||||
|
return val + RELATIVE_DECAY;
|
||||||
|
} else {
|
||||||
|
return 0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float get_fader_knob_mode_value(float raw_analog, FADER_RELATIVE &fader) {
|
||||||
|
// add new value...
|
||||||
|
const float delta = calculate_analog_raw_delta(fader.previous_raw, raw_analog);
|
||||||
|
fader.effective_value += (delta * 20.f);
|
||||||
|
fader.previous_raw = raw_analog;
|
||||||
|
|
||||||
|
// capture the result after adding new input value
|
||||||
|
fader.effective_value = CLAMP(fader.effective_value, -1.f, 1.f);
|
||||||
|
const float result = fader.effective_value;
|
||||||
|
|
||||||
|
// post-process for next iteration: apply decay (return to center over time)
|
||||||
|
fader.effective_value = apply_decay(fader.effective_value);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* class definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct AIO_SCI_COMM {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_NMGR_IOB2 {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1 {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__SETTING {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_WRFIRM {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__INPUT
|
||||||
|
{
|
||||||
|
uint8_t DevIoCounter;
|
||||||
|
uint8_t bExIoAErr;
|
||||||
|
uint8_t bExIoBErr;
|
||||||
|
uint8_t bPcPowerOn;
|
||||||
|
uint8_t bPcPowerCheck;
|
||||||
|
uint8_t bCoin1Jam;
|
||||||
|
uint8_t bCoin2Jam;
|
||||||
|
uint8_t bCoin3Jam;
|
||||||
|
uint8_t bCoin4Jam;
|
||||||
|
uint8_t Coin1Count;
|
||||||
|
uint8_t Coin2Count;
|
||||||
|
uint8_t Coin3Count;
|
||||||
|
uint8_t Coin4Count;
|
||||||
|
uint16_t AnalogCh1;
|
||||||
|
uint16_t AnalogCh2;
|
||||||
|
uint16_t AnalogCh3;
|
||||||
|
uint16_t AnalogCh4;
|
||||||
|
uint8_t CN8_8;
|
||||||
|
uint8_t CN8_9;
|
||||||
|
uint8_t CN8_10;
|
||||||
|
uint8_t CN9_8;
|
||||||
|
uint8_t CN9_9;
|
||||||
|
uint8_t CN9_10;
|
||||||
|
uint8_t CN11_11;
|
||||||
|
uint8_t CN11_12;
|
||||||
|
uint8_t CN11_13;
|
||||||
|
uint8_t CN11_14;
|
||||||
|
uint8_t CN11_15;
|
||||||
|
uint8_t CN11_16;
|
||||||
|
uint8_t CN11_17;
|
||||||
|
uint8_t CN11_18;
|
||||||
|
uint8_t CN11_19;
|
||||||
|
uint8_t CN11_20;
|
||||||
|
uint8_t CN12_11;
|
||||||
|
uint8_t CN12_12;
|
||||||
|
uint8_t CN12_13;
|
||||||
|
uint8_t CN12_14;
|
||||||
|
uint8_t CN12_15;
|
||||||
|
uint8_t CN12_16;
|
||||||
|
uint8_t CN12_17;
|
||||||
|
uint8_t CN12_18;
|
||||||
|
uint8_t CN12_19;
|
||||||
|
uint8_t CN12_20;
|
||||||
|
uint8_t CN12_21;
|
||||||
|
uint8_t CN12_22;
|
||||||
|
uint8_t CN12_23;
|
||||||
|
uint8_t CN12_24;
|
||||||
|
uint8_t CN15_3;
|
||||||
|
uint8_t CN15_4;
|
||||||
|
uint8_t CN15_5;
|
||||||
|
uint8_t CN15_6;
|
||||||
|
uint8_t CN15_7;
|
||||||
|
uint8_t CN15_8;
|
||||||
|
uint8_t CN15_9;
|
||||||
|
uint8_t CN15_10;
|
||||||
|
uint8_t CN15_11;
|
||||||
|
uint8_t CN15_12;
|
||||||
|
uint8_t CN15_13;
|
||||||
|
uint8_t CN15_14;
|
||||||
|
uint8_t CN15_15;
|
||||||
|
uint8_t CN15_16;
|
||||||
|
uint8_t CN15_17;
|
||||||
|
uint8_t CN15_18;
|
||||||
|
uint8_t CN15_19;
|
||||||
|
uint8_t CN15_20;
|
||||||
|
uint8_t CN19_8;
|
||||||
|
uint8_t CN19_9;
|
||||||
|
uint8_t CN19_10;
|
||||||
|
uint8_t CN19_11;
|
||||||
|
uint8_t CN19_12;
|
||||||
|
uint8_t CN19_13;
|
||||||
|
uint8_t CN19_14;
|
||||||
|
uint8_t CN19_15;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__INPUTDATA {
|
||||||
|
uint8_t data[247];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__OUTPUTDATA {
|
||||||
|
uint8_t data[48];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__ICNPIN {
|
||||||
|
uint16_t Ain[4];
|
||||||
|
uint64_t CnPin;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__DEVSTATUS {
|
||||||
|
uint8_t InputCounter;
|
||||||
|
uint8_t OutputCounter;
|
||||||
|
uint8_t IoResetCounter;
|
||||||
|
uint8_t TapeLedCounter;
|
||||||
|
uint8_t TapeLedRate[8];
|
||||||
|
AIO_IOB2_BI2X_AC1__INPUT Input;
|
||||||
|
AIO_IOB2_BI2X_AC1__INPUTDATA InputData;
|
||||||
|
AIO_IOB2_BI2X_AC1__OUTPUTDATA OutputData;
|
||||||
|
AIO_IOB2_BI2X_AC1__ICNPIN ICnPinHist[20];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* typedefs
|
||||||
|
*/
|
||||||
|
|
||||||
|
// libaio-iob2_video.dll
|
||||||
|
typedef AIO_IOB2_BI2X_AC1* (__fastcall *aioIob2Bi2xAC1_Create_t)(AIO_NMGR_IOB2 *i_pNodeMgr, uint32_t i_DevId,
|
||||||
|
AIO_IOB2_BI2X_AC1__SETTING *i_Setting);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_GetDeviceStatus_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl,
|
||||||
|
AIO_IOB2_BI2X_AC1__DEVSTATUS *o_DevStatus);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_SetWatchDogTimer_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint8_t i_Count);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_AddCounter_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_Counter,
|
||||||
|
uint32_t i_Count);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_SetOutputData_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_CnPin,
|
||||||
|
uint8_t i_Data);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_SetTapeLedDataPart_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_TapeLedCh,
|
||||||
|
uint32_t i_Offset, uint8_t *i_pData,
|
||||||
|
uint32_t i_cntTapeLed, bool i_bReverse);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2x_SetTapeLedDataGroup_t)(AIO_IOB2_BI2X_AC1* i_pNodeCtl, uint32_t i_bfGroup);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2x_SetTapeLedDataLimit_t)(AIO_IOB2_BI2X_AC1* i_pNodeCtl, uint32_t i_Channel,
|
||||||
|
uint8_t i_Scale, uint8_t i_Limit);
|
||||||
|
typedef AIO_IOB2_BI2X_WRFIRM *(__fastcall *aioIob2Bi2x_CreateWriteFirmContext_t)(uint32_t i_SerialNumber,
|
||||||
|
uint32_t i_bfIob);
|
||||||
|
typedef AIO_SCI_COMM* (__fastcall *aioIob2Bi2x_OpenSciUsbCdc_t)(uint32_t i_SerialNumber);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2x_DestroyWriteFirmContext_t)(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm);
|
||||||
|
typedef int32_t (__fastcall *aioIob2Bi2x_WriteFirmGetState_t)(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm);
|
||||||
|
typedef bool (__fastcall *aioIob2Bi2x_WriteFirmIsCompleted_t)(int32_t i_State);
|
||||||
|
typedef bool (__fastcall *aioIob2Bi2x_WriteFirmIsError_t)(int32_t i_State);
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
typedef AIO_NMGR_IOB2 *(__fastcall *aioNMgrIob2_Create_t)(AIO_SCI_COMM *i_pSci, uint32_t i_bfMode);
|
||||||
|
typedef void (__fastcall *aioNMgrIob_BeginManage_t)(AIO_NMGR_IOB2 *i_pNodeMgr);
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
typedef void (__fastcall *aioSci_Destroy_t)(AIO_SCI_COMM *i_pNodeMgr);
|
||||||
|
typedef void (__fastcall *aioNodeMgr_Destroy_t)(AIO_NMGR_IOB2 *i_pNodeMgr);
|
||||||
|
typedef int32_t (__fastcall *aioNodeMgr_GetState_t)(AIO_NMGR_IOB2 *i_pNodeMgr);
|
||||||
|
typedef bool (__fastcall *aioNodeMgr_IsReady_t)(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State);
|
||||||
|
typedef bool (__fastcall *aioNodeMgr_IsError_t)(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State);
|
||||||
|
typedef void (__fastcall *aioNodeCtl_Destroy_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl);
|
||||||
|
typedef int32_t (__fastcall *aioNodeCtl_GetState_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl);
|
||||||
|
typedef bool (__fastcall *aioNodeCtl_IsReady_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, int32_t i_State);
|
||||||
|
typedef bool (__fastcall *aioNodeCtl_IsError_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, int32_t i_State);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* function pointers
|
||||||
|
*/
|
||||||
|
|
||||||
|
// libaio-iob2_video.dll
|
||||||
|
static aioIob2Bi2xAC1_Create_t aioIob2Bi2xAC1_Create_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_GetDeviceStatus_t aioIob2Bi2xAC1_GetDeviceStatus_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_SetWatchDogTimer_t aioIob2Bi2xAC1_SetWatchDogTimer_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_AddCounter_t aioIob2Bi2xAC1_AddCounter_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_SetOutputData_t aioIob2Bi2xAC1_SetOutputData_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_SetTapeLedDataPart_t aioIob2Bi2xAC1_SetTapeLedDataPart_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_SetTapeLedDataGroup_t aioIob2Bi2x_SetTapeLedDataGroup_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_SetTapeLedDataLimit_t aioIob2Bi2x_SetTapeLedDataLimit_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_OpenSciUsbCdc_t aioIob2Bi2x_OpenSciUsbCdc_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_CreateWriteFirmContext_t aioIob2Bi2x_CreateWriteFirmContext_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_DestroyWriteFirmContext_t aioIob2Bi2x_DestroyWriteFirmContext_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_WriteFirmGetState_t aioIob2Bi2x_WriteFirmGetState_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_WriteFirmIsCompleted_t aioIob2Bi2x_WriteFirmIsCompleted_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_WriteFirmIsError_t aioIob2Bi2x_WriteFirmIsError_orig = nullptr;
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
static aioNMgrIob2_Create_t aioNMgrIob2_Create_orig = nullptr;
|
||||||
|
static aioNMgrIob_BeginManage_t aioNMgrIob_BeginManage_orig = nullptr;
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
static aioSci_Destroy_t aioSci_Destroy_orig = nullptr;
|
||||||
|
static aioNodeMgr_Destroy_t aioNodeMgr_Destroy_orig = nullptr;
|
||||||
|
static aioNodeMgr_GetState_t aioNodeMgr_GetState_orig = nullptr;
|
||||||
|
static aioNodeMgr_IsReady_t aioNodeMgr_IsReady_orig = nullptr;
|
||||||
|
static aioNodeMgr_IsError_t aioNodeMgr_IsError_orig = nullptr;
|
||||||
|
static aioNodeCtl_Destroy_t aioNodeCtl_Destroy_orig = nullptr;
|
||||||
|
static aioNodeCtl_GetState_t aioNodeCtl_GetState_orig = nullptr;
|
||||||
|
static aioNodeCtl_IsReady_t aioNodeCtl_IsReady_orig = nullptr;
|
||||||
|
static aioNodeCtl_IsError_t aioNodeCtl_IsError_orig = nullptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
static AIO_IOB2_BI2X_AC1 *aioIob2Bi2xAc1;
|
||||||
|
static AIO_SCI_COMM *aioSciComm;
|
||||||
|
static AIO_NMGR_IOB2 *aioNmgrIob2;
|
||||||
|
static AIO_IOB2_BI2X_WRFIRM *aioIob2Bi2xWrfirm;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* implementations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// libaio-iob2_video.dll
|
||||||
|
|
||||||
|
static AIO_IOB2_BI2X_AC1* __fastcall aioIob2Bi2xAC1_Create(AIO_NMGR_IOB2 *i_pNodeMgr, uint32_t i_DevId,
|
||||||
|
AIO_IOB2_BI2X_AC1__SETTING *i_Setting) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
log_info("bi2x_hook", "aioIob2Bi2xAC1_Create hook hit");
|
||||||
|
aioIob2Bi2xAc1 = new AIO_IOB2_BI2X_AC1;
|
||||||
|
return aioIob2Bi2xAc1;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2xAC1_Create_orig(i_pNodeMgr, i_DevId, i_Setting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2xAC1_GetDeviceStatus(AIO_IOB2_BI2X_AC1 *i_pNodeCtl,
|
||||||
|
AIO_IOB2_BI2X_AC1__DEVSTATUS *o_DevStatus) {
|
||||||
|
RI_MGR->devices_flush_output();
|
||||||
|
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2xAC1_GetDeviceStatus_orig(i_pNodeCtl, o_DevStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(o_DevStatus, 0x00, sizeof(AIO_IOB2_BI2X_AC1__DEVSTATUS));
|
||||||
|
|
||||||
|
auto &buttons = get_buttons();
|
||||||
|
o_DevStatus->Input.CN8_8 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Test]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN8_9 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Service]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN8_10 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::CoinMech]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN15_10 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Headphone]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN15_12 = 0xFF; // Recorder off; present in I/O test menu but unused in game
|
||||||
|
|
||||||
|
o_DevStatus->Input.CN12_11 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button1]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_12 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button2]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_13 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button3]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_14 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button4]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_15 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button5]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_16 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button6]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_17 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button7]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_18 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button8]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_19 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button9]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_20 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button10]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_21 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button11]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_22 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button12]) ? 0 : 0xFF;
|
||||||
|
|
||||||
|
auto &analogs = get_analogs();
|
||||||
|
|
||||||
|
// FADER-L
|
||||||
|
float val = 0.f;
|
||||||
|
if (analogs[Analogs::FaderL].isSet()) {
|
||||||
|
if (PC_KNOB_MODE) {
|
||||||
|
val = get_fader_knob_mode_value(
|
||||||
|
GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderL]),
|
||||||
|
fader_l_relative);
|
||||||
|
} else {
|
||||||
|
val = (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderL]) - 0.5f) * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Left]) &&
|
||||||
|
GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Right])) {
|
||||||
|
val = 0.f;
|
||||||
|
} else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Left])) {
|
||||||
|
val = -1.0f;
|
||||||
|
} else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Right])) {
|
||||||
|
val = +1.0f;
|
||||||
|
}
|
||||||
|
o_DevStatus->Input.CN15_7 = (val < 0.2f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN15_6 = (val > -0.85f && val < 0.35f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN15_5 = (val > -0.6f && val < 0.6f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN15_4 = (val > -0.35f && val < 0.85f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN15_3 = (val > -0.2f) ? 0xFF : 0;
|
||||||
|
|
||||||
|
// FADER-R
|
||||||
|
val = 0.f;
|
||||||
|
if (analogs[Analogs::FaderR].isSet()) {
|
||||||
|
if (PC_KNOB_MODE) {
|
||||||
|
val = get_fader_knob_mode_value(
|
||||||
|
GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderR]),
|
||||||
|
fader_r_relative);
|
||||||
|
} else {
|
||||||
|
val = (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderR]) - 0.5f) * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Left]) &&
|
||||||
|
GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Right])) {
|
||||||
|
val = 0.f;
|
||||||
|
} else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Left])) {
|
||||||
|
val = -1.0f;
|
||||||
|
} else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Right])) {
|
||||||
|
val = +1.0f;
|
||||||
|
}
|
||||||
|
o_DevStatus->Input.CN11_20 = (val < 0.2f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN11_19 = (val > -0.85f && val < 0.35f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN9_10 = (val > -0.6f && val < 0.6f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN9_9 = (val > -0.35f && val < 0.85f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN9_8 = (val > -0.2f) ? 0xFF : 0;
|
||||||
|
|
||||||
|
// coin
|
||||||
|
o_DevStatus->Input.Coin1Count = eamuse_coin_get_stock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2xAC1_SetWatchDogTimer(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint8_t i_Count) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2xAC1_SetWatchDogTimer_orig(i_pNodeCtl, i_Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2xAC1_AddCounter(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_Counter, uint32_t i_Count) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1 && i_Count == 0) {
|
||||||
|
eamuse_coin_set_stock((uint16_t) i_Count);
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2xAC1_AddCounter_orig(i_pNodeCtl, i_Counter, i_Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2xAC1_SetOutputData(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_CnPin, uint8_t i_Data) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2xAC1_SetOutputData_orig(i_pNodeCtl, i_CnPin, i_Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i_CnPin == 0x1) {
|
||||||
|
eamuse_coin_set_block(i_Data == 0xFF);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &lights = get_lights();
|
||||||
|
if (i_CnPin == 0x11) {
|
||||||
|
GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::IC_READER_R), i_Data / 255.0f);
|
||||||
|
} else if (i_CnPin == 0x12) {
|
||||||
|
GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::IC_READER_G), i_Data / 255.0f);
|
||||||
|
} else if (i_CnPin == 0x13) {
|
||||||
|
GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::IC_READER_B), i_Data / 255.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2xAC1_SetTapeLedDataPart(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_TapeLedCh,
|
||||||
|
uint32_t i_Offset, uint8_t *i_pData,
|
||||||
|
uint32_t i_cntTapeLed, bool i_bReverse) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2xAC1_SetTapeLedDataPart_orig(i_pNodeCtl, i_TapeLedCh, i_Offset, i_pData, i_cntTapeLed, i_bReverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO implement tape led
|
||||||
|
// there are >200 lights in total, adding each one separately probably isn't the best idea...
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2x_SetTapeLedDataGroup(AIO_IOB2_BI2X_AC1* i_pNodeCtl, uint32_t i_bfGroup) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2x_SetTapeLedDataGroup_orig(i_pNodeCtl, i_bfGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2x_SetTapeLedDataLimit(AIO_IOB2_BI2X_AC1* i_pNodeCtl, uint32_t i_Channel,
|
||||||
|
uint8_t i_Scale, uint8_t i_Limit) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2x_SetTapeLedDataLimit_orig(i_pNodeCtl, i_Channel, i_Scale, i_Limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static AIO_SCI_COMM *__fastcall aioIob2Bi2x_OpenSciUsbCdc(uint32_t i_SerialNumber) {
|
||||||
|
aioSciComm = new AIO_SCI_COMM;
|
||||||
|
return aioSciComm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AIO_IOB2_BI2X_WRFIRM *__fastcall aioIob2Bi2x_CreateWriteFirmContext(
|
||||||
|
uint32_t i_SerialNumber, uint32_t i_bfIob) {
|
||||||
|
|
||||||
|
aioIob2Bi2xWrfirm = new AIO_IOB2_BI2X_WRFIRM;
|
||||||
|
return aioIob2Bi2xWrfirm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall aioIob2Bi2x_DestroyWriteFirmContext(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm) {
|
||||||
|
if (i_pWrFirm == aioIob2Bi2xWrfirm) {
|
||||||
|
delete aioIob2Bi2xWrfirm;
|
||||||
|
aioIob2Bi2xWrfirm = nullptr;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2x_DestroyWriteFirmContext_orig(i_pWrFirm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t __fastcall aioIob2Bi2x_WriteFirmGetState(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm) {
|
||||||
|
if (i_pWrFirm == aioIob2Bi2xWrfirm) {
|
||||||
|
return 8;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2x_WriteFirmGetState_orig(i_pWrFirm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioIob2Bi2x_WriteFirmIsCompleted(int32_t i_State) {
|
||||||
|
if (aioIob2Bi2xWrfirm != nullptr) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2x_WriteFirmIsCompleted_orig(i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioIob2Bi2x_WriteFirmIsError(int32_t i_State) {
|
||||||
|
if (aioIob2Bi2xWrfirm != nullptr) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2x_WriteFirmIsError_orig(i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
|
||||||
|
static AIO_NMGR_IOB2 *__fastcall aioNMgrIob2_Create(AIO_SCI_COMM *i_pSci, uint32_t i_bfMode) {
|
||||||
|
if (i_pSci == aioSciComm) {
|
||||||
|
aioNmgrIob2 = new AIO_NMGR_IOB2;
|
||||||
|
return aioNmgrIob2;
|
||||||
|
} else {
|
||||||
|
return aioNMgrIob2_Create_orig(i_pSci, i_bfMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall aioNMgrIob_BeginManage(AIO_NMGR_IOB2 *i_pNodeMgr) {
|
||||||
|
if (i_pNodeMgr != aioNmgrIob2) {
|
||||||
|
return aioNMgrIob_BeginManage_orig(i_pNodeMgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
|
||||||
|
static void __fastcall aioSci_Destroy(AIO_SCI_COMM *i_pNodeMgr) {
|
||||||
|
if (i_pNodeMgr == aioSciComm) {
|
||||||
|
delete aioSciComm;
|
||||||
|
} else {
|
||||||
|
return aioSci_Destroy_orig(i_pNodeMgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall aioNodeMgr_Destroy(AIO_NMGR_IOB2 *i_pNodeMgr) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
delete aioNmgrIob2;
|
||||||
|
aioNmgrIob2 = nullptr;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_Destroy_orig(i_pNodeMgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t __fastcall aioNodeMgr_GetState(AIO_NMGR_IOB2 *i_pNodeMgr) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_GetState_orig(i_pNodeMgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeMgr_IsReady(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_IsReady_orig(i_pNodeMgr, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeMgr_IsError(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_IsError_orig(i_pNodeMgr, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall aioNodeCtl_Destroy(AIO_IOB2_BI2X_AC1 *i_pNodeCtl) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1) {
|
||||||
|
delete aioIob2Bi2xAc1;
|
||||||
|
aioIob2Bi2xAc1 = nullptr;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_Destroy_orig(i_pNodeCtl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t __fastcall aioNodeCtl_GetState(AIO_IOB2_BI2X_AC1 *i_pNodeCtl) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_GetState_orig(i_pNodeCtl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeCtl_IsReady(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, int32_t i_State) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_IsReady_orig(i_pNodeCtl, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeCtl_IsError(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, int32_t i_State) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_IsError_orig(i_pNodeCtl, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bi2x_hook_init() {
|
||||||
|
// avoid double init
|
||||||
|
static bool initialized = false;
|
||||||
|
if (initialized) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// announce
|
||||||
|
log_info("bi2x_hook", "init");
|
||||||
|
|
||||||
|
// libaio-iob2_video.dll
|
||||||
|
const auto libaioIob2VideoDll = "libaio-iob2_video.dll";
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_Create",
|
||||||
|
aioIob2Bi2xAC1_Create, &aioIob2Bi2xAC1_Create_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_GetDeviceStatus",
|
||||||
|
aioIob2Bi2xAC1_GetDeviceStatus, &aioIob2Bi2xAC1_GetDeviceStatus_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_SetWatchDogTimer",
|
||||||
|
aioIob2Bi2xAC1_SetWatchDogTimer, &aioIob2Bi2xAC1_SetWatchDogTimer_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_AddCounter",
|
||||||
|
aioIob2Bi2xAC1_AddCounter, &aioIob2Bi2xAC1_AddCounter_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_SetOutputData",
|
||||||
|
aioIob2Bi2xAC1_SetOutputData, &aioIob2Bi2xAC1_SetOutputData_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_SetTapeLedDataPart",
|
||||||
|
aioIob2Bi2xAC1_SetTapeLedDataPart, &aioIob2Bi2xAC1_SetTapeLedDataPart_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_SetTapeLedDataGroup",
|
||||||
|
aioIob2Bi2x_SetTapeLedDataGroup, &aioIob2Bi2x_SetTapeLedDataGroup_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_SetTapeLedDataLimit",
|
||||||
|
aioIob2Bi2x_SetTapeLedDataLimit, &aioIob2Bi2x_SetTapeLedDataLimit_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_OpenSciUsbCdc",
|
||||||
|
aioIob2Bi2x_OpenSciUsbCdc, &aioIob2Bi2x_OpenSciUsbCdc_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_CreateWriteFirmContext",
|
||||||
|
aioIob2Bi2x_CreateWriteFirmContext, &aioIob2Bi2x_CreateWriteFirmContext_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_DestroyWriteFirmContext",
|
||||||
|
aioIob2Bi2x_DestroyWriteFirmContext, &aioIob2Bi2x_DestroyWriteFirmContext_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_WriteFirmGetState",
|
||||||
|
aioIob2Bi2x_WriteFirmGetState, &aioIob2Bi2x_WriteFirmGetState_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_WriteFirmIsCompleted",
|
||||||
|
aioIob2Bi2x_WriteFirmIsCompleted, &aioIob2Bi2x_WriteFirmIsCompleted_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_WriteFirmIsError",
|
||||||
|
aioIob2Bi2x_WriteFirmIsError, &aioIob2Bi2x_WriteFirmIsError_orig);
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
const auto libaioIobDll = "libaio-iob.dll";
|
||||||
|
execexe::trampoline_try(libaioIobDll, "aioNMgrIob2_Create",
|
||||||
|
aioNMgrIob2_Create, &aioNMgrIob2_Create_orig);
|
||||||
|
execexe::trampoline_try(libaioIobDll, "aioNMgrIob_BeginManage",
|
||||||
|
aioNMgrIob_BeginManage, &aioNMgrIob_BeginManage_orig);
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
const auto libaioDll = "libaio.dll";
|
||||||
|
execexe::trampoline_try(libaioDll, "aioSci_Destroy",
|
||||||
|
aioSci_Destroy, &aioSci_Destroy_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_Destroy",
|
||||||
|
aioNodeMgr_Destroy, &aioNodeMgr_Destroy_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_GetState",
|
||||||
|
aioNodeMgr_GetState, &aioNodeMgr_GetState_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_IsReady",
|
||||||
|
aioNodeMgr_IsReady, &aioNodeMgr_IsReady_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_IsError",
|
||||||
|
aioNodeMgr_IsError, &aioNodeMgr_IsError_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_Destroy",
|
||||||
|
aioNodeCtl_Destroy, &aioNodeCtl_Destroy_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_GetState",
|
||||||
|
aioNodeCtl_GetState, &aioNodeCtl_GetState_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_IsReady",
|
||||||
|
aioNodeCtl_IsReady, &aioNodeCtl_IsReady_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_IsError",
|
||||||
|
aioNodeCtl_IsError, &aioNodeCtl_IsError_orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace games::pc {
|
||||||
|
void bi2x_hook_init();
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
std::vector<Button> &games::pc::get_buttons() {
|
||||||
|
static std::vector<Button> buttons;
|
||||||
|
|
||||||
|
if (buttons.empty()) {
|
||||||
|
buttons = GameAPI::Buttons::getButtons("Polaris Chord");
|
||||||
|
|
||||||
|
GameAPI::Buttons::sortButtons(
|
||||||
|
&buttons,
|
||||||
|
"Service",
|
||||||
|
"Test",
|
||||||
|
"Coin Mech",
|
||||||
|
"Button 1",
|
||||||
|
"Button 2",
|
||||||
|
"Button 3",
|
||||||
|
"Button 4",
|
||||||
|
"Button 5",
|
||||||
|
"Button 6",
|
||||||
|
"Button 7",
|
||||||
|
"Button 8",
|
||||||
|
"Button 9",
|
||||||
|
"Button 10",
|
||||||
|
"Button 11",
|
||||||
|
"Button 12",
|
||||||
|
"Fader-L Left",
|
||||||
|
"Fader-L Right",
|
||||||
|
"Fader-R Left",
|
||||||
|
"Fader-R Right",
|
||||||
|
"Headphone"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string games::pc::get_buttons_help() {
|
||||||
|
// keep to max 100 characters wide
|
||||||
|
return
|
||||||
|
" FADER-L FADER-R \n"
|
||||||
|
"\n"
|
||||||
|
" B1 B2 B3 ... B11 B12\n"
|
||||||
|
"\n"
|
||||||
|
" Most menu interactions are on the touch screen; you can use your mouse.\n"
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Analog> &games::pc::get_analogs() {
|
||||||
|
static std::vector<Analog> analogs;
|
||||||
|
|
||||||
|
if (analogs.empty()) {
|
||||||
|
analogs = GameAPI::Analogs::getAnalogs("Polaris Chord");
|
||||||
|
|
||||||
|
GameAPI::Analogs::sortAnalogs(
|
||||||
|
&analogs,
|
||||||
|
"Fader-L",
|
||||||
|
"Fader-R"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return analogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Light> &games::pc::get_lights() {
|
||||||
|
static std::vector<Light> lights;
|
||||||
|
|
||||||
|
if (lights.empty()) {
|
||||||
|
lights = GameAPI::Lights::getLights("Polaris Chord");
|
||||||
|
|
||||||
|
GameAPI::Lights::sortLights(
|
||||||
|
&lights,
|
||||||
|
"IC Reader R",
|
||||||
|
"IC Reader G",
|
||||||
|
"IC Reader B"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lights;
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "cfg/api.h"
|
||||||
|
|
||||||
|
namespace games::pc {
|
||||||
|
namespace Buttons {
|
||||||
|
enum {
|
||||||
|
Service,
|
||||||
|
Test,
|
||||||
|
CoinMech,
|
||||||
|
Button1,
|
||||||
|
Button2,
|
||||||
|
Button3,
|
||||||
|
Button4,
|
||||||
|
Button5,
|
||||||
|
Button6,
|
||||||
|
Button7,
|
||||||
|
Button8,
|
||||||
|
Button9,
|
||||||
|
Button10,
|
||||||
|
Button11,
|
||||||
|
Button12,
|
||||||
|
FaderL_Left,
|
||||||
|
FaderL_Right,
|
||||||
|
FaderR_Left,
|
||||||
|
FaderR_Right,
|
||||||
|
Headphone
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Analogs {
|
||||||
|
enum {
|
||||||
|
FaderL,
|
||||||
|
FaderR,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Lights {
|
||||||
|
typedef enum {
|
||||||
|
IC_READER_R,
|
||||||
|
IC_READER_G,
|
||||||
|
IC_READER_B,
|
||||||
|
} pc_lights_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// getters
|
||||||
|
std::vector<Button> &get_buttons();
|
||||||
|
std::string get_buttons_help();
|
||||||
|
std::vector<Analog> &get_analogs();
|
||||||
|
std::vector<Light> &get_lights();
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
#include "pc.h"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
|
||||||
|
#include "bi2x_hook.h"
|
||||||
|
#include "util/detour.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
#include "util/fileutils.h"
|
||||||
|
#include "util/unity_player.h"
|
||||||
|
#include "util/execexe.h"
|
||||||
|
#include "acioemu/handle.h"
|
||||||
|
#include "misc/wintouchemu.h"
|
||||||
|
#include "hooks/graphics/graphics.h"
|
||||||
|
#include "rawinput/rawinput.h"
|
||||||
|
|
||||||
|
namespace games::pc {
|
||||||
|
std::string PC_INJECT_ARGS = "";
|
||||||
|
bool PC_NO_IO = false;
|
||||||
|
|
||||||
|
static acioemu::ACIOHandle *acioHandle = nullptr;
|
||||||
|
static std::wstring portName = L"COM1";
|
||||||
|
|
||||||
|
static decltype(RegisterRawInputDevices) *RegisterRawInputDevices_orig = nullptr;
|
||||||
|
static decltype(EnumDisplaySettingsW) *EnumDisplaySettingsW_orig = nullptr;
|
||||||
|
static decltype(QueryDisplayConfig) *QueryDisplayConfig_orig = nullptr;
|
||||||
|
|
||||||
|
static BOOL WINAPI RegisterRawInputDevices_hook(PCRAWINPUTDEVICE pRawInputDevices, UINT uiNumDevices, UINT cbSize) {
|
||||||
|
|
||||||
|
// if the caller is spice itself, then pass through.
|
||||||
|
if (pRawInputDevices &&
|
||||||
|
(uiNumDevices > 0) &&
|
||||||
|
(pRawInputDevices[0].hwndTarget == RI_MGR->input_hwnd)) {
|
||||||
|
|
||||||
|
return RegisterRawInputDevices_orig(pRawInputDevices, uiNumDevices, cbSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, it must be the game; prevent the game from registering for raw input
|
||||||
|
// and hijacking WM_INPUT messages.
|
||||||
|
SetLastError(0xDEADBEEF);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL WINAPI EnumDisplaySettingsW_hook(LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode) {
|
||||||
|
auto result = EnumDisplaySettingsW_orig(lpszDeviceName, iModeNum, lpDevMode);
|
||||||
|
|
||||||
|
// https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Screen-currentResolution.html
|
||||||
|
// "If the player is running in windowed mode, this returns the current dimensions of the game window in pixels and the display refresh rate."
|
||||||
|
// Override it to 1920x1080 to avoid broken UI under Windowed mode
|
||||||
|
if (result && iModeNum == ENUM_CURRENT_SETTINGS) {
|
||||||
|
// Actually make it returns size of the game window, Can I?
|
||||||
|
lpDevMode->dmPelsWidth = 1920;
|
||||||
|
lpDevMode->dmPelsHeight = 1080;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG WINAPI QueryDisplayConfig_hook(UINT32, UINT32*, DISPLAYCONFIG_PATH_INFO*, UINT32*, DISPLAYCONFIG_MODE_INFO*, DISPLAYCONFIG_TOPOLOGY_ID*) {
|
||||||
|
// make unity fallback to EnumDisplaySettingsW as I don't
|
||||||
|
// want to deal with this api which is way more complex
|
||||||
|
return ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCGame::attach() {
|
||||||
|
Game::attach();
|
||||||
|
|
||||||
|
// add card reader
|
||||||
|
acioHandle = new acioemu::ACIOHandle(portName.c_str(), 1);
|
||||||
|
devicehook_init_trampoline();
|
||||||
|
devicehook_add(acioHandle);
|
||||||
|
|
||||||
|
execexe::init();
|
||||||
|
execexe::init_deferred([] () {
|
||||||
|
execexe::init_port_hook(portName, acioHandle);
|
||||||
|
execexe::load_library("libaio.dll");
|
||||||
|
execexe::load_library("libaio-iob.dll");
|
||||||
|
execexe::load_library("libaio-iob_video.dll");
|
||||||
|
execexe::load_library("libaio-iob2_video.dll");
|
||||||
|
execexe::load_library("win10actlog.dll");
|
||||||
|
|
||||||
|
if (!PC_NO_IO) {
|
||||||
|
bi2x_hook_init();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto user32Dll = "user32.dll";
|
||||||
|
detour::trampoline_try(user32Dll, "RegisterRawInputDevices",
|
||||||
|
RegisterRawInputDevices_hook, &RegisterRawInputDevices_orig);
|
||||||
|
detour::trampoline_try(user32Dll, "QueryDisplayConfig",
|
||||||
|
QueryDisplayConfig_hook, &QueryDisplayConfig_orig);
|
||||||
|
detour::trampoline_try(user32Dll, "EnumDisplaySettingsW",
|
||||||
|
EnumDisplaySettingsW_hook, &EnumDisplaySettingsW_orig);
|
||||||
|
|
||||||
|
if (GRAPHICS_SHOW_CURSOR) {
|
||||||
|
unity_utils::force_show_cursor(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
unity_utils::set_args(
|
||||||
|
std::format("{} {}{}",
|
||||||
|
GetCommandLineA(),
|
||||||
|
PC_INJECT_ARGS,
|
||||||
|
unity_utils::get_unity_player_args()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCGame::detach() {
|
||||||
|
Game::detach();
|
||||||
|
|
||||||
|
devicehook_dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "games/game.h"
|
||||||
|
|
||||||
|
namespace games::pc {
|
||||||
|
extern std::string PC_INJECT_ARGS;
|
||||||
|
extern bool PC_NO_IO;
|
||||||
|
extern bool PC_KNOB_MODE;
|
||||||
|
|
||||||
|
class PCGame : public games::Game {
|
||||||
|
public:
|
||||||
|
PCGame() : Game("Polaris Chord") {}
|
||||||
|
|
||||||
|
virtual void attach() override;
|
||||||
|
virtual void detach() override;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -14,134 +14,24 @@
|
|||||||
#include <mfidl.h>
|
#include <mfidl.h>
|
||||||
|
|
||||||
#include "avs/game.h"
|
#include "avs/game.h"
|
||||||
#include "hooks/cfgmgr32hook.h"
|
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
#include "util/memutils.h"
|
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
|
|
||||||
static VTBL_TYPE(IMFActivate, GetAllocatedString) GetAllocatedString_orig = nullptr;
|
|
||||||
|
|
||||||
static decltype(MFEnumDeviceSources) *MFEnumDeviceSources_orig = nullptr;
|
|
||||||
|
|
||||||
namespace games::sdvx {
|
namespace games::sdvx {
|
||||||
|
|
||||||
static std::wstring CAMERA0_ID;
|
|
||||||
|
|
||||||
static HRESULT WINAPI GetAllocatedString_hook(IMFActivate* This, REFGUID guidKey, LPWSTR *ppwszValue,
|
|
||||||
UINT32 *pcchLength) {
|
|
||||||
// call the original
|
|
||||||
HRESULT result = GetAllocatedString_orig(This, guidKey, ppwszValue, pcchLength);
|
|
||||||
|
|
||||||
// try first camera
|
|
||||||
wchar_t *pwc = nullptr;
|
|
||||||
if (CAMERA0_ID.length() == 23)
|
|
||||||
pwc = wcsstr(*ppwszValue, CAMERA0_ID.c_str());
|
|
||||||
|
|
||||||
// check if camera could be identified
|
|
||||||
if (pwc) {
|
|
||||||
|
|
||||||
// fake the USB IDs
|
|
||||||
pwc[4] = L'2';
|
|
||||||
pwc[5] = L'8';
|
|
||||||
pwc[6] = L'8';
|
|
||||||
pwc[7] = L'c';
|
|
||||||
pwc[13] = L'0';
|
|
||||||
pwc[14] = L'0';
|
|
||||||
pwc[15] = L'0';
|
|
||||||
pwc[16] = L'2';
|
|
||||||
pwc[21] = L'0';
|
|
||||||
pwc[22] = L'0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// return original result
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hook_camera(IMFActivate* camera, size_t no, std::wstring camera_id, std::string camera_instance) {
|
|
||||||
|
|
||||||
// don't hook if camera 0 is already hooked
|
|
||||||
if (CAMERA0_ID.length() > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// save the camera ID
|
|
||||||
CAMERA0_ID = camera_id;
|
|
||||||
|
|
||||||
// cfgmgr hook
|
|
||||||
CFGMGR32_HOOK_SETTING camera_setting;
|
|
||||||
camera_setting.device_instance = 0xDEADBEEF;
|
|
||||||
camera_setting.parent_instance = ~camera_setting.device_instance;
|
|
||||||
camera_setting.device_id = "USB\\VEN_1022&DEV_7908";
|
|
||||||
camera_setting.device_node_id = "USB\\VID_288C&PID_0002&MI_00\\?&????????&?&????";
|
|
||||||
if (camera_instance.length() == 17) {
|
|
||||||
for (int i = 0; i < 17; i++) {
|
|
||||||
camera_setting.device_node_id[28 + i] = camera_instance[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cfgmgr32hook_add(camera_setting);
|
|
||||||
|
|
||||||
// save original method for later use
|
|
||||||
if (GetAllocatedString_orig == nullptr) {
|
|
||||||
GetAllocatedString_orig = camera->lpVtbl->GetAllocatedString;
|
|
||||||
}
|
|
||||||
|
|
||||||
// hook allocated string method for camera identification
|
|
||||||
memutils::VProtectGuard camera_guard(camera->lpVtbl);
|
|
||||||
camera->lpVtbl->GetAllocatedString = GetAllocatedString_hook;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT WINAPI MFEnumDeviceSources_hook(IMFAttributes *pAttributes, IMFActivate ***pppSourceActivate,
|
static HRESULT WINAPI MFEnumDeviceSources_hook(IMFAttributes *pAttributes, IMFActivate ***pppSourceActivate,
|
||||||
UINT32 *pcSourceActivate) {
|
UINT32 *pcSourceActivate) {
|
||||||
|
|
||||||
// call original function
|
*pppSourceActivate = nullptr;
|
||||||
HRESULT result_orig = MFEnumDeviceSources_orig(pAttributes, pppSourceActivate, pcSourceActivate);
|
*pcSourceActivate = 0;
|
||||||
|
log_misc("sdvx", "MFEnumDeviceSources_hook called, returning 0 cameras");
|
||||||
// check for capture devices
|
return S_OK;
|
||||||
if (FAILED(result_orig) || !*pcSourceActivate) {
|
|
||||||
return result_orig;
|
|
||||||
}
|
|
||||||
|
|
||||||
// iterate cameras
|
|
||||||
size_t cam_hook_num = 0;
|
|
||||||
for (size_t cam_num = 0; cam_num < *pcSourceActivate && cam_hook_num < 1; cam_num++) {
|
|
||||||
|
|
||||||
// flip
|
|
||||||
size_t cam_num_flipped = cam_num;
|
|
||||||
|
|
||||||
// get camera link
|
|
||||||
IMFActivate *camera = (*pppSourceActivate)[cam_num_flipped];
|
|
||||||
LPWSTR camera_link_lpwstr;
|
|
||||||
UINT32 camera_link_length;
|
|
||||||
if (SUCCEEDED(camera->lpVtbl->GetAllocatedString(
|
|
||||||
camera,
|
|
||||||
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
|
|
||||||
&camera_link_lpwstr,
|
|
||||||
&camera_link_length))) {
|
|
||||||
|
|
||||||
// cut name to make ID
|
|
||||||
std::wstring camera_link_ws = std::wstring(camera_link_lpwstr);
|
|
||||||
std::wstring camera_id = camera_link_ws.substr(8, 23);
|
|
||||||
|
|
||||||
// get camera instance
|
|
||||||
std::string camera_link = ws2s(camera_link_ws);
|
|
||||||
std::string camera_instance = camera_link.substr(32, 17);
|
|
||||||
|
|
||||||
// hook the camera
|
|
||||||
hook_camera(camera, cam_hook_num, camera_id, camera_instance);
|
|
||||||
|
|
||||||
// increase camera hook number
|
|
||||||
cam_hook_num++;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return result
|
|
||||||
return result_orig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void camera_init() {
|
void camera_init() {
|
||||||
|
|
||||||
// camera media framework hook
|
// camera media framework hook
|
||||||
MFEnumDeviceSources_orig = detour::iat_try(
|
log_info("sdvx", "installing camera hooks...");
|
||||||
"MFEnumDeviceSources", MFEnumDeviceSources_hook, avs::game::DLL_INSTANCE);
|
detour::iat_try("MFEnumDeviceSources", MFEnumDeviceSources_hook, avs::game::DLL_INSTANCE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "acioemu/handle.h"
|
#include "acioemu/handle.h"
|
||||||
#include "cfg/configurator.h"
|
#include "cfg/configurator.h"
|
||||||
|
#include "launcher/signal.h"
|
||||||
|
|
||||||
static decltype(RegCloseKey) *RegCloseKey_orig = nullptr;
|
static decltype(RegCloseKey) *RegCloseKey_orig = nullptr;
|
||||||
static decltype(RegEnumKeyA) *RegEnumKeyA_orig = nullptr;
|
static decltype(RegEnumKeyA) *RegEnumKeyA_orig = nullptr;
|
||||||
@@ -39,7 +40,6 @@ namespace games::sdvx {
|
|||||||
const char *ORIGINAL_ASIO_DEVICE_NAME = "XONAR SOUND CARD(64)";
|
const char *ORIGINAL_ASIO_DEVICE_NAME = "XONAR SOUND CARD(64)";
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
bool DISABLECAMS = false;
|
|
||||||
bool NATIVETOUCH = false;
|
bool NATIVETOUCH = false;
|
||||||
uint8_t DIGITAL_KNOB_SENS = 16;
|
uint8_t DIGITAL_KNOB_SENS = 16;
|
||||||
SdvxOverlayPosition OVERLAY_POS = SDVX_OVERLAY_BOTTOM;
|
SdvxOverlayPosition OVERLAY_POS = SDVX_OVERLAY_BOTTOM;
|
||||||
@@ -210,6 +210,10 @@ namespace games::sdvx {
|
|||||||
out = "";
|
out = "";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (data.find("SuperstepSound: Audio device is not available") != std::string::npos) {
|
||||||
|
launcher::signal::SUPERSTEP_SOUND_ERROR = TRUE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,17 +373,17 @@ namespace games::sdvx {
|
|||||||
winuser_hook_init(avs::game::DLL_INSTANCE);
|
winuser_hook_init(avs::game::DLL_INSTANCE);
|
||||||
|
|
||||||
// hook camera
|
// hook camera
|
||||||
if (!DISABLECAMS) {
|
|
||||||
camera_init();
|
camera_init();
|
||||||
}
|
|
||||||
|
|
||||||
// RGB CAMERA error ignore
|
// RGB CAMERA error ignore for SDVX5
|
||||||
if (!replace_pattern(
|
// SDVX5: boot sequence triggers camera error if camera is not detected
|
||||||
|
// SDVX6: boots fine, but game title screen in attract loop will have camera error (cosmetic only)
|
||||||
|
if (replace_pattern(
|
||||||
avs::game::DLL_INSTANCE,
|
avs::game::DLL_INSTANCE,
|
||||||
"418D480484C074218D51FD",
|
"418D480484C074218D51FD",
|
||||||
"????????????9090??????",
|
"????????????9090??????",
|
||||||
0, 0)) {
|
0, 0)) {
|
||||||
log_info("sdvx", "did not find matching signature for camera error patch");
|
log_info("sdvx", "applied camera error patch (sdvx5)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove log spam
|
// remove log spam
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ namespace games::sdvx {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
extern bool DISABLECAMS;
|
|
||||||
extern bool NATIVETOUCH;
|
extern bool NATIVETOUCH;
|
||||||
extern uint8_t DIGITAL_KNOB_SENS;
|
extern uint8_t DIGITAL_KNOB_SENS;
|
||||||
extern std::optional<std::string> ASIO_DRIVER;
|
extern std::optional<std::string> ASIO_DRIVER;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ constexpr UINT CODEPAGE_SHIFT_JIS = 932;
|
|||||||
static decltype(GetACP) *GetACP_orig = nullptr;
|
static decltype(GetACP) *GetACP_orig = nullptr;
|
||||||
static decltype(GetOEMCP) *GetOEMCP_orig = nullptr;
|
static decltype(GetOEMCP) *GetOEMCP_orig = nullptr;
|
||||||
static decltype(MultiByteToWideChar) *MultiByteToWideChar_orig = nullptr;
|
static decltype(MultiByteToWideChar) *MultiByteToWideChar_orig = nullptr;
|
||||||
|
static decltype(GetLocaleInfoEx) *GetLocaleInfoEx_orig = nullptr;
|
||||||
|
|
||||||
#ifdef SPICE64
|
#ifdef SPICE64
|
||||||
static decltype(GetSystemDefaultLCID) *GetSystemDefaultLCID_orig = nullptr;
|
static decltype(GetSystemDefaultLCID) *GetSystemDefaultLCID_orig = nullptr;
|
||||||
@@ -119,6 +120,48 @@ static int WINAPI MultiByteToWideChar_hook(
|
|||||||
cchWideChar);
|
cchWideChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int WINAPI GetLocaleInfoEx_hook (
|
||||||
|
LPCWSTR lpLocaleName,
|
||||||
|
LCTYPE LCType,
|
||||||
|
LPWSTR lpLCData,
|
||||||
|
int cchData)
|
||||||
|
{
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (lpLocaleName == LOCALE_NAME_INVARIANT) {
|
||||||
|
log_misc("hooks::lang", "GetLocaleInfoEx_hook hit (LOCALE_NAME_INVARIANT), {}, {}", LCType, cchData);
|
||||||
|
} else if (lpLocaleName == LOCALE_NAME_SYSTEM_DEFAULT) {
|
||||||
|
log_misc("hooks::lang", "GetLocaleInfoEx_hook hit (LOCALE_NAME_SYSTEM_DEFAULT), {}, {}", LCType, cchData);
|
||||||
|
} else if (lpLocaleName == LOCALE_NAME_USER_DEFAULT) {
|
||||||
|
log_misc("hooks::lang", "GetLocaleInfoEx_hook hit (LOCALE_NAME_USER_DEFAULT), {}, {}", LCType, cchData);
|
||||||
|
} else {
|
||||||
|
log_misc("hooks::lang", "GetLocaleInfoEx_hook hit ({}), {}, {}", ws2s(lpLocaleName), LCType, cchData);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (lpLocaleName == LOCALE_NAME_USER_DEFAULT &&
|
||||||
|
LCType == LOCALE_SISO639LANGNAME &&
|
||||||
|
lpLCData != NULL &&
|
||||||
|
cchData >= 3) {
|
||||||
|
log_misc("hooks::lang",
|
||||||
|
"GetLocaleInfoEx_hook hit (LOCALE_NAME_USER_DEFAULT / LOCALE_SISO639LANGNAME), return `ja`");
|
||||||
|
wcscpy(lpLCData, L"ja");
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lpLocaleName == LOCALE_NAME_USER_DEFAULT &&
|
||||||
|
LCType == LOCALE_SISO3166CTRYNAME &&
|
||||||
|
lpLCData != NULL &&
|
||||||
|
cchData >= 3) {
|
||||||
|
log_misc("hooks::lang",
|
||||||
|
"GetLocaleInfoEx_hook hit (LOCALE_NAME_USER_DEFAULT / LOCALE_SISO3166CTRYNAME), return `JP`");
|
||||||
|
wcscpy(lpLCData, L"JP");
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetLocaleInfoEx_orig(lpLocaleName, LCType, lpLCData, cchData);
|
||||||
|
}
|
||||||
|
|
||||||
void hooks::lang::early_init() {
|
void hooks::lang::early_init() {
|
||||||
log_info("hooks::lang", "early initialization");
|
log_info("hooks::lang", "early initialization");
|
||||||
|
|
||||||
@@ -138,6 +181,14 @@ void hooks::lang::early_init() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (avs::game::is_model("XIF")) {
|
||||||
|
log_info("hooks::lang", "hooking GetLocaleInfoEx");
|
||||||
|
detour::trampoline_try(
|
||||||
|
"kernel32.dll",
|
||||||
|
"GetLocaleInfoEx",
|
||||||
|
GetLocaleInfoEx_hook,
|
||||||
|
&GetLocaleInfoEx_orig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hooks::lang::init() {
|
void hooks::lang::init() {
|
||||||
|
|||||||
@@ -141,13 +141,17 @@ static ULONG WINAPI GetAdaptersInfo_hook(PIP_ADAPTER_INFO pAdapterInfo, PULONG p
|
|||||||
|
|
||||||
static int WINAPI bind_hook(SOCKET s, const struct sockaddr *name, int namelen) {
|
static int WINAPI bind_hook(SOCKET s, const struct sockaddr *name, int namelen) {
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma ide diagnostic ignored "OCDFAInspection"
|
#pragma ide diagnostic ignored "OCDFAInspection"
|
||||||
|
#endif
|
||||||
|
|
||||||
// cast to sockaddr_in
|
// cast to sockaddr_in
|
||||||
struct sockaddr_in *in_name = (struct sockaddr_in *) name;
|
struct sockaddr_in *in_name = (struct sockaddr_in *) name;
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
// override bind to allow all hosts
|
// override bind to allow all hosts
|
||||||
in_name->sin_addr.s_addr = inet_addr("0.0.0.0");
|
in_name->sin_addr.s_addr = inet_addr("0.0.0.0");
|
||||||
|
|||||||
@@ -61,6 +61,7 @@
|
|||||||
#include "games/ccj/trackball.h"
|
#include "games/ccj/trackball.h"
|
||||||
#include "games/qks/qks.h"
|
#include "games/qks/qks.h"
|
||||||
#include "games/mfg/mfg.h"
|
#include "games/mfg/mfg.h"
|
||||||
|
#include "games/pc/pc.h"
|
||||||
#include "games/museca/museca.h"
|
#include "games/museca/museca.h"
|
||||||
#include "hooks/avshook.h"
|
#include "hooks/avshook.h"
|
||||||
#include "hooks/audio/audio.h"
|
#include "hooks/audio/audio.h"
|
||||||
@@ -150,6 +151,9 @@ static bool check_dll(const std::string &model) {
|
|||||||
|
|
||||||
void update_msvcrt_args(int argc, char *argv[]);
|
void update_msvcrt_args(int argc, char *argv[]);
|
||||||
|
|
||||||
|
void dump_button_bindings(std::vector<Button> *buttons);
|
||||||
|
void dump_analog_bindings();
|
||||||
|
|
||||||
int main_implementation(int argc, char *argv[]) {
|
int main_implementation(int argc, char *argv[]) {
|
||||||
|
|
||||||
// remember argv, argv
|
// remember argv, argv
|
||||||
@@ -219,6 +223,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
bool attach_ccj = false;
|
bool attach_ccj = false;
|
||||||
bool attach_qks = false;
|
bool attach_qks = false;
|
||||||
bool attach_mfg = false;
|
bool attach_mfg = false;
|
||||||
|
bool attach_pc = false;
|
||||||
bool attach_museca = false;
|
bool attach_museca = false;
|
||||||
bool show_cursor_if_no_touch = false;
|
bool show_cursor_if_no_touch = false;
|
||||||
|
|
||||||
@@ -244,6 +249,11 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
// parse arguments
|
// parse arguments
|
||||||
LAUNCHER_OPTIONS = launcher::parse_options(argc, argv);
|
LAUNCHER_OPTIONS = launcher::parse_options(argc, argv);
|
||||||
|
|
||||||
|
// command line override (must be done before merging options with cfg)
|
||||||
|
if (LAUNCHER_OPTIONS->at(launcher::Options::OptionConflictResolution).value_bool()) {
|
||||||
|
launcher::USE_CMD_OVERRIDE = true;
|
||||||
|
}
|
||||||
|
|
||||||
// determine config file path - must be done before anything else
|
// determine config file path - must be done before anything else
|
||||||
const auto &cfg_path = LAUNCHER_OPTIONS->at(launcher::Options::ConfigurationPath);
|
const auto &cfg_path = LAUNCHER_OPTIONS->at(launcher::Options::ConfigurationPath);
|
||||||
if (cfg_path.is_active()) {
|
if (cfg_path.is_active()) {
|
||||||
@@ -285,6 +295,7 @@ 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() &&
|
if (options[launcher::Options::EAmusementEmulation].value_bool() &&
|
||||||
options[launcher::Options::ServiceURL].is_active() &&
|
options[launcher::Options::ServiceURL].is_active() &&
|
||||||
!cfg::CONFIGURATOR_STANDALONE) {
|
!cfg::CONFIGURATOR_STANDALONE) {
|
||||||
@@ -424,9 +435,6 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::LoadSoundVoltexModule].value_bool()) {
|
if (options[launcher::Options::LoadSoundVoltexModule].value_bool()) {
|
||||||
attach_sdvx = true;
|
attach_sdvx = true;
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::SDVXDisableCameras].value_bool()) {
|
|
||||||
games::sdvx::DISABLECAMS = true;
|
|
||||||
}
|
|
||||||
if (options[launcher::Options::SDVXNativeTouch].value_bool()) {
|
if (options[launcher::Options::SDVXNativeTouch].value_bool()) {
|
||||||
games::sdvx::NATIVETOUCH = true;
|
games::sdvx::NATIVETOUCH = true;
|
||||||
}
|
}
|
||||||
@@ -617,12 +625,18 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::LoadMFGModule].value_bool()) {
|
if (options[launcher::Options::LoadMFGModule].value_bool()) {
|
||||||
attach_mfg = true;
|
attach_mfg = true;
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::LoadPCModule].value_bool()) {
|
||||||
|
attach_pc = true;
|
||||||
|
}
|
||||||
if (options[launcher::Options::LoadMusecaModule].value_bool()) {
|
if (options[launcher::Options::LoadMusecaModule].value_bool()) {
|
||||||
attach_museca = true;
|
attach_museca = true;
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::DDR43Mode].value_bool()) {
|
if (options[launcher::Options::DDR43Mode].value_bool()) {
|
||||||
games::ddr::SDMODE = true;
|
games::ddr::SDMODE = true;
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::DDRSkipCodecRegisteration].value_bool()) {
|
||||||
|
games::ddr::NO_CODEC_REGISTRATION = true;
|
||||||
|
}
|
||||||
if (options[launcher::Options::LoadSteelChronicleModule].value_bool()) {
|
if (options[launcher::Options::LoadSteelChronicleModule].value_bool()) {
|
||||||
attach_sc = true;
|
attach_sc = true;
|
||||||
}
|
}
|
||||||
@@ -1092,6 +1106,15 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::MFGNoIO].is_active()) {
|
if (options[launcher::Options::MFGNoIO].is_active()) {
|
||||||
games::mfg::MFG_NO_IO = options[launcher::Options::MFGNoIO].value_bool();
|
games::mfg::MFG_NO_IO = options[launcher::Options::MFGNoIO].value_bool();
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::PCArgs].is_active()) {
|
||||||
|
games::pc::PC_INJECT_ARGS = options[launcher::Options::PCArgs].value_text();
|
||||||
|
}
|
||||||
|
if (options[launcher::Options::PCNoIO].is_active()) {
|
||||||
|
games::pc::PC_NO_IO = options[launcher::Options::PCNoIO].value_bool();
|
||||||
|
}
|
||||||
|
if (options[launcher::Options::PCKnobMode].value_bool()) {
|
||||||
|
games::pc::PC_KNOB_MODE = true;
|
||||||
|
}
|
||||||
if (options[launcher::Options::spice2x_EnableSMXStage].value_bool()) {
|
if (options[launcher::Options::spice2x_EnableSMXStage].value_bool()) {
|
||||||
rawinput::ENABLE_SMX_STAGE = true;
|
rawinput::ENABLE_SMX_STAGE = true;
|
||||||
}
|
}
|
||||||
@@ -1220,6 +1243,51 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
log_info("launcher", "arguments:\n{}", arguments.str());
|
log_info("launcher", "arguments:\n{}", arguments.str());
|
||||||
|
|
||||||
|
// print out conflicts
|
||||||
|
size_t conflicts = 0;
|
||||||
|
for (const auto &option : options) {
|
||||||
|
if (option.conflicting && option.get_definition().type != OptionType::Bool) {
|
||||||
|
conflicts += 1;
|
||||||
|
if (launcher::USE_CMD_OVERRIDE) {
|
||||||
|
log_warning(
|
||||||
|
"launcher",
|
||||||
|
"multiple values for -{}, command line args take precedence: {}",
|
||||||
|
option.get_definition().name,
|
||||||
|
option.value);
|
||||||
|
} else {
|
||||||
|
log_warning(
|
||||||
|
"launcher",
|
||||||
|
"multiple values for -{}, spicecfg values take precedence: {}",
|
||||||
|
option.get_definition().name,
|
||||||
|
option.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (conflicts) {
|
||||||
|
if (launcher::USE_CMD_OVERRIDE) {
|
||||||
|
log_info(
|
||||||
|
"launcher",
|
||||||
|
"user specified -cmdoverride, therefore command line args took precedence over spicecfg");
|
||||||
|
} else {
|
||||||
|
log_warning(
|
||||||
|
"launcher",
|
||||||
|
"spicecfg values take precedence over command line args; to change this behavior, use -cmdoverride");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options[launcher::Options::GameExecutable].is_active() && !cfg::CONFIGURATOR_STANDALONE) {
|
||||||
|
log_warning(
|
||||||
|
"launcher",
|
||||||
|
"WARNING - user specified -exec option\n\n\n"
|
||||||
|
"!!! !!!\n"
|
||||||
|
"!!! Using -exec option disables all game-specific hooks! !!!\n"
|
||||||
|
"!!! Unless you know exactly what you are doing, clear -exec !!!\n"
|
||||||
|
"!!! and try again. Using -exec by itself will result in weird !!!\n"
|
||||||
|
"!!! errors and loss of functionality. !!!\n"
|
||||||
|
"!!! !!!\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
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)) {
|
||||||
@@ -1681,6 +1749,16 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Polaris Chord
|
||||||
|
if (check_dll("kamunity.dll") && fileutils::dir_exists("game/svm_Data")) {
|
||||||
|
avs::game::DLL_NAME = "kamunity.dll";
|
||||||
|
attach_io = true;
|
||||||
|
attach_pc = true;
|
||||||
|
launcher::signal::USE_VEH_WORKAROUND = true;
|
||||||
|
show_cursor_if_no_touch = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Busou Shinki: Armored Princess Battle Conductor
|
// Busou Shinki: Armored Princess Battle Conductor
|
||||||
if (check_dll("kamunity.dll") && fileutils::file_exists("game/bsac_app.exe")) {
|
if (check_dll("kamunity.dll") && fileutils::file_exists("game/bsac_app.exe")) {
|
||||||
avs::game::DLL_NAME = "kamunity.dll";
|
avs::game::DLL_NAME = "kamunity.dll";
|
||||||
@@ -1705,7 +1783,14 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
// usage error
|
// usage error
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE
|
if (!cfg::CONFIGURATOR_STANDALONE
|
||||||
&& (!CHECK_DLL_IGNORE_ARCH)) {
|
&& (!CHECK_DLL_IGNORE_ARCH)) {
|
||||||
log_fatal("launcher", "module auto detection failed.");
|
log_fatal(
|
||||||
|
"launcher",
|
||||||
|
"module auto detection failed!\n\n"
|
||||||
|
"This usually means one of the following:\n\n"
|
||||||
|
" 1. You put spice executables in the wrong place, or\n"
|
||||||
|
" 2. XML files in prop directory are malformed or missing, or\n"
|
||||||
|
" 3. You passed in invalid options (usually, path overrides like -exec)\n\n"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1833,6 +1918,10 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
avs::core::set_default_heap_size("kamunity.dll");
|
avs::core::set_default_heap_size("kamunity.dll");
|
||||||
games.push_back(new games::mfg::MFGGame());
|
games.push_back(new games::mfg::MFGGame());
|
||||||
}
|
}
|
||||||
|
if (attach_pc) {
|
||||||
|
avs::core::HEAP_SIZE = 536870912; // 512MB
|
||||||
|
games.push_back(new games::pc::PCGame());
|
||||||
|
}
|
||||||
|
|
||||||
// apply user heap size, if defined
|
// apply user heap size, if defined
|
||||||
if (user_heap_size > 0) {
|
if (user_heap_size > 0) {
|
||||||
@@ -1874,6 +1963,11 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
libutils::warn_if_dll_exists("d3d12.dll");
|
libutils::warn_if_dll_exists("d3d12.dll");
|
||||||
libutils::warn_if_dll_exists("dxgi.dll");
|
libutils::warn_if_dll_exists("dxgi.dll");
|
||||||
libutils::warn_if_dll_exists("opengl32.dll");
|
libutils::warn_if_dll_exists("opengl32.dll");
|
||||||
|
libutils::warn_if_dll_exists("nvcuda.dll");
|
||||||
|
libutils::warn_if_dll_exists("nvcuvid.dll");
|
||||||
|
libutils::warn_if_dll_exists("nvEncodeAPI64.dll");
|
||||||
|
libutils::warn_if_dll_exists("msvcr100.dll");
|
||||||
|
libutils::warn_if_dll_exists("dsound.dll");
|
||||||
|
|
||||||
// complain loudly & early about dll load ordering issue
|
// complain loudly & early about dll load ordering issue
|
||||||
libutils::check_duplicate_dlls();
|
libutils::check_duplicate_dlls();
|
||||||
@@ -1895,6 +1989,21 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
// print devices
|
// print devices
|
||||||
RI_MGR->devices_print();
|
RI_MGR->devices_print();
|
||||||
|
|
||||||
|
auto buttons = games::get_buttons(eamuse_get_game());
|
||||||
|
log_misc("rawinput", "Button mappings:");
|
||||||
|
dump_button_bindings(buttons);
|
||||||
|
|
||||||
|
log_misc("rawinput", "Keypad button mappings:");
|
||||||
|
auto keypads = games::get_buttons_keypads(eamuse_get_game());
|
||||||
|
dump_button_bindings(keypads);
|
||||||
|
|
||||||
|
log_misc("rawinput", "Overlay button mappings:");
|
||||||
|
auto overlay_buttons = games::get_buttons_overlay(eamuse_get_game());
|
||||||
|
dump_button_bindings(overlay_buttons);
|
||||||
|
|
||||||
|
log_misc("rawinput", "Analog mappings:");
|
||||||
|
dump_analog_bindings();
|
||||||
|
|
||||||
// for certain games, show cursor if no touch is available (must be called after RI_MGR is available)
|
// for certain games, show cursor if no touch is available (must be called after RI_MGR is available)
|
||||||
if (show_cursor_if_no_touch && !is_touch_available("launcher::main_implementation")) {
|
if (show_cursor_if_no_touch && !is_touch_available("launcher::main_implementation")) {
|
||||||
GRAPHICS_SHOW_CURSOR = true;
|
GRAPHICS_SHOW_CURSOR = true;
|
||||||
@@ -2036,15 +2145,6 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
networkhook_init();
|
networkhook_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
// layeredfs
|
|
||||||
if (fileutils::dir_exists("data_mods") &&
|
|
||||||
!fileutils::file_exists("ifs_hook.dll") &&
|
|
||||||
!fileutils::file_exists(MODULE_PATH / "ifs_hook.dll")) {
|
|
||||||
log_warning("launcher", "data_mods directory was found, but ifs_hook.dll is not present; your mods will not load");
|
|
||||||
log_warning("launcher", "to fix this, download ifs_layeredfs and add it as a DLL hook (-k)");
|
|
||||||
log_warning("launcher", "https://github.com/mon/ifs_layeredfs");
|
|
||||||
}
|
|
||||||
|
|
||||||
update_msvcrt_args(argc, argv);
|
update_msvcrt_args(argc, argv);
|
||||||
|
|
||||||
// load hooks
|
// load hooks
|
||||||
@@ -2058,6 +2158,14 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// layeredfs
|
||||||
|
if (fileutils::dir_exists("data_mods") &&
|
||||||
|
GetModuleHandleA("ifs_hook.dll") == nullptr) {
|
||||||
|
log_warning("launcher", "data_mods directory was found, but ifs_hook.dll is not present; your mods will not load");
|
||||||
|
log_warning("launcher", "to fix this, download ifs_layeredfs and add it as a DLL hook (-k)");
|
||||||
|
log_warning("launcher", "https://github.com/mon/ifs_layeredfs");
|
||||||
|
}
|
||||||
|
|
||||||
// apply patches
|
// apply patches
|
||||||
{
|
{
|
||||||
overlay::windows::PatchManager patch_manager(nullptr, true);
|
overlay::windows::PatchManager patch_manager(nullptr, true);
|
||||||
@@ -2280,6 +2388,65 @@ void update_msvcrt_args(int argc, char *argv[]) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dump_button_bindings(std::vector<Button> *buttons) {
|
||||||
|
if (!buttons) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto button = buttons->begin(); button != buttons->end(); ++button) {
|
||||||
|
if (!button->isSet()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button->isNaive()) {
|
||||||
|
log_misc(
|
||||||
|
"rawinput", " [{}] dev=Naive, vkey={}",
|
||||||
|
button->getName(),
|
||||||
|
button->getVKey()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
log_misc(
|
||||||
|
"rawinput", " [{}] dev={}, vkey={}, analogtype={}",
|
||||||
|
button->getName(),
|
||||||
|
button->getDeviceIdentifier(),
|
||||||
|
button->getVKey(),
|
||||||
|
button->getAnalogType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& alt : button->getAlternatives()) {
|
||||||
|
if (alt.getVKey() == INVALID_VKEY) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
log_misc(
|
||||||
|
"rawinput", " [{}] (alt) dev={}, vkey={}, analogtype={}",
|
||||||
|
button->getName(),
|
||||||
|
alt.isNaive() ? "Naive" : alt.getDeviceIdentifier(),
|
||||||
|
alt.getVKey(),
|
||||||
|
alt.getAnalogType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_analog_bindings() {
|
||||||
|
auto analogs = games::get_analogs(eamuse_get_game());
|
||||||
|
if (!analogs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto& analog : *analogs) {
|
||||||
|
if (!analog.isSet()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
log_misc(
|
||||||
|
"rawinput", " [{}] dev={}, index={}",
|
||||||
|
analog.getName(),
|
||||||
|
analog.getDeviceIdentifier(),
|
||||||
|
analog.getIndex()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef SPICETOOLS_SPICECFG_STANDALONE
|
#ifndef SPICETOOLS_SPICECFG_STANDALONE
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
return main_implementation(argc, argv);
|
return main_implementation(argc, argv);
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ static const std::vector<std::string> CATEGORY_ORDER_BASIC = {
|
|||||||
"Game Options",
|
"Game Options",
|
||||||
"Common",
|
"Common",
|
||||||
"Network",
|
"Network",
|
||||||
"Overlay",
|
|
||||||
"Graphics (Common)",
|
"Graphics (Common)",
|
||||||
"Graphics (Full Screen)",
|
"Graphics (Full Screen)",
|
||||||
"Graphics (Windowed)",
|
"Graphics (Windowed)",
|
||||||
@@ -26,35 +25,42 @@ static const std::vector<std::string> CATEGORY_ORDER_BASIC = {
|
|||||||
|
|
||||||
static const std::vector<std::string> CATEGORY_ORDER_ADVANCED = {
|
static const std::vector<std::string> CATEGORY_ORDER_ADVANCED = {
|
||||||
"Game Options (Advanced)",
|
"Game Options (Advanced)",
|
||||||
|
"Overlay",
|
||||||
"Network (Advanced)",
|
"Network (Advanced)",
|
||||||
"Performance",
|
"Performance",
|
||||||
"Miscellaneous",
|
"Miscellaneous",
|
||||||
"Paths",
|
|
||||||
"Touch Parameters",
|
"Touch Parameters",
|
||||||
"I/O Options",
|
"I/O Options",
|
||||||
"NFC Card Readers",
|
"NFC Card Readers",
|
||||||
};
|
};
|
||||||
static const std::vector<std::string> CATEGORY_ORDER_DEV = {
|
static const std::vector<std::string> CATEGORY_ORDER_DEV = {
|
||||||
"Network Adapters",
|
"Path Overrides",
|
||||||
|
"Network (Development)",
|
||||||
|
"Audio (Hacks)",
|
||||||
"I/O Modules",
|
"I/O Modules",
|
||||||
"Development",
|
"Development",
|
||||||
|
"Debug Log",
|
||||||
};
|
};
|
||||||
static const std::vector<std::string> CATEGORY_ORDER_NONE = {
|
static const std::vector<std::string> CATEGORY_ORDER_NONE = {
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool launcher::USE_CMD_OVERRIDE = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Option Definitions
|
* Option Definitions
|
||||||
* Be aware that the order must be the same as in the enum launcher::Options!
|
* Be aware that the order must be the same as in the enum launcher::Options!
|
||||||
*/
|
*/
|
||||||
static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||||
{
|
{
|
||||||
.title = "Game Executable",
|
.title = "Override Game Executable & Disable Hooks",
|
||||||
.name = "exec",
|
.name = "exec",
|
||||||
.desc = "Path to the game DLL file",
|
.desc = "Path to the game DLL file.\n\n"
|
||||||
|
"This option is typically not needed; leave it empty to allow spice to auto-detect your game.\n\n"
|
||||||
|
"WARNING: this option also disables all game-specific hooks and turns off most I/O modules!",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.setting_name = "*.dll",
|
.setting_name = "*.dll",
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Open Configurator",
|
.title = "Open Configurator",
|
||||||
@@ -81,6 +87,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Network",
|
.category = "Network",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// ServiceURL
|
||||||
.title = "EA Service URL",
|
.title = "EA Service URL",
|
||||||
.name = "url",
|
.name = "url",
|
||||||
.desc = "Sets a custom service URL override",
|
.desc = "Sets a custom service URL override",
|
||||||
@@ -142,6 +149,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Graphics (Windowed)",
|
.category = "Graphics (Windowed)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// InjectHook
|
||||||
.title = "Inject DLL Hooks",
|
.title = "Inject DLL Hooks",
|
||||||
.name = "k",
|
.name = "k",
|
||||||
.desc = "Multiple files are allowed; use multiple -k flags, or in SpiceCfg, separate by "
|
.desc = "Multiple files are allowed; use multiple -k flags, or in SpiceCfg, separate by "
|
||||||
@@ -152,6 +160,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Common",
|
.category = "Common",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// EarlyInjectHook
|
||||||
.title = "Inject Early DLL Hooks",
|
.title = "Inject Early DLL Hooks",
|
||||||
.name = "z",
|
.name = "z",
|
||||||
.desc = "Equivalent to 'Inject DLL Hooks' option, but ensures hooks are injected before "
|
.desc = "Equivalent to 'Inject DLL Hooks' option, but ensures hooks are injected before "
|
||||||
@@ -263,7 +272,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "nolegacy",
|
.name = "nolegacy",
|
||||||
.desc = "Disables legacy key activation in-game.",
|
.desc = "Disables legacy key activation in-game.",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Miscellaneous",
|
.category = "I/O Options",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Discord Rich Presence",
|
.title = "Discord Rich Presence",
|
||||||
@@ -305,7 +314,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.desc = "This is NOT the EA service URL; use -url for that. "
|
.desc = "This is NOT the EA service URL; use -url for that. "
|
||||||
"Force the use of an adapter with the specified network. Must also provide -subnet",
|
"Force the use of an adapter with the specified network. Must also provide -subnet",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Network Adapters",
|
.category = "Network (Development)",
|
||||||
.sensitive = true,
|
.sensitive = true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -313,21 +322,21 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "subnet",
|
.name = "subnet",
|
||||||
.desc = "Force the use of an adapter with the specified subnet. Must also provide -network",
|
.desc = "Force the use of an adapter with the specified subnet. Must also provide -network",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Network Adapters",
|
.category = "Network (Development)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Disable Network Fixes",
|
.title = "Disable Network Fixes",
|
||||||
.name = "netfixdisable",
|
.name = "netfixdisable",
|
||||||
.desc = "Force disables network fixes",
|
.desc = "Force disables network fixes",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Network Adapters",
|
.category = "Network (Development)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "HTTP/1.1",
|
.title = "HTTP/1.1",
|
||||||
.name = "http11",
|
.name = "http11",
|
||||||
.desc = "Sets EA3 http11 value",
|
.desc = "Sets EA3 http11 value",
|
||||||
.type = OptionType::Enum,
|
.type = OptionType::Enum,
|
||||||
.category = "Network (Advanced)",
|
.category = "Network (Development)",
|
||||||
.elements = {{"0", "Off"}, {"1", "On"}},
|
.elements = {{"0", "Off"}, {"1", "On"}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -335,7 +344,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "ssldisable",
|
.name = "ssldisable",
|
||||||
.desc = "Prevents the SSL protocol from being registered",
|
.desc = "Prevents the SSL protocol from being registered",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Network (Advanced)",
|
.category = "Network (Development)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "URL Slash",
|
.title = "URL Slash",
|
||||||
@@ -350,7 +359,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "r",
|
.name = "r",
|
||||||
.desc = "Set custom SOFTID override",
|
.desc = "Set custom SOFTID override",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Network (Advanced)",
|
.category = "Network (Development)",
|
||||||
.sensitive = true,
|
.sensitive = true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -668,6 +677,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// SDVXPrinterOutputPath
|
||||||
.title = "SDVX Printer Output Path",
|
.title = "SDVX Printer Output Path",
|
||||||
.name = "printerpath",
|
.name = "printerpath",
|
||||||
.desc = "Path to folder where images will be stored",
|
.desc = "Path to folder where images will be stored",
|
||||||
@@ -692,6 +702,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// SDVXPrinterOutputFormat
|
||||||
.title = "SDVX Printer Output Format",
|
.title = "SDVX Printer Output Format",
|
||||||
.name = "printerformat",
|
.name = "printerformat",
|
||||||
.desc = "File format for printer output",
|
.desc = "File format for printer output",
|
||||||
@@ -710,10 +721,13 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "SDVX Disable Cameras",
|
.title = "SDVX Disable Cameras (DEPRECATED - no longer needed)",
|
||||||
.name = "sdvxdisablecams",
|
.name = "sdvxdisablecams",
|
||||||
.desc = "Disables cameras",
|
.desc = "This option does nothing.\n\n"
|
||||||
|
"This option was used in the past to fix cameras in SDVX5 but this is no longer "
|
||||||
|
"needed as camera check will always be skipped with a built-in patch.",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
|
.hidden = true,
|
||||||
.game_name = "Sound Voltex",
|
.game_name = "Sound Voltex",
|
||||||
.category = "Game Options",
|
.category = "Game Options",
|
||||||
},
|
},
|
||||||
@@ -799,6 +813,15 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.game_name = "Dance Dance Revolution",
|
.game_name = "Dance Dance Revolution",
|
||||||
.category = "Game Options",
|
.category = "Game Options",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// DDRSkipCodecRegisteration
|
||||||
|
.title = "DDR Skip Codec Registration",
|
||||||
|
.name = "ddrnocodec",
|
||||||
|
.desc = "Prevent automatic registration of codecs in the com folder",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.game_name = "Dance Dance Revolution",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.title = "Force Load Pop'n Music Module",
|
.title = "Force Load Pop'n Music Module",
|
||||||
.name = "pnm",
|
.name = "pnm",
|
||||||
@@ -1026,7 +1049,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
// LoadCCJModule
|
// LoadCCJModule
|
||||||
.title = "Force Load Chase Chase Jokers",
|
.title = "Force Load Chase Chase Jokers Module",
|
||||||
.name = "ccj",
|
.name = "ccj",
|
||||||
.desc = "manually enable Chase Chase Jokers module",
|
.desc = "manually enable Chase Chase Jokers module",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
@@ -1035,7 +1058,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
// LoadQKSModule
|
// LoadQKSModule
|
||||||
.title = "Force Load QuizKnock STADIUM",
|
.title = "Force Load QuizKnock STADIUM Module",
|
||||||
.name = "qks",
|
.name = "qks",
|
||||||
.desc = "manually enable QuizKnock STADIUM module",
|
.desc = "manually enable QuizKnock STADIUM module",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
@@ -1044,16 +1067,25 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
// LoadMFGModule
|
// LoadMFGModule
|
||||||
.title = "Force Load Mahjong Fight Girl",
|
.title = "Force Load Mahjong Fight Girl Module",
|
||||||
.name = "mfg",
|
.name = "mfg",
|
||||||
.desc = "manually enable Mahjong Fight Girl module",
|
.desc = "manually enable Mahjong Fight Girl module",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.game_name = "Mahjong Fight Girl",
|
.game_name = "Mahjong Fight Girl",
|
||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// LoadPCModule
|
||||||
|
.title = "Force Load Polaris Chord Module",
|
||||||
|
.name = "pc",
|
||||||
|
.desc = "manually enable Polaris Chord module",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.game_name = "Polaris Chord",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// LoadMusecaModule
|
// LoadMusecaModule
|
||||||
.title = "Force Load Museca",
|
.title = "Force Load Museca Module",
|
||||||
.name = "museca",
|
.name = "museca",
|
||||||
.desc = "manually enable Museca module",
|
.desc = "manually enable Museca module",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
@@ -1061,88 +1093,88 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Modules Folder Path",
|
.title = "Modules Folder Override",
|
||||||
.name = "modules",
|
.name = "modules",
|
||||||
.desc = "Sets a custom path to the modules folder",
|
.desc = "Sets a custom path to the modules folder",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Screenshot Folder Path",
|
.title = "Screenshot Folder Override",
|
||||||
.name = "screenshotpath",
|
.name = "screenshotpath",
|
||||||
.desc = "Sets a custom path to the screenshots folder",
|
.desc = "Sets a custom path to the screenshots folder",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Configuration Path",
|
.title = "Configuration Path Override",
|
||||||
.name = "cfgpath",
|
.name = "cfgpath",
|
||||||
.desc = "Sets a custom file path for config file. Must be passed via the command line. "
|
.desc = "Sets a custom file path for config file. Must be passed via the command line. "
|
||||||
"If left empty, %appdata%\\spicetools.xml will be used",
|
"If left empty, %appdata%\\spicetools.xml will be used",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.setting_name = "(default)",
|
.setting_name = "(default)",
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
.disabled = true,
|
.disabled = true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// ScreenResizeConfigPath
|
// ScreenResizeConfigPath
|
||||||
.title = "Screen Resize Config Path",
|
.title = "Screen Resize Config Path Override",
|
||||||
.name = "resizecfgpath",
|
.name = "resizecfgpath",
|
||||||
.desc = "Sets a custom file path for screen resize config file. "
|
.desc = "Sets a custom file path for screen resize config file. "
|
||||||
"If left empty, %appdata%\\spice2x\\spicetools_screen_resize.json will be used",
|
"If left empty, %appdata%\\spice2x\\spicetools_screen_resize.json will be used",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// PatchManagerConfigPath
|
// PatchManagerConfigPath
|
||||||
.title = "Patch Manager Config Path",
|
.title = "Patch Manager Config Path Override",
|
||||||
.name = "patchcfgpath",
|
.name = "patchcfgpath",
|
||||||
.desc = "Sets a custom file path for patch manager config file. Can be used to manage 'profiles' for auto-patches. "
|
.desc = "Sets a custom file path for patch manager config file. Can be used to manage 'profiles' for auto-patches. "
|
||||||
"If left empty, %appdata%\\spice2x\\spicetools_patch_manager.json will be used",
|
"If left empty, %appdata%\\spice2x\\spicetools_patch_manager.json will be used",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Intel SDE Folder Path",
|
.title = "Intel SDE Folder",
|
||||||
.name = "sde",
|
.name = "sde",
|
||||||
.desc = "Path to Intel SDE kit path for automatic attaching",
|
.desc = "Path to Intel SDE kit path for automatic attaching",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Path to ea3-config.xml",
|
.title = "ea3-config.xml Override",
|
||||||
.name = "e",
|
.name = "e",
|
||||||
.desc = "Sets a custom path to ea3-config.xml",
|
.desc = "Sets a custom path to ea3-config.xml",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Path to app-config.xml",
|
.title = "app-config.xml Override",
|
||||||
.name = "a",
|
.name = "a",
|
||||||
.desc = "Sets a custom path to app-config.xml",
|
.desc = "Sets a custom path to app-config.xml",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Path to avs-config.xml",
|
.title = "avs-config.xml Override",
|
||||||
.name = "v",
|
.name = "v",
|
||||||
.desc = "Sets a custom path to avs-config.xml",
|
.desc = "Sets a custom path to avs-config.xml",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Path to bootstrap.xml",
|
.title = "bootstrap.xml Override",
|
||||||
.name = "b",
|
.name = "b",
|
||||||
.desc = "Sets a custom path to bootstrap.xml",
|
.desc = "Sets a custom path to bootstrap.xml",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Path to log.txt",
|
.title = "log.txt Override",
|
||||||
.name = "y",
|
.name = "y",
|
||||||
.desc = "Sets a custom path to log.txt",
|
.desc = "Sets a custom path to log.txt",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "API TCP Port",
|
.title = "API TCP Port",
|
||||||
@@ -1311,6 +1343,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Touch Parameters",
|
.category = "Touch Parameters",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// ICCAReaderPort
|
||||||
.title = "ICCA Reader Port",
|
.title = "ICCA Reader Port",
|
||||||
.name = "reader",
|
.name = "reader",
|
||||||
.desc = "Connects to and uses a ICCA on a given COM port",
|
.desc = "Connects to and uses a ICCA on a given COM port",
|
||||||
@@ -1387,11 +1420,12 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// SextetStreamPort
|
||||||
.title = "SextetStream Port",
|
.title = "SextetStream Port",
|
||||||
.name = "sextet",
|
.name = "sextet",
|
||||||
.desc = "Use a SextetStream device on a given COM port",
|
.desc = "Use a SextetStream device on a given COM port",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Miscellaneous",
|
.category = "I/O Options",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Enable BemaniTools 5 API",
|
.title = "Enable BemaniTools 5 API",
|
||||||
@@ -1492,7 +1526,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
"you use a different backend instead of exclusive WASAPI).\n\n"
|
"you use a different backend instead of exclusive WASAPI).\n\n"
|
||||||
"Check this if you want games to natively access your audio device",
|
"Check this if you want games to natively access your audio device",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Audio",
|
.category = "Audio (Hacks)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// spice2x_DisableVolumeHook
|
// spice2x_DisableVolumeHook
|
||||||
@@ -1504,7 +1538,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
"Default: off (prevent games from changing audio volume by hooking IAudioEndpointVolume).\n\n"
|
"Default: off (prevent games from changing audio volume by hooking IAudioEndpointVolume).\n\n"
|
||||||
"Check this if you want games to freely change your volume",
|
"Check this if you want games to freely change your volume",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Audio",
|
.category = "Audio (Hacks)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Spice Audio Hook Backend",
|
.title = "Spice Audio Hook Backend",
|
||||||
@@ -1529,7 +1563,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
"This is automatically enabled when required and not normally needed",
|
"This is automatically enabled when required and not normally needed",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.hidden = true,
|
.hidden = true,
|
||||||
.category = "Audio",
|
.category = "Audio (Hacks)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// DelayBy5Seconds
|
// DelayBy5Seconds
|
||||||
@@ -1582,11 +1616,11 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.elements = {{"0", "90 (CW)"}, {"1", "270 (CCW)"}},
|
.elements = {{"0", "90 (CW)"}, {"1", "270 (CCW)"}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Log Level",
|
.title = "AVS Log Level",
|
||||||
.name = "loglevel",
|
.name = "loglevel",
|
||||||
.desc = "Set the level of detail that gets written to the log",
|
.desc = "Set the level of detail for AVS log messages written to the log. Does not affect logging from spice",
|
||||||
.type = OptionType::Enum,
|
.type = OptionType::Enum,
|
||||||
.category = "Performance",
|
.category = "Debug Log",
|
||||||
.elements = {{"fatal", ""}, {"warning", ""}, {"info", ""}, {"misc", ""}, {"all", ""}, {"disable", ""}},
|
.elements = {{"fatal", ""}, {"warning", ""}, {"info", ""}, {"misc", ""}, {"all", ""}, {"disable", ""}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1594,14 +1628,14 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "automap",
|
.name = "automap",
|
||||||
.desc = "Enable automap in patch configuration",
|
.desc = "Enable automap in patch configuration",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Network (Development)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "EA Netdump",
|
.title = "EA Netdump",
|
||||||
.name = "netdump",
|
.name = "netdump",
|
||||||
.desc = "Enable automap in network dumping configuration",
|
.desc = "Enable automap in network dumping configuration",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Network (Development)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Discord RPC AppID Override",
|
.title = "Discord RPC AppID Override",
|
||||||
@@ -1615,35 +1649,35 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "logblock",
|
.name = "logblock",
|
||||||
.desc = "Slower but safer logging used for debugging",
|
.desc = "Slower but safer logging used for debugging",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Debug Log",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Debug CreateFile",
|
.title = "Debug CreateFile",
|
||||||
.name = "createfiledebug",
|
.name = "createfiledebug",
|
||||||
.desc = "Outputs CreateFile debug prints",
|
.desc = "Outputs CreateFile debug prints",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Debug Log",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Verbose Graphics Logging",
|
.title = "Verbose Graphics Logging",
|
||||||
.name = "graphicsverbose",
|
.name = "graphicsverbose",
|
||||||
.desc = "Enable the verbose logging of graphics hook code",
|
.desc = "Enable the verbose logging of graphics hook code",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Debug Log",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Verbose AVS Logging",
|
.title = "Verbose AVS Logging",
|
||||||
.name = "avsverbose",
|
.name = "avsverbose",
|
||||||
.desc = "Enable the verbose logging of AVS filesystem functions",
|
.desc = "Enable the verbose logging of AVS filesystem functions",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Debug Log",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Disable Colored Output",
|
.title = "Disable Colored Output",
|
||||||
.name = "nocolor",
|
.name = "nocolor",
|
||||||
.desc = "Disable terminal colors for log outputs to console",
|
.desc = "Disable terminal colors for log outputs to console",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Debug Log",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Disable ACP Hook",
|
.title = "Disable ACP Hook",
|
||||||
@@ -1678,7 +1712,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "pebprint",
|
.name = "pebprint",
|
||||||
.desc = "Prints PEB on startup to console",
|
.desc = "Prints PEB on startup to console",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Debug Log",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// DumpSystemInfo
|
// DumpSystemInfo
|
||||||
@@ -1686,7 +1720,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "sysdump",
|
.name = "sysdump",
|
||||||
.desc = "Print system information to the log on startup. Default: basic",
|
.desc = "Print system information to the log on startup. Default: basic",
|
||||||
.type = OptionType::Enum,
|
.type = OptionType::Enum,
|
||||||
.category = "Development",
|
.category = "Debug Log",
|
||||||
.elements = {
|
.elements = {
|
||||||
{"none", "Nothing"},
|
{"none", "Nothing"},
|
||||||
{"basic", "OS, CPU, SMBIOS, GPU"},
|
{"basic", "OS, CPU, SMBIOS, GPU"},
|
||||||
@@ -1771,6 +1805,35 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.game_name = "Mahjong Fight Girl",
|
.game_name = "Mahjong Fight Girl",
|
||||||
.category = "Game Options (Advanced)"
|
.category = "Game Options (Advanced)"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// PCArgs
|
||||||
|
.title = "PC Arguments Override",
|
||||||
|
.name = "pcargs",
|
||||||
|
.desc = "Command line arguments passed to the game.",
|
||||||
|
.type = OptionType::Text,
|
||||||
|
.setting_name = "",
|
||||||
|
.game_name = "Polaris Chord",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// PCNoIO
|
||||||
|
.title = "PC Disable IO Emulation",
|
||||||
|
.name = "pcnoio",
|
||||||
|
.desc = "Disables BI2X hooks for PC",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.setting_name = "",
|
||||||
|
.game_name = "Polaris Chord",
|
||||||
|
.category = "Game Options (Advanced)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// PCKnobMode
|
||||||
|
.title = "PC Fader Knobs Mode",
|
||||||
|
.name = "pcknobs",
|
||||||
|
.desc = "Allows SDVX knobs and IIDX turntables to be bound as Polaris Chord faders",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.game_name = "Polaris Chord",
|
||||||
|
.category = "Game Options",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// spice2x_LightsOverallBrightness
|
// spice2x_LightsOverallBrightness
|
||||||
.title = "Lights Brightness Adjustment",
|
.title = "Lights Brightness Adjustment",
|
||||||
@@ -1916,7 +1979,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.desc = "For certain buggy ASIO drivers, force unload of ASIO driver when audio stream stops. "
|
.desc = "For certain buggy ASIO drivers, force unload of ASIO driver when audio stream stops. "
|
||||||
"Used for working around ASIO drivers that lock up after force quitting games",
|
"Used for working around ASIO drivers that lock up after force quitting games",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Audio",
|
.category = "Audio (Hacks)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// spice2x_IIDXNoESpec
|
// spice2x_IIDXNoESpec
|
||||||
@@ -2260,6 +2323,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Game Options",
|
.category = "Game Options",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// LovePlusPrinterOutputPath
|
||||||
.title = "LovePlus Printer Output Path",
|
.title = "LovePlus Printer Output Path",
|
||||||
.name = "lpprinterpath",
|
.name = "lpprinterpath",
|
||||||
.desc = "Path to folder where images will be stored",
|
.desc = "Path to folder where images will be stored",
|
||||||
@@ -2284,6 +2348,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// LovePlusPrinterOutputFormat
|
||||||
.title = "LovePlus Printer Output Format",
|
.title = "LovePlus Printer Output Format",
|
||||||
.name = "lpprinterformat",
|
.name = "lpprinterformat",
|
||||||
.desc = "File format for printer output",
|
.desc = "File format for printer output",
|
||||||
@@ -2301,6 +2366,16 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.game_name = "LovePlus",
|
.game_name = "LovePlus",
|
||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// OptionConflictResolution
|
||||||
|
.title = "Command Line Args Override",
|
||||||
|
.name = "cmdoverride",
|
||||||
|
.desc = "By default, option values in spicecfg take precedence over command-line args, for legacy compat.\n"
|
||||||
|
"When this is specified in command line, command-line args take precedence instead",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.category = "Development",
|
||||||
|
.disabled = true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::vector<std::string> &launcher::get_categories(Options::OptionsCategory category) {
|
const std::vector<std::string> &launcher::get_categories(Options::OptionsCategory category) {
|
||||||
@@ -2381,7 +2456,7 @@ std::unique_ptr<std::vector<Option>> launcher::parse_options(int argc, char *arg
|
|||||||
} else {
|
} else {
|
||||||
// validate it is an integer
|
// validate it is an integer
|
||||||
try {
|
try {
|
||||||
std::stoull(argv[i], nullptr, 16);
|
auto _ = std::stoull(argv[i], nullptr, 16);
|
||||||
} catch (const std::exception &ex) {
|
} catch (const std::exception &ex) {
|
||||||
log_fatal("options", "parameter for -{} is not a hex number: {}", alias, argv[i]);
|
log_fatal("options", "parameter for -{} is not a hex number: {}", alias, argv[i]);
|
||||||
}
|
}
|
||||||
@@ -2482,12 +2557,25 @@ std::vector<Option> launcher::merge_options(
|
|||||||
auto &new_option = merged.emplace_back(option.get_definition(), "");
|
auto &new_option = merged.emplace_back(option.get_definition(), "");
|
||||||
new_option.disabled = true;
|
new_option.disabled = true;
|
||||||
|
|
||||||
|
if (USE_CMD_OVERRIDE) {
|
||||||
|
// command-line arguments take precedence (opt-in)
|
||||||
|
for (auto &value : override.values()) {
|
||||||
|
new_option.value_add(value);
|
||||||
|
}
|
||||||
|
for (auto &value : option.values()) {
|
||||||
|
new_option.value_add(value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// spicecfg options take precedence (default)
|
||||||
|
// this sucks, but it's the default for legacy spicetools compat
|
||||||
for (auto &value : option.values()) {
|
for (auto &value : option.values()) {
|
||||||
new_option.value_add(value);
|
new_option.value_add(value);
|
||||||
}
|
}
|
||||||
for (auto &value : override.values()) {
|
for (auto &value : override.values()) {
|
||||||
new_option.value_add(value);
|
new_option.value_add(value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
new_option.conflicting = true;
|
||||||
} else {
|
} else {
|
||||||
auto &new_option = merged.emplace_back(override.get_definition(), "");
|
auto &new_option = merged.emplace_back(override.get_definition(), "");
|
||||||
new_option.disabled = true;
|
new_option.disabled = true;
|
||||||
@@ -2503,7 +2591,6 @@ std::vector<Option> launcher::merge_options(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ namespace launcher {
|
|||||||
spice2x_SDVXSubRedraw,
|
spice2x_SDVXSubRedraw,
|
||||||
LoadDDRModule,
|
LoadDDRModule,
|
||||||
DDR43Mode,
|
DDR43Mode,
|
||||||
|
DDRSkipCodecRegisteration,
|
||||||
LoadPopnMusicModule,
|
LoadPopnMusicModule,
|
||||||
PopnMusicForceHDMode,
|
PopnMusicForceHDMode,
|
||||||
PopnMusicForceSDMode,
|
PopnMusicForceSDMode,
|
||||||
@@ -117,6 +118,7 @@ namespace launcher {
|
|||||||
LoadCCJModule,
|
LoadCCJModule,
|
||||||
LoadQKSModule,
|
LoadQKSModule,
|
||||||
LoadMFGModule,
|
LoadMFGModule,
|
||||||
|
LoadPCModule,
|
||||||
LoadMusecaModule,
|
LoadMusecaModule,
|
||||||
PathToModules,
|
PathToModules,
|
||||||
ScreenshotFolder,
|
ScreenshotFolder,
|
||||||
@@ -201,6 +203,9 @@ namespace launcher {
|
|||||||
MFGArgs,
|
MFGArgs,
|
||||||
MFGCabType,
|
MFGCabType,
|
||||||
MFGNoIO,
|
MFGNoIO,
|
||||||
|
PCArgs,
|
||||||
|
PCNoIO,
|
||||||
|
PCKnobMode,
|
||||||
spice2x_LightsOverallBrightness,
|
spice2x_LightsOverallBrightness,
|
||||||
spice2x_WindowBorder,
|
spice2x_WindowBorder,
|
||||||
spice2x_WindowSize,
|
spice2x_WindowSize,
|
||||||
@@ -246,6 +251,7 @@ namespace launcher {
|
|||||||
LovePlusPrinterOutputOverwrite,
|
LovePlusPrinterOutputOverwrite,
|
||||||
LovePlusPrinterOutputFormat,
|
LovePlusPrinterOutputFormat,
|
||||||
LovePlusPrinterJPGQuality,
|
LovePlusPrinterJPGQuality,
|
||||||
|
OptionConflictResolution,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class OptionsCategory {
|
enum class OptionsCategory {
|
||||||
@@ -257,6 +263,8 @@ namespace launcher {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern bool USE_CMD_OVERRIDE;
|
||||||
|
|
||||||
const std::vector<std::string> &get_categories(Options::OptionsCategory category);
|
const std::vector<std::string> &get_categories(Options::OptionsCategory category);
|
||||||
const std::vector<OptionDefinition> &get_option_definitions();
|
const std::vector<OptionDefinition> &get_option_definitions();
|
||||||
std::unique_ptr<std::vector<Option>> parse_options(int argc, char *argv[]);
|
std::unique_ptr<std::vector<Option>> parse_options(int argc, char *argv[]);
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ namespace richpresence {
|
|||||||
{"Busou Shinki: Armored Princess Battle Conductor", "1226739666741366916"},
|
{"Busou Shinki: Armored Princess Battle Conductor", "1226739666741366916"},
|
||||||
{"Chase Chase Jokers", "1226739863915593770"},
|
{"Chase Chase Jokers", "1226739863915593770"},
|
||||||
{"QuizKnock STADIUM", "1226739930328334478"},
|
{"QuizKnock STADIUM", "1226739930328334478"},
|
||||||
|
{"Mahjong Fight Girl", "1417371188342030468"},
|
||||||
|
{"Polaris Chord", "1417371592224407552"},
|
||||||
};
|
};
|
||||||
|
|
||||||
// state
|
// state
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
|
|
||||||
|
#include "acio/acio.h"
|
||||||
#include "external/stackwalker/stackwalker.h"
|
#include "external/stackwalker/stackwalker.h"
|
||||||
#include "hooks/libraryhook.h"
|
#include "hooks/libraryhook.h"
|
||||||
#include "launcher/shutdown.h"
|
#include "launcher/shutdown.h"
|
||||||
@@ -28,6 +29,9 @@ namespace launcher::signal {
|
|||||||
// settings
|
// settings
|
||||||
bool DISABLE = false;
|
bool DISABLE = false;
|
||||||
bool USE_VEH_WORKAROUND = false;
|
bool USE_VEH_WORKAROUND = false;
|
||||||
|
|
||||||
|
// states
|
||||||
|
bool SUPERSTEP_SOUND_ERROR = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define V(variant) case variant: return #variant
|
#define V(variant) case variant: return #variant
|
||||||
@@ -97,6 +101,26 @@ static LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *Exception
|
|||||||
// print signal
|
// print signal
|
||||||
log_warning("signal", "exception raised: {}", exception_code(ExceptionRecord));
|
log_warning("signal", "exception raised: {}", exception_code(ExceptionRecord));
|
||||||
|
|
||||||
|
// check ACIO init failures
|
||||||
|
if (acio::IO_INIT_IN_PROGRESS) {
|
||||||
|
log_warning(
|
||||||
|
"signal",
|
||||||
|
"exception raised during ACIO init, this usually happens when a third party application interferes with hooks");
|
||||||
|
log_warning(
|
||||||
|
"signal",
|
||||||
|
" please check for the following, disable them, and try launching the game again:");
|
||||||
|
log_warning(
|
||||||
|
"signal",
|
||||||
|
" RivaTuner Statistics Server (RTSS), MSI Afterburner, kernel mode anti-cheat");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (launcher::signal::SUPERSTEP_SOUND_ERROR) {
|
||||||
|
log_warning("signal", "audio initialization error was previously detected during boot!");
|
||||||
|
log_warning("signal", " (W:SuperstepSound: Audio device is not available!!!)");
|
||||||
|
log_warning("signal", " this crash is most likely related to audio init failure");
|
||||||
|
log_warning("signal", " fix your audio device, double check your audio options/patches, and try again");
|
||||||
|
}
|
||||||
|
|
||||||
// walk the exception chain
|
// walk the exception chain
|
||||||
struct _EXCEPTION_RECORD *record_cause = ExceptionRecord->ExceptionRecord;
|
struct _EXCEPTION_RECORD *record_cause = ExceptionRecord->ExceptionRecord;
|
||||||
while (record_cause != nullptr) {
|
while (record_cause != nullptr) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace launcher::signal {
|
|||||||
// settings
|
// settings
|
||||||
extern bool DISABLE;
|
extern bool DISABLE;
|
||||||
extern bool USE_VEH_WORKAROUND;
|
extern bool USE_VEH_WORKAROUND;
|
||||||
|
extern bool SUPERSTEP_SOUND_ERROR;
|
||||||
|
|
||||||
//void print_stacktrace();
|
//void print_stacktrace();
|
||||||
void attach();
|
void attach();
|
||||||
|
|||||||
@@ -659,6 +659,8 @@ void eamuse_autodetect_game() {
|
|||||||
eamuse_set_game("QuizKnock STADIUM");
|
eamuse_set_game("QuizKnock STADIUM");
|
||||||
else if (avs::game::is_model("VFG"))
|
else if (avs::game::is_model("VFG"))
|
||||||
eamuse_set_game("Mahjong Fight Girl");
|
eamuse_set_game("Mahjong Fight Girl");
|
||||||
|
else if (avs::game::is_model("XIF"))
|
||||||
|
eamuse_set_game("Polaris Chord");
|
||||||
else {
|
else {
|
||||||
log_warning("eamuse", "unknown game model: {}", avs::game::MODEL);
|
log_warning("eamuse", "unknown game model: {}", avs::game::MODEL);
|
||||||
eamuse_set_game("unknown");
|
eamuse_set_game("unknown");
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ static void __cdecl cardunit_update() {
|
|||||||
bool kb_insert_press = false;
|
bool kb_insert_press = false;
|
||||||
|
|
||||||
// eamio keypress
|
// eamio keypress
|
||||||
kb_insert_press |= eamuse_get_keypad_state(unit) & (1 << EAM_IO_INSERT);
|
kb_insert_press |= static_cast<bool>(eamuse_get_keypad_state(unit) & (1 << EAM_IO_INSERT));
|
||||||
|
|
||||||
// update card inserts
|
// update card inserts
|
||||||
if (eamuse_card_insert_consume((int) EXTDEV_CARDUNIT_COUNT, unit) ||
|
if (eamuse_card_insert_consume((int) EXTDEV_CARDUNIT_COUNT, unit) ||
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "touch/touch.h"
|
#include "touch/touch.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
|
#include "hooks/graphics/graphics.h"
|
||||||
|
|
||||||
#if !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) || \
|
#if !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) || \
|
||||||
!defined(IMGUI_DISABLE_DEFAULT_ALLOCATORS) || \
|
!defined(IMGUI_DISABLE_DEFAULT_ALLOCATORS) || \
|
||||||
@@ -175,10 +176,22 @@ static void ImGui_ImplSpice_UpdateMousePos() {
|
|||||||
static_cast<int>(pos.y / io.DisplaySize.y * window_size.y));
|
static_cast<int>(pos.y / io.DisplaySize.y * window_size.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto active_window = ::GetForegroundWindow();
|
||||||
|
|
||||||
|
// if the main focus is a windowed subscreen, put the imgui cursor in a place that won't
|
||||||
|
// trigger any overlay, don't process anything else
|
||||||
|
const auto is_windowed_subscreen =
|
||||||
|
(GRAPHICS_IIDX_WSUB && active_window == TDJ_SUBSCREEN_WINDOW) ||
|
||||||
|
(active_window == SDVX_SUBSCREEN_WINDOW);
|
||||||
|
if (is_windowed_subscreen) {
|
||||||
|
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// set mouse position
|
// set mouse position
|
||||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||||
POINT pos;
|
POINT pos;
|
||||||
if (HWND active_window = ::GetForegroundWindow()) {
|
if (active_window) {
|
||||||
if (active_window == g_hWnd
|
if (active_window == g_hWnd
|
||||||
|| ::IsChild(active_window, g_hWnd)
|
|| ::IsChild(active_window, g_hWnd)
|
||||||
|| ::IsChild(g_hWnd, active_window)
|
|| ::IsChild(g_hWnd, active_window)
|
||||||
@@ -208,7 +221,7 @@ static void ImGui_ImplSpice_UpdateMousePos() {
|
|||||||
static size_t delay_touch = 0;
|
static size_t delay_touch = 0;
|
||||||
static size_t delay_touch_target = 2;
|
static size_t delay_touch_target = 2;
|
||||||
static DWORD last_touch_id = ~0u;
|
static DWORD last_touch_id = ~0u;
|
||||||
if (!touch_points.empty()) {
|
if (!touch_points.empty() && !is_windowed_subscreen) {
|
||||||
|
|
||||||
// use the first touch point
|
// use the first touch point
|
||||||
auto &tp = touch_points[0];
|
auto &tp = touch_points[0];
|
||||||
|
|||||||
@@ -174,18 +174,18 @@ void overlay::SpiceOverlay::init() {
|
|||||||
// https://github.com/ocornut/imgui/issues/707#issuecomment-760220280
|
// https://github.com/ocornut/imgui/issues/707#issuecomment-760220280
|
||||||
// r, g, b, a
|
// r, g, b, a
|
||||||
ImVec4* colors = ImGui::GetStyle().Colors;
|
ImVec4* colors = ImGui::GetStyle().Colors;
|
||||||
// colors[ImGuiCol_Text] = ImVec4(0.75f, 0.75f, 0.75f, 1.00f);
|
|
||||||
// colors[ImGuiCol_TextDisabled] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f);
|
|
||||||
|
|
||||||
// colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.94f);
|
// note: also see bg_alpha value in each overlay window
|
||||||
// colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 1.0f);
|
||||||
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.f, 0.f, 0.94f);
|
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 1.0f);
|
||||||
|
|
||||||
colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);
|
colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);
|
||||||
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||||
colors[ImGuiCol_FrameBg] = ImVec4(0.37f, 0.14f, 0.00f, 0.54f);
|
|
||||||
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.37f, 0.14f, 0.14f, 0.67f);
|
colors[ImGuiCol_FrameBg] = ImVec4(0.18f, 0.18f, 0.18f, 0.54f);
|
||||||
colors[ImGuiCol_FrameBgActive] = ImVec4(0.39f, 0.20f, 0.20f, 0.67f);
|
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.18f, 0.18f, 0.18f, 0.80f);
|
||||||
|
colors[ImGuiCol_FrameBgActive] = ImVec4(0.24f, 0.24f, 0.24f, 0.80f);
|
||||||
|
|
||||||
colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);
|
colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);
|
||||||
colors[ImGuiCol_TitleBgActive] = ImVec4(0.48f, 0.16f, 0.16f, 1.00f);
|
colors[ImGuiCol_TitleBgActive] = ImVec4(0.48f, 0.16f, 0.16f, 1.00f);
|
||||||
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.48f, 0.16f, 0.16f, 1.00f);
|
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.48f, 0.16f, 0.16f, 1.00f);
|
||||||
@@ -194,16 +194,16 @@ void overlay::SpiceOverlay::init() {
|
|||||||
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
|
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
|
||||||
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
|
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
|
||||||
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
|
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
|
||||||
colors[ImGuiCol_CheckMark] = ImVec4(0.56f, 0.10f, 0.10f, 1.00f);
|
colors[ImGuiCol_CheckMark] = ImVec4(0.89f, 0.00f, 0.19f, 1.00f);
|
||||||
colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 0.19f, 0.19f, 0.40f);
|
colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 0.19f, 0.19f, 0.40f);
|
||||||
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.89f, 0.00f, 0.19f, 1.00f);
|
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.89f, 0.00f, 0.19f, 1.00f);
|
||||||
|
|
||||||
colors[ImGuiCol_Button] = ImVec4(1.00f, 0.19f, 0.19f, 0.40f);
|
colors[ImGuiCol_Button] = ImVec4(1.00f, 0.19f, 0.19f, 0.40f);
|
||||||
colors[ImGuiCol_ButtonHovered] = ImVec4(0.80f, 0.17f, 0.00f, 1.00f);
|
colors[ImGuiCol_ButtonHovered] = ImVec4(0.80f, 0.17f, 0.00f, 1.00f);
|
||||||
colors[ImGuiCol_ButtonActive] = ImVec4(0.89f, 0.00f, 0.19f, 1.00f);
|
colors[ImGuiCol_ButtonActive] = ImVec4(0.80f, 0.17f, 0.00f, 0.90f);
|
||||||
|
|
||||||
colors[ImGuiCol_Header] = ImVec4(0.33f, 0.35f, 0.36f, 0.53f);
|
colors[ImGuiCol_Header] = ImVec4(0.33f, 0.35f, 0.36f, 0.53f);
|
||||||
colors[ImGuiCol_HeaderHovered] = ImVec4(0.76f, 0.28f, 0.44f, 0.67f);
|
colors[ImGuiCol_HeaderHovered] = ImVec4(0.44f, 0.44f, 0.44f, 0.67f);
|
||||||
colors[ImGuiCol_HeaderActive] = ImVec4(0.47f, 0.47f, 0.47f, 0.67f);
|
colors[ImGuiCol_HeaderActive] = ImVec4(0.47f, 0.47f, 0.47f, 0.67f);
|
||||||
colors[ImGuiCol_Separator] = ImVec4(0.32f, 0.32f, 0.32f, 1.00f);
|
colors[ImGuiCol_Separator] = ImVec4(0.32f, 0.32f, 0.32f, 1.00f);
|
||||||
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.32f, 0.32f, 0.32f, 1.00f);
|
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.32f, 0.32f, 0.32f, 1.00f);
|
||||||
@@ -228,7 +228,7 @@ void overlay::SpiceOverlay::init() {
|
|||||||
colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f);
|
colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f);
|
||||||
colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f);
|
colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f);
|
||||||
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||||
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.04f);
|
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.02f);
|
||||||
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
|
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
|
||||||
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
|
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
|
||||||
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
|
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace overlay {
|
|||||||
ImVec2 init_size = ImVec2(0, 0);
|
ImVec2 init_size = ImVec2(0, 0);
|
||||||
ImVec2 size_min = ImVec2(0, 0);
|
ImVec2 size_min = ImVec2(0, 0);
|
||||||
ImVec2 size_max = ImVec2(-1, -1);
|
ImVec2 size_max = ImVec2(-1, -1);
|
||||||
float bg_alpha = 0.8f;
|
float bg_alpha = 0.96f;
|
||||||
|
|
||||||
Window(SpiceOverlay *overlay);
|
Window(SpiceOverlay *overlay);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#include "avs/ea3.h"
|
#include "avs/ea3.h"
|
||||||
#include "avs/game.h"
|
#include "avs/game.h"
|
||||||
#include "launcher/launcher.h"
|
#include "launcher/launcher.h"
|
||||||
#include "launcher/shutdown.h"
|
|
||||||
#include "launcher/options.h"
|
#include "launcher/options.h"
|
||||||
#include "misc/eamuse.h"
|
#include "misc/eamuse.h"
|
||||||
#include "overlay/imgui/extensions.h"
|
#include "overlay/imgui/extensions.h"
|
||||||
@@ -2914,7 +2913,7 @@ namespace overlay::windows {
|
|||||||
ImGui::TextUnformatted("");
|
ImGui::TextUnformatted("");
|
||||||
|
|
||||||
if (ImGui::Button(PROJECT_URL)) {
|
if (ImGui::Button(PROJECT_URL)) {
|
||||||
launch_shell(PROJECT_URL, nullptr);
|
launch_shell(PROJECT_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::TextUnformatted("");
|
ImGui::TextUnformatted("");
|
||||||
@@ -2979,31 +2978,28 @@ namespace overlay::windows {
|
|||||||
void Config::build_menu(int *game_selected) {
|
void Config::build_menu(int *game_selected) {
|
||||||
bool about_popup = false;
|
bool about_popup = false;
|
||||||
bool licenses_popup = false;
|
bool licenses_popup = false;
|
||||||
bool shutdown_popup = false;
|
|
||||||
if (ImGui::BeginMenuBar()) {
|
if (ImGui::BeginMenuBar()) {
|
||||||
|
|
||||||
// [spice2x]
|
// [spice2x]
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.f, 0.f, 1.f));
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.f, 0.f, 1.f));
|
||||||
ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImVec4(1.f, 0.f, 0.f, 1.f));
|
if (ImGui::BeginMenu("[spice2x]")) {
|
||||||
ImGui::BeginDisabled(!cfg::CONFIGURATOR_STANDALONE);
|
ImGui::PopStyleColor();
|
||||||
if (ImGui::MenuItem("[spice2x]")) {
|
if (ImGui::MenuItem("spice2x.github.io")) {
|
||||||
launch_shell(PROJECT_URL, nullptr);
|
launch_shell(PROJECT_URL);
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
if (ImGui::MenuItem("Licenses")) {
|
||||||
|
licenses_popup = true;
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("About")) {
|
||||||
|
about_popup = true;
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
} else {
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
ImGui::PopStyleColor();
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
// game selector
|
|
||||||
ImGui::PushItemWidth(MIN(580, MAX(80, ImGui::GetWindowSize().x - 520)));
|
|
||||||
ImGui::Combo("##game_selector", game_selected, games_names.data(), (int)games_list.size());
|
|
||||||
ImGui::PopItemWidth();
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
// shortcuts
|
// shortcuts
|
||||||
if (ImGui::BeginMenu("Shortcuts", cfg::CONFIGURATOR_STANDALONE)) {
|
if (ImGui::BeginMenu("Shortcuts")) {
|
||||||
if (ImGui::MenuItem("USB Game Controllers")) {
|
if (ImGui::MenuItem("USB Game Controllers")) {
|
||||||
launch_shell("control.exe", "joy.cpl");
|
launch_shell("control.exe", "joy.cpl");
|
||||||
}
|
}
|
||||||
@@ -3016,32 +3012,25 @@ namespace overlay::windows {
|
|||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
// popup menus
|
// help
|
||||||
if (ImGui::MenuItem("Licenses")) {
|
if (ImGui::BeginMenu("Help")) {
|
||||||
licenses_popup = true;
|
if (ImGui::MenuItem("FAQ")) {
|
||||||
|
launch_shell("https://github.com/spice2x/spice2x.github.io/wiki/Known-issues");
|
||||||
}
|
}
|
||||||
if (ImGui::MenuItem("About")) {
|
if (ImGui::MenuItem("Wiki")) {
|
||||||
about_popup = true;
|
launch_shell("https://github.com/spice2x/spice2x.github.io/wiki");
|
||||||
}
|
|
||||||
|
|
||||||
// power - only active in games
|
|
||||||
if (ImGui::BeginMenu("Power", !cfg::CONFIGURATOR_STANDALONE)) {
|
|
||||||
if (ImGui::MenuItem("Restart Game")) {
|
|
||||||
launcher::restart();
|
|
||||||
}
|
|
||||||
if (ImGui::MenuItem("Exit Game")) {
|
|
||||||
launcher::shutdown();
|
|
||||||
}
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::Separator();
|
|
||||||
ImGui::Spacing();
|
|
||||||
if (ImGui::MenuItem("Shutdown PC")) {
|
|
||||||
shutdown_popup = true;
|
|
||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
// game selector
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.34f, 0.14f, 0.14f, 0.54f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.34f, 0.14f, 0.14f, 0.54f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.34f, 0.14f, 0.14f, 0.64f));
|
||||||
|
ImGui::PushItemWidth(MIN(700, MAX(100, ImGui::GetWindowSize().x - 400)));
|
||||||
|
ImGui::Combo("##game_selector", game_selected, games_names.data(), (int)games_list.size());
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
|
||||||
ImGui::BeginDisabled();
|
ImGui::BeginDisabled();
|
||||||
if (!avs::game::is_model("000")) {
|
if (!avs::game::is_model("000")) {
|
||||||
@@ -3059,45 +3048,9 @@ namespace overlay::windows {
|
|||||||
if (licenses_popup) {
|
if (licenses_popup) {
|
||||||
ImGui::OpenPopup("Licenses##topbarpopup");
|
ImGui::OpenPopup("Licenses##topbarpopup");
|
||||||
}
|
}
|
||||||
if (shutdown_popup) {
|
|
||||||
ImGui::OpenPopup("System##topbarpopup");
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw popups
|
// draw popups
|
||||||
{
|
{
|
||||||
// unused_open is needed for close button to appear on the popup
|
|
||||||
bool unused_open = true;
|
|
||||||
|
|
||||||
if (ImGui::BeginPopupModal(
|
|
||||||
"System##topbarpopup",
|
|
||||||
&unused_open,
|
|
||||||
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize)) {
|
|
||||||
|
|
||||||
static bool force_shutdown = false;
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::Checkbox("Force", &force_shutdown);
|
|
||||||
ImGui::Spacing();
|
|
||||||
|
|
||||||
const ImVec2 button_size(100.f, 0.f);
|
|
||||||
|
|
||||||
ImGui::Spacing();
|
|
||||||
if (ImGui::Button("Shutdown PC", button_size)) {
|
|
||||||
this->shutdown_system(force_shutdown, false);
|
|
||||||
}
|
|
||||||
ImGui::Spacing();
|
|
||||||
if (ImGui::Button("Reboot PC", button_size)) {
|
|
||||||
this->shutdown_system(force_shutdown, true);
|
|
||||||
}
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::Separator();
|
|
||||||
ImGui::Spacing();
|
|
||||||
if (ImGui::Button("Cancel", button_size)) {
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
const ImVec2 popup_size(
|
const ImVec2 popup_size(
|
||||||
std::min(ImGui::GetIO().DisplaySize.x * 0.9f, 800.f),
|
std::min(ImGui::GetIO().DisplaySize.x * 0.9f, 800.f),
|
||||||
std::min(ImGui::GetIO().DisplaySize.y * 0.9f, 800.f));
|
std::min(ImGui::GetIO().DisplaySize.y * 0.9f, 800.f));
|
||||||
@@ -3122,23 +3075,4 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::shutdown_system(bool force, bool reboot_instead) {
|
|
||||||
if (!acquire_shutdown_privs()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UINT flags = 0;
|
|
||||||
if (force) {
|
|
||||||
flags |= EWX_FORCE;
|
|
||||||
}
|
|
||||||
if (reboot_instead) {
|
|
||||||
flags |= EWX_REBOOT;
|
|
||||||
} else {
|
|
||||||
flags |= EWX_SHUTDOWN | EWX_HYBRID_SHUTDOWN;
|
|
||||||
}
|
|
||||||
if (!ExitWindowsEx(flags, SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_MAINTENANCE)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
launcher::shutdown(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ namespace overlay::windows {
|
|||||||
void build_about();
|
void build_about();
|
||||||
void build_licenses();
|
void build_licenses();
|
||||||
void build_launcher();
|
void build_launcher();
|
||||||
void launch_shell(LPCSTR app, LPCSTR file);
|
void launch_shell(LPCSTR app, LPCSTR file=nullptr);
|
||||||
|
|
||||||
static void build_page_selector(int *page);
|
static void build_page_selector(int *page);
|
||||||
void build_menu(int *game_selected);
|
void build_menu(int *game_selected);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace overlay::windows {
|
|||||||
| ImGuiWindowFlags_NoNavFocus
|
| ImGuiWindowFlags_NoNavFocus
|
||||||
| ImGuiWindowFlags_NoNavInputs
|
| ImGuiWindowFlags_NoNavInputs
|
||||||
| ImGuiWindowFlags_NoDocking;
|
| ImGuiWindowFlags_NoDocking;
|
||||||
this->bg_alpha = 0.4f;
|
this->bg_alpha = 0.5f;
|
||||||
this->start_time = std::chrono::system_clock::now();
|
this->start_time = std::chrono::system_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ namespace overlay::windows {
|
|||||||
{"arkmmd.dll", {"gamemmd.dll"}},
|
{"arkmmd.dll", {"gamemmd.dll"}},
|
||||||
{"arkklp.dll", {"lpac.dll"}},
|
{"arkklp.dll", {"lpac.dll"}},
|
||||||
{"arknck.dll", {"weac.dll"}},
|
{"arknck.dll", {"weac.dll"}},
|
||||||
{"gdxg.dll", {"game.dll"}}
|
{"gdxg.dll", {"game.dll", "libshare-pj.dll"}}
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t url_recent_idx = -1;
|
static size_t url_recent_idx = -1;
|
||||||
@@ -230,7 +230,13 @@ namespace overlay::windows {
|
|||||||
auto const register_fn = reinterpret_cast<decltype(&LdrRegisterDllNotification)>
|
auto const register_fn = reinterpret_cast<decltype(&LdrRegisterDllNotification)>
|
||||||
(GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "LdrRegisterDllNotification"));
|
(GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "LdrRegisterDllNotification"));
|
||||||
|
|
||||||
auto callback = [] CALLBACK (ULONG reason, PCLDR_DLL_NOTIFICATION_DATA data, PVOID ctx) {
|
auto callback =
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
static_cast<PLDR_DLL_NOTIFICATION_FUNCTION>([]
|
||||||
|
#else
|
||||||
|
[] CALLBACK
|
||||||
|
#endif
|
||||||
|
(ULONG reason, PCLDR_DLL_NOTIFICATION_DATA data, PVOID ctx) {
|
||||||
if (reason == LDR_DLL_NOTIFICATION_REASON_LOADED) {
|
if (reason == LDR_DLL_NOTIFICATION_REASON_LOADED) {
|
||||||
auto const dll = strtolower(std::filesystem::path({
|
auto const dll = strtolower(std::filesystem::path({
|
||||||
data->Loaded.FullDllName->Buffer,
|
data->Loaded.FullDllName->Buffer,
|
||||||
@@ -241,7 +247,11 @@ namespace overlay::windows {
|
|||||||
static_cast<PatchManager*>(ctx)->reload_local_patches(true);
|
static_cast<PatchManager*>(ctx)->reload_local_patches(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
)
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
if (register_fn && NT_SUCCESS(register_fn(0, callback, this, &ldr_notify_cookie))) {
|
if (register_fn && NT_SUCCESS(register_fn(0, callback, this, &ldr_notify_cookie))) {
|
||||||
log_info("patchmanager", "registered for DLL load notifications");
|
log_info("patchmanager", "registered for DLL load notifications");
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ namespace rawinput {
|
|||||||
|
|
||||||
HotplugManager *hotplug;
|
HotplugManager *hotplug;
|
||||||
std::vector<Device> devices;
|
std::vector<Device> devices;
|
||||||
HWND input_hwnd = nullptr;
|
|
||||||
WNDCLASSEX input_hwnd_class {};
|
WNDCLASSEX input_hwnd_class {};
|
||||||
std::thread *input_thread = nullptr;
|
std::thread *input_thread = nullptr;
|
||||||
std::thread *flush_thread = nullptr;
|
std::thread *flush_thread = nullptr;
|
||||||
@@ -91,6 +90,8 @@ namespace rawinput {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
HWND input_hwnd = nullptr;
|
||||||
|
|
||||||
RawInputManager();
|
RawInputManager();
|
||||||
~RawInputManager();
|
~RawInputManager();
|
||||||
|
|
||||||
|
|||||||
@@ -240,8 +240,11 @@ static LRESULT CALLBACK SpiceTouchWndProc(HWND hWnd, UINT msg, WPARAM wParam, LP
|
|||||||
rawinput::touch::display_update();
|
rawinput::touch::display_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto is_windowed_sub =
|
||||||
|
(GRAPHICS_IIDX_WSUB && hWnd == TDJ_SUBSCREEN_WINDOW) || (hWnd == SDVX_SUBSCREEN_WINDOW);
|
||||||
|
|
||||||
if (msg == WM_CLOSE) {
|
if (msg == WM_CLOSE) {
|
||||||
if ((GRAPHICS_IIDX_WSUB && hWnd == TDJ_SUBSCREEN_WINDOW) || (hWnd == SDVX_SUBSCREEN_WINDOW)) {
|
if (is_windowed_sub) {
|
||||||
log_misc("touch", "ignore WM_CLOSE for subscreen window");
|
log_misc("touch", "ignore WM_CLOSE for subscreen window");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -461,11 +464,14 @@ static LRESULT CALLBACK SpiceTouchWndProc(HWND hWnd, UINT msg, WPARAM wParam, LP
|
|||||||
};
|
};
|
||||||
|
|
||||||
// check if imgui is handling this mouse event
|
// check if imgui is handling this mouse event
|
||||||
if (overlay::OVERLAY != nullptr && overlay::OVERLAY->get_active() && ImGui::GetIO().WantCaptureMouse) {
|
if (is_windowed_sub) {
|
||||||
|
// do nothing, don't let imgui hijack clicks on the sub window
|
||||||
|
result.action = ACTION_PASS;
|
||||||
|
|
||||||
|
} else if (overlay::OVERLAY != nullptr && overlay::OVERLAY->get_active() && ImGui::GetIO().WantCaptureMouse) {
|
||||||
result.action = ACTION_RETURN_DEFAULT;
|
result.action = ACTION_RETURN_DEFAULT;
|
||||||
|
|
||||||
} else if (TOUCH_HANDLER != nullptr) {
|
} else if (TOUCH_HANDLER != nullptr) {
|
||||||
|
|
||||||
// call touch handler
|
// call touch handler
|
||||||
TOUCH_HANDLER->handle_message(result, hWnd, msg, wParam, lParam);
|
TOUCH_HANDLER->handle_message(result, hWnd, msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,8 +106,10 @@ bool detour::inline_restore(void *address, char *data) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma ide diagnostic ignored "OCDFAInspection"
|
#pragma ide diagnostic ignored "OCDFAInspection"
|
||||||
|
#endif
|
||||||
|
|
||||||
static void *pe_offset(void *ptr, size_t offset) {
|
static void *pe_offset(void *ptr, size_t offset) {
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
@@ -282,7 +284,9 @@ void **detour::iat_find_proc(const char *iid_name, void *proc, HMODULE module) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
void *detour::iat_try(const char *function, void *new_func, HMODULE module, const char *iid_name) {
|
void *detour::iat_try(const char *function, void *new_func, HMODULE module, const char *iid_name) {
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,13 @@ namespace execexe {
|
|||||||
static decltype(&CreateFileA) execexe_CreateFileA = nullptr;
|
static decltype(&CreateFileA) execexe_CreateFileA = nullptr;
|
||||||
static decltype(&CreateFileW) execexe_CreateFileW = nullptr;
|
static decltype(&CreateFileW) execexe_CreateFileW = nullptr;
|
||||||
static decltype(&CloseHandle) execexe_CloseHandle = nullptr;
|
static decltype(&CloseHandle) execexe_CloseHandle = nullptr;
|
||||||
|
static uint64_t (*execexe_PreLoadLibraries)(const char *) = nullptr;
|
||||||
|
|
||||||
static std::wstring plugins_dir;
|
static std::wstring plugins_dir;
|
||||||
static acioemu::ACIOHandle *acio = nullptr;
|
static acioemu::ACIOHandle *acio = nullptr;
|
||||||
static std::wstring port_name;
|
static std::wstring port_name;
|
||||||
static bool port_opened = false;
|
static bool port_opened = false;
|
||||||
|
static std::function<void()> deferred_function = nullptr;
|
||||||
|
|
||||||
static HANDLE WINAPI execexe_CreateFileA_hook(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
static HANDLE WINAPI execexe_CreateFileA_hook(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||||
@@ -62,6 +64,24 @@ namespace execexe {
|
|||||||
return execexe_CloseHandle(hObject);
|
return execexe_CloseHandle(hObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint64_t execexe_PreLoadLibraries_hook(const char *libs) {
|
||||||
|
static bool init = false;
|
||||||
|
|
||||||
|
uint64_t result = execexe_PreLoadLibraries(libs);
|
||||||
|
if (init) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
init = true;
|
||||||
|
log_info("execexe", "execexe_PreLoadLibraries hook hit");
|
||||||
|
|
||||||
|
if (deferred_function) {
|
||||||
|
deferred_function();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
HMODULE init() {
|
HMODULE init() {
|
||||||
execexe_module = libutils::load_library("execexe.dll");
|
execexe_module = libutils::load_library("execexe.dll");
|
||||||
execexe_LoadLibraryW = libutils::get_proc<decltype(&LoadLibraryW)>(execexe_module, MAKEINTRESOURCE(34));
|
execexe_LoadLibraryW = libutils::get_proc<decltype(&LoadLibraryW)>(execexe_module, MAKEINTRESOURCE(34));
|
||||||
@@ -70,6 +90,7 @@ namespace execexe {
|
|||||||
execexe_CloseHandle = libutils::get_proc<decltype(&CloseHandle)>(execexe_module, MAKEINTRESOURCE(7));
|
execexe_CloseHandle = libutils::get_proc<decltype(&CloseHandle)>(execexe_module, MAKEINTRESOURCE(7));
|
||||||
execexe_CreateFileA = libutils::get_proc<decltype(&CreateFileA)>(execexe_module, MAKEINTRESOURCE(9));
|
execexe_CreateFileA = libutils::get_proc<decltype(&CreateFileA)>(execexe_module, MAKEINTRESOURCE(9));
|
||||||
execexe_CreateFileW = libutils::get_proc<decltype(&CreateFileW)>(execexe_module, MAKEINTRESOURCE(11));
|
execexe_CreateFileW = libutils::get_proc<decltype(&CreateFileW)>(execexe_module, MAKEINTRESOURCE(11));
|
||||||
|
execexe_PreLoadLibraries = libutils::get_proc<decltype(execexe_PreLoadLibraries)>(execexe_module, MAKEINTRESOURCE(48));
|
||||||
|
|
||||||
auto module_path = libutils::module_file_name(nullptr);
|
auto module_path = libutils::module_file_name(nullptr);
|
||||||
module_path = module_path.replace_extension("");
|
module_path = module_path.replace_extension("");
|
||||||
@@ -79,6 +100,15 @@ namespace execexe {
|
|||||||
return execexe_module;
|
return execexe_module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void init_deferred(std::function<void()> init_func) {
|
||||||
|
if (deferred_function) {
|
||||||
|
log_fatal("execexe", "deferred init function is already set");
|
||||||
|
}
|
||||||
|
deferred_function = std::move(init_func);
|
||||||
|
detour::trampoline("execexe.dll", MAKEINTRESOURCE(48),
|
||||||
|
execexe_PreLoadLibraries_hook, &execexe_PreLoadLibraries);
|
||||||
|
}
|
||||||
|
|
||||||
void init_port_hook(const std::wstring &portName, acioemu::ACIOHandle *acioHandle) {
|
void init_port_hook(const std::wstring &portName, acioemu::ACIOHandle *acioHandle) {
|
||||||
static bool init = false;
|
static bool init = false;
|
||||||
if (init)
|
if (init)
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <functional>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include "acioemu/handle.h"
|
#include "acioemu/handle.h"
|
||||||
|
|
||||||
namespace execexe {
|
namespace execexe {
|
||||||
HMODULE init();
|
HMODULE init();
|
||||||
|
void init_deferred(std::function<void()> init_func);
|
||||||
void init_port_hook(const std::wstring &portName, acioemu::ACIOHandle *acioHandle);
|
void init_port_hook(const std::wstring &portName, acioemu::ACIOHandle *acioHandle);
|
||||||
HMODULE load_library(const char *module_name, bool fatal = true);
|
HMODULE load_library(const char *module_name, bool fatal = true);
|
||||||
FARPROC get_proc(HMODULE module, const char *proc_name, bool fatal = true);
|
FARPROC get_proc(HMODULE module, const char *proc_name, bool fatal = true);
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ std::string peb::entry_name(const LDR_DATA_TABLE_ENTRY* entry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PEB* peb::peb_get() {
|
const PEB* peb::peb_get() {
|
||||||
#ifdef SPICE64
|
#ifdef _WIN64
|
||||||
return reinterpret_cast<const PEB *>(__readgsqword(0x60));
|
return reinterpret_cast<const PEB *>(__readgsqword(0x60));
|
||||||
#else
|
#else
|
||||||
return reinterpret_cast<const PEB *>(__readfsdword(0x30));
|
return reinterpret_cast<const PEB *>(__readfsdword(0x30));
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace tapeledutils {
|
namespace tapeledutils {
|
||||||
|
|
||||||
@@ -20,6 +22,15 @@ namespace tapeledutils {
|
|||||||
float b;
|
float b;
|
||||||
} rgb_float3_t;
|
} rgb_float3_t;
|
||||||
|
|
||||||
|
struct tape_led {
|
||||||
|
std::vector<rgb_float3_t> data;
|
||||||
|
int index_r, index_g, index_b; // Averaged RGB light output indexes
|
||||||
|
std::string lightName;
|
||||||
|
|
||||||
|
tape_led(size_t data_size, int index_r, int index_g, int index_b, std::string lightName)
|
||||||
|
: data(std::vector<rgb_float3_t>(data_size)), index_r(index_r), index_g(index_g), index_b(index_b), lightName(std::move(lightName)) {}
|
||||||
|
};
|
||||||
|
|
||||||
bool is_enabled();
|
bool is_enabled();
|
||||||
rgb_float3_t pick_color_from_led_tape(uint8_t *data, size_t data_size);
|
rgb_float3_t pick_color_from_led_tape(uint8_t *data, size_t data_size);
|
||||||
size_t get_led_index_using_avg_algo(size_t data_size);
|
size_t get_led_index_using_avg_algo(size_t data_size);
|
||||||
|
|||||||
Reference in New Issue
Block a user