mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
cd0ba51b5a
## Link to GitHub Issue or related Pull Request, if one exists
n/a
## Description of change
Adds a flat-C, headers-only library for writing DLL plugins with spice.
This is meant to be an alternative to writing applications over spice
API which doesn't suit some scenarios like writing custom
high-performance I/O modules.
All you have to do is:
1. Create a 32-bit or 64-bit DLL with `spice_sdk_entry_point` as a
DLLExport
1. Include `spicesdk.h`, and optionally `spicesdk_io.h` (see
`extras\sdk\include`)
1. `spice_sdk_entry_point` will be called when hooks get initialized.
Call `init` with valid parameters.
1. When `init` returns, `SPICE_SDK_V0` will be filled out with a series
of function pointers; your DLL can now start calling into it.
1. Compile your DLL and add it as a DLL hook (`-k`) in spice when
launching the game.
See `v0_cpp.cpp` for an example.
V0 implements the following functions:
```
log;
get_game_info;
get_avs_info;
get_button;
set_button;
get_analog;
set_analog;
get_light;
set_light;
set_touch;
clear_touch;
insert_card;
set_keypad;
```
V0 is focused on providing common utility functions needed in a lot of
DLL hooks (get AVS info, log messages to file), and implementing I/O.
In the future, we could have more interesting things like:
* scanning and modifying memory
* installing DLL hooks
* having direct hooks into I/O emulation modules
* getting full tape LEDs
* having a callback into DX9 `Present` call
* drawing an ImGui window
More detailed documentation is coming soon in form of a wiki page.
## Testing
See included sample DLL.
2681 lines
94 KiB
C++
2681 lines
94 KiB
C++
#include <condition_variable>
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include <assert.h>
|
|
#include <shlwapi.h>
|
|
#include <cfg/configurator.h>
|
|
|
|
#include "api/modules/capture.h"
|
|
#include "acio/acio.h"
|
|
#include "acio/icca/icca.h"
|
|
#include "acio/mdxf/mdxf.h"
|
|
#include "api/controller.h"
|
|
#include "avs/automap.h"
|
|
#include "avs/core.h"
|
|
#include "avs/ea3.h"
|
|
#include "avs/game.h"
|
|
#include "build/defs.h"
|
|
#include "cfg/spicecfg.h"
|
|
#include "cfg/config.h"
|
|
#include "cfg/screen_resize.h"
|
|
#include "easrv/easrv.h"
|
|
#include "external/cardio/cardio_runner.h"
|
|
#ifndef NO_SCARD
|
|
#include "external/scard/scard.h"
|
|
#endif
|
|
#include "games/game.h"
|
|
#include "games/io.h"
|
|
#include "games/bbc/bbc.h"
|
|
#include "games/bs/bs.h"
|
|
#include "games/ddr/ddr.h"
|
|
#include "games/dea/dea.h"
|
|
#include "games/drs/drs.h"
|
|
#include "games/gitadora/gitadora.h"
|
|
#include "games/hpm/hpm.h"
|
|
#include "games/iidx/iidx.h"
|
|
#ifdef SPICE64
|
|
#include "games/iidx/camera.h"
|
|
#endif
|
|
#include "games/iidx/poke.h"
|
|
#include "games/jb/jb.h"
|
|
#include "games/mga/mga.h"
|
|
#include "games/nost/nost.h"
|
|
#include "games/nost/poke.h"
|
|
#include "games/popn/popn.h"
|
|
#include "games/qma/qma.h"
|
|
#include "games/rb/rb.h"
|
|
#include "games/rf3d/rf3d.h"
|
|
#include "games/sc/sc.h"
|
|
#include "games/scotto/scotto.h"
|
|
#include "games/sdvx/sdvx.h"
|
|
#include "games/shared/printer.h"
|
|
#include "games/silentscope/silentscope.h"
|
|
#include "games/mfc/mfc.h"
|
|
#include "games/ftt/ftt.h"
|
|
#include "games/loveplus/loveplus.h"
|
|
#include "games/we/we.h"
|
|
#include "games/otoca/otoca.h"
|
|
#include "games/shogikai/shogikai.h"
|
|
#include "games/pcm/pcm.h"
|
|
#include "games/onpara/onpara.h"
|
|
#include "games/bc/bc.h"
|
|
#include "games/ccj/ccj.h"
|
|
#include "games/ccj/trackball.h"
|
|
#include "games/qks/qks.h"
|
|
#include "games/mfg/mfg.h"
|
|
#include "games/pc/pc.h"
|
|
#include "games/museca/museca.h"
|
|
#include "hooks/avshook.h"
|
|
#include "hooks/audio/audio.h"
|
|
#include "hooks/debughook.h"
|
|
#include "hooks/devicehook.h"
|
|
#include "hooks/graphics/nvenc_hook.h"
|
|
#include "hooks/input/dinput8/hook.h"
|
|
#include "hooks/graphics/graphics.h"
|
|
#include "hooks/lang.h"
|
|
#include "hooks/networkhook.h"
|
|
#include "hooks/unisintrhook.h"
|
|
#include "launcher/launcher.h"
|
|
#include "launcher/logger.h"
|
|
#include "launcher/signal.h"
|
|
#include "launcher/superexit.h"
|
|
#include "launcher/richpresence.h"
|
|
#include "launcher/shutdown.h"
|
|
#include "launcher/options.h"
|
|
#include "misc/bt5api.h"
|
|
#include "misc/device.h"
|
|
#include "misc/eamuse.h"
|
|
#include "misc/extdev.h"
|
|
#include "misc/ami2000.h"
|
|
#include "misc/sciunit.h"
|
|
#include "misc/sde.h"
|
|
#include "misc/wintouchemu.h"
|
|
#include "overlay/overlay.h"
|
|
#include "overlay/windows/patch_manager.h"
|
|
#include "overlay/windows/iidx_seg.h"
|
|
#include "rawinput/rawinput.h"
|
|
#include "rawinput/touch.h"
|
|
#include "reader/reader.h"
|
|
#include "sdk/sdk.h"
|
|
#include "stubs/stubs.h"
|
|
#include "touch/touch.h"
|
|
#include "util/cpuutils.h"
|
|
#include "util/crypt.h"
|
|
#include "util/deferlog.h"
|
|
#include "util/fileutils.h"
|
|
#include "util/libutils.h"
|
|
#include "util/logging.h"
|
|
#include "util/peb.h"
|
|
#include "util/socd_cleaner.h"
|
|
#include "util/sysutils.h"
|
|
#include "util/tapeled.h"
|
|
#include "util/time.h"
|
|
#include "util/utils.h"
|
|
#include "avs/ssl.h"
|
|
#include "nvapi/nvapi.h"
|
|
#include "hooks/graphics/nvapi_hook.h"
|
|
|
|
// std::max
|
|
#ifdef max
|
|
#undef max
|
|
#endif
|
|
|
|
// constants
|
|
static const char *STUBS[] = {"kbt.dll", "kld.dll"};
|
|
|
|
// general settings
|
|
static std::vector<std::string> game_hooks;
|
|
static std::vector<std::string> early_hooks;
|
|
std::filesystem::path MODULE_PATH;
|
|
HANDLE LOG_FILE = INVALID_HANDLE_VALUE;
|
|
std::string LOG_FILE_PATH = "";
|
|
int LAUNCHER_ARGC = 0;
|
|
char **LAUNCHER_ARGV = nullptr;
|
|
std::unique_ptr<std::vector<Option>> LAUNCHER_OPTIONS;
|
|
|
|
std::mutex CARD_OVERRIDES_LOCK;
|
|
std::string CARD_OVERRIDES[2];
|
|
|
|
// sub-systems
|
|
std::unique_ptr<api::Controller> API_CONTROLLER;
|
|
std::unique_ptr<rawinput::RawInputManager> RI_MGR;
|
|
|
|
// trigger NVIDIA Optimus & AMD Enduro High Performance Graphics
|
|
extern "C" {
|
|
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
|
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
|
}
|
|
|
|
static bool CHECK_DLL_IGNORE_ARCH = false;
|
|
static bool check_dll(const std::string &model) {
|
|
if (cfg::CONFIGURATOR_STANDALONE || CHECK_DLL_IGNORE_ARCH) {
|
|
return fileutils::file_exists(MODULE_PATH / model);
|
|
} else {
|
|
return fileutils::verify_header_pe(MODULE_PATH / model);
|
|
}
|
|
}
|
|
|
|
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[]) {
|
|
|
|
// remember argv, argv
|
|
LAUNCHER_ARGC = argc;
|
|
LAUNCHER_ARGV = argv;
|
|
|
|
// register exception handler and control handler
|
|
launcher::signal::init();
|
|
|
|
// start logger
|
|
logger::start();
|
|
|
|
// get module path
|
|
MODULE_PATH = libutils::module_file_name(nullptr).parent_path();
|
|
|
|
// initialize crypt
|
|
crypt::init();
|
|
|
|
// initialize timer
|
|
init_performance_counter();
|
|
|
|
// api settings
|
|
bool api_enable = false;
|
|
bool api_pretty = false;
|
|
bool api_debug = false;
|
|
unsigned short api_port = 1337;
|
|
std::string api_pass = "";
|
|
std::vector<std::string> api_serial_port;
|
|
std::vector<DWORD> api_serial_baud;
|
|
|
|
// attach settings
|
|
bool attach_io = false;
|
|
bool attach_acio = false;
|
|
bool attach_icca = false;
|
|
bool attach_device = false;
|
|
bool attach_extdev = false;
|
|
bool attach_ami2000 = false;
|
|
bool attach_sciunit = false;
|
|
bool attach_cpusbxpkm_printer = false;
|
|
bool attach_iidx = false;
|
|
bool attach_sdvx = false;
|
|
bool attach_jb = false;
|
|
bool attach_rb = false;
|
|
bool attach_shogikai = false;
|
|
bool attach_mga = false;
|
|
bool attach_sc = false;
|
|
bool attach_popn = false;
|
|
bool attach_ddr = false;
|
|
bool attach_gitadora = false;
|
|
bool attach_nostalgia = false;
|
|
bool attach_bbc = false;
|
|
bool attach_hpm = false;
|
|
bool attach_qma = false;
|
|
bool attach_dea = false;
|
|
bool attach_mfc = false;
|
|
bool attach_ftt = false;
|
|
bool attach_bs = false;
|
|
bool attach_loveplus = false;
|
|
bool attach_scotto = false;
|
|
bool attach_rf3d = false;
|
|
bool attach_drs = false;
|
|
bool attach_we = false;
|
|
bool attach_otoca = false;
|
|
bool attach_silentscope = false;
|
|
bool attach_pcm = false;
|
|
bool attach_onpara = false;
|
|
bool attach_bc = false;
|
|
bool attach_ccj = false;
|
|
bool attach_qks = false;
|
|
bool attach_mfg = false;
|
|
bool attach_pc = false;
|
|
bool attach_museca = false;
|
|
bool show_cursor_if_no_touch = false;
|
|
|
|
// misc settings
|
|
size_t user_heap_size = 0;
|
|
unsigned short easrv_port = 0;
|
|
bool easrv_maint = true;
|
|
bool easrv_smart = false;
|
|
bool load_stubs = false;
|
|
bool netfix_disable = false;
|
|
bool lang_disable = false;
|
|
std::string process_priority_str = "high";
|
|
bool cardio_enabled = false;
|
|
bool peb_print = false;
|
|
bool cfg_run = false;
|
|
bool rich_presence = false;
|
|
bool automap = false;
|
|
bool ssl_disable = false;
|
|
bool dump_sysinfo = true;
|
|
std::vector<std::string> sextet_devices;
|
|
std::optional<rawinput::MidiNoteAlgorithm> midi_algo;
|
|
|
|
// parse arguments
|
|
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
|
|
const auto &cfg_path = LAUNCHER_OPTIONS->at(launcher::Options::ConfigurationPath);
|
|
if (cfg_path.is_active()) {
|
|
CONFIG_PATH_OVERRIDE = cfg_path.value_text();
|
|
}
|
|
|
|
// detect model used to load option overrides
|
|
auto options_version = launcher::detect_gameversion(
|
|
LAUNCHER_OPTIONS->at(launcher::Options::PathToEa3Config).value,
|
|
LAUNCHER_OPTIONS->at(launcher::Options::PathToBootstrap).value
|
|
);
|
|
if (!options_version.model.empty() && options_version.model.size() < 4) {
|
|
if (options_version.dest.size() == 1) {
|
|
avs::game::DEST[0] = options_version.dest[0];
|
|
}
|
|
if (options_version.spec.size() == 1) {
|
|
avs::game::SPEC[0] = options_version.spec[0];
|
|
}
|
|
if (options_version.rev.size() == 1) {
|
|
avs::game::REV[0] = options_version.rev[0];
|
|
}
|
|
if (options_version.ext.size() == 10) {
|
|
strcpy(avs::game::EXT, options_version.ext.c_str());
|
|
}
|
|
strcpy(avs::game::MODEL, options_version.model.c_str());
|
|
eamuse_autodetect_game();
|
|
}
|
|
|
|
// grab merged game options
|
|
auto options_ptr = games::get_options(eamuse_get_game());
|
|
if (!options_ptr) {
|
|
options_ptr = LAUNCHER_OPTIONS.get();
|
|
}
|
|
auto &options = *options_ptr;
|
|
|
|
// check options
|
|
// TODO: get rid of some booleans here and make use of the options directly
|
|
if (options[launcher::Options::OpenConfigurator].value_bool()) {
|
|
CHECK_DLL_IGNORE_ARCH = true;
|
|
cfg::CONFIGURATOR_TYPE = cfg::ConfigType::Config;
|
|
cfg_run = true;
|
|
}
|
|
|
|
// -ea, but ignored if -url is set
|
|
if (options[launcher::Options::EAmusementEmulation].value_bool() &&
|
|
!options[launcher::Options::ServiceURL].is_active()) {
|
|
avs::ea3::URL_SLASH = 1;
|
|
easrv_port = 8080;
|
|
}
|
|
|
|
if (options[launcher::Options::SmartEAmusement].value_bool()) {
|
|
easrv_smart = true;
|
|
}
|
|
if (options[launcher::Options::EAmusementMaintenance].is_active()) {
|
|
easrv_maint = options[launcher::Options::EAmusementMaintenance].value_uint32() > 0;
|
|
}
|
|
if (options[launcher::Options::spice2x_EAmusementMaintenance].value_bool()) {
|
|
easrv_maint = true;
|
|
}
|
|
if (options[launcher::Options::WindowedMode].value_bool()) {
|
|
GRAPHICS_WINDOWED = true;
|
|
}
|
|
if (options[launcher::Options::GraphicsForceRefresh].is_active()) {
|
|
GRAPHICS_FORCE_REFRESH = options[launcher::Options::GraphicsForceRefresh].value_uint32();
|
|
}
|
|
if (options[launcher::Options::FullscreenSubRefreshRate].is_active()) {
|
|
GRAPHICS_FORCE_REFRESH_SUB =
|
|
options[launcher::Options::FullscreenSubRefreshRate].value_uint32();
|
|
}
|
|
if (options[launcher::Options::GraphicsForceSingleAdapter].value_bool()) {
|
|
GRAPHICS_FORCE_SINGLE_ADAPTER = true;
|
|
}
|
|
if (options[launcher::Options::ForceBackBufferCount].is_active()) {
|
|
const auto n = options[launcher::Options::ForceBackBufferCount].value_uint32();
|
|
if (n == 2 || n == 3) {
|
|
// user provided 2 => double buffering => 1 back buffer
|
|
// user provided 3 => triple buffering => 2 back buffers
|
|
GRAPHICS_FORCE_VSYNC_BUFFER = n - 1;
|
|
} else {
|
|
log_warning("graphics", "invalid parameter specified for -vsyncbuffer: {}", n);
|
|
}
|
|
}
|
|
if (options[launcher::Options::spice2x_IIDXNoSub].value_bool()) {
|
|
GRAPHICS_FORCE_SINGLE_ADAPTER = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_SDVXNoSub].value_bool()) {
|
|
GRAPHICS_FORCE_SINGLE_ADAPTER = true;
|
|
GRAPHICS_PREVENT_SECONDARY_WINDOW = true;
|
|
}
|
|
if (options[launcher::Options::DXDisplayAdapter].is_active() &&
|
|
options[launcher::Options::DXDisplayAdapter].value_uint32() != D3DADAPTER_DEFAULT) {
|
|
D3D9_ADAPTER = options[launcher::Options::DXDisplayAdapter].value_uint32();
|
|
|
|
// when we fix up adapter numbers, we only fix the first adapter, and not any subsequent
|
|
// adapters, so we can't deal with multi-monitor games
|
|
GRAPHICS_FORCE_SINGLE_ADAPTER = true;
|
|
}
|
|
if (options[launcher::Options::CaptureCursor].value_bool()) {
|
|
GRAPHICS_CAPTURE_CURSOR = true;
|
|
}
|
|
if (options[launcher::Options::ShowCursor].value_bool()) {
|
|
GRAPHICS_SHOW_CURSOR = true;
|
|
}
|
|
if (options[launcher::Options::VerboseGraphicsLogging].value_bool()) {
|
|
GRAPHICS_LOG_HRESULT = true;
|
|
}
|
|
if (options[launcher::Options::VerboseAVSLogging].value_bool()) {
|
|
hooks::avs::config::LOG = true;
|
|
}
|
|
if (options[launcher::Options::AllowEA3Verbose].value_bool()) {
|
|
avs::ea3::EA3_DEBUG_VERBOSE = true;
|
|
}
|
|
|
|
std::optional<graphics_orientation> monitor_orientation;
|
|
if (options[launcher::Options::spice2x_AutoOrientation].is_active()) {
|
|
monitor_orientation =
|
|
(graphics_orientation)options[launcher::Options::spice2x_AutoOrientation].value_uint32();
|
|
} else if (options[launcher::Options::AdjustOrientation].value_bool()) {
|
|
monitor_orientation = ORIENTATION_CW;
|
|
}
|
|
|
|
if (options[launcher::Options::spice2x_NoD3D9DeviceHook].value_bool()) {
|
|
D3D9_DEVICE_HOOK_DISABLE = true;
|
|
// touch emulation gets disabled, might as well turn these on
|
|
games::iidx::NATIVE_TOUCH = true;
|
|
games::sdvx::NATIVETOUCH = true;
|
|
// not strictly necessary as it will fail to init anyway, but cleaner to just disable it now
|
|
overlay::ENABLED = false;
|
|
// leaving these on without dx9hooks result in torn state and therefore failure to draw
|
|
GRAPHICS_FORCE_SINGLE_ADAPTER = false;
|
|
}
|
|
|
|
if (options[launcher::Options::spice2x_NvapiProfile].value_bool() && !cfg::CONFIGURATOR_STANDALONE) {
|
|
nvapi::ADD_PROFILE = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_NoNVAPI].value_bool()) {
|
|
nvapi_hook::BYPASS_NVAPI = true;
|
|
}
|
|
|
|
if (options[launcher::Options::LogLevel].is_active()) {
|
|
avs::core::LOG_LEVEL_CUSTOM = options[launcher::Options::LogLevel].value_text();
|
|
}
|
|
for (auto &hook : options[launcher::Options::InjectHook].values_text()) {
|
|
std::string buffer;
|
|
std::stringstream stream(hook);
|
|
std::vector<std::string> tokens;
|
|
while (stream >> buffer) {
|
|
game_hooks.push_back(buffer);
|
|
}
|
|
}
|
|
for (auto &hook : options[launcher::Options::EarlyInjectHook].values_text()) {
|
|
std::string buffer;
|
|
std::stringstream stream(hook);
|
|
std::vector<std::string> tokens;
|
|
while (stream >> buffer) {
|
|
early_hooks.push_back(buffer);
|
|
}
|
|
}
|
|
if (options[launcher::Options::LoadStubs].value_bool()) {
|
|
load_stubs = true;
|
|
}
|
|
if (options[launcher::Options::EnableAllIOModules].value_bool()) {
|
|
attach_io = true;
|
|
}
|
|
if (options[launcher::Options::EnableACIOModule].value_bool()) {
|
|
attach_acio = true;
|
|
}
|
|
if (options[launcher::Options::EnableICCAModule].value_bool()) {
|
|
attach_icca = true;
|
|
}
|
|
if (options[launcher::Options::EnableDEVICEModule].value_bool()) {
|
|
attach_device = true;
|
|
}
|
|
if (options[launcher::Options::EnableEXTDEVModule].value_bool()) {
|
|
attach_extdev = true;
|
|
}
|
|
if (options[launcher::Options::EnableAMI2000Module].value_bool()) {
|
|
attach_ami2000 = true;
|
|
}
|
|
if (options[launcher::Options::EnableDevicePassthrough].value_bool()) {
|
|
hooks::device::ENABLE = false;
|
|
}
|
|
if (options[launcher::Options::LoadSoundVoltexModule].value_bool()) {
|
|
attach_sdvx = true;
|
|
}
|
|
if (options[launcher::Options::SDVXNativeTouch].value_bool()) {
|
|
games::sdvx::NATIVETOUCH = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_SDVXDigitalKnobSensitivity].is_active()) {
|
|
games::sdvx::DIGITAL_KNOB_SENS = (uint8_t)
|
|
options[launcher::Options::spice2x_SDVXDigitalKnobSensitivity].value_uint32();
|
|
}
|
|
if (options[launcher::Options::spice2x_SDVXAsioDriver].is_active()) {
|
|
games::sdvx::ASIO_DRIVER = options[launcher::Options::spice2x_SDVXAsioDriver].value_text();
|
|
}
|
|
if (options[launcher::Options::spice2x_SDVXSubPos].is_active()) {
|
|
auto txt = options[launcher::Options::spice2x_SDVXSubPos].value_text();
|
|
if (txt == "top") {
|
|
games::sdvx::OVERLAY_POS = games::sdvx::SDVX_OVERLAY_TOP;
|
|
} else if (txt == "center") {
|
|
games::sdvx::OVERLAY_POS = games::sdvx::SDVX_OVERLAY_MIDDLE;
|
|
} else if (txt == "bottomleft") {
|
|
games::sdvx::OVERLAY_POS = games::sdvx::SDVX_OVERLAY_BOTTOM_LEFT;
|
|
} else if (txt == "bottomright") {
|
|
games::sdvx::OVERLAY_POS = games::sdvx::SDVX_OVERLAY_BOTTOM_RIGHT;
|
|
}
|
|
// else - bottom
|
|
}
|
|
if (options[launcher::Options::spice2x_SDVXSubRedraw].value_bool()) {
|
|
SUBSCREEN_FORCE_REDRAW = true;
|
|
}
|
|
if (options[launcher::Options::SDVXSubMonitorOverride].is_active()) {
|
|
sysutils::SECOND_MONITOR_OVERRIDE = options[launcher::Options::SDVXSubMonitorOverride].value_text();
|
|
}
|
|
if (options[launcher::Options::LoadIIDXModule].value_bool()) {
|
|
attach_iidx = true;
|
|
}
|
|
if (options[launcher::Options::IIDXCameraOrderFlip].value_bool()) {
|
|
games::iidx::FLIP_CAMS = true;
|
|
}
|
|
|
|
// IIDX CONNECT_CAMERA logic here for cases where user is running without -iidx module
|
|
// for now, we assume that user may be running on a cab
|
|
// (games::iidx::DISABLE_CAMS starts out as false unless user overrides)
|
|
// we will check again in IIDX module with a different default
|
|
assert(!games::iidx::DISABLE_CAMS.has_value());
|
|
if (options[launcher::Options::IIDXDisableCameras].value_bool()) {
|
|
games::iidx::DISABLE_CAMS = true;
|
|
}
|
|
if (options[launcher::Options::IIDXCabCamAccess].is_active() &&
|
|
options[launcher::Options::IIDXCabCamAccess].value_text() == "off") {
|
|
games::iidx::DISABLE_CAMS = true;
|
|
}
|
|
if (options[launcher::Options::IIDXCamHook].value_bool()) {
|
|
games::iidx::TDJ_CAMERA = true;
|
|
// Disable legacy behaviour to avoid conflict
|
|
games::iidx::DISABLE_CAMS = true;
|
|
}
|
|
// CONNECT_CAMERA env var will be set once logging is enabled
|
|
|
|
if (options[launcher::Options::IIDXCamHookOverride].is_active()) {
|
|
games::iidx::TDJ_CAMERA_OVERRIDE = options[launcher::Options::IIDXCamHookOverride].value_text();
|
|
}
|
|
if (options[launcher::Options::IIDXCamHookRatio].is_active() &&
|
|
options[launcher::Options::IIDXCamHookRatio].value_text() == "169") {
|
|
games::iidx::TDJ_CAMERA_PREFER_16_9 = true;
|
|
}
|
|
if (options[launcher::Options::IIDXSoundOutputDevice].is_active()) {
|
|
games::iidx::SOUND_OUTPUT_DEVICE = options[launcher::Options::IIDXSoundOutputDevice].value_text();
|
|
}
|
|
if (options[launcher::Options::IIDXAsioDriver].is_active()) {
|
|
games::iidx::ASIO_DRIVER = options[launcher::Options::IIDXAsioDriver].value_text();
|
|
}
|
|
if (options[launcher::Options::IIDXTDJMode].value_bool()) {
|
|
games::iidx::TDJ_MODE = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_IIDXDigitalTTSensitivity].is_active()) {
|
|
games::iidx::DIGITAL_TT_SENS = (uint8_t)
|
|
options[launcher::Options::spice2x_IIDXDigitalTTSensitivity].value_uint32();
|
|
}
|
|
if (options[launcher::Options::spice2x_IIDXLDJForce720p].value_bool()) {
|
|
games::iidx::FORCE_720P = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_IIDXTDJSubSize].is_active()) {
|
|
games::iidx::SUBSCREEN_OVERLAY_SIZE =
|
|
options[launcher::Options::spice2x_IIDXTDJSubSize].value_text();
|
|
}
|
|
if (options[launcher::Options::spice2x_IIDXLEDFontSize].is_active()) {
|
|
overlay::windows::IIDX_SEGMENT_FONT_SIZE =
|
|
options[launcher::Options::spice2x_IIDXLEDFontSize].value_uint32();
|
|
}
|
|
if (options[launcher::Options::spice2x_IIDXLEDColor].is_active()) {
|
|
overlay::windows::IIDX_SEGMENT_FONT_COLOR =
|
|
options[launcher::Options::spice2x_IIDXLEDColor].value_hex64();
|
|
}
|
|
if (options[launcher::Options::spice2x_IIDXLEDPos].is_active()) {
|
|
overlay::windows::IIDX_SEGMENT_LOCATION =
|
|
options[launcher::Options::spice2x_IIDXLEDPos].value_text();
|
|
}
|
|
if (options[launcher::Options::IIDXLEDBorderless].value_bool()) {
|
|
overlay::windows::IIDX_SEGMENT_BORDERLESS = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_IIDXNoESpec].value_bool()) {
|
|
games::iidx::DISABLE_ESPEC_IO = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_IIDXNativeTouch].value_bool()) {
|
|
games::iidx::NATIVE_TOUCH = true;
|
|
}
|
|
// should come later since this will override a few settings
|
|
if (options[launcher::Options::spice2x_IIDXWindowedTDJ].value_bool() ||
|
|
(options[launcher::Options::IIDXTDJMode].value_bool() && GRAPHICS_WINDOWED)) {
|
|
games::iidx::TDJ_MODE = true;
|
|
GRAPHICS_WINDOWED = true;
|
|
games::iidx::SCREEN_MODE = "2";
|
|
}
|
|
#ifdef SPICE64
|
|
if (options[launcher::Options::IIDXRecQuality].is_active()) {
|
|
nvenc_hook::VIDEO_CQP_STRING_OVERRIDE = options[launcher::Options::IIDXRecQuality].value_text();
|
|
}
|
|
if (options[launcher::Options::IIDXRecDisable].value_bool()) {
|
|
nvenc_hook::FORCE_DISABLE = true;
|
|
}
|
|
#endif
|
|
if (options[launcher::Options::OtocaCamHook].value_bool()) {
|
|
games::otoca::BYPASS_CAMERA = true;
|
|
}
|
|
|
|
if (options[launcher::Options::LoadJubeatModule].value_bool()) {
|
|
attach_jb = true;
|
|
}
|
|
if (options[launcher::Options::LoadBeatstreamModule].value_bool()) {
|
|
attach_bs = true;
|
|
}
|
|
if (options[launcher::Options::LoadReflecBeatModule].value_bool()) {
|
|
attach_rb = true;
|
|
}
|
|
if (options[launcher::Options::LoadShogikaiModule].value_bool()) {
|
|
attach_shogikai = true;
|
|
}
|
|
if (options[launcher::Options::LoadPopnMusicModule].value_bool()) {
|
|
attach_popn = true;
|
|
}
|
|
if (options[launcher::Options::PopnMusicForceHDMode].value_bool()) {
|
|
avs::ea3::PCB_TYPE = 1;
|
|
}
|
|
if (options[launcher::Options::PopnMusicForceSDMode].value_bool()) {
|
|
avs::ea3::PCB_TYPE = 0;
|
|
}
|
|
if (options[launcher::Options::PopnNoSub].value_bool()) {
|
|
GRAPHICS_FORCE_SINGLE_ADAPTER = true;
|
|
GRAPHICS_PREVENT_SECONDARY_WINDOW = true;
|
|
}
|
|
if (options[launcher::Options::PopnSubMonitorOverride].is_active()) {
|
|
sysutils::SECOND_MONITOR_OVERRIDE = options[launcher::Options::PopnSubMonitorOverride].value_text();
|
|
}
|
|
if (options[launcher::Options::PopnNativeTouch].value_bool()) {
|
|
games::popn::NATIVE_TOUCH = true;
|
|
}
|
|
if (options[launcher::Options::LoadMetalGearArcadeModule].value_bool()) {
|
|
attach_mga = true;
|
|
}
|
|
if (options[launcher::Options::LoadGitaDoraModule].value_bool()) {
|
|
attach_gitadora = true;
|
|
}
|
|
if (options[launcher::Options::GitaDoraCabinetType].is_active()) {
|
|
games::gitadora::CAB_TYPE = options[launcher::Options::GitaDoraCabinetType].value_uint32();
|
|
}
|
|
if (options[launcher::Options::GitaDoraArenaSingleWindow].value_bool() && GRAPHICS_WINDOWED) {
|
|
games::gitadora::ARENA_SINGLE_WINDOW = true;
|
|
}
|
|
if (options[launcher::Options::GitaDoraWailHold].is_active()) {
|
|
socd::TILT_HOLD_MS = options[launcher::Options::GitaDoraWailHold].value_uint32();
|
|
}
|
|
if (options[launcher::Options::GitaDoraPickAlgo].is_active()) {
|
|
const auto text = options[launcher::Options::GitaDoraPickAlgo].value_text();
|
|
if (text == "legacy") {
|
|
games::gitadora::PICK_ALGO.reset();
|
|
} else if (text == "neutral") {
|
|
games::gitadora::PICK_ALGO = socd::SocdAlgorithm::Neutral;
|
|
} else if (text == "raw") {
|
|
games::gitadora::PICK_ALGO = socd::SocdAlgorithm::None;
|
|
}
|
|
}
|
|
if (options[launcher::Options::GitaDoraSubOverlaySize].is_active()) {
|
|
games::gitadora::SUBSCREEN_OVERLAY_SIZE = options[launcher::Options::GitaDoraSubOverlaySize].value_text();
|
|
}
|
|
if (options[launcher::Options::LoadNostalgiaModule].value_bool()) {
|
|
attach_nostalgia = true;
|
|
}
|
|
if (options[launcher::Options::LoadBBCModule].value_bool()) {
|
|
attach_bbc = true;
|
|
}
|
|
if (options[launcher::Options::LoadHelloPopnMusicModule].value_bool()) {
|
|
attach_hpm = true;
|
|
}
|
|
if (options[launcher::Options::LoadQuizMagicAcademyModule].value_bool()) {
|
|
attach_qma = true;
|
|
}
|
|
if (options[launcher::Options::LoadDanceEvolutionModule].value_bool()) {
|
|
attach_dea = true;
|
|
}
|
|
if (options[launcher::Options::LoadLovePlusModule].value_bool()) {
|
|
attach_loveplus = true;
|
|
}
|
|
if (options[launcher::Options::GitaDoraTwoChannelAudio].value_bool()) {
|
|
games::gitadora::TWOCHANNEL = true;
|
|
}
|
|
if (options[launcher::Options::GitaDoraLefty].is_active()) {
|
|
const auto text = options[launcher::Options::GitaDoraLefty].value_text();
|
|
if (text == "p1") {
|
|
games::gitadora::P1_LEFTY = true;
|
|
} else if (text == "p2") {
|
|
games::gitadora::P2_LEFTY = true;
|
|
} else if (text == "both") {
|
|
games::gitadora::P1_LEFTY = true;
|
|
games::gitadora::P2_LEFTY = true;
|
|
}
|
|
}
|
|
if (options[launcher::Options::LoadDDRModule].value_bool()) {
|
|
attach_ddr = true;
|
|
}
|
|
if (options[launcher::Options::LoadMahjongFightClubModule].value_bool()) {
|
|
attach_mfc = true;
|
|
}
|
|
if (options[launcher::Options::LoadFutureTomTomModule].value_bool()) {
|
|
attach_ftt = true;
|
|
}
|
|
if (options[launcher::Options::LoadScottoModule].value_bool()) {
|
|
attach_scotto = true;
|
|
}
|
|
if (options[launcher::Options::LoadRoadFighters3DModule].value_bool()) {
|
|
attach_rf3d = true;
|
|
}
|
|
if (options[launcher::Options::LoadDanceRushModule].value_bool()) {
|
|
attach_drs = true;
|
|
}
|
|
if (options[launcher::Options::LoadWinningElevenModule].value_bool()) {
|
|
attach_we = true;
|
|
}
|
|
if (options[launcher::Options::LoadOtocaModule].value_bool()) {
|
|
attach_otoca = true;
|
|
}
|
|
if (options[launcher::Options::LoadChargeMachineModule].value_bool()) {
|
|
attach_pcm = true;
|
|
}
|
|
if (options[launcher::Options::LoadOngakuParadiseModule].value_bool()) {
|
|
attach_onpara = true;
|
|
}
|
|
if (options[launcher::Options::LoadBusouShinkiModule].value_bool()) {
|
|
attach_bc = true;
|
|
}
|
|
if (options[launcher::Options::LoadCCJModule].value_bool()) {
|
|
attach_ccj = true;
|
|
}
|
|
if (options[launcher::Options::LoadQKSModule].value_bool()) {
|
|
attach_qks = true;
|
|
}
|
|
if (options[launcher::Options::LoadMFGModule].value_bool()) {
|
|
attach_mfg = true;
|
|
}
|
|
if (options[launcher::Options::LoadPCModule].value_bool()) {
|
|
attach_pc = true;
|
|
}
|
|
if (options[launcher::Options::LoadMusecaModule].value_bool()) {
|
|
attach_museca = true;
|
|
}
|
|
if (options[launcher::Options::DDR43Mode].value_bool()) {
|
|
games::ddr::SDMODE = true;
|
|
}
|
|
if (options[launcher::Options::DDRSkipCodecRegisteration].value_bool()) {
|
|
games::ddr::NO_CODEC_REGISTRATION = true;
|
|
}
|
|
if (options[launcher::Options::LoadSteelChronicleModule].value_bool()) {
|
|
attach_sc = true;
|
|
}
|
|
if (options[launcher::Options::DisableNetworkFixes].value_bool()) {
|
|
netfix_disable = true;
|
|
}
|
|
if (options[launcher::Options::DisableACPHook].value_bool()) {
|
|
lang_disable = true;
|
|
}
|
|
if (options[launcher::Options::DisableSignalHandling].value_bool()) {
|
|
launcher::signal::DISABLE = true;
|
|
}
|
|
if (options[launcher::Options::DebugCreateFile].value_bool()) {
|
|
DEVICE_CREATEFILE_DEBUG = true;
|
|
}
|
|
if (options[launcher::Options::BlockingLogger].value_bool()) {
|
|
logger::BLOCKING = true;
|
|
}
|
|
if (options[launcher::Options::OutputPEB].value_bool()) {
|
|
peb_print = true;
|
|
}
|
|
if (options[launcher::Options::DumpSystemInfo].is_active()) {
|
|
if (options[launcher::Options::DumpSystemInfo].value_text() == "all") {
|
|
rawinput::DUMP_HID_DEVICES_TO_LOG = true;
|
|
} else if (options[launcher::Options::DumpSystemInfo].value_text() == "basic") {
|
|
dump_sysinfo = true;
|
|
} else {
|
|
dump_sysinfo = false;
|
|
}
|
|
}
|
|
if (options[launcher::Options::EnableBemaniTools5API].value_bool()) {
|
|
BT5API_ENABLED = true;
|
|
}
|
|
if (options[launcher::Options::CardIOHIDReaderSupport].value_bool()) {
|
|
cardio_enabled = true;
|
|
}
|
|
if (options[launcher::Options::SDVXPrinterEmulation].value_bool()) {
|
|
attach_cpusbxpkm_printer = true;
|
|
}
|
|
|
|
// printer overwrite
|
|
if (options[launcher::Options::SDVXPrinterOutputOverwrite].value_bool() ||
|
|
options[launcher::Options::LovePlusPrinterOutputOverwrite].value_bool()) {
|
|
games::shared::PRINTER_OVERWRITE_FILE = true;
|
|
}
|
|
|
|
// printer output path
|
|
for (auto &path : options[launcher::Options::SDVXPrinterOutputPath].values_text()) {
|
|
games::shared::PRINTER_PATH.push_back(path);
|
|
}
|
|
for (auto &path : options[launcher::Options::LovePlusPrinterOutputPath].values_text()) {
|
|
games::shared::PRINTER_PATH.push_back(path);
|
|
}
|
|
|
|
// printer file format
|
|
for (auto &path : options[launcher::Options::SDVXPrinterOutputFormat].values_text()) {
|
|
games::shared::PRINTER_FORMAT.push_back(path);
|
|
}
|
|
for (auto &path : options[launcher::Options::LovePlusPrinterOutputFormat].values_text()) {
|
|
games::shared::PRINTER_FORMAT.push_back(path);
|
|
}
|
|
|
|
// printer JPG quality
|
|
if (options[launcher::Options::SDVXPrinterJPGQuality].is_active()) {
|
|
games::shared::PRINTER_JPG_QUALITY = options[launcher::Options::SDVXPrinterJPGQuality].value_uint32();
|
|
} else if (options[launcher::Options::LovePlusPrinterJPGQuality].is_active()) {
|
|
games::shared::PRINTER_JPG_QUALITY = options[launcher::Options::LovePlusPrinterJPGQuality].value_uint32();
|
|
}
|
|
|
|
// printer output clear
|
|
if (options[launcher::Options::SDVXPrinterOutputClear].value_bool() ||
|
|
options[launcher::Options::LovePlusPrinterOutputClear].value_bool()) {
|
|
games::shared::PRINTER_CLEAR = true;
|
|
}
|
|
|
|
if (options[launcher::Options::HTTP11].is_active()) {
|
|
avs::ea3::HTTP11 = options[launcher::Options::HTTP11].value_uint32();
|
|
}
|
|
if (options[launcher::Options::DisableSSL].value_bool()) {
|
|
ssl_disable = true;
|
|
}
|
|
if (options[launcher::Options::URLSlash].is_active()) {
|
|
avs::ea3::URL_SLASH = options[launcher::Options::URLSlash].value_uint32();
|
|
}
|
|
if (options[launcher::Options::spice2x_ProcessPriority].is_active()) {
|
|
process_priority_str = options[launcher::Options::spice2x_ProcessPriority].value_text();
|
|
} else if (options[launcher::Options::RealtimeProcessPriority].value_bool()) {
|
|
process_priority_str = "realtime";
|
|
}
|
|
if (options[launcher::Options::HeapSize].is_active()) {
|
|
user_heap_size = options[launcher::Options::HeapSize].value_uint32();
|
|
}
|
|
if (options[launcher::Options::DisableAvsVfsDriveMountRedirection].is_active()) {
|
|
hooks::avs::config::DISABLE_VFS_DRIVE_REDIRECTION = true;
|
|
}
|
|
if (options[launcher::Options::DisableAvsCache].is_active()) {
|
|
hooks::avs::config::DISABLE_CACHE = true;
|
|
}
|
|
if (options[launcher::Options::ScreenResizeConfigPath].is_active()) {
|
|
cfg::SCREEN_RESIZE_CFG_PATH_OVERRIDE =
|
|
options[launcher::Options::ScreenResizeConfigPath].value_text();
|
|
}
|
|
if (options[launcher::Options::PatchManagerConfigPath].is_active()) {
|
|
overlay::windows::PATCH_MANAGER_CFG_PATH_OVERRIDE =
|
|
options[launcher::Options::PatchManagerConfigPath].value_text();
|
|
}
|
|
if (options[launcher::Options::PathToAppConfig].is_active()) {
|
|
avs::ea3::APP_PATH = options[launcher::Options::PathToAppConfig].value_text();
|
|
}
|
|
if (options[launcher::Options::PathToAvsConfig].is_active()) {
|
|
avs::core::CFG_PATH = options[launcher::Options::PathToAvsConfig].value_text();
|
|
}
|
|
if (options[launcher::Options::PathToEa3Config].is_active()) {
|
|
avs::ea3::CFG_PATH = options[launcher::Options::PathToEa3Config].value_text();
|
|
}
|
|
if (options[launcher::Options::PathToBootstrap].is_active()) {
|
|
avs::ea3::BOOTSTRAP_PATH = options[launcher::Options::PathToBootstrap].value_text();
|
|
}
|
|
if (options[launcher::Options::PathToLog].is_active()) {
|
|
avs::core::LOG_PATH = options[launcher::Options::PathToLog].value_text();
|
|
}
|
|
if (options[launcher::Options::PCBID].is_active()) {
|
|
avs::ea3::PCBID_CUSTOM = options[launcher::Options::PCBID].value_text();
|
|
}
|
|
if (options[launcher::Options::SOFTID].is_active()) {
|
|
avs::ea3::SOFTID_CUSTOM = options[launcher::Options::SOFTID].value_text();
|
|
}
|
|
if (options[launcher::Options::ServiceURL].is_active()) {
|
|
avs::ea3::URL_CUSTOM = options[launcher::Options::ServiceURL].value_text();
|
|
}
|
|
if (options[launcher::Options::PathToModules].is_active()) {
|
|
std::error_code err;
|
|
|
|
auto &path = options[launcher::Options::PathToModules].value_text();
|
|
auto module_path = std::filesystem::absolute(path, err);
|
|
|
|
if (err) {
|
|
if (cfg::CONFIGURATOR_STANDALONE) {
|
|
log_warning("launcher", "failed to resolve module path '{}': {}", path, err.message());
|
|
} else {
|
|
log_fatal("launcher", "failed to resolve module path '{}': {}", path, err.message());
|
|
}
|
|
}
|
|
|
|
MODULE_PATH = std::move(module_path);
|
|
SetDllDirectoryW(MODULE_PATH.c_str());
|
|
}
|
|
if (options[launcher::Options::Player1Card].is_active()) {
|
|
std::lock_guard<std::mutex> lock(CARD_OVERRIDES_LOCK);
|
|
CARD_OVERRIDES[0] = options[launcher::Options::Player1Card].value_text();
|
|
}
|
|
if (options[launcher::Options::Player2Card].is_active()) {
|
|
std::lock_guard<std::mutex> lock(CARD_OVERRIDES_LOCK);
|
|
CARD_OVERRIDES[1] = options[launcher::Options::Player2Card].value_text();
|
|
}
|
|
if (options[launcher::Options::Player1PinMacro].is_active()) {
|
|
PIN_MACRO_ENABLED = true;
|
|
PIN_MACRO_VALUES[0] = options[launcher::Options::Player1PinMacro].value_text();
|
|
}
|
|
if (options[launcher::Options::Player2PinMacro].is_active()) {
|
|
PIN_MACRO_ENABLED = true;
|
|
PIN_MACRO_VALUES[1] = options[launcher::Options::Player2PinMacro].value_text();
|
|
}
|
|
|
|
for (auto &reader : options[launcher::Options::ICCAReaderPort].values_text()) {
|
|
static int reader_id = 0;
|
|
if (reader_id < 2) {
|
|
start_reader_thread(reader, reader_id++);
|
|
} else {
|
|
if (!cfg::CONFIGURATOR_STANDALONE) {
|
|
log_fatal("launcher", "too many readers specified (maximum is 2)");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
for (auto &sextet : options[launcher::Options::SextetStreamPort].values_text()) {
|
|
sextet_devices.emplace_back(sextet);
|
|
}
|
|
#ifndef NO_SCARD
|
|
if (options[launcher::Options::HIDSmartCard].value_bool()) {
|
|
WINSCARD_CONFIG.cardinfo_callback = eamuse_scard_callback;
|
|
scard_threadstart();
|
|
}
|
|
if (options[launcher::Options::HIDSmartCardOrderFlip].value_bool()) {
|
|
WINSCARD_CONFIG.flip_order = true;
|
|
}
|
|
if (options[launcher::Options::HIDSmartCardOrderToggle].value_bool()) {
|
|
WINSCARD_CONFIG.toggle_order = true;
|
|
}
|
|
if (options[launcher::Options::HIDSmartCardIdConvert].is_active()) {
|
|
const auto text = options[launcher::Options::HIDSmartCardIdConvert].value_text();
|
|
if (text == "fix") {
|
|
WINSCARD_CONFIG.add_padding_to_old_cards = true;
|
|
} else if (text == "all") {
|
|
WINSCARD_CONFIG.add_padding_to_old_cards = true;
|
|
WINSCARD_CONFIG.add_padding_to_felica = true;
|
|
}
|
|
}
|
|
#endif
|
|
if (options[launcher::Options::CardIOHIDReaderOrderFlip].value_bool()) {
|
|
CARDIO_RUNNER_FLIP = true;
|
|
}
|
|
if (options[launcher::Options::CardIOHIDReaderOrderToggle].value_bool()) {
|
|
CARDIO_RUNNER_TOGGLE = true;
|
|
}
|
|
if (options[launcher::Options::ICCAReaderPortToggle].is_active()) {
|
|
start_reader_thread(options[launcher::Options::ICCAReaderPortToggle].value_text(), -1);
|
|
}
|
|
if (options[launcher::Options::IntelSDEFolder].is_active()) {
|
|
sde_init(options[launcher::Options::IntelSDEFolder].value_text());
|
|
}
|
|
if (options[launcher::Options::AdapterNetwork].is_active()) {
|
|
NETWORK_ADDRESS = options[launcher::Options::AdapterNetwork].value_text();
|
|
}
|
|
if (options[launcher::Options::AdapterSubnet].is_active()) {
|
|
NETWORK_SUBNET = options[launcher::Options::AdapterSubnet].value_text();
|
|
}
|
|
|
|
if (options[launcher::Options::APITCPPort].is_active()) {
|
|
api_enable = true;
|
|
api_port = options[launcher::Options::APITCPPort].value_uint32();
|
|
}
|
|
if (options[launcher::Options::APIPassword].is_active()) {
|
|
api_pass = options[launcher::Options::APIPassword].value_text();
|
|
}
|
|
if (options[launcher::Options::APISerialPort].is_active()) {
|
|
api_serial_port.push_back(options[launcher::Options::APISerialPort].value_text());
|
|
}
|
|
if (options[launcher::Options::APISerialBaud].is_active()) {
|
|
api_serial_baud.push_back(options[launcher::Options::APISerialBaud].value_uint32());
|
|
}
|
|
if (options[launcher::Options::APIPretty].value_bool()) {
|
|
api_pretty = true;
|
|
}
|
|
if (options[launcher::Options::APIVerboseLogging].value_bool()) {
|
|
api::LOGGING = true;
|
|
}
|
|
if (options[launcher::Options::APIDebugMode].value_bool()) {
|
|
api_debug = true;
|
|
}
|
|
if (options[launcher::Options::APIScreenMirrorQuality].is_active()) {
|
|
api::modules::CAPTURE_QUALITY = options[launcher::Options::APIScreenMirrorQuality].value_uint32();
|
|
}
|
|
if (options[launcher::Options::APIScreenMirrorDivide].is_active()) {
|
|
api::modules::CAPTURE_DIVIDE = options[launcher::Options::APIScreenMirrorDivide].value_uint32();
|
|
}
|
|
|
|
if (options[launcher::Options::DisableDebugHooks].value_bool()) {
|
|
debughook::DEBUGHOOK_LOGGING = false;
|
|
}
|
|
if (options[launcher::Options::ForceWinTouch].value_bool()) {
|
|
rawinput::touch::DISABLED = true;
|
|
}
|
|
if (options[launcher::Options::SDVXForce720p].value_bool()) {
|
|
GRAPHICS_SDVX_FORCE_720 = true;
|
|
}
|
|
if (options[launcher::Options::InvertTouchCoordinates].value_bool()) {
|
|
rawinput::touch::INVERTED = true;
|
|
}
|
|
// DisableTouchCardInsert is no longer honored in spice2x
|
|
// if (options[launcher::Options::DisableTouchCardInsert].value_bool()) {
|
|
// SPICETOUCH_CARD_DISABLE = true;
|
|
// }
|
|
if (options[launcher::Options::spice2x_TouchCardInsert].value_bool()) {
|
|
SPICETOUCH_CARD_DISABLE = false;
|
|
}
|
|
if (options[launcher::Options::ForceTouchEmulation].value_bool()) {
|
|
wintouchemu::FORCE = true;
|
|
}
|
|
if (options[launcher::Options::Graphics9On12].value_bool()) {
|
|
GRAPHICS_9_ON_12_STATE = DX9ON12_FORCE_ON;
|
|
}
|
|
if (options[launcher::Options::spice2x_Dx9On12].is_active()) {
|
|
auto &name = options[launcher::Options::spice2x_Dx9On12].value_text();
|
|
if (name == "0") {
|
|
GRAPHICS_9_ON_12_STATE = DX9ON12_FORCE_OFF;
|
|
} else if (name == "1") {
|
|
GRAPHICS_9_ON_12_STATE = DX9ON12_FORCE_ON;
|
|
}
|
|
// do not explicitly set GRAPHICS_9_ON_12_STATE to default here; must respect
|
|
// legacy Graphics9On12 option from above if set
|
|
}
|
|
if (options[launcher::Options::NoLegacy].value_bool() && !cfg_run) {
|
|
rawinput::NOLEGACY = true;
|
|
}
|
|
if (options[launcher::Options::RichPresence].value_bool()) {
|
|
rich_presence = true;
|
|
}
|
|
if (options[launcher::Options::DiscordAppID].is_active()) {
|
|
richpresence::discord::APPID_OVERRIDE = options[launcher::Options::DiscordAppID].value_text();
|
|
}
|
|
if (options[launcher::Options::ScreenshotFolder].is_active()) {
|
|
GRAPHICS_SCREENSHOT_DIR = options[launcher::Options::ScreenshotFolder].value_text();
|
|
}
|
|
if (options[launcher::Options::DisableColoredOutput].value_bool()) {
|
|
logger::COLOR = false;
|
|
}
|
|
if (options[launcher::Options::DisableOverlay].value_bool()) {
|
|
overlay::ENABLED = false;
|
|
}
|
|
if (options[launcher::Options::OverlayScaling].is_active() && !cfg::CONFIGURATOR_STANDALONE && !cfg_run) {
|
|
const auto val = options[launcher::Options::OverlayScaling].value_uint32();
|
|
if (10 <= val && val <= 400 && val != 100) {
|
|
overlay::UI_SCALE_PERCENT = options[launcher::Options::OverlayScaling].value_uint32();
|
|
}
|
|
}
|
|
if (options[launcher::Options::DisableAudioHooks].value_bool()) {
|
|
hooks::audio::ENABLED = false;
|
|
deferredlogs::defer_error_messages({
|
|
"audio hooks are forcibly disabled by user (-audiohookdisable)",
|
|
" having hooks disabled means some required audio fixes are not being applied",
|
|
" if you have audio-related crashes, you should try again after clearing this option"
|
|
});
|
|
}
|
|
if (options[launcher::Options::spice2x_DisableVolumeHook].value_bool()) {
|
|
hooks::audio::VOLUME_HOOK_ENABLED = false;
|
|
}
|
|
|
|
if (options[launcher::Options::AudioBackend].is_active()) {
|
|
auto &name = options[launcher::Options::AudioBackend].value_text();
|
|
auto backend = hooks::audio::name_to_backend(name.c_str());
|
|
if (!backend.has_value() && !cfg::CONFIGURATOR_STANDALONE) {
|
|
log_fatal("launcher", "invalid audio backend: {}", name);
|
|
}
|
|
hooks::audio::BACKEND = backend;
|
|
}
|
|
|
|
if (options[launcher::Options::AsioDriverId].is_active()) {
|
|
hooks::audio::ASIO_DRIVER_ID = options[launcher::Options::AsioDriverId].value_uint32();
|
|
}
|
|
if (options[launcher::Options::AsioDriverName].is_active()) {
|
|
hooks::audio::BACKEND = hooks::audio::name_to_backend("asio");
|
|
hooks::audio::ASIO_DRIVER_NAME = options[launcher::Options::AsioDriverName].value_text();
|
|
// this new option overrides the old one
|
|
hooks::audio::ASIO_DRIVER_ID.reset();
|
|
}
|
|
|
|
if (options[launcher::Options::AudioDummy].value_bool()) {
|
|
hooks::audio::USE_DUMMY = true;
|
|
}
|
|
if (options[launcher::Options::EAAutomap].value_bool()) {
|
|
easrv_maint = false;
|
|
automap = true;
|
|
avs::automap::ENABLED = true;
|
|
avs::automap::PATCH = true;
|
|
avs::automap::RESTRICT_NETWORK = true;
|
|
avs::automap::DUMP = true;
|
|
}
|
|
if (options[launcher::Options::EANetdump].value_bool()) {
|
|
easrv_maint = false;
|
|
automap = true;
|
|
avs::automap::ENABLED = true;
|
|
avs::automap::PATCH = false;
|
|
avs::automap::RESTRICT_NETWORK = true;
|
|
avs::automap::DUMP = true;
|
|
}
|
|
if (options[launcher::Options::GameExecutable].is_active()) {
|
|
avs::game::DLL_NAME = options[launcher::Options::GameExecutable].value_text();
|
|
}
|
|
if (options[launcher::Options::spice2x_LightsOverallBrightness].is_active()) {
|
|
rawinput::HID_LIGHT_BRIGHTNESS =
|
|
(uint8_t)options[launcher::Options::spice2x_LightsOverallBrightness].value_uint32();
|
|
}
|
|
if (options[launcher::Options::spice2x_FpsAutoShow].value_bool()) {
|
|
overlay::AUTO_SHOW_FPS = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_FpsOpposite].value_bool()) {
|
|
overlay::FPS_SHOULD_FLIP = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_SubScreenAutoShow].value_bool()) {
|
|
overlay::AUTO_SHOW_SUBSCREEN = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_IOPanelAutoShow].value_bool()) {
|
|
overlay::AUTO_SHOW_IOPANEL = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_KeypadAutoShow].is_active()) {
|
|
auto s = options[launcher::Options::spice2x_KeypadAutoShow].value_uint32();
|
|
switch (s) {
|
|
case 1:
|
|
overlay::AUTO_SHOW_KEYPAD_P1 = true;
|
|
break;
|
|
case 2:
|
|
overlay::AUTO_SHOW_KEYPAD_P2 = true;
|
|
break;
|
|
case 3:
|
|
overlay::AUTO_SHOW_KEYPAD_P1 = true;
|
|
overlay::AUTO_SHOW_KEYPAD_P2 = true;
|
|
break;
|
|
}
|
|
}
|
|
if (options[launcher::Options::spice2x_WindowBorder].is_active()) {
|
|
GRAPHICS_WINDOW_STYLE = options[launcher::Options::spice2x_WindowBorder].value_uint32();
|
|
}
|
|
if (options[launcher::Options::spice2x_WindowSize].is_active()) {
|
|
std::pair<uint32_t, uint32_t> result;
|
|
if (parse_width_height(options[launcher::Options::spice2x_WindowSize].value_text(), result)) {
|
|
GRAPHICS_WINDOW_SIZE = result;
|
|
} else if (!cfg_run && !cfg::CONFIGURATOR_STANDALONE) {
|
|
log_fatal("launcher", "failed to parse -windowsize");
|
|
}
|
|
}
|
|
if (options[launcher::Options::spice2x_WindowPosition].is_active()) {
|
|
GRAPHICS_WINDOW_POS = options[launcher::Options::spice2x_WindowPosition].value_text();
|
|
}
|
|
GRAPHICS_WINDOW_ALWAYS_ON_TOP = options[launcher::Options::spice2x_WindowAlwaysOnTop].value_bool();
|
|
GRAPHICS_WINDOW_BACKBUFFER_SCALE = options[launcher::Options::WindowForceScaling].value_bool();
|
|
GRAPHICS_WINDOW_DISABLE_ROUNDED_CORNERS = options[launcher::Options::WindowDisableRoundedCorners].value_bool();
|
|
|
|
// IIDX/SDVX Windowed Subscreen
|
|
if (options[launcher::Options::spice2x_IIDXWindowedSubscreenSize].is_active()) {
|
|
GRAPHICS_WSUB_SIZE = options[launcher::Options::spice2x_IIDXWindowedSubscreenSize].value_text();
|
|
} else if (options[launcher::Options::SDVXWindowedSubscreenSize].is_active()) {
|
|
GRAPHICS_WSUB_SIZE = options[launcher::Options::SDVXWindowedSubscreenSize].value_text();
|
|
}
|
|
if (options[launcher::Options::spice2x_IIDXWindowedSubscreenPosition].is_active()) {
|
|
GRAPHICS_WSUB_POS = options[launcher::Options::spice2x_IIDXWindowedSubscreenPosition].value_text();
|
|
} else if (options[launcher::Options::SDVXWindowedSubscreenPosition].is_active()) {
|
|
GRAPHICS_WSUB_POS = options[launcher::Options::SDVXWindowedSubscreenPosition].value_text();
|
|
}
|
|
if (options[launcher::Options::IIDXWindowedSubscreenBorderless].value_bool() ||
|
|
options[launcher::Options::SDVXWindowedSubscreenBorderless].value_bool()) {
|
|
GRAPHICS_WSUB_BORDERLESS = true;
|
|
}
|
|
if (options[launcher::Options::IIDXWindowedSubscreenAlwaysOnTop].value_bool() ||
|
|
options[launcher::Options::SDVXWindowedSubscreenAlwaysOnTop].value_bool()) {
|
|
GRAPHICS_WSUB_ALWAYS_ON_TOP = true;
|
|
}
|
|
if (options[launcher::Options::IIDXSubMonitorOverride].is_active()) {
|
|
sysutils::SECOND_MONITOR_OVERRIDE = options[launcher::Options::IIDXSubMonitorOverride].value_text();
|
|
}
|
|
|
|
if (options[launcher::Options::spice2x_JubeatLegacyTouch].value_bool()) {
|
|
games::jb::TOUCH_LEGACY_BOX = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_RBTouchScale].is_active()) {
|
|
games::rb::TOUCH_SCALING = options[launcher::Options::spice2x_RBTouchScale].value_uint32();
|
|
}
|
|
if (options[launcher::Options::spice2x_AsioForceUnload].value_bool()) {
|
|
hooks::audio::ASIO_FORCE_UNLOAD_ON_STOP = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_DRSDisableTouch].value_bool()) {
|
|
games::drs::DISABLE_TOUCH = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_DRSTransposeTouch].value_bool()) {
|
|
games::drs::TRANSPOSE_TOUCH = true;
|
|
}
|
|
if (options[launcher::Options::DRSRGBCameraHook].value_bool()) {
|
|
games::drs::RGB_CAMERA_HOOK = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_AutoCard].is_active()) {
|
|
const auto text = options[launcher::Options::spice2x_AutoCard].value_text();
|
|
if (text == "p1") {
|
|
AUTO_INSERT_CARD[0] = true;
|
|
} else if (text == "p2") {
|
|
AUTO_INSERT_CARD[1] = true;
|
|
} else if (text == "both") {
|
|
AUTO_INSERT_CARD[0] = true;
|
|
AUTO_INSERT_CARD[1] = true;
|
|
}
|
|
}
|
|
if (options[launcher::Options::spice2x_LowLatencySharedAudio].value_bool()) {
|
|
hooks::audio::LOW_LATENCY_SHARED_WASAPI = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_TapeLedAlgorithm].is_active()) {
|
|
const auto text = options[launcher::Options::spice2x_TapeLedAlgorithm].value_text();
|
|
if (text == "off") {
|
|
tapeledutils::TAPE_LED_ALGORITHM = tapeledutils::TAPE_LED_USE_NONE;
|
|
} else if (text == "avg") {
|
|
tapeledutils::TAPE_LED_ALGORITHM = tapeledutils::TAPE_LED_USE_AVERAGE;
|
|
} else if (text == "first") {
|
|
tapeledutils::TAPE_LED_ALGORITHM = tapeledutils::TAPE_LED_USE_FIRST;
|
|
} else if (text == "last") {
|
|
tapeledutils::TAPE_LED_ALGORITHM = tapeledutils::TAPE_LED_USE_LAST;
|
|
}
|
|
}
|
|
if (options[launcher::Options::CCJTrackballSensitivity].is_active()) {
|
|
games::ccj::TRACKBALL_SENSITIVITY = (uint8_t)
|
|
options[launcher::Options::CCJTrackballSensitivity].value_uint32();
|
|
}
|
|
if (options[launcher::Options::CCJMouseTrackball].value_bool()) {
|
|
games::ccj::MOUSE_TRACKBALL = true;
|
|
}
|
|
if (options[launcher::Options::CCJMouseTrackballWithToggle].value_bool()) {
|
|
games::ccj::MOUSE_TRACKBALL_USE_TOGGLE = true;
|
|
}
|
|
if (options[launcher::Options::CCJArgs].is_active()) {
|
|
games::ccj::CCJ_INJECT_ARGS = options[launcher::Options::CCJArgs].value_text();
|
|
}
|
|
if (options[launcher::Options::QKSArgs].is_active()) {
|
|
games::qks::QKS_INJECT_ARGS = options[launcher::Options::QKSArgs].value_text();
|
|
}
|
|
if (options[launcher::Options::MFGArgs].is_active()) {
|
|
games::mfg::MFG_INJECT_ARGS = options[launcher::Options::MFGArgs].value_text();
|
|
}
|
|
if (options[launcher::Options::MFGCabType].is_active()) {
|
|
games::mfg::MFG_CABINET_TYPE = options[launcher::Options::MFGCabType].value_text();
|
|
}
|
|
if (options[launcher::Options::MFGNoIO].is_active()) {
|
|
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()) {
|
|
rawinput::ENABLE_SMX_STAGE = true;
|
|
}
|
|
if (options[launcher::Options::spice2x_EnableSMXDedicab].value_bool()) {
|
|
rawinput::ENABLE_SMX_DEDICAB = true;
|
|
}
|
|
if (options[launcher::Options::InputRequiresFocus].is_active()) {
|
|
const auto &text = options[launcher::Options::InputRequiresFocus].value_text();
|
|
if (text == "always") {
|
|
rawinput::NAIVE_REQUIRE_FOCUS = true;
|
|
rawinput::RAWINPUT_REQUIRE_FOCUS = true;
|
|
} else if (text == "never") {
|
|
rawinput::NAIVE_REQUIRE_FOCUS = false;
|
|
rawinput::RAWINPUT_REQUIRE_FOCUS = false;
|
|
}
|
|
}
|
|
if (options[launcher::Options::DDRP4IOBufferMode].is_active()) {
|
|
if (options[launcher::Options::DDRP4IOBufferMode].value_text() == "thread") {
|
|
acio::MDXF_BUFFER_FILL_MODE = acio::MDXFBufferFillMode::THREAD_MODE;
|
|
} else if (options[launcher::Options::DDRP4IOBufferMode].value_text() == "backfill") {
|
|
acio::MDXF_BUFFER_FILL_MODE = acio::MDXFBufferFillMode::BACKFILL_MODE;
|
|
}
|
|
}
|
|
|
|
if (options[launcher::Options::MidiAlgoVer].is_active()) {
|
|
if (options[launcher::Options::MidiAlgoVer].value_text() == "legacy") {
|
|
midi_algo = rawinput::MidiNoteAlgorithm::LEGACY;
|
|
} else if (options[launcher::Options::MidiAlgoVer].value_text() == "v2") {
|
|
midi_algo = rawinput::MidiNoteAlgorithm::V2;
|
|
} else if (options[launcher::Options::MidiAlgoVer].value_text() == "v2_drum") {
|
|
midi_algo = rawinput::MidiNoteAlgorithm::V2_DRUM;
|
|
}
|
|
// else - automatic (no value)
|
|
}
|
|
if (cfg::CONFIGURATOR_STANDALONE) {
|
|
// three reasons for this hardcoded value
|
|
// 1) poll rate is tied to framerate in spicecfg, and the software ImGui renderer has
|
|
// inconsistent framerate, often failing to meet 60fps
|
|
// 2) the default is 20ms which is 1 frame, which is too quick for the user to see
|
|
// 3) to help with binding process
|
|
rawinput::MIDI_NOTE_SUSTAIN = 100;
|
|
} else if (options[launcher::Options::MidiNoteSustain].is_active()) {
|
|
rawinput::MIDI_NOTE_SUSTAIN = options[launcher::Options::MidiNoteSustain].value_uint32();
|
|
}
|
|
|
|
if (options[launcher::Options::LovePlusCamEnable].value_bool()) {
|
|
games::loveplus::CAMERA_ENABLE = true;
|
|
}
|
|
|
|
// API debugging
|
|
if (api_debug && !cfg::CONFIGURATOR_STANDALONE) {
|
|
API_CONTROLLER = std::make_unique<api::Controller>(api_port, api_pass, api_pretty);
|
|
for (size_t i = 0; i < std::min(api_serial_port.size(), api_serial_baud.size()); i++) {
|
|
API_CONTROLLER->listen_serial(api_serial_port[i], api_serial_baud[i]);
|
|
}
|
|
if (cfg_run) {
|
|
exit(spicecfg_run(sextet_devices));
|
|
} else {
|
|
while (API_CONTROLLER->server_running) {
|
|
Sleep(100);
|
|
}
|
|
}
|
|
log_fatal("launcher", "API server stopped");
|
|
}
|
|
|
|
// delay
|
|
if (!cfg::CONFIGURATOR_STANDALONE) {
|
|
DWORD delayInSeconds = 0;
|
|
if (options[launcher::Options::spice2x_DelayByNSeconds].is_active()) {
|
|
delayInSeconds = (DWORD)options[launcher::Options::spice2x_DelayByNSeconds].value_uint32();
|
|
} else if (options[launcher::Options::DelayBy5Seconds].value_bool()) {
|
|
delayInSeconds = 5;
|
|
}
|
|
|
|
if (0 < delayInSeconds) {
|
|
log_info("launcher", "delay by {}ms...", delayInSeconds * 1000);
|
|
Sleep(delayInSeconds * 1000);
|
|
}
|
|
}
|
|
|
|
// create log file
|
|
// configurator does not write a log file because it tends to cause the
|
|
// config file to be corrupt...
|
|
if (!cfg::CONFIGURATOR_STANDALONE) {
|
|
avs::core::create_log();
|
|
}
|
|
|
|
// log
|
|
#if SPICE_LINUX
|
|
#ifdef SPICE64
|
|
log_info("launcher", "SpiceTools Bootstrap (x64) (spice2x) for Linux");
|
|
#else
|
|
log_info("launcher", "SpiceTools Bootstrap (x32) (spice2x) for Linux");
|
|
#endif
|
|
#elif SPICE_XP
|
|
#ifdef SPICE64
|
|
log_info("launcher", "SpiceTools Bootstrap (x64) (spice2x) for WinXP");
|
|
#else
|
|
log_info("launcher", "SpiceTools Bootstrap (x32) (spice2x) for WinXP");
|
|
#endif
|
|
#else
|
|
#ifdef SPICE64
|
|
log_info("launcher", "SpiceTools Bootstrap (x64) (spice2x)");
|
|
#elif SPICE32_LARGE_ADDRESS_AWARE
|
|
log_info("launcher", "SpiceTools Bootstrap (x32 - Large Address Aware) (spice2x)");
|
|
#else
|
|
log_info("launcher", "SpiceTools Bootstrap (x32) (spice2x)");
|
|
#endif
|
|
#endif
|
|
|
|
log_info("launcher", "{}", VERSION_STRING);
|
|
|
|
// note: distribution of modified version of this software without providing source is GPLv3 license violation.
|
|
log_info("launcher", "spice2x is free & open source; if you paid money for it, you got scammed");
|
|
log_info("launcher", "visit https://spice2x.github.io to download the latest version for free");
|
|
|
|
// log command line arguments
|
|
std::ostringstream arguments;
|
|
for (auto &root_option : options) {
|
|
std::vector<Option> options_all { root_option };
|
|
|
|
options_all.insert(options_all.end(),
|
|
root_option.alternatives.begin(),
|
|
root_option.alternatives.end());
|
|
|
|
for (const auto &option : options_all) {
|
|
if (option.is_active()) {
|
|
auto &definition = option.get_definition();
|
|
|
|
arguments << " ";
|
|
arguments << "-";
|
|
|
|
if (definition.display_name.empty()) {
|
|
arguments << definition.name;
|
|
} else {
|
|
arguments << definition.display_name;
|
|
}
|
|
|
|
if (definition.type != OptionType::Bool) {
|
|
arguments << " ";
|
|
|
|
if (definition.sensitive) {
|
|
arguments << std::string(5, '*');
|
|
} else {
|
|
arguments << option.value;
|
|
}
|
|
}
|
|
|
|
arguments << "\n";
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
const auto& value = option.get_definition().sensitive ? "*****" : option.value;
|
|
if (launcher::USE_CMD_OVERRIDE) {
|
|
log_warning(
|
|
"launcher",
|
|
"multiple values for -{}, command line args take precedence: {}",
|
|
option.get_definition().name,
|
|
value);
|
|
} else {
|
|
log_warning(
|
|
"launcher",
|
|
"multiple values for -{}, spicecfg values take precedence: {}",
|
|
option.get_definition().name,
|
|
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 (launcher::signal::DISABLE && !cfg::CONFIGURATOR_STANDALONE) {
|
|
log_warning(
|
|
"launcher",
|
|
"WARNING - user specified -signaldisable option\n\n\n"
|
|
"!!! !!!\n"
|
|
"!!! Using -signaldisable option disables all exception handling, !!!\n"
|
|
"!!! which means when the game crashes it will likely just vanish !!!\n"
|
|
"!!! without troubleshooting information in the logs. !!!\n"
|
|
"!!! !!!\n"
|
|
);
|
|
}
|
|
|
|
if (options[launcher::Options::FullscreenResolution].is_active()) {
|
|
std::pair<uint32_t, uint32_t> result;
|
|
if (parse_width_height(options[launcher::Options::FullscreenResolution].value_text(), result)) {
|
|
GRAPHICS_FS_CUSTOM_RESOLUTION = result;
|
|
} else if (!cfg_run && !cfg::CONFIGURATOR_STANDALONE) {
|
|
log_fatal("launcher", "failed to parse -forceres");
|
|
}
|
|
}
|
|
|
|
if (options[launcher::Options::FullscreenSubResolution].is_active()) {
|
|
std::pair<uint32_t, uint32_t> result;
|
|
if (parse_width_height(options[launcher::Options::FullscreenSubResolution].value_text(), result)) {
|
|
GRAPHICS_FS_CUSTOM_RESOLUTION_SUB = result;
|
|
} else if (!cfg_run && !cfg::CONFIGURATOR_STANDALONE) {
|
|
log_fatal("launcher", "failed to parse -forceressub");
|
|
}
|
|
}
|
|
|
|
// SDVXFullscreenLandscape disabled due to it messing with in-game camera angle
|
|
// FullscreenOrientationFlip continues to live on, however.
|
|
if (options[launcher::Options::SDVXFullscreenLandscape].value_bool() && !cfg::CONFIGURATOR_STANDALONE) {
|
|
log_fatal("launcher", "-sdvxlandscape removed due to a camera bug in SDVX!");
|
|
}
|
|
// if (options[launcher::Options::SDVXFullscreenLandscape].value_bool() && !GRAPHICS_WINDOWED) {
|
|
// #if SPICE64
|
|
// GRAPHICS_FS_ORIENTATION_SWAP = true;
|
|
// #else
|
|
// log_warning("launcher", "-sdvxlandscape is not supported in 32-bit SDVX, ignoring...");
|
|
// #endif
|
|
// }
|
|
|
|
if (options[launcher::Options::FullscreenOrientationFlip].value_bool() && !GRAPHICS_WINDOWED) {
|
|
GRAPHICS_FS_ORIENTATION_SWAP = true;
|
|
}
|
|
|
|
if (games::iidx::DISABLE_CAMS.has_value() &&
|
|
games::iidx::DISABLE_CAMS.value() &&
|
|
!cfg::CONFIGURATOR_STANDALONE) {
|
|
log_misc("launcher", "CONNECT_CAMERA env var set to 0");
|
|
SetEnvironmentVariable("CONNECT_CAMERA", "0");
|
|
}
|
|
|
|
// deleted options
|
|
if (options[launcher::Options::OpenKFControl].value_bool() && !cfg::CONFIGURATOR_STANDALONE) {
|
|
log_fatal("launcher", "KFControl has been removed from spice2x; please use an older version.");
|
|
}
|
|
if (options[launcher::Options::VREnable].value_bool()) {
|
|
log_warning("launcher", "-vr has been removed from spice2x; ignoring");
|
|
}
|
|
if (options[launcher::Options::ExecuteScript].is_active()) {
|
|
log_warning("launcher", "-script has been removed from spice2x; ignoring");
|
|
}
|
|
|
|
// disable automatic system/monitor sleep
|
|
if (!SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED)) {
|
|
log_warning("launcher", "could not set thread execution state: {}", GetLastError());
|
|
}
|
|
|
|
if (!cfg::CONFIGURATOR_STANDALONE) {
|
|
|
|
// set process priority
|
|
cpuutils::set_processor_priority(process_priority_str);
|
|
|
|
// set process affinity
|
|
if (options[launcher::Options::spice2x_ProcessAffinity].is_active()) {
|
|
uint64_t affinity = options[launcher::Options::spice2x_ProcessAffinity].value_hex64();
|
|
cpuutils::set_processor_affinity(affinity, true);
|
|
|
|
// efficiency class (but only if no affinity is set)
|
|
} else if (options[launcher::Options::spice2x_ProcessorEfficiencyClass].is_active()) {
|
|
const auto eff_class_str =
|
|
options[launcher::Options::spice2x_ProcessorEfficiencyClass].value_text();
|
|
if (eff_class_str == "ecores") {
|
|
cpuutils::set_processor_affinity(cpuutils::CpuEfficiencyClass::PreferECores);
|
|
} else if (eff_class_str == "pcores") {
|
|
cpuutils::set_processor_affinity(cpuutils::CpuEfficiencyClass::PreferPCores);
|
|
}
|
|
}
|
|
|
|
// initialize nvapi if available
|
|
nvapi::initialize();
|
|
// add application profile to nvcp
|
|
nvapi::set_profile_settings();
|
|
// enable super exit
|
|
superexit::enable();
|
|
|
|
// enable subscreen touch emulation
|
|
if (options[launcher::Options::spice2x_IIDXEmulateSubscreenKeypadTouch].is_active()) {
|
|
games::iidx::poke::enable();
|
|
}
|
|
if (options[launcher::Options::NostalgiaPoke].is_active()) {
|
|
games::nost::ENABLE_POKE = TRUE;
|
|
}
|
|
}
|
|
|
|
// early hooks
|
|
for (auto &hook : early_hooks) {
|
|
log_info("launcher", "loading early hook DLL {}", hook);
|
|
libutils::print_dll_info(hook);
|
|
HMODULE module;
|
|
if (!(module = libutils::try_library(hook))) {
|
|
log_warning("launcher", "failed to load early hook {}: {}", hook, get_last_error_string());
|
|
deferredlogs::defer_error_messages({
|
|
fmt::format("failed to load early hook {}:", hook),
|
|
fmt::format(" {}", get_last_error_string())
|
|
});
|
|
}
|
|
}
|
|
|
|
// auto detect game if not specified
|
|
if (avs::game::DLL_NAME.empty()) {
|
|
bool module_path_tried = false;
|
|
do {
|
|
|
|
// IIDX
|
|
if (check_dll("bm2dx.dll")) {
|
|
avs::game::DLL_NAME = "bm2dx.dll";
|
|
attach_io = true;
|
|
attach_iidx = true;
|
|
// automatically show cursor in windowed mode to interact with second window (sub)
|
|
if (GRAPHICS_WINDOWED) {
|
|
GRAPHICS_SHOW_CURSOR = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// SDVX
|
|
if (check_dll("soundvoltex.dll")) {
|
|
avs::game::DLL_NAME = "soundvoltex.dll";
|
|
attach_io = true;
|
|
attach_sdvx = true;
|
|
#ifdef SPICE64
|
|
debughook::DEBUGHOOK_LOGGING = false;
|
|
#endif
|
|
// automatically show cursor in windowed mode to interact with second window (sub)
|
|
if (GRAPHICS_WINDOWED) {
|
|
GRAPHICS_SHOW_CURSOR = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// JB
|
|
if (check_dll("jubeat.dll")) {
|
|
avs::game::DLL_NAME = "jubeat.dll";
|
|
attach_io = true;
|
|
attach_jb = true;
|
|
break;
|
|
}
|
|
|
|
// RB
|
|
if (check_dll("reflecbeat.dll")) {
|
|
avs::game::DLL_NAME = "reflecbeat.dll";
|
|
attach_io = true;
|
|
attach_rb = true;
|
|
break;
|
|
}
|
|
|
|
// Shogikai
|
|
if (check_dll("shogi_engine.dll")) {
|
|
avs::game::DLL_NAME = "system.dll";
|
|
attach_io = true;
|
|
attach_shogikai = true;
|
|
show_cursor_if_no_touch = true;
|
|
break;
|
|
}
|
|
|
|
// PCM & MGA
|
|
if (check_dll("launch.dll")) {
|
|
avs::game::DLL_NAME = "launch.dll";
|
|
attach_io = true;
|
|
|
|
// MGA uses ESS while PCM does not
|
|
if (check_dll("ess.dll")) {
|
|
attach_mga = true;
|
|
} else {
|
|
attach_pcm = true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// DEA
|
|
if (check_dll("arkkdm.dll")) {
|
|
avs::game::DLL_NAME = "arkkdm.dll";
|
|
attach_io = true;
|
|
attach_dea = true;
|
|
|
|
// the game is windowed by default unless we set the env
|
|
if (GRAPHICS_WINDOWED) {
|
|
GRAPHICS_WINDOWED = false;
|
|
} else {
|
|
SetEnvironmentVariable("DAMAC_VIEWER_FULLSCREEN", "0");
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// BS
|
|
if (check_dll("beatstream.dll")) {
|
|
avs::game::DLL_NAME = "beatstream.dll";
|
|
attach_io = true;
|
|
attach_bs = true;
|
|
|
|
// game crash fix
|
|
easrv_maint = false;
|
|
show_cursor_if_no_touch = true;
|
|
break;
|
|
}
|
|
|
|
// RF3D
|
|
if (check_dll("jgt.dll")) {
|
|
avs::game::DLL_NAME = "jgt.dll";
|
|
attach_io = true;
|
|
attach_rf3d = true;
|
|
break;
|
|
}
|
|
|
|
// MUSECA
|
|
if (check_dll("museca.dll")) {
|
|
avs::game::DLL_NAME = "museca.dll";
|
|
attach_io = true;
|
|
attach_museca = true;
|
|
break;
|
|
}
|
|
|
|
// pop'n Lapistoria/eclale/UsaNeko/peace
|
|
if (check_dll("popn22.dll")) {
|
|
avs::game::DLL_NAME = "popn22.dll";
|
|
attach_io = true;
|
|
attach_popn = true;
|
|
break;
|
|
}
|
|
|
|
// pop'n Sunny Park
|
|
if (check_dll("popn21.dll")) {
|
|
avs::game::DLL_NAME = "popn21.dll";
|
|
attach_io = true;
|
|
attach_popn = true;
|
|
break;
|
|
}
|
|
|
|
// pop'n Fantasia
|
|
if (check_dll("popn20.dll")) {
|
|
avs::game::DLL_NAME = "popn20.dll";
|
|
attach_io = true;
|
|
attach_popn = true;
|
|
break;
|
|
}
|
|
|
|
// pop'n Tune Street
|
|
if (check_dll("popn19.dll")) {
|
|
avs::game::DLL_NAME = "popn19.dll";
|
|
attach_io = true;
|
|
attach_popn = true;
|
|
break;
|
|
}
|
|
|
|
// DDR Ace/A20 (bio2)
|
|
if (check_dll("arkmdxbio2.dll")) {
|
|
avs::game::DLL_NAME = "arkmdxbio2.dll";
|
|
attach_io = true;
|
|
attach_ddr = true;
|
|
break;
|
|
}
|
|
|
|
// DDR Ace/A20 (p3io)
|
|
if (check_dll("arkmdxp3.dll")) {
|
|
avs::game::DLL_NAME = "arkmdxp3.dll";
|
|
attach_io = true;
|
|
attach_ddr = true;
|
|
break;
|
|
}
|
|
|
|
// DDR Ace/A20 (p4io)
|
|
if (check_dll("arkmdxp4.dll")) {
|
|
avs::game::DLL_NAME = "arkmdxp4.dll";
|
|
attach_io = true;
|
|
attach_ddr = true;
|
|
break;
|
|
}
|
|
|
|
// DDR 2013/2014 (old cabinets)
|
|
if (check_dll("mdxja_945.dll")) {
|
|
avs::game::DLL_NAME = "mdxja_945.dll";
|
|
attach_io = true;
|
|
attach_ddr = true;
|
|
break;
|
|
}
|
|
|
|
// DDR 2013/2014 (white cabinet)
|
|
if (check_dll("mdxja_hm65.dll")) {
|
|
avs::game::DLL_NAME = "mdxja_hm65.dll";
|
|
attach_io = true;
|
|
attach_ddr = true;
|
|
break;
|
|
}
|
|
|
|
// DDR X2/X3
|
|
if (check_dll("ddr.dll")) {
|
|
avs::game::DLL_NAME = "ddr.dll";
|
|
attach_io = true;
|
|
attach_ddr = true;
|
|
break;
|
|
}
|
|
|
|
// GitaDora
|
|
if (check_dll("gdxg.dll")) {
|
|
avs::game::DLL_NAME = "gdxg.dll";
|
|
attach_io = true;
|
|
attach_device = true;
|
|
attach_extdev = true;
|
|
attach_ami2000 = true;
|
|
attach_gitadora = true;
|
|
break;
|
|
}
|
|
|
|
// Nostalgia
|
|
if (check_dll("nostalgia.dll")) {
|
|
avs::game::DLL_NAME = "nostalgia.dll";
|
|
attach_io = true;
|
|
attach_nostalgia = true;
|
|
show_cursor_if_no_touch = true;
|
|
break;
|
|
}
|
|
|
|
// Bishi Bashi Channel
|
|
if (check_dll("bsch.dll")) {
|
|
avs::game::DLL_NAME = "bsch.dll";
|
|
attach_io = true;
|
|
attach_bbc = true;
|
|
break;
|
|
}
|
|
|
|
if (check_dll("popn.dll")) {
|
|
avs::game::DLL_NAME = "popn.dll";
|
|
attach_io = true;
|
|
|
|
if (check_dll("libaio-iob2_video.dll")) {
|
|
// pop'n music (pika cabinet)
|
|
attach_popn = true;
|
|
// automatically show cursor in windowed mode to interact with second window (sub)
|
|
if (GRAPHICS_WINDOWED) {
|
|
GRAPHICS_SHOW_CURSOR = true;
|
|
}
|
|
} else {
|
|
// HELLO! Pop'n Music
|
|
attach_hpm = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Quiz Magic Academy
|
|
if (check_dll("client.dll")) {
|
|
avs::game::DLL_NAME = "client.dll";
|
|
attach_io = true;
|
|
attach_qma = true;
|
|
break;
|
|
}
|
|
|
|
// LovePlus
|
|
if (check_dll("arkklp.dll")) {
|
|
avs::game::DLL_NAME = "arkklp.dll";
|
|
attach_io = true;
|
|
attach_loveplus = true;
|
|
attach_cpusbxpkm_printer = true;
|
|
break;
|
|
}
|
|
|
|
// Steel Chronicle
|
|
if (check_dll("arkkgg.dll")) {
|
|
avs::game::DLL_NAME = "arkkgg.dll";
|
|
attach_io = true;
|
|
attach_sc = true;
|
|
easrv_maint = false;
|
|
break;
|
|
}
|
|
|
|
// Mahjong Fight Club
|
|
if (check_dll("allinone.dll")) {
|
|
avs::game::DLL_NAME = "system.dll";
|
|
attach_io = true;
|
|
attach_mfc = true;
|
|
break;
|
|
|
|
// Mahjong Fight Club - 2025?
|
|
// they removed allinone.dll and moved i/o into system.dll
|
|
} else if (check_dll("system.dll") && fileutils::file_exists("data/mfc.ini")) {
|
|
avs::game::DLL_NAME = "system.dll";
|
|
attach_io = true;
|
|
attach_mfc = true;
|
|
break;
|
|
}
|
|
|
|
// FutureTomTom
|
|
if (check_dll("arkmmd.dll")) {
|
|
avs::game::DLL_NAME = "arkmmd.dll";
|
|
attach_io = true;
|
|
attach_ftt = true;
|
|
|
|
// the game is windowed by default unless we set the env
|
|
if (!GRAPHICS_WINDOWED) {
|
|
SetEnvironmentVariable("DAMAC_VIEWER_FULLSCREEN", "0");
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// Scotto
|
|
if (check_dll("scotto.dll")) {
|
|
avs::game::DLL_NAME = "scotto.dll";
|
|
attach_io = true;
|
|
attach_scotto = true;
|
|
break;
|
|
}
|
|
|
|
// TsumTsum
|
|
if (check_dll("arko26.dll")) {
|
|
avs::game::DLL_NAME = "arko26.dll";
|
|
attach_io = true;
|
|
break;
|
|
}
|
|
|
|
// DANCERUSH
|
|
if (check_dll("superstep.dll")) {
|
|
avs::game::DLL_NAME = "superstep.dll";
|
|
attach_io = true;
|
|
attach_drs = true;
|
|
break;
|
|
}
|
|
|
|
// Winning Eleven 2012
|
|
if (check_dll("weac12_bootstrap_release.dll")) {
|
|
avs::game::DLL_NAME = "weac12_bootstrap_release.dll";
|
|
attach_io = true;
|
|
attach_we = true;
|
|
break;
|
|
}
|
|
|
|
// Winning Eleven 2014
|
|
if (check_dll("arknck.dll")) {
|
|
avs::game::DLL_NAME = "arknck.dll";
|
|
attach_io = true;
|
|
attach_we = true;
|
|
show_cursor_if_no_touch = true;
|
|
break;
|
|
}
|
|
|
|
// Otoca D'or
|
|
if (check_dll("arkkep.dll")) {
|
|
avs::game::DLL_NAME = "arkkep.dll";
|
|
attach_io = true;
|
|
attach_otoca = true;
|
|
break;
|
|
}
|
|
|
|
// Silent Scope: Bone Eater
|
|
if (check_dll("arkndd.dll")) {
|
|
avs::game::DLL_NAME = "arkndd.dll";
|
|
attach_io = true;
|
|
attach_silentscope = true;
|
|
break;
|
|
}
|
|
|
|
// Ongaku Paradise
|
|
if (check_dll("arkjc9.dll")) {
|
|
avs::game::DLL_NAME = "arkjc9.dll";
|
|
attach_io = true;
|
|
attach_onpara = true;
|
|
break;
|
|
}
|
|
|
|
// Chase Chase Jokers
|
|
if (check_dll("kamunity.dll") && fileutils::file_exists("game/chaseproject.exe")) {
|
|
avs::game::DLL_NAME = "kamunity.dll";
|
|
attach_io = true;
|
|
attach_ccj = true;
|
|
show_cursor_if_no_touch = true;
|
|
break;
|
|
}
|
|
|
|
// QuizKnock STADIUM
|
|
if (check_dll("kamunity.dll") && fileutils::file_exists("game/uks.exe")) {
|
|
avs::game::DLL_NAME = "kamunity.dll";
|
|
attach_io = true;
|
|
attach_qks = true;
|
|
show_cursor_if_no_touch = true;
|
|
break;
|
|
}
|
|
|
|
// Mahjong Fight Girl
|
|
if (check_dll("kamunity.dll") && fileutils::dir_exists("game/MFGClient_Data")) {
|
|
avs::game::DLL_NAME = "kamunity.dll";
|
|
attach_io = true;
|
|
attach_mfg = true;
|
|
launcher::signal::USE_VEH_WORKAROUND = true;
|
|
show_cursor_if_no_touch = true;
|
|
break;
|
|
}
|
|
|
|
// Polaris Chord
|
|
if (check_dll("kamunity.dll") && fileutils::file_exists("game/svm.exe")) {
|
|
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
|
|
if (check_dll("kamunity.dll") && fileutils::file_exists("game/bsac_app.exe")) {
|
|
avs::game::DLL_NAME = "kamunity.dll";
|
|
attach_io = true;
|
|
attach_bc = true;
|
|
show_cursor_if_no_touch = true;
|
|
break;
|
|
}
|
|
|
|
// try module path
|
|
if (!module_path_tried) {
|
|
module_path_tried = true;
|
|
|
|
MODULE_PATH /= "modules";
|
|
SetDllDirectoryW(MODULE_PATH.c_str());
|
|
|
|
MODULE_PATH /= "";
|
|
|
|
continue;
|
|
}
|
|
|
|
// usage error
|
|
if (!cfg::CONFIGURATOR_STANDALONE
|
|
&& (!CHECK_DLL_IGNORE_ARCH)) {
|
|
log_warning(
|
|
"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 (do not specify -exec or -modules if you don't know what you're doing)\n\n"
|
|
);
|
|
|
|
log_fatal("launcher", "module auto detection failed, see log.txt for troubleshooting");
|
|
}
|
|
break;
|
|
|
|
} while (true);
|
|
}
|
|
|
|
// set error mode to show all errors
|
|
SetErrorMode(0);
|
|
|
|
// set the AVS heap size to a default value varying by game
|
|
avs::core::set_default_heap_size(avs::game::DLL_NAME);
|
|
|
|
// load the games
|
|
std::vector<games::Game *> games;
|
|
if (attach_popn) {
|
|
games.push_back(new games::popn::POPNGame());
|
|
}
|
|
if (attach_bbc) {
|
|
avs::core::set_default_heap_size("bsch.dll");
|
|
games.push_back(new games::bbc::BBCGame());
|
|
}
|
|
if (attach_ddr) {
|
|
avs::core::set_default_heap_size("arkmdxp3.dll");
|
|
games.push_back(new games::ddr::DDRGame());
|
|
}
|
|
if (attach_iidx) {
|
|
avs::core::set_default_heap_size("bm2dx.dll");
|
|
games.push_back(new games::iidx::IIDXGame());
|
|
}
|
|
if (attach_sdvx) {
|
|
avs::core::set_default_heap_size("soundvoltex.dll");
|
|
games.push_back(new games::sdvx::SDVXGame());
|
|
}
|
|
if (attach_jb) {
|
|
avs::core::set_default_heap_size("jubeat.dll");
|
|
games.push_back(new games::jb::JBGame());
|
|
}
|
|
if (attach_nostalgia) {
|
|
avs::core::set_default_heap_size("nostalgia.dll");
|
|
games.push_back(new games::nost::NostGame());
|
|
}
|
|
if (attach_gitadora) {
|
|
games.push_back(new games::gitadora::GitaDoraGame());
|
|
}
|
|
if (attach_hpm) {
|
|
avs::core::set_default_heap_size("popn.dll");
|
|
games.push_back(new games::hpm::HPMGame());
|
|
}
|
|
if (attach_mga) {
|
|
games.push_back(new games::mga::MGAGame());
|
|
}
|
|
if (attach_sc) {
|
|
games.push_back(new games::sc::SCGame());
|
|
}
|
|
if (attach_rb) {
|
|
games.push_back(new games::rb::RBGame());
|
|
}
|
|
if (attach_shogikai) {
|
|
games.push_back(new games::shogikai::ShogikaiGame());
|
|
}
|
|
if (attach_qma) {
|
|
avs::core::set_default_heap_size("client.dll");
|
|
games.push_back(new games::qma::QMAGame());
|
|
}
|
|
if (attach_dea) {
|
|
games.push_back(new games::dea::DEAGame());
|
|
}
|
|
if (attach_mfc) {
|
|
avs::core::set_default_heap_size("system.dll");
|
|
games.push_back(new games::mfc::MFCGame());
|
|
}
|
|
if (attach_ftt) {
|
|
avs::core::set_default_heap_size("arkmmd.dll");
|
|
games.push_back(new games::ftt::FTTGame());
|
|
}
|
|
if (attach_bs) {
|
|
games.push_back(new games::bs::BSGame());
|
|
}
|
|
if (attach_loveplus) {
|
|
games.push_back(new games::loveplus::LovePlusGame());
|
|
}
|
|
if (attach_scotto) {
|
|
avs::core::set_default_heap_size("scotto.dll");
|
|
games.push_back(new games::scotto::ScottoGame());
|
|
}
|
|
if (attach_rf3d) {
|
|
games.push_back(new games::rf3d::RF3DGame());
|
|
}
|
|
if (attach_museca) {
|
|
games.push_back(new games::museca::MusecaGame());
|
|
}
|
|
if (attach_drs) {
|
|
avs::core::set_default_heap_size("superstep.dll");
|
|
games.push_back(new games::drs::DRSGame());
|
|
}
|
|
if (attach_we) {
|
|
games.push_back(new games::we::WEGame());
|
|
}
|
|
if (attach_otoca) {
|
|
games.push_back(new games::otoca::OtocaGame());
|
|
}
|
|
if (attach_silentscope) {
|
|
games.push_back(new games::silentscope::SilentScopeGame());
|
|
}
|
|
if (attach_pcm) {
|
|
games.push_back(new games::pcm::PCMGame());
|
|
}
|
|
if (attach_onpara) {
|
|
avs::core::set_default_heap_size("arkjc9.dll");
|
|
games.push_back(new games::onpara::OnparaGame());
|
|
}
|
|
if (attach_bc) {
|
|
avs::core::set_default_heap_size("kamunity.dll");
|
|
games.push_back(new games::bc::BCGame());
|
|
}
|
|
if (attach_ccj) {
|
|
avs::core::set_default_heap_size("kamunity.dll");
|
|
games.push_back(new games::ccj::CCJGame());
|
|
}
|
|
if (attach_qks) {
|
|
avs::core::set_default_heap_size("kamunity.dll");
|
|
games.push_back(new games::qks::QKSGame());
|
|
}
|
|
if (attach_mfg) {
|
|
avs::core::set_default_heap_size("kamunity.dll");
|
|
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
|
|
if (user_heap_size > 0) {
|
|
avs::core::HEAP_SIZE = user_heap_size;
|
|
}
|
|
|
|
// call pre-attach
|
|
for (auto game : games) {
|
|
game->pre_attach();
|
|
}
|
|
|
|
// run configuration utility
|
|
if (cfg_run || cfg::CONFIGURATOR_STANDALONE) {
|
|
// cardio thread for cfg
|
|
if (cardio_enabled) {
|
|
cardio_runner_start(true);
|
|
}
|
|
|
|
if (!midi_algo.has_value()) {
|
|
midi_algo = rawinput::MidiNoteAlgorithm::V2;
|
|
}
|
|
rawinput::set_midi_algorithm(midi_algo.value());
|
|
|
|
if (api_enable || api_debug) {
|
|
API_CONTROLLER = std::make_unique<api::Controller>(api_port, api_pass, api_pretty);
|
|
for (size_t i = 0; i < std::min(api_serial_port.size(), api_serial_baud.size()); i++) {
|
|
API_CONTROLLER->listen_serial(api_serial_port[i], api_serial_baud[i]);
|
|
}
|
|
}
|
|
exit(spicecfg_run(sextet_devices));
|
|
}
|
|
|
|
// log some DLLs found in path (purely for troubleshooting purposes to detect
|
|
// dxvk, ForceD3D9On12, ifs_layeredfs, etc)
|
|
libutils::warn_if_dll_exists("d3d8.dll");
|
|
libutils::warn_if_dll_exists("d3d9.dll");
|
|
libutils::warn_if_dll_exists("d3d10core.dll");
|
|
libutils::warn_if_dll_exists("d3d11.dll");
|
|
libutils::warn_if_dll_exists("d3d12.dll");
|
|
libutils::warn_if_dll_exists("dxgi.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
|
|
libutils::check_duplicate_dlls();
|
|
|
|
// print cpu features
|
|
if (!cfg::CONFIGURATOR_STANDALONE && dump_sysinfo) {
|
|
cpuutils::print_cpu_features();
|
|
sysutils::print_os();
|
|
sysutils::print_smbios();
|
|
sysutils::print_gpus();
|
|
}
|
|
|
|
// fix up monitor
|
|
if (options[launcher::Options::PrimaryMonitor].is_active()) {
|
|
change_primary_monitor(options[launcher::Options::PrimaryMonitor].value_text());
|
|
}
|
|
update_monitor_on_boot(monitor_orientation, GRAPHICS_FORCE_REFRESH);
|
|
|
|
// initialize raw input
|
|
RI_MGR = std::make_unique<rawinput::RawInputManager>();
|
|
for (const auto &device : sextet_devices) {
|
|
RI_MGR->sextet_register(device);
|
|
}
|
|
|
|
// print devices
|
|
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)
|
|
if (show_cursor_if_no_touch && !is_touch_available("launcher::main_implementation")) {
|
|
GRAPHICS_SHOW_CURSOR = true;
|
|
}
|
|
|
|
// cardio
|
|
if (cardio_enabled) {
|
|
cardio_runner_start(true);
|
|
}
|
|
|
|
// load stubs
|
|
if (load_stubs) {
|
|
for (const auto &stub : STUBS) {
|
|
if (fileutils::verify_header_pe(MODULE_PATH / stub)) {
|
|
libutils::load_library(MODULE_PATH / stub);
|
|
} else {
|
|
log_warning("launcher", "failed to load stubs!");
|
|
load_stubs = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// locale hook
|
|
if (!lang_disable) {
|
|
hooks::lang::early_init();
|
|
}
|
|
|
|
// load DLLs
|
|
avs::core::load_dll();
|
|
avs::ea3::load_dll();
|
|
|
|
// net fix
|
|
if (!netfix_disable) {
|
|
networkhook_init();
|
|
}
|
|
|
|
// boot AVS
|
|
avs::core::boot();
|
|
|
|
// initialize SSL
|
|
if (!ssl_disable) {
|
|
avs::ssl::init();
|
|
}
|
|
|
|
// copy defaults to nvram
|
|
avs::core::copy_defaults();
|
|
|
|
// prepare patches
|
|
{
|
|
overlay::windows::PatchManager patch_manager(nullptr, false);
|
|
}
|
|
|
|
// load game
|
|
avs::game::load_dll();
|
|
|
|
// attach games
|
|
for (auto game : games) {
|
|
game->attach();
|
|
}
|
|
|
|
#if SPICE64 && !SPICE_XP
|
|
if (!cfg::CONFIGURATOR_STANDALONE) {
|
|
if (games::iidx::TDJ_CAMERA) {
|
|
games::iidx::init_camera_hooks();
|
|
}
|
|
if (!D3D9_DEVICE_HOOK_DISABLE) {
|
|
nvenc_hook::initialize();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// attach stub functions
|
|
if (!load_stubs) {
|
|
stubs::attach();
|
|
}
|
|
|
|
// locale hook
|
|
if (!lang_disable) {
|
|
hooks::lang::init();
|
|
}
|
|
|
|
// exception/signal hook
|
|
launcher::signal::attach();
|
|
|
|
// audio hook
|
|
hooks::audio::init();
|
|
|
|
// DirectInput 8 hook
|
|
hooks::input::dinput8::init();
|
|
|
|
// D3D9 hook
|
|
graphics_init();
|
|
|
|
// debug hook
|
|
debughook::attach();
|
|
|
|
// device debug
|
|
if (DEVICE_CREATEFILE_DEBUG) {
|
|
devicehook_init();
|
|
}
|
|
|
|
// server
|
|
if (easrv_port != 0u && !easrv_smart) {
|
|
easrv_start(easrv_port, easrv_maint, 4, 8);
|
|
}
|
|
|
|
// acio attach
|
|
if (attach_io || attach_acio) {
|
|
acio::attach();
|
|
}
|
|
|
|
// acio icca attach
|
|
if (attach_icca) {
|
|
acio::attach_icca();
|
|
}
|
|
|
|
// device attach
|
|
if (attach_io || attach_device) {
|
|
spicedevice_attach();
|
|
}
|
|
|
|
// ext dev attach
|
|
if (attach_io || attach_extdev) {
|
|
extdev_attach();
|
|
}
|
|
|
|
// ami 2000 card reader attach
|
|
if (attach_io || attach_ami2000) {
|
|
ami2000_attach();
|
|
}
|
|
|
|
// sci unit attach
|
|
if (attach_io || attach_sciunit) {
|
|
sciunit_attach();
|
|
}
|
|
|
|
// SDVX printer attach
|
|
if (attach_cpusbxpkm_printer) {
|
|
games::shared::printer_attach();
|
|
}
|
|
|
|
// net fix
|
|
if (!netfix_disable) {
|
|
networkhook_init();
|
|
}
|
|
|
|
update_msvcrt_args(argc, argv);
|
|
|
|
// load hooks
|
|
for (auto &hook : game_hooks) {
|
|
log_info("launcher", "loading hook DLL {}", hook);
|
|
libutils::print_dll_info(hook);
|
|
HMODULE module;
|
|
if (!(module = libutils::try_library(hook))) {
|
|
log_warning("launcher", "failed to load hook {}: {}", hook, get_last_error_string());
|
|
deferredlogs::defer_error_messages({
|
|
fmt::format("failed to load hook {}:", hook),
|
|
fmt::format(" {}", get_last_error_string())
|
|
});
|
|
} else {
|
|
bt5api_hook(module);
|
|
sdk::register_sdk_hooks(hook, module);
|
|
}
|
|
}
|
|
|
|
// layeredfs
|
|
if (fileutils::dir_exists("data_mods") &&
|
|
GetModuleHandleA("ifs_hook.dll") == nullptr) {
|
|
log_warning("launcher", "data_mods directory found, but ifs_hook.dll is not loaded; mods will not load");
|
|
deferredlogs::defer_error_messages({
|
|
"data_mods directory was found, but ifs_hook.dll is not loaded",
|
|
" your mods will not load",
|
|
" to fix this, download ifs_layeredfs and add it as a DLL hook (-k)",
|
|
" https://github.com/mon/ifs_layeredfs"
|
|
});
|
|
}
|
|
|
|
// apply patches
|
|
{
|
|
overlay::windows::PatchManager patch_manager(nullptr, true);
|
|
}
|
|
|
|
// load AVS-EA3
|
|
avs::ea3::boot(easrv_port, easrv_maint, easrv_smart);
|
|
|
|
// eamuse init
|
|
eamuse_autodetect_game();
|
|
|
|
// unis device hook
|
|
unisintrhook_init();
|
|
|
|
// BT5API
|
|
if (BT5API_ENABLED) {
|
|
bt5api_init();
|
|
}
|
|
|
|
// init SDK
|
|
sdk::init_sdk_modules();
|
|
|
|
// API
|
|
if (api_enable || std::min(api_serial_port.size(), api_serial_baud.size()) > 0) {
|
|
API_CONTROLLER = std::make_unique<api::Controller>(api_port, api_pass, api_pretty);
|
|
}
|
|
for (size_t i = 0; i < std::min(api_serial_port.size(), api_serial_baud.size()); i++) {
|
|
API_CONTROLLER->listen_serial(api_serial_port[i], api_serial_baud[i]);
|
|
}
|
|
|
|
// start coin input thread
|
|
eamuse_coin_start_thread();
|
|
|
|
// pin macro
|
|
if (!cfg::CONFIGURATOR_STANDALONE && PIN_MACRO_ENABLED) {
|
|
eamuse_pin_macro_start_thread();
|
|
}
|
|
|
|
// print PEB
|
|
if (peb_print) {
|
|
peb::peb_print();
|
|
}
|
|
|
|
// enable automap
|
|
if (automap) {
|
|
avs::automap::enable();
|
|
}
|
|
|
|
// initialize rich presence
|
|
if (rich_presence) {
|
|
richpresence::init();
|
|
}
|
|
|
|
// turn off controlled game lights
|
|
auto lights = games::get_lights(eamuse_get_game());
|
|
if (lights) {
|
|
for (auto &light : *lights) {
|
|
GameAPI::Lights::writeLight(RI_MGR, light, 0.f);
|
|
}
|
|
RI_MGR->devices_flush_output();
|
|
}
|
|
|
|
// update rawinput midi algorithm, which is game-dependent
|
|
if (!midi_algo.has_value()) {
|
|
if (games::gitadora::is_drum() || avs::game::is_model("MMD")) {
|
|
// GITADORA DrumMania, FutureTomTom
|
|
midi_algo = rawinput::MidiNoteAlgorithm::V2_DRUM;
|
|
} else {
|
|
midi_algo = rawinput::MidiNoteAlgorithm::V2;
|
|
}
|
|
}
|
|
rawinput::set_midi_algorithm(midi_algo.value());
|
|
|
|
// attach games
|
|
for (auto game : games) {
|
|
game->post_attach();
|
|
}
|
|
|
|
// game start
|
|
log_info("launcher", "calling game entry");
|
|
avs::game::entry_main();
|
|
|
|
// clear presence
|
|
richpresence::shutdown();
|
|
|
|
// detach games
|
|
for (auto game : games) {
|
|
game->detach();
|
|
}
|
|
|
|
// sci unit detach
|
|
if (attach_io || attach_sciunit) {
|
|
sciunit_detach();
|
|
}
|
|
|
|
// ext dev detach
|
|
if (attach_io || attach_extdev) {
|
|
extdev_detach();
|
|
}
|
|
|
|
// device detach
|
|
if (attach_io || attach_device) {
|
|
spicedevice_detach();
|
|
}
|
|
|
|
// acio detach
|
|
if (attach_io || attach_acio) {
|
|
acio::detach();
|
|
}
|
|
|
|
// delete games
|
|
while (!games.empty()) {
|
|
delete games.back();
|
|
games.pop_back();
|
|
}
|
|
|
|
// free api controller
|
|
API_CONTROLLER.reset();
|
|
|
|
// stop coin input thread
|
|
eamuse_coin_stop_thread();
|
|
|
|
eamuse_pin_macro_stop_thread();
|
|
|
|
// BT5API
|
|
if (BT5API_ENABLED) {
|
|
bt5api_dispose();
|
|
}
|
|
|
|
sdk::fini_sdk_modules();
|
|
|
|
// stop raw input
|
|
RI_MGR.reset();
|
|
|
|
// debug hook
|
|
debughook::detach();
|
|
|
|
#ifndef NO_SCARD
|
|
// scard
|
|
scard_fini();
|
|
#endif
|
|
|
|
// stop reader thread in case it was running
|
|
stop_reader_thread();
|
|
|
|
// cardio
|
|
if (cardio_enabled) {
|
|
cardio_runner_stop();
|
|
}
|
|
|
|
// server
|
|
if (easrv_port != 0u) {
|
|
easrv_shutdown();
|
|
}
|
|
|
|
// AVS EA3 shutdown
|
|
avs::ea3::shutdown();
|
|
|
|
// AVS cleanup
|
|
avs::core::shutdown();
|
|
|
|
// dispose crypt
|
|
crypt::dispose();
|
|
|
|
// disable super exit
|
|
superexit::disable();
|
|
|
|
// disable poke
|
|
games::iidx::poke::disable();
|
|
|
|
#if SPICE64 && !SPICE_XP
|
|
games::iidx::camera_release();
|
|
#endif
|
|
|
|
// shutdown
|
|
log_warning("launcher", "end");
|
|
launcher::stop_subsystems();
|
|
|
|
return 0;
|
|
}
|
|
|
|
// https://github.com/spice2x/spice2x.github.io/issues/264
|
|
// huge ugly hack to work around things that broke when MinGW switched from msvcrt to ucrt
|
|
// this is done to ensure that any DLL hooks that rely on msvcrt continue to work
|
|
void update_msvcrt_args(int argc, char *argv[]) {
|
|
#if defined(_UCRT)
|
|
auto msvc = LoadLibraryA("msvcrt.dll");
|
|
if (!msvc) {
|
|
log_warning("launcher", "failed to load msvcrt.dll");
|
|
return;
|
|
}
|
|
|
|
// get __argc
|
|
PINT32 argc_addr = (PINT32)GetProcAddress(msvc, "__argc");
|
|
if (!argc_addr) {
|
|
log_warning("launcher", "failed to find msvcrt!__argc");
|
|
return;
|
|
}
|
|
try {
|
|
if (*argc_addr == argc) {
|
|
log_warning("launcher", "msvcrt!__argc is already set");
|
|
return;
|
|
}
|
|
} catch (const std::exception &e) {
|
|
log_warning("launcher", "exception while reading msvcrt!_argc: {}", e.what());
|
|
}
|
|
|
|
// get __argv
|
|
PCHAR **argv_addr = (PCHAR **)GetProcAddress(msvc, "__argv");
|
|
if (!argv_addr) {
|
|
log_warning("launcher", "failed to find msvcrt!__argv");
|
|
return;
|
|
}
|
|
|
|
// update them
|
|
try {
|
|
log_info("launcher", "msvcrt!__argc value before: {}", *argc_addr);
|
|
*argc_addr = argc;
|
|
log_info("launcher", "msvcrt!__argc value after: {}", *argc_addr);
|
|
*argv_addr = argv;
|
|
} catch (const std::exception &e) {
|
|
log_warning("launcher", "exception while messing with msvcrt!_argc and _argv: {}", e.what());
|
|
}
|
|
|
|
#else
|
|
log_misc("launcher", "not UCRT, skipping msvcrt!_argc / _argv hacks");
|
|
#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(),
|
|
button->getVKeyString()
|
|
);
|
|
} else {
|
|
log_misc(
|
|
"rawinput", " [{}] dev={}, vkey={}, analogtype={}",
|
|
button->getName(),
|
|
button->getDeviceIdentifier(),
|
|
button->getVKey(),
|
|
static_cast<uint32_t>(button->getAnalogType())
|
|
);
|
|
}
|
|
|
|
for (auto& alt : button->getAlternatives()) {
|
|
if (!alt.isValid()) {
|
|
continue;
|
|
}
|
|
if (alt.isNaive()) {
|
|
log_misc(
|
|
"rawinput", " [{}] (alt) dev=Naive, vkey={} ({})",
|
|
alt.getName(),
|
|
alt.getVKey(),
|
|
alt.getVKeyString()
|
|
);
|
|
} else {
|
|
log_misc(
|
|
"rawinput", " [{}] (alt) dev={}, vkey={}, analogtype={}",
|
|
alt.getName(),
|
|
alt.getDeviceIdentifier(),
|
|
alt.getVKey(),
|
|
static_cast<uint32_t>(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
|
|
int main(int argc, char *argv[]) {
|
|
return main_implementation(argc, argv);
|
|
}
|
|
#endif
|