## Link to GitHub Issue, if one exists Fixes #276 ## Description of change Note: this change is not compatible with previous screen resize config; i.e., if you had the zoom setting dialed into a certain view, after this change it won't be the same area, so you'll have to set up a scene again. I think this is a worthwhile cost since the old logic is just broken in weird ways, and preserving old settings is really tedious math (for a feature that not many people use). Besides, this change will only use the new Scenes values from the JSON. Rewrite the DX9 image scaler logic. * Previously, the rendering surface was fixed at `4096*4096 px`. Now, this is relative to the backbuffer dimensions, which depends on the game & respects user provided `-forceres`. * Remove "center" option, make it the default. Above two changes fix the aspect ratio issue (scaling in portrait games not respecting screen ratio) and things breaking at higher res (1080p when zoomed out far enough, or when forced to run at 4k resolution for example) * Use `scenes` leaf of screen resize JSON config for Scene 1 as well, completely removing ourselves from being compatible with older spice2x versions for these values. * Add additional bounds check before calling `StretchRect` to avoid users getting stuck with a bad layout, which can kill performance. ## Compiling 🦾 ## Testing Tested 32 bit (popn / ddr), 64 bit (ldj), portrait and landscape modes (kfc)
2231 lines
75 KiB
C++
2231 lines
75 KiB
C++
#include <condition_variable>
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include <shlwapi.h>
|
|
#include <cfg/configurator.h>
|
|
|
|
#include "acio/acio.h"
|
|
#include "acio/icca/icca.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"
|
|
#include "external/scard/scard.h"
|
|
#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/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/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 "stubs/stubs.h"
|
|
#include "touch/touch.h"
|
|
#include "util/cpuutils.h"
|
|
#include "util/crypt.h"
|
|
#include "util/fileutils.h"
|
|
#include "util/libutils.h"
|
|
#include "util/logging.h"
|
|
#include "util/peb.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::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[]);
|
|
|
|
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_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_museca = 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);
|
|
|
|
// 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
|
|
);
|
|
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;
|
|
}
|
|
if (options[launcher::Options::EAmusementEmulation].value_bool() &&
|
|
options[launcher::Options::ServiceURL].is_active() &&
|
|
!cfg::CONFIGURATOR_STANDALONE) {
|
|
log_fatal(
|
|
"launcher",
|
|
"BAD EAMUSE SETTINGS ERROR\n\n\n"
|
|
"-------------------------------------------------------------------\n"
|
|
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
|
|
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
|
"A service URL is set **AND** E-Amusement emulation is enabled.\n"
|
|
"Either remove the service URL, or disable E-Amusement emulation.\n"
|
|
"Otherwise you may experience problems logging in.\n"
|
|
"-------------------------------------------------------------------\n\n\n"
|
|
);
|
|
}
|
|
if (options[launcher::Options::EAmusementEmulation].value_bool()) {
|
|
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::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::DisplayAdapter].is_active()) {
|
|
D3D9_ADAPTER = options[launcher::Options::DisplayAdapter].value_uint32();
|
|
}
|
|
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::spice2x_AutoOrientation].is_active()) {
|
|
GRAPHICS_ADJUST_ORIENTATION =
|
|
(graphics_orientation)options[launcher::Options::spice2x_AutoOrientation].value_uint32();
|
|
} else if (options[launcher::Options::AdjustOrientation].value_bool()) {
|
|
GRAPHICS_ADJUST_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::EnableSCIUNITModule].value_bool()) {
|
|
attach_sciunit = 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::SDVXDisableCameras].value_bool()) {
|
|
games::sdvx::DISABLECAMS = 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::LoadIIDXModule].value_bool()) {
|
|
attach_iidx = true;
|
|
}
|
|
if (options[launcher::Options::IIDXCameraOrderFlip].value_bool()) {
|
|
games::iidx::FLIP_CAMS = true;
|
|
}
|
|
if (options[launcher::Options::IIDXDisableCameras].value_bool()) {
|
|
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;
|
|
}
|
|
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::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();
|
|
}
|
|
#endif
|
|
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::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::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::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::LoadMusecaModule].value_bool()) {
|
|
attach_museca = true;
|
|
}
|
|
if (options[launcher::Options::DDR43Mode].value_bool()) {
|
|
games::ddr::SDMODE = 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;
|
|
}
|
|
if (options[launcher::Options::SDVXPrinterOutputOverwrite].value_bool()) {
|
|
games::shared::PRINTER_OVERWRITE_FILE = true;
|
|
}
|
|
for (auto &path : options[launcher::Options::SDVXPrinterOutputPath].values_text()) {
|
|
games::shared::PRINTER_PATH.push_back(path);
|
|
}
|
|
for (auto &path : options[launcher::Options::SDVXPrinterOutputFormat].values_text()) {
|
|
games::shared::PRINTER_FORMAT.push_back(path);
|
|
}
|
|
if (options[launcher::Options::SDVXPrinterJPGQuality].is_active()) {
|
|
games::shared::PRINTER_JPG_QUALITY = options[launcher::Options::SDVXPrinterJPGQuality].value_uint32();
|
|
}
|
|
if (options[launcher::Options::SDVXPrinterOutputClear].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::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()) {
|
|
CARD_OVERRIDES[0] = options[launcher::Options::Player1Card].value_text();
|
|
}
|
|
if (options[launcher::Options::Player2Card].is_active()) {
|
|
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);
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
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::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::CONFIGURATOR_STANDALONE) {
|
|
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::DisableAudioHooks].value_bool()) {
|
|
hooks::audio::ENABLED = false;
|
|
}
|
|
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::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 {
|
|
log_warning("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();
|
|
|
|
// IIDX Windowed Subscreen
|
|
if (options[launcher::Options::spice2x_IIDXWindowedSubscreenSize].is_active()) {
|
|
GRAPHICS_IIDX_WSUB_SIZE = options[launcher::Options::spice2x_IIDXWindowedSubscreenSize].value_text();
|
|
}
|
|
if (options[launcher::Options::spice2x_IIDXWindowedSubscreenPosition].is_active()) {
|
|
GRAPHICS_IIDX_WSUB_POS = options[launcher::Options::spice2x_IIDXWindowedSubscreenPosition].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::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::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::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();
|
|
}
|
|
|
|
// 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
|
|
#ifdef SPICE64
|
|
log_info("launcher", "SpiceTools Bootstrap (x64) (spice2x)");
|
|
#else
|
|
log_info("launcher", "SpiceTools Bootstrap (x32) (spice2x)");
|
|
#endif
|
|
log_info("launcher", "{}", VERSION_STRING);
|
|
|
|
// 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());
|
|
|
|
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 {
|
|
log_warning("launcher", "failed to parse -forceres");
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
// deleted options
|
|
if (options[launcher::Options::OpenKFControl].value_bool()) {
|
|
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);
|
|
HMODULE module;
|
|
if (!(module = libutils::try_library(hook))) {
|
|
log_warning("launcher", "failed to load early hook {}", hook);
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
|
|
// automatically show cursor when no touchscreen is available
|
|
if (!is_touch_available()) {
|
|
GRAPHICS_SHOW_CURSOR = 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;
|
|
|
|
// automatically show cursor when no touchscreen is available
|
|
if (!is_touch_available()) {
|
|
GRAPHICS_SHOW_CURSOR = 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_gitadora = true;
|
|
break;
|
|
}
|
|
|
|
// Nostalgia
|
|
if (check_dll("nostalgia.dll")) {
|
|
avs::game::DLL_NAME = "nostalgia.dll";
|
|
attach_io = true;
|
|
attach_nostalgia = true;
|
|
|
|
// automatically show cursor when no touchscreen is available
|
|
if (!is_touch_available()) {
|
|
GRAPHICS_SHOW_CURSOR = true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// Bishi Bashi Channel
|
|
if (check_dll("bsch.dll")) {
|
|
avs::game::DLL_NAME = "bsch.dll";
|
|
attach_io = true;
|
|
attach_bbc = true;
|
|
break;
|
|
}
|
|
|
|
// HELLO! Pop'n Music
|
|
if (check_dll("popn.dll")) {
|
|
avs::game::DLL_NAME = "popn.dll";
|
|
attach_io = true;
|
|
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;
|
|
}
|
|
|
|
// 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) {
|
|
GRAPHICS_WINDOWED = false;
|
|
} else {
|
|
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;
|
|
|
|
// automatically show cursor when no touchscreen is available
|
|
if (!is_touch_available()) {
|
|
GRAPHICS_SHOW_CURSOR = 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;
|
|
// automatically show cursor when no touchscreen is available
|
|
if (!is_touch_available()) {
|
|
GRAPHICS_SHOW_CURSOR = 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;
|
|
// automatically show cursor when no touchscreen is available
|
|
if (!is_touch_available()) {
|
|
GRAPHICS_SHOW_CURSOR = 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;
|
|
// automatically show cursor when no touchscreen is available
|
|
if (!is_touch_available()) {
|
|
GRAPHICS_SHOW_CURSOR = 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;
|
|
// automatically show cursor when no touchscreen is available
|
|
if (!is_touch_available()) {
|
|
GRAPHICS_SHOW_CURSOR = 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_fatal("launcher", "module auto detection failed.");
|
|
}
|
|
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());
|
|
}
|
|
|
|
// 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));
|
|
}
|
|
|
|
// print cpu features
|
|
if (!cfg::CONFIGURATOR_STANDALONE && dump_sysinfo) {
|
|
cpuutils::print_cpu_features();
|
|
sysutils::print_os();
|
|
sysutils::print_smbios();
|
|
sysutils::print_gpus();
|
|
}
|
|
|
|
// 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();
|
|
|
|
// 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();
|
|
}
|
|
|
|
#ifdef SPICE64
|
|
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();
|
|
}
|
|
|
|
// 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();
|
|
}
|
|
|
|
// 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);
|
|
|
|
// load hooks
|
|
for (auto &hook : game_hooks) {
|
|
log_info("launcher", "loading hook DLL {}", hook);
|
|
HMODULE module;
|
|
if (!(module = libutils::try_library(hook))) {
|
|
log_warning("launcher", "failed to load hook {}", hook);
|
|
} else {
|
|
bt5api_hook(module);
|
|
}
|
|
}
|
|
|
|
// 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();
|
|
}
|
|
|
|
// 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();
|
|
}
|
|
|
|
// stop raw input
|
|
RI_MGR.reset();
|
|
|
|
// debug hook
|
|
debughook::detach();
|
|
|
|
// scard
|
|
scard_fini();
|
|
|
|
// 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();
|
|
|
|
#ifdef SPICE64
|
|
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
|
|
}
|
|
|
|
#ifndef SPICETOOLS_SPICECFG_STANDALONE
|
|
int main(int argc, char *argv[]) {
|
|
return main_implementation(argc, argv);
|
|
}
|
|
#endif
|