spicetools/launcher/launcher.cpp

1972 lines
65 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 "external/layeredfs/hook.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/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/museca/museca.h"
#include "hooks/avshook.h"
#include "hooks/audio/audio.h"
#include "hooks/debughook.h"
#include "hooks/devicehook.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 "script/manager.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/vrutil.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/tapeled.h"
#include "util/time.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;
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);
}
}
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_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;
std::vector<std::string> sextet_devices;
// 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::OpenKFControl].value_bool()) {
CHECK_DLL_IGNORE_ARCH = true;
cfg::CONFIGURATOR_TYPE = cfg::ConfigType::KFControl;
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::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);
}
}
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;
}
}
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::IIDXTDJCamera].value_bool()) {
games::iidx::TDJ_CAMERA = true;
// Disable legacy behaviour to avoid conflict
games::iidx::DISABLE_CAMS = true;
}
if (options[launcher::Options::IIDXTDJCameraOverride].is_active()) {
games::iidx::TDJ_CAMERA_OVERRIDE = options[launcher::Options::IIDXTDJCameraOverride].value_text();
}
if (options[launcher::Options::IIDXTDJCameraRatio].is_active() &&
options[launcher::Options::IIDXTDJCameraRatio].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";
}
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::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::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::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();
}
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::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_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()) {
GRAPHICS_WINDOW_SIZE = options[launcher::Options::spice2x_WindowSize].value_text();
}
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();
// 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::spice2x_EnableSMXStage].value_bool()) {
rawinput::ENABLE_SMX_STAGE = 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
#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());
// 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()) {
poke::enable();
}
}
// 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;
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;
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;
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());
}
// 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) {
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) {
cpuutils::print_cpu_features();
}
// 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
if (!avs::core::load_dll()) {
log_fatal("launcher", "avs boot failure");
}
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();
// load game
avs::game::load_dll();
// VR
if (options[launcher::Options::VREnable].is_active()) {
vrutil::init();
}
// attach games
for (auto game : games) {
game->attach();
}
// 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"))
{
layeredfs::init();
}
// 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 scripts
script::manager_scan();
script::manager_boot();
// 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();
// 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();
}
// 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();
// clean up VR
vrutil::shutdown();
// script shutdown
script::manager_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();
// 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
poke::disable();
#ifdef SPICE64
games::iidx::camera_release();
#endif
// shutdown
log_warning("launcher", "end");
launcher::stop_subsystems();
return 0;
}
#ifndef SPICETOOLS_SPICECFG_STANDALONE
int main(int argc, char *argv[]) {
return main_implementation(argc, argv);
}
#endif