diff --git a/.gitignore b/.gitignore index 07a2a7a..8dfb3a6 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,9 @@ dist/* external/cv2pdb/* -.ccache/* \ No newline at end of file +.ccache/* + +# Visual Studio +.vs +out +CMakeSettings.json diff --git a/.idea/.gitignore b/.idea/.gitignore index 13566b8..3588def 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -6,3 +6,5 @@ # Datasource local storage ignored files /dataSources/ /dataSources.local.xml +# Unnecessary plugin data +/markdown-navigator.xml diff --git a/.idea/runConfigurations/Deploy_Extra_x86_.xml b/.idea/runConfigurations/Deploy_Extra_x86_.xml index bca6430..dd7d022 100644 --- a/.idea/runConfigurations/Deploy_Extra_x86_.xml +++ b/.idea/runConfigurations/Deploy_Extra_x86_.xml @@ -16,6 +16,7 @@ + diff --git a/.idea/runConfigurations/spicetools_stubs_cpusbxpkm.xml b/.idea/runConfigurations/spicetools_stubs_cpusbxpkm.xml new file mode 100644 index 0000000..167d0da --- /dev/null +++ b/.idea/runConfigurations/spicetools_stubs_cpusbxpkm.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index bc12575..5d0d8f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,25 @@ if(MSVC) # enable COMDAT folding for even smaller release builds add_link_options("$<$:/OPT:ICF>") + + # always use UTF-8 (fix 4819) + add_compile_options("/utf-8") + + # spectre mitigation warning + add_compile_options("/wd5045") + + # implicit type convert warnings + add_compile_options("/wd4244") + add_compile_options("/wd4267") + add_compile_options("/wd4305") + + # unreferenced local variable + add_compile_options("/wd4101") + + # warning in winbase.h?? + add_compile_options("/wd5039") + + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # disable warnings about using non _s variants like strncpy add_compile_definitions(_CRT_SECURE_NO_WARNINGS) @@ -124,8 +143,8 @@ else() # https://github.com/msys2/MINGW-packages/pull/6880 # some games crash if some DLLS load above 4GB VA, so manually set base address to standard 32-bit VA, # and might as well double make sure ASLR is disabled here - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000,--enable-stdcall-fixup") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000,--enable-stdcall-fixup") # set visibility to hidden set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fvisibility=hidden") @@ -160,8 +179,8 @@ else() set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-fno-ident -ffunction-sections -fdata-sections") # linker fix to load below 4GB - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000,--enable-stdcall-fixup") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000,--enable-stdcall-fixup") # set visibility to hidden set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fvisibility=hidden") @@ -184,8 +203,8 @@ else() set(CMAKE_CXX_FLAGS_DEBUG "-gdwarf") # linker fix to load below 4GB - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--disable-dynamicbase,--image-base=0x400000") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--disable-dynamicbase,--image-base=0x400000") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--disable-dynamicbase,--image-base=0x400000,--enable-stdcall-fixup") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--disable-dynamicbase,--image-base=0x400000,--enable-stdcall-fixup") # enable debug symbols on level 3 and keep frame pointers set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g3 -fno-omit-frame-pointer") @@ -443,6 +462,9 @@ set(SOURCE_FILES ${SOURCE_FILES} games/mfg/mfg.cpp games/mfg/io.cpp games/mfg/bi2a_hook.cpp + games/pc/pc.cpp + games/pc/io.cpp + games/pc/bi2x_hook.cpp # hooks hooks/audio/audio.cpp @@ -592,6 +614,8 @@ set(SOURCE_FILES ${SOURCE_FILES} util/lz77.cpp util/tapeled.cpp util/execexe.cpp + util/dependencies.cpp + util/deferlog.cpp ) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Source Files" FILES ${SOURCE_FILES}) @@ -742,6 +766,16 @@ if(NOT MSVC) set_target_properties(spicetools_stubs_nvEncodeAPI64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64") endif() +# cpusbxpkm.dll (32 bit) +set(SOURCE_FILES stubs/cpusbxpkm.cpp) +add_library(spicetools_stubs_cpusbxpkm SHARED ${SOURCE_FILES} stubs/cpusbxpkm.def) +set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES PREFIX "") +set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES OUTPUT_NAME "cpusbxpkm") + +if(NOT MSVC) + set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32") +endif() + # output directories #################### @@ -751,7 +785,7 @@ set_target_properties(spicetools_cfg RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools") # output 32bit -set_target_properties(spicetools_spice spicetools_spice_laa spicetools_stubs_kbt spicetools_stubs_kld +set_target_properties(spicetools_spice spicetools_spice_laa spicetools_stubs_kbt spicetools_stubs_kld spicetools_stubs_cpusbxpkm PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive32" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32" diff --git a/README.md b/README.md index e7c754d..f224037 100644 --- a/README.md +++ b/README.md @@ -247,6 +247,25 @@ which also means that your hex edits are applicable directly. - sets the contents of the 16 segment display and disables writes from game - ticker_reset() - re-enables writes from game +- tapeled_get(name: str, ...) + - returns a list containing a dict of the current tape LED states. The dict keys are: + - `Stage Left` + - `Stage Right` + - `Cabinet Left` + - `Cabinet Right` + - `Control Panel Under` + - `Ceiling Left` + - `Title Left` + - `Title Right` + - `Ceiling Right` + - `Touch Panel Left` + - `Touch Panel Right` + - `Side Panel Left Inner` + - `Side Panel Left Outer` + - `Side Panel Left` + - `Side Panel Right Outer` + - `Side Panel Right Inner` + - `Side Panel Right` #### LCD - info() diff --git a/acio/acio.cpp b/acio/acio.cpp index 2ae28f4..be8546f 100644 --- a/acio/acio.cpp +++ b/acio/acio.cpp @@ -41,6 +41,7 @@ namespace acio { HINSTANCE DLL_INSTANCE = nullptr; std::vector MODULES; + std::atomic IO_INIT_IN_PROGRESS = false; } /* @@ -58,6 +59,7 @@ static inline acio::HookMode get_hookmode() { void acio::attach() { log_info("acio", "SpiceTools ACIO"); + IO_INIT_IN_PROGRESS = true; // load settings and instance acio::DLL_INSTANCE = LoadLibraryA("libacio.dll"); @@ -111,6 +113,8 @@ void acio::attach() { for (auto &module : MODULES) { module->attach(); } + + IO_INIT_IN_PROGRESS = false; } void acio::attach_icca() { diff --git a/acio/acio.h b/acio/acio.h index b2f1838..e9497a2 100644 --- a/acio/acio.h +++ b/acio/acio.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -11,6 +12,7 @@ namespace acio { // globals extern HINSTANCE DLL_INSTANCE; extern std::vector MODULES; + extern std::atomic IO_INIT_IN_PROGRESS; void attach(); void attach_icca(); diff --git a/acio2emu/handle.cpp b/acio2emu/handle.cpp index 2e6a86e..155ac73 100644 --- a/acio2emu/handle.cpp +++ b/acio2emu/handle.cpp @@ -31,7 +31,7 @@ namespace acio2emu { } }; - IOBHandle::IOBHandle(std::wstring device) : device_(device) { + IOBHandle::IOBHandle(LPCWSTR device) : device_(device) { nodes_[0] = std::make_unique(this); } diff --git a/acio2emu/handle.h b/acio2emu/handle.h index 5939d54..d24bb22 100644 --- a/acio2emu/handle.h +++ b/acio2emu/handle.h @@ -26,7 +26,7 @@ namespace acio2emu { void forward_packet_(const Packet &packet); public: - IOBHandle(std::wstring device); + IOBHandle(LPCWSTR device); bool register_node(std::unique_ptr node); int number_of_nodes() const; diff --git a/acioemu/icca.cpp b/acioemu/icca.cpp index 2733aa7..56fce06 100644 --- a/acioemu/icca.cpp +++ b/acioemu/icca.cpp @@ -102,7 +102,7 @@ bool ICCADevice::parse_msg(MessageData *msg_in, // send version data auto msg = this->create_msg(msg_in, MSG_VERSION_SIZE); if ( - avs::game::is_model({"LDJ", "TBS", "UJK"}) || + avs::game::is_model({"LDJ", "TBS", "UJK", "XIF"}) || // SDVX Valkyrie cabinet mode (avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H')) ) { @@ -373,7 +373,7 @@ void ICCADevice::update_card(int unit) { bool kb_insert_press = false; // eamio keypress - kb_insert_press |= eamuse_get_keypad_state((size_t) unit) & (1 << EAM_IO_INSERT); + kb_insert_press |= static_cast(eamuse_get_keypad_state((size_t) unit) & (1 << EAM_IO_INSERT)); // check for card if (this->cards[unit] == nullptr && (eamuse_card_insert_consume(this->node_count, unit) || kb_insert_press)) { @@ -521,7 +521,7 @@ void ICCADevice::update_status(int unit) { buffer[10] = felica ? 0x01 : 0x00; } else if ( - avs::game::is_model({"LDJ", "TBS"}) || + avs::game::is_model({"LDJ", "TBS", "XIF"}) || // SDVX Valkyrie cabinet mode (avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))) { diff --git a/api/modules/capture.cpp b/api/modules/capture.cpp index 9cab7e7..5bef6a3 100644 --- a/api/modules/capture.cpp +++ b/api/modules/capture.cpp @@ -9,6 +9,9 @@ using namespace rapidjson; namespace api::modules { + std::optional CAPTURE_QUALITY; + std::optional CAPTURE_DIVIDE; + static thread_local std::vector CAPTURE_BUFFER; Capture::Capture() : Module("capture") { @@ -44,12 +47,21 @@ namespace api::modules { int screen = 0; int quality = 70; int divide = 1; - if (req.params.Size() > 0 && req.params[0].IsUint()) + if (req.params.Size() > 0 && req.params[0].IsUint()) { screen = req.params[0].GetUint(); - if (req.params.Size() > 1 && req.params[1].IsUint()) + } + + if (CAPTURE_QUALITY.has_value()) { + quality = CAPTURE_QUALITY.value(); + } else if (req.params.Size() > 1 && req.params[1].IsUint()) { quality = req.params[1].GetUint(); - if (req.params.Size() > 2 && req.params[2].IsUint()) + } + + if (CAPTURE_DIVIDE.has_value()) { + divide = CAPTURE_DIVIDE.value(); + } else if (req.params.Size() > 2 && req.params[2].IsUint()) { divide = req.params[2].GetUint(); + } // receive JPEG data uint64_t timestamp = 0; diff --git a/api/modules/capture.h b/api/modules/capture.h index 8b02b02..fb8c55d 100644 --- a/api/modules/capture.h +++ b/api/modules/capture.h @@ -1,10 +1,15 @@ #pragma once +#include + #include "api/module.h" #include "api/request.h" namespace api::modules { + extern std::optional CAPTURE_QUALITY; + extern std::optional CAPTURE_DIVIDE; + class Capture : public Module { public: Capture(); diff --git a/api/modules/iidx.cpp b/api/modules/iidx.cpp index 43860b2..b65423f 100644 --- a/api/modules/iidx.cpp +++ b/api/modules/iidx.cpp @@ -1,13 +1,9 @@ #include "iidx.h" #include -#include -#include "games/iidx/iidx.h" -#include "external/rapidjson/document.h" using namespace std::placeholders; using namespace rapidjson; - namespace api::modules { // settings @@ -17,6 +13,11 @@ namespace api::modules { functions["ticker_get"] = std::bind(&IIDX::ticker_get, this, _1, _2); functions["ticker_set"] = std::bind(&IIDX::ticker_set, this, _1, _2); functions["ticker_reset"] = std::bind(&IIDX::ticker_reset, this, _1, _2); + functions["tapeled_get"] = std::bind(&IIDX::tapeled_get, this, _1, _2); + + for (auto &light : games::iidx::TAPELED_MAPPING) { + this->lights_by_names.emplace(light.lightName, light); + } } /** @@ -69,4 +70,51 @@ namespace api::modules { // disable read only games::iidx::IIDXIO_LED_TICKER_READONLY = false; } + + /** + * tapeled_get() + * tapeled_get(name: str, ...) + */ + void IIDX::tapeled_get(Request &req, Response &res) { + Value response_object(kObjectType); + + // all tape leds + if (req.params.Size() == 0) { + // Iterate through each device and dump its lights data into the response + for (const auto &mapping : games::iidx::TAPELED_MAPPING) { + copy_tapeled_data(res, response_object, mapping); + } + } else { + // specified light names + for (Value ¶m : req.params.GetArray()) { + // check params + if (!param.IsString()) { + error_type(res, "name", "string"); + return; + } + const auto name = param.GetString(); + if (const auto &it = lights_by_names.find(name); it != lights_by_names.end()) { + const auto mapping = it->second.get(); + copy_tapeled_data(res, response_object, mapping); + } + } + } + + res.add_data(response_object); + } + + void IIDX::copy_tapeled_data(Response &res, Value &response_object, const tapeledutils::tape_led &mapping) { + // Create an array for the light state + Value light_state(kArrayType); + light_state.Reserve(mapping.data.capacity() * 3, res.doc()->GetAllocator()); + for (const auto [r, g, b] : mapping.data) { + light_state.PushBack(r, res.doc()->GetAllocator()); + light_state.PushBack(g, res.doc()->GetAllocator()); + light_state.PushBack(b, res.doc()->GetAllocator()); + } + + // Can't use StringRef here, turns some strings partially into null bytes for some reason + Value light_name(mapping.lightName.c_str(), res.doc()->GetAllocator()); + response_object.AddMember(light_name, light_state, res.doc()->GetAllocator()); + } } diff --git a/api/modules/iidx.h b/api/modules/iidx.h index 50fea1e..41ae20e 100644 --- a/api/modules/iidx.h +++ b/api/modules/iidx.h @@ -2,6 +2,7 @@ #include "api/module.h" #include "api/request.h" +#include "games/iidx/iidx.h" namespace api::modules { @@ -10,10 +11,16 @@ namespace api::modules { IIDX(); private: + // state + robin_hood::unordered_map> lights_by_names; // function definitions void ticker_get(Request &req, Response &res); void ticker_set(Request &req, Response &res); void ticker_reset(Request &req, Response &res); + void tapeled_get(Request &req, Response &res); + + // helper + void copy_tapeled_data(Response &res, rapidjson::Value &response_object, const tapeledutils::tape_led &mapping); }; } diff --git a/api/resources/python/spiceapi/iidx.py b/api/resources/python/spiceapi/iidx.py index b2736e1..79050a5 100644 --- a/api/resources/python/spiceapi/iidx.py +++ b/api/resources/python/spiceapi/iidx.py @@ -16,3 +16,13 @@ def iidx_ticker_set(con: Connection, text: str): def iidx_ticker_reset(con: Connection): req = Request("iidx", "ticker_reset") con.request(req) + + +def iidx_tapeled_get(con: Connection, *light_names): + req = Request("iidx", "tapeled_get") + + for light_name in light_names: + req.add_param(light_name) + + res = con.request(req) + return res.get_data() diff --git a/avs/core.cpp b/avs/core.cpp index e46b549..59b648f 100644 --- a/avs/core.cpp +++ b/avs/core.cpp @@ -8,6 +8,8 @@ #include "external/robin_hood.h" #include "launcher/logger.h" +#include "launcher/signal.h" +#include "util/deferlog.h" #include "util/detour.h" #include "util/fileutils.h" #include "util/libutils.h" @@ -1741,7 +1743,17 @@ namespace avs { return; } - static void create_dir( + static void avs_dir_err(const std::filesystem::path &src_path) + { + deferredlogs::defer_error_messages({ + "AVS filesystem initialization failure was previously detected during boot!", + fmt::format(" ERROR: directory could not be created: {}", src_path.string().c_str()), + fmt::format(" if you see a crash, it may have been caused by bad contents in {}", avs::core::CFG_PATH.c_str()), + " fix the XML file and try again" + }); + } + + static void create_avs_dir( const std::string_view &avs_path, const std::string_view &src_path) { @@ -1750,6 +1762,7 @@ namespace avs { auto real_path = std::filesystem::absolute(src_path, err); if (err) { + avs_dir_err(real_path); log_warning("avs-core", "failed to resolve '{}' path: {}", avs_path, err.message()); return; } @@ -1759,7 +1772,9 @@ namespace avs { if (created) { log_info("avs-core", "created '{}' at '{}'", avs_path, real_path.string()); } + if (err) { + avs_dir_err(real_path); log_warning("avs-core", "failed to create '{}' folder at '{}': {}", avs_path, real_path.string(), @@ -1820,7 +1835,7 @@ namespace avs { return; } - create_dir(avs_path, device_path); + create_avs_dir(avs_path, device_path); } static void create_avs_config_fs_table( @@ -1875,7 +1890,7 @@ namespace avs { continue; } - create_dir(dst_path, src_path); + create_avs_dir(dst_path, src_path); } while ((vfs_node = property_node_traversal(vfs_node, TRAVERSE_NEXT_SEARCH_RESULT))); } @@ -1929,6 +1944,7 @@ namespace avs { static const char *LOG_LEVELS[] = { "disable", "fatal", "warning", "info", "misc", "all" }; char current_log_level_buffer[32] { 0 }; uint32_t current_log_level = 0; + std::string log_level_as_str; if (VERSION == AVSLEGACY || VERSION == AVS21360) { auto level_node = property_search(config, config_node, "/log/level"); @@ -1944,6 +1960,7 @@ namespace avs { { if (current_log_level < std::size(LOG_LEVELS)) { log_info("avs-core", "log level: {}", LOG_LEVELS[current_log_level]); + log_level_as_str = LOG_LEVELS[current_log_level]; } else { log_fatal("avs-core", "log level ({}) is invalid!", current_log_level); } @@ -1963,7 +1980,7 @@ namespace avs { level_node = property_node_create(config, config_node, NODE_TYPE_str, "/log/level", LOG_LEVELS[current_log_level]); } else { - log_fatal("avs-core", "log level ({}) is invalid!", current_log_level); + log_fatal("avs-core", "log level ({}) is invalid! *", current_log_level); } } @@ -1976,12 +1993,27 @@ namespace avs { if (property_node_refer(config, config_node, "/log/level", NODE_TYPE_str, current_log_level_buffer, sizeof(current_log_level_buffer)) > 0) { - log_info("avs-core", "log level: {}", current_log_level_buffer); + log_info("avs-core", "log level: {} *", current_log_level_buffer); + log_level_as_str = current_log_level_buffer; } else { - log_warning("avs-core", "log level: unknown"); + log_warning("avs-core", "log level: unknown *"); } } + if (log_level_as_str == "disable" || + log_level_as_str == "fatal" || + log_level_as_str == "warning" || + log_level_as_str == "info") { + + deferredlogs::defer_error_messages({ + fmt::format( + "log level is set to `{}` (either in avs-config.xml or using -loglevel)", log_level_as_str), + " this log file may have omitted important error messages from the game", + " if you are troubleshooting crashes or failures, it is recommended that you", + " set AVS Log Level (-loglevel) option to `all`", + }); + } + // fix time offset auto t_now = std::time(nullptr); auto tm_now = *std::gmtime(&t_now); diff --git a/avs/core.h b/avs/core.h index 779f25d..a99c238 100644 --- a/avs/core.h +++ b/avs/core.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace avs { namespace core { diff --git a/avs/ea3.cpp b/avs/ea3.cpp index 58598b4..2c804c5 100644 --- a/avs/ea3.cpp +++ b/avs/ea3.cpp @@ -41,6 +41,7 @@ namespace avs { int HTTP11 = -1; int URL_SLASH = -1; int PCB_TYPE = -1; + bool EA3_DEBUG_VERBOSE = false; // handle std::string VERSION_STR = "unknown"; @@ -356,6 +357,12 @@ namespace avs { } } + // fall back to default PCBID if node is not found + if (!EA3_PCBID[0] && PCBID_CUSTOM.empty()) { + log_warning("avs-ea3", "no PCBID set, falling back to default PCBID value (04040000000000000000)"); + PCBID_CUSTOM = "04040000000000000000"; + } + // custom PCBID if (!PCBID_CUSTOM.empty()) { @@ -399,13 +406,18 @@ namespace avs { avs::core::NODE_TYPE_str, "/ea3/id/accountid", &EA3_ACCOUNTID); } - // check if PCBID is defined + // check if PCBID is defined - should never hit, left for sanity check only if (avs::core::property_search(ea3_config, nullptr, "/ea3/id/pcbid") == nullptr) { log_fatal("avs-ea3", "node not found: /ea3/id/pcbid (try using -p to specify PCBID)"); } else if (strlen(EA3_PCBID) == 0) { log_fatal("avs-ea3", "no PCBID set (try using -p to specify PCBID)"); } + // remove since it can expose pcbid in logged requests + if (!EA3_DEBUG_VERBOSE) { + avs::core::property_search_remove_safe(ea3_config, nullptr, "/ea3/debug/verbose"); + } + // remember IDs char pcbid_buffer[256] { 0 }; char accountid_buffer[256] { 0 }; diff --git a/avs/ea3.h b/avs/ea3.h index 267daf8..d4a8d1a 100644 --- a/avs/ea3.h +++ b/avs/ea3.h @@ -28,6 +28,7 @@ namespace avs { extern int HTTP11; extern int URL_SLASH; extern int PCB_TYPE; + extern bool EA3_DEBUG_VERBOSE; // handle extern std::string VERSION_STR; diff --git a/avs/game.cpp b/avs/game.cpp index ca5c1a2..adefa8f 100644 --- a/avs/game.cpp +++ b/avs/game.cpp @@ -80,7 +80,7 @@ namespace avs { if (130 <= dll_path_s.length()) { log_warning( "avs-game", - "PATH TOO LONG WARNING\n\n\n" + "PATH TOO LONG WARNING\n\n" "-------------------------------------------------------------------\n" "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" "WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n" @@ -95,10 +95,26 @@ namespace avs { "-------------------------------------------------------------------\n\n", dll_path_s, dll_path_s.length()); } + + // ddr gamemdx.dll user error + if (avs::game::is_model("MDX") && DLL_NAME == "gamemdx.dll") { + log_fatal( + "ddr", + "BAD GAME DLL ERROR\n\n" + "!!! !!!\n" + "!!! -exec gamemdx.dll was specified !!!\n" + "!!! this is the wrong DLL; the game will not load !!!\n" + "!!! remove -exec argument and try again. !!!\n" + "!!! !!!\n" + ); + } + + // file not found on disk if (!fileutils::file_exists(dll_path)) { log_warning("avs-game", "game DLL could not be found on disk: {}", dll_path.string().c_str()); log_warning("avs-game", "double check -exec and -modules parameters; unless you know what you're doing, leave them blank"); } + if (fileutils::verify_header_pe(dll_path)) { DLL_INSTANCE = libutils::load_library(dll_path); } @@ -106,7 +122,7 @@ namespace avs { // load entry points dll_entry_init = (ENTRY_INIT_T) libutils::get_proc(DLL_INSTANCE, ENTRY_INIT_NAME); dll_entry_main = (ENTRY_MAIN_T) libutils::get_proc(DLL_INSTANCE, ENTRY_MAIN_NAME); - log_info("avs-game", "loaded successfully ({})", fmt::ptr(DLL_INSTANCE)); + log_info("avs-game", "loaded {} successfully ({})", DLL_NAME, fmt::ptr(DLL_INSTANCE)); } bool entry_init(char *sid_code, void *app_param) { diff --git a/build/resource.h b/build/resource.h index c356936..62f4372 100644 --- a/build/resource.h +++ b/build/resource.h @@ -2,7 +2,6 @@ #define IDC_STATIC -1 #define IDD_DIALOG1 129 -#define IDR_CHANGELOG 130 #define IDR_LICENSES 131 #define IDR_PATCHES 132 #define IDR_README 133 diff --git a/build_all.sh b/build_all.sh index 713512a..4283280 100755 --- a/build_all.sh +++ b/build_all.sh @@ -60,7 +60,7 @@ DIST_ENABLE=1 DIST_FOLDER="./dist" DIST_NAME="spice2x-$(date +%y)-$(date +%m)-$(date +%d).zip" DIST_COMMENT=${DIST_NAME}$'\n'"$GIT_BRANCH - $GIT_HEAD"$'\nThank you for playing.' -TARGETS_32="spicetools_stubs_kbt spicetools_stubs_kld spicetools_cfg spicetools_spice spicetools_spice_laa" +TARGETS_32="spicetools_stubs_kbt spicetools_stubs_kld spicetools_cfg spicetools_spice spicetools_spice_laa spicetools_stubs_cpusbxpkm" TARGETS_64="spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvEncodeAPI64 spicetools_stubs_nvcuvid spicetools_stubs_nvcuda spicetools_spice64" # determine build type @@ -181,7 +181,7 @@ fi echo "Copy files to output directory..." rm -rf ${OUTDIR} mkdir -p ${OUTDIR} -#mkdir -p ${OUTDIR}/stubs/32 +mkdir -p ${OUTDIR}/stubs/32 mkdir -p ${OUTDIR}/stubs/64 mkdir -p ${OUTDIR}/extras/largeaddressaware if false # ((DEBUG > 0)) @@ -200,6 +200,7 @@ then #cp ${BUILDDIR_64}/spicetools/64/nvEncodeAPI64.dll ${OUTDIR}/stubs/64 2>/dev/null #cp ${BUILDDIR_64}/spicetools/64/nvcuda.dll ${OUTDIR}/stubs/64 2>/dev/null #cp ${BUILDDIR_64}/spicetools/64/nvcuvid.dll ${OUTDIR}/stubs/64 2>/dev/null + #cp ${BUILDDIR_32}/spicetools/32/cpusbxpkm.dll ${OUTDIR}/stubs/32 2>/dev/null else # release files cp ${BUILDDIR_32}/spicetools/spicecfg.exe ${OUTDIR} 2>/dev/null @@ -213,6 +214,7 @@ else cp ${BUILDDIR_64}/spicetools/64/nvEncodeAPI64.dll ${OUTDIR}/stubs/64 2>/dev/null cp ${BUILDDIR_64}/spicetools/64/nvcuda.dll ${OUTDIR}/stubs/64 2>/dev/null cp ${BUILDDIR_64}/spicetools/64/nvcuvid.dll ${OUTDIR}/stubs/64 2>/dev/null + cp ${BUILDDIR_32}/spicetools/32/cpusbxpkm.dll ${OUTDIR}/stubs/32 2>/dev/null fi # pack source files to output directory diff --git a/cfg/Win32D.rc b/cfg/Win32D.rc index ed201c0..cec5bfd 100644 --- a/cfg/Win32D.rc +++ b/cfg/Win32D.rc @@ -9,7 +9,6 @@ #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -IDR_CHANGELOG RCDATA "../changelog.txt" IDR_LICENSES RCDATA "../licenses.txt" IDR_PATCHES RCDATA "../build/patches.json" IDR_README RCDATA "../readme.txt" diff --git a/cfg/api.cpp b/cfg/api.cpp index ace41c4..461c9d1 100644 --- a/cfg/api.cpp +++ b/cfg/api.cpp @@ -1,5 +1,8 @@ #include "api.h" +#include + +#include "launcher/superexit.h" #include "rawinput/rawinput.h" #include "rawinput/piuio.h" #include "util/time.h" @@ -64,18 +67,29 @@ GameAPI::Buttons::State GameAPI::Buttons::getState(rawinput::RawInputManager *ma auto current_button = &_button; auto alternatives = check_alts ? ¤t_button->getAlternatives() : nullptr; unsigned int button_count = 0; + std::optional window_has_focus; while (true) { // naive behavior if (current_button->isNaive()) { + GameAPI::Buttons::State state; + auto vkey = current_button->getVKey(); + + // check for focus + if (vkey != INVALID_VKEY && rawinput::NAIVE_REQUIRE_FOCUS) { + if (!window_has_focus.has_value()) { + window_has_focus = superexit::has_focus(); + } + if (!window_has_focus.value()) { + vkey = INVALID_VKEY; + } + } // read - auto vkey = current_button->getVKey(); - GameAPI::Buttons::State state; - if (vkey == 0xFF) { + if (vkey == INVALID_VKEY) { state = BUTTON_NOT_PRESSED; } else { - state = (GetAsyncKeyState(current_button->getVKey()) & 0x8000) ? BUTTON_PRESSED : BUTTON_NOT_PRESSED; + state = (GetAsyncKeyState(vkey) & 0x8000) ? BUTTON_PRESSED : BUTTON_NOT_PRESSED; } // invert @@ -106,6 +120,16 @@ GameAPI::Buttons::State GameAPI::Buttons::getState(rawinput::RawInputManager *ma auto &devid = current_button->getDeviceIdentifier(); auto device = manager->devices_get(devid, false); // TODO: fix to update only + // check for focus + if (device && rawinput::RAWINPUT_REQUIRE_FOCUS) { + if (!window_has_focus.has_value()) { + window_has_focus = superexit::has_focus(); + } + if (!window_has_focus.value()) { + device = nullptr; + } + } + // get state if device was marked as updated GameAPI::Buttons::State state = current_button->getLastState(); double *last_up = nullptr; @@ -571,6 +595,12 @@ float GameAPI::Analogs::getState(rawinput::Device *device, Analog &analog) { switch (device->type) { case rawinput::MOUSE: { + // check for focus + if (rawinput::NAIVE_REQUIRE_FOCUS && !superexit::has_focus()) { + value = analog.getLastState(); + break; + } + // get mouse position auto mouse = device->mouseInfo; long pos; diff --git a/cfg/button.cpp b/cfg/button.cpp index 439f9b3..134439f 100644 --- a/cfg/button.cpp +++ b/cfg/button.cpp @@ -284,7 +284,7 @@ std::string Button::getDisplayString(rawinput::RawInputManager* manager) { std::string vKeyString = fmt::format("{:#x}", vKey); // device must be existing - if (this->device_identifier.empty() && vKey == 0xFF) { + if (this->device_identifier.empty() && vKey == INVALID_VKEY) { return ""; } diff --git a/cfg/button.h b/cfg/button.h index 4043047..b320b11 100644 --- a/cfg/button.h +++ b/cfg/button.h @@ -33,12 +33,14 @@ enum ButtonAnalogType { extern const char *ButtonAnalogTypeStr[]; +constexpr unsigned short INVALID_VKEY = UINT16_C(0xFF); + class Button { private: std::vector